Implement a lose interface for streaming internally in tvheadend.
This commit is contained in:
parent
f90324f925
commit
92409b644e
14 changed files with 313 additions and 131 deletions
2
Makefile
2
Makefile
|
@ -2,7 +2,7 @@
|
|||
|
||||
SRCS = main.c access.c dtable.c tcp.c http.c notify.c epg.c xmltv.c spawn.c
|
||||
|
||||
SRCS += packet.c
|
||||
SRCS += packet.c streaming.c
|
||||
|
||||
VPATH += dvr
|
||||
SRCS += dvr_db.c
|
||||
|
|
24
cwc.c
24
cwc.c
|
@ -888,6 +888,24 @@ cwc_transport_destroy(th_descrambler_t *td)
|
|||
free(ct);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static inline th_stream_t *
|
||||
cwc_find_stream_by_caid(th_transport_t *t, int caid)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
th_stream_t *st;
|
||||
streaming_component_t *sc;
|
||||
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
if(st->st_caid == caid)
|
||||
return st;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if our CAID's matches, and if so, link
|
||||
|
@ -908,11 +926,7 @@ cwc_transport_start(th_transport_t *t)
|
|||
if(cwc->cwc_caid == 0)
|
||||
continue;
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link)
|
||||
if(st->st_caid == cwc->cwc_caid)
|
||||
break;
|
||||
|
||||
if(st == NULL)
|
||||
if((st = cwc_find_stream_by_caid(t, cwc->cwc_caid)) == NULL)
|
||||
continue;
|
||||
|
||||
ct = calloc(1, sizeof(cwc_transport_t));
|
||||
|
|
|
@ -393,6 +393,7 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
|
|||
th_dvb_mux_instance_t *tdmi_src, *tdmi_dst;
|
||||
th_transport_t *t_src, *t_dst;
|
||||
th_stream_t *st_src, *st_dst;
|
||||
streaming_component_t *sc_src;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
|
@ -437,15 +438,16 @@ dvb_adapter_clone(th_dvb_adapter_t *dst, th_dvb_adapter_t *src)
|
|||
|
||||
pthread_mutex_lock(&t_src->tht_stream_mutex);
|
||||
|
||||
LIST_FOREACH(st_src, &t_src->tht_streams, st_link) {
|
||||
LIST_FOREACH(sc_src, &t_src->tht_streaming_pad.sp_components, sc_link) {
|
||||
st_src = (th_stream_t *)sc_src;
|
||||
|
||||
st_dst = transport_add_stream(t_dst,
|
||||
st_src->st_pid,
|
||||
st_src->st_type);
|
||||
st_src->st_sc.sc_type);
|
||||
|
||||
st_dst->st_tb = (AVRational){1, 90000};
|
||||
|
||||
memcpy(st_dst->st_lang, st_src->st_lang, 4);
|
||||
memcpy(st_dst->st_sc.sc_lang, st_src->st_sc.sc_lang, 4);
|
||||
st_dst->st_frame_duration = st_src->st_frame_duration;
|
||||
st_dst->st_caid = st_src->st_caid;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,8 @@ static int
|
|||
dvb_transport_start(th_transport_t *t, unsigned int weight, int status,
|
||||
int force_start)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
struct dmx_pes_filter_params dmx_param;
|
||||
th_stream_t *st;
|
||||
int w, fd, pid;
|
||||
|
@ -86,7 +88,8 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int status,
|
|||
}
|
||||
tdmi = t->tht_dvb_mux_instance;
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link) {
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
|
||||
fd = open(tda->tda_demux_path, O_RDWR);
|
||||
|
||||
|
@ -139,6 +142,8 @@ dvb_transport_start(th_transport_t *t, unsigned int weight, int status,
|
|||
static void
|
||||
dvb_transport_stop(th_transport_t *t)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
th_dvb_adapter_t *tda = t->tht_dvb_mux_instance->tdmi_adapter;
|
||||
th_stream_t *st;
|
||||
|
||||
|
@ -148,7 +153,8 @@ dvb_transport_stop(th_transport_t *t)
|
|||
LIST_REMOVE(t, tht_active_link);
|
||||
pthread_mutex_unlock(&tda->tda_delivery_mutex);
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link) {
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
close(st->st_demuxer_fd);
|
||||
st->st_demuxer_fd = -1;
|
||||
}
|
||||
|
|
1
packet.h
1
packet.h
|
@ -33,6 +33,7 @@ typedef struct th_pkt {
|
|||
int pkt_duration;
|
||||
int pkt_refcount;
|
||||
|
||||
uint8_t pkt_streamindex;
|
||||
uint8_t pkt_frametype;
|
||||
uint8_t pkt_commercial;
|
||||
|
||||
|
|
14
parsers.c
14
parsers.c
|
@ -117,20 +117,20 @@ parse_raw_mpeg(th_transport_t *t, th_stream_t *st, uint8_t *data,
|
|||
}
|
||||
|
||||
|
||||
switch(st->st_type) {
|
||||
case HTSTV_MPEG2VIDEO:
|
||||
switch(st->st_sc.sc_type) {
|
||||
case SCT_MPEG2VIDEO:
|
||||
parse_video(t, st, data, len, parse_mpeg2video);
|
||||
break;
|
||||
|
||||
case HTSTV_H264:
|
||||
case SCT_H264:
|
||||
parse_video(t, st, data, len, parse_h264);
|
||||
break;
|
||||
|
||||
case HTSTV_MPEG2AUDIO:
|
||||
case SCT_MPEG2AUDIO:
|
||||
parse_audio(t, st, data, len, start, parse_mpegaudio);
|
||||
break;
|
||||
|
||||
case HTSTV_AC3:
|
||||
case SCT_AC3:
|
||||
parse_audio(t, st, data, len, start, parse_ac3);
|
||||
break;
|
||||
|
||||
|
@ -897,8 +897,8 @@ parser_enqueue_packet(th_transport_t *t, th_stream_t *st, th_pkt_t *pkt)
|
|||
|
||||
/* Per stream type analysis */
|
||||
|
||||
switch(st->st_type) {
|
||||
case HTSTV_MPEG2VIDEO:
|
||||
switch(st->st_sc.sc_type) {
|
||||
case SCT_MPEG2VIDEO:
|
||||
for(i = 0; i < pkt->pkt_payloadlen && err == 0; i++) {
|
||||
sc = (sc << 8) | buf[i];
|
||||
|
||||
|
|
66
psi.c
66
psi.c
|
@ -92,7 +92,7 @@ psi_parse_pat(th_transport_t *t, uint8_t *ptr, int len,
|
|||
pid = (ptr[2] & 0x1f) << 8 | ptr[3];
|
||||
|
||||
if(prognum != 0) {
|
||||
st = transport_add_stream(t, pid, HTSTV_PMT);
|
||||
st = transport_add_stream(t, pid, SCT_PMT);
|
||||
st->st_section_docrc = 1;
|
||||
st->st_got_section = pmt_callback;
|
||||
|
||||
|
@ -177,7 +177,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
|
|||
int dllen;
|
||||
uint8_t dtag, dlen;
|
||||
uint16_t sid;
|
||||
tv_streamtype_t hts_stream_type;
|
||||
streaming_component_type_t hts_stream_type;
|
||||
th_stream_t *st;
|
||||
char lang[4];
|
||||
int frameduration;
|
||||
|
@ -208,7 +208,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
|
|||
|
||||
switch(dtag) {
|
||||
case DVB_DESC_CA:
|
||||
st = transport_add_stream(t, (ptr[2] & 0x1f) << 8 | ptr[3], HTSTV_CA);
|
||||
st = transport_add_stream(t, (ptr[2] & 0x1f) << 8 | ptr[3], SCT_CA);
|
||||
st->st_caid = (ptr[0] << 8) | ptr[1];
|
||||
break;
|
||||
|
||||
|
@ -233,17 +233,17 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
|
|||
switch(estype) {
|
||||
case 0x01:
|
||||
case 0x02:
|
||||
hts_stream_type = HTSTV_MPEG2VIDEO;
|
||||
hts_stream_type = SCT_MPEG2VIDEO;
|
||||
break;
|
||||
|
||||
case 0x03:
|
||||
case 0x04:
|
||||
case 0x81:
|
||||
hts_stream_type = HTSTV_MPEG2AUDIO;
|
||||
hts_stream_type = SCT_MPEG2AUDIO;
|
||||
break;
|
||||
|
||||
case 0x1b:
|
||||
hts_stream_type = HTSTV_H264;
|
||||
hts_stream_type = SCT_H264;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -268,12 +268,12 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
|
|||
|
||||
case DVB_DESC_TELETEXT:
|
||||
if(estype == 0x06)
|
||||
hts_stream_type = HTSTV_TELETEXT;
|
||||
hts_stream_type = SCT_TELETEXT;
|
||||
break;
|
||||
|
||||
case DVB_DESC_AC3:
|
||||
if(estype == 0x06 || estype == 0x81)
|
||||
hts_stream_type = HTSTV_AC3;
|
||||
hts_stream_type = SCT_AC3;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -285,7 +285,7 @@ psi_parse_pmt(th_transport_t *t, uint8_t *ptr, int len, int chksvcid)
|
|||
if(hts_stream_type != 0) {
|
||||
st = transport_add_stream(t, pid, hts_stream_type);
|
||||
st->st_tb = (AVRational){1, 90000};
|
||||
memcpy(st->st_lang, lang, 4);
|
||||
memcpy(st->st_sc.sc_lang, lang, 4);
|
||||
|
||||
if(st->st_frame_duration == 0)
|
||||
st->st_frame_duration = frameduration;
|
||||
|
@ -346,19 +346,19 @@ psi_build_pmt(th_muxer_t *tm, uint8_t *buf0, int maxlen, int pcrpid)
|
|||
continue;
|
||||
|
||||
switch(st->st_type) {
|
||||
case HTSTV_MPEG2VIDEO:
|
||||
case SCT_MPEG2VIDEO:
|
||||
c = 0x02;
|
||||
break;
|
||||
|
||||
case HTSTV_MPEG2AUDIO:
|
||||
case SCT_MPEG2AUDIO:
|
||||
c = 0x03;
|
||||
break;
|
||||
|
||||
case HTSTV_H264:
|
||||
case SCT_H264:
|
||||
c = 0x1b;
|
||||
break;
|
||||
|
||||
case HTSTV_AC3:
|
||||
case SCT_AC3:
|
||||
c = 0x06;
|
||||
break;
|
||||
|
||||
|
@ -377,7 +377,7 @@ psi_build_pmt(th_muxer_t *tm, uint8_t *buf0, int maxlen, int pcrpid)
|
|||
dlen = 0;
|
||||
|
||||
switch(st->st_type) {
|
||||
case HTSTV_AC3:
|
||||
case SCT_AC3:
|
||||
buf[0] = DVB_DESC_AC3;
|
||||
buf[1] = 1;
|
||||
buf[2] = 0; /* XXX: generate real AC3 desc */
|
||||
|
@ -525,15 +525,15 @@ psi_caid2name(uint16_t caid)
|
|||
*
|
||||
*/
|
||||
static struct strtab streamtypetab[] = {
|
||||
{ "MPEG2VIDEO", HTSTV_MPEG2VIDEO },
|
||||
{ "MPEG2AUDIO", HTSTV_MPEG2AUDIO },
|
||||
{ "H264", HTSTV_H264 },
|
||||
{ "AC3", HTSTV_AC3 },
|
||||
{ "TELETEXT", HTSTV_TELETEXT },
|
||||
{ "SUBTITLES", HTSTV_SUBTITLES },
|
||||
{ "CA", HTSTV_CA },
|
||||
{ "PMT", HTSTV_PMT },
|
||||
{ "PAT", HTSTV_PAT },
|
||||
{ "MPEG2VIDEO", SCT_MPEG2VIDEO },
|
||||
{ "MPEG2AUDIO", SCT_MPEG2AUDIO },
|
||||
{ "H264", SCT_H264 },
|
||||
{ "AC3", SCT_AC3 },
|
||||
{ "TELETEXT", SCT_TELETEXT },
|
||||
{ "SUBTITLES", SCT_SUBTITLES },
|
||||
{ "CA", SCT_CA },
|
||||
{ "PMT", SCT_PMT },
|
||||
{ "PAT", SCT_PAT },
|
||||
};
|
||||
|
||||
|
||||
|
@ -543,7 +543,7 @@ static struct strtab streamtypetab[] = {
|
|||
|
||||
|
||||
const char *
|
||||
htstvstreamtype2txt(tv_streamtype_t s)
|
||||
streaming_component_type2txt(streaming_component_type_t s)
|
||||
{
|
||||
return val2str(s, streamtypetab) ?: "INVALID";
|
||||
}
|
||||
|
@ -555,6 +555,8 @@ htstvstreamtype2txt(tv_streamtype_t s)
|
|||
void
|
||||
psi_save_transport_settings(htsmsg_t *m, th_transport_t *t)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
th_stream_t *st;
|
||||
htsmsg_t *sub;
|
||||
|
||||
|
@ -564,16 +566,18 @@ psi_save_transport_settings(htsmsg_t *m, th_transport_t *t)
|
|||
|
||||
lock_assert(&t->tht_stream_mutex);
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link) {
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
|
||||
sub = htsmsg_create();
|
||||
|
||||
htsmsg_add_u32(sub, "pid", st->st_pid);
|
||||
htsmsg_add_str(sub, "type", val2str(st->st_type, streamtypetab) ?: "?");
|
||||
htsmsg_add_str(sub, "type", val2str(sc->sc_type, streamtypetab) ?: "?");
|
||||
|
||||
if(st->st_lang[0])
|
||||
htsmsg_add_str(sub, "language", st->st_lang);
|
||||
if(sc->sc_lang[0])
|
||||
htsmsg_add_str(sub, "language", sc->sc_lang);
|
||||
|
||||
if(st->st_type == HTSTV_CA)
|
||||
if(sc->sc_type == SCT_CA)
|
||||
htsmsg_add_str(sub, "caid", psi_caid2name(st->st_caid));
|
||||
|
||||
if(st->st_frame_duration)
|
||||
|
@ -594,7 +598,7 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
|
|||
htsmsg_field_t *f;
|
||||
uint32_t u32;
|
||||
th_stream_t *st;
|
||||
tv_streamtype_t type;
|
||||
streaming_component_type_t type;
|
||||
const char *v;
|
||||
uint32_t pid, i;
|
||||
|
||||
|
@ -625,7 +629,7 @@ psi_load_transport_settings(htsmsg_t *m, th_transport_t *t)
|
|||
st->st_tb = (AVRational){1, 90000};
|
||||
|
||||
if((v = htsmsg_get_str(c, "language")) != NULL)
|
||||
av_strlcpy(st->st_lang, v, 4);
|
||||
av_strlcpy(st->st_sc.sc_lang, v, 4);
|
||||
|
||||
if(!htsmsg_get_u32(c, "frameduration", &u32))
|
||||
st->st_frame_duration = u32;
|
||||
|
|
30
streaming.c
Normal file
30
streaming.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/**
|
||||
* Streaming helpers
|
||||
* Copyright (C) 2008 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "tvhead.h"
|
||||
#include "streaming.h"
|
||||
|
||||
void
|
||||
streaming_pad_init(streaming_pad_t *sp, pthread_mutex_t *mutex)
|
||||
{
|
||||
LIST_INIT(&sp->sp_targets);
|
||||
LIST_INIT(&sp->sp_components);
|
||||
sp->sp_mutex = mutex;
|
||||
}
|
34
streaming.h
Normal file
34
streaming.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Stream plumbing, connects individual streaming components to each other
|
||||
* Copyright (C) 2008 Andreas Öman
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef STREAMING_H_
|
||||
#define STREAMING_H_
|
||||
|
||||
#include "tvhead.h"
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void streaming_pad_init(streaming_pad_t *pd, pthread_mutex_t *mutex);
|
||||
|
||||
void streaming_taget_init(streaming_target_t *st);
|
||||
|
||||
void streaming_target_connect(streaming_pad_t *pd, streaming_target_t *st);
|
||||
|
||||
#endif /* STREAMING_H_ */
|
59
transports.c
59
transports.c
|
@ -35,7 +35,7 @@
|
|||
#include "transports.h"
|
||||
#include "subscriptions.h"
|
||||
#include "tsdemux.h"
|
||||
|
||||
#include "streaming.h"
|
||||
#include "v4l.h"
|
||||
#include "psi.h"
|
||||
#include "packet.h"
|
||||
|
@ -62,6 +62,9 @@ static void transport_data_timeout(void *aux);
|
|||
static void
|
||||
transport_stop(th_transport_t *t)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
|
||||
th_descrambler_t *td;
|
||||
th_stream_t *st;
|
||||
|
||||
|
@ -84,7 +87,8 @@ transport_stop(th_transport_t *t)
|
|||
/**
|
||||
* Clean up each stream
|
||||
*/
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link) {
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
|
||||
if(st->st_parser != NULL)
|
||||
av_parser_close(st->st_parser);
|
||||
|
@ -208,6 +212,9 @@ transport_unlink_muxer(th_muxer_t *tm)
|
|||
int
|
||||
transport_start(th_transport_t *t, unsigned int weight, int force_start)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
|
||||
th_stream_t *st;
|
||||
AVCodec *c;
|
||||
enum CodecID id;
|
||||
|
@ -221,7 +228,12 @@ transport_start(th_transport_t *t, unsigned int weight, int force_start)
|
|||
|
||||
t->tht_dts_start = AV_NOPTS_VALUE;
|
||||
t->tht_pcr_drift = 0;
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link) {
|
||||
|
||||
/**
|
||||
* Initialize stream
|
||||
*/
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
|
||||
st->st_startcond = 0xffffffff;
|
||||
st->st_curdts = AV_NOPTS_VALUE;
|
||||
|
@ -237,11 +249,11 @@ transport_start(th_transport_t *t, unsigned int weight, int force_start)
|
|||
st->st_pcr_recovery_fails = 0;
|
||||
/* Open ffmpeg context and parser */
|
||||
|
||||
switch(st->st_type) {
|
||||
case HTSTV_MPEG2VIDEO: id = CODEC_ID_MPEG2VIDEO; break;
|
||||
case HTSTV_MPEG2AUDIO: id = CODEC_ID_MP3; break;
|
||||
case HTSTV_H264: id = CODEC_ID_H264; break;
|
||||
case HTSTV_AC3: id = CODEC_ID_AC3; break;
|
||||
switch(sc->sc_type) {
|
||||
case SCT_MPEG2VIDEO: id = CODEC_ID_MPEG2VIDEO; break;
|
||||
case SCT_MPEG2AUDIO: id = CODEC_ID_MP3; break;
|
||||
case SCT_H264: id = CODEC_ID_H264; break;
|
||||
case SCT_AC3: id = CODEC_ID_AC3; break;
|
||||
default: id = CODEC_ID_NONE; break;
|
||||
}
|
||||
|
||||
|
@ -424,7 +436,8 @@ transport_data_timeout(void *aux, int64_t now)
|
|||
void
|
||||
transport_destroy(th_transport_t *t)
|
||||
{
|
||||
th_stream_t *st;
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
th_subscription_t *s;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
@ -453,9 +466,9 @@ transport_destroy(th_transport_t *t)
|
|||
free(t->tht_chname);
|
||||
free(t->tht_provider);
|
||||
|
||||
while((st = LIST_FIRST(&t->tht_streams)) != NULL) {
|
||||
LIST_REMOVE(st, st_link);
|
||||
free(st);
|
||||
while((sc = LIST_FIRST(&sp->sp_components)) != NULL) {
|
||||
LIST_REMOVE(sc, sc_link);
|
||||
free(sc);
|
||||
}
|
||||
|
||||
abort();// serviceprobe_delete(t);
|
||||
|
@ -476,11 +489,12 @@ transport_create(const char *identifier, int type, int source_type)
|
|||
lock_assert(&global_lock);
|
||||
|
||||
pthread_mutex_init(&t->tht_stream_mutex, NULL);
|
||||
pthread_cond_init(&t->tht_stream_cond, NULL);
|
||||
t->tht_identifier = strdup(identifier);
|
||||
t->tht_type = type;
|
||||
t->tht_source_type = source_type;
|
||||
|
||||
streaming_pad_init(&t->tht_streaming_pad, &t->tht_stream_mutex);
|
||||
|
||||
LIST_INSERT_HEAD(&transporthash[hash], t, tht_hash_link);
|
||||
return t;
|
||||
}
|
||||
|
@ -510,25 +524,31 @@ transport_find_by_identifier(const char *identifier)
|
|||
*
|
||||
*/
|
||||
th_stream_t *
|
||||
transport_add_stream(th_transport_t *t, int pid, tv_streamtype_t type)
|
||||
transport_add_stream(th_transport_t *t, int pid,
|
||||
streaming_component_type_t type)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
th_stream_t *st;
|
||||
int i = 0;
|
||||
|
||||
lock_assert(&t->tht_stream_mutex);
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link) {
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
i++;
|
||||
if(pid != -1 && st->st_pid == pid)
|
||||
return st;
|
||||
}
|
||||
|
||||
st = calloc(1, sizeof(th_stream_t));
|
||||
st->st_index = i;
|
||||
sc = &st->st_sc;
|
||||
sc->sc_index = i;
|
||||
sc->sc_type = type;
|
||||
LIST_INSERT_HEAD(&sp->sp_components, sc, sc_link);
|
||||
|
||||
st->st_pid = pid;
|
||||
st->st_type = type;
|
||||
st->st_demuxer_fd = -1;
|
||||
LIST_INSERT_HEAD(&t->tht_streams, st, st_link);
|
||||
|
||||
TAILQ_INIT(&st->st_ptsq);
|
||||
TAILQ_INIT(&st->st_durationq);
|
||||
|
@ -633,7 +653,8 @@ transport_is_tv(th_transport_t *t)
|
|||
int
|
||||
transport_is_available(th_transport_t *t)
|
||||
{
|
||||
return transport_servicetype_txt(t) && LIST_FIRST(&t->tht_streams);
|
||||
return transport_servicetype_txt(t) &&
|
||||
LIST_FIRST(&t->tht_streaming_pad.sp_components);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
19
transports.h
19
transports.h
|
@ -38,7 +38,7 @@ void transport_unmap_channel(th_transport_t *t);
|
|||
th_transport_t *transport_find(channel_t *ch, unsigned int weight);
|
||||
|
||||
th_stream_t *transport_add_stream(th_transport_t *t, int pid,
|
||||
tv_streamtype_t type);
|
||||
streaming_component_type_t type);
|
||||
|
||||
void transport_set_priority(th_transport_t *t, int prio);
|
||||
|
||||
|
@ -62,4 +62,21 @@ void transport_remove_subscriber(th_transport_t *t, th_subscription_t *s);
|
|||
|
||||
//void transport_unlink_muxer(th_muxer_t *tm);
|
||||
|
||||
static inline th_stream_t *
|
||||
transport_find_stream_by_pid(th_transport_t *t, int pid)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
th_stream_t *st;
|
||||
streaming_component_t *sc;
|
||||
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
if(st->st_pid == pid)
|
||||
return st;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif /* TRANSPORTS_H */
|
||||
|
|
32
tsdemux.c
32
tsdemux.c
|
@ -53,7 +53,7 @@ got_section(th_transport_t *t, th_stream_t *st)
|
|||
{
|
||||
th_descrambler_t *td;
|
||||
|
||||
if(st->st_type == HTSTV_CA) {
|
||||
if(st->st_sc.sc_type == SCT_CA) {
|
||||
LIST_FOREACH(td, &t->tht_descramblers, td_transport_link)
|
||||
td->td_table(td, t, st,
|
||||
st->st_section->ps_data, st->st_section->ps_offset);
|
||||
|
@ -95,11 +95,11 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, uint8_t *tsb)
|
|||
off = tsb[3] & 0x20 ? tsb[4] + 5 : 4;
|
||||
pusi = tsb[1] & 0x40;
|
||||
|
||||
switch(st->st_type) {
|
||||
switch(st->st_sc.sc_type) {
|
||||
|
||||
case HTSTV_CA:
|
||||
case HTSTV_PAT:
|
||||
case HTSTV_PMT:
|
||||
case SCT_CA:
|
||||
case SCT_PAT:
|
||||
case SCT_PMT:
|
||||
if(st->st_section == NULL)
|
||||
st->st_section = calloc(1, sizeof(struct psi_section));
|
||||
|
||||
|
@ -125,7 +125,7 @@ ts_recv_packet0(th_transport_t *t, th_stream_t *st, uint8_t *tsb)
|
|||
got_section(t, st);
|
||||
break;
|
||||
|
||||
case HTSTV_TELETEXT:
|
||||
case SCT_TELETEXT:
|
||||
// teletext_input(t, tsb);
|
||||
break;
|
||||
|
||||
|
@ -195,12 +195,7 @@ ts_recv_packet1(th_transport_t *t, uint8_t *tsb)
|
|||
th_descrambler_t *td;
|
||||
|
||||
pid = (tsb[1] & 0x1f) << 8 | tsb[2];
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link)
|
||||
if(st->st_pid == pid)
|
||||
break;
|
||||
|
||||
if(st == NULL)
|
||||
if((st = transport_find_stream_by_pid(t, pid)) == NULL)
|
||||
return;
|
||||
|
||||
t->tht_packets = 1;
|
||||
|
@ -250,15 +245,8 @@ void
|
|||
ts_recv_packet2(th_transport_t *t, uint8_t *tsb)
|
||||
{
|
||||
th_stream_t *st;
|
||||
int pid;
|
||||
int pid = (tsb[1] & 0x1f) << 8 | tsb[2];
|
||||
|
||||
pid = (tsb[1] & 0x1f) << 8 | tsb[2];
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link)
|
||||
if(st->st_pid == pid)
|
||||
break;
|
||||
|
||||
if(st == NULL)
|
||||
return;
|
||||
|
||||
ts_recv_packet0(t, st, tsb);
|
||||
if((st = transport_find_stream_by_pid(t, pid)) != NULL)
|
||||
ts_recv_packet0(t, st, tsb);
|
||||
}
|
||||
|
|
115
tvhead.h
115
tvhead.h
|
@ -106,15 +106,70 @@ TAILQ_HEAD(th_refpkt_queue, th_refpkt);
|
|||
TAILQ_HEAD(th_muxpkt_queue, th_muxpkt);
|
||||
LIST_HEAD(autorec_list, autorec);
|
||||
TAILQ_HEAD(th_pktref_queue, th_pktref);
|
||||
LIST_HEAD(streaming_target_list, streaming_target);
|
||||
LIST_HEAD(streaming_component_list, streaming_component);
|
||||
|
||||
extern time_t dispatch_clock;
|
||||
extern int startupcounter;
|
||||
extern struct th_transport_list all_transports;
|
||||
extern struct channel_tree channel_name_tree;
|
||||
extern struct th_subscription_list subscriptions;
|
||||
|
||||
struct th_transport;
|
||||
struct th_stream;
|
||||
|
||||
typedef enum {
|
||||
SCT_MPEG2VIDEO = 1,
|
||||
SCT_MPEG2AUDIO,
|
||||
SCT_H264,
|
||||
SCT_AC3,
|
||||
SCT_TELETEXT,
|
||||
SCT_SUBTITLES,
|
||||
SCT_CA,
|
||||
SCT_PAT,
|
||||
SCT_PMT,
|
||||
} streaming_component_type_t;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
typedef struct streaming_component {
|
||||
LIST_ENTRY(streaming_component) sc_link;
|
||||
|
||||
streaming_component_type_t sc_type;
|
||||
int sc_index;
|
||||
|
||||
char sc_lang[4]; /* ISO 639 3-letter language code */
|
||||
|
||||
} streaming_component_t;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A streaming pad generates data.
|
||||
*
|
||||
* It has one or more streaming_targets attached to it
|
||||
*/
|
||||
typedef struct streaming_pad {
|
||||
struct streaming_target_list sp_targets;
|
||||
struct streaming_component_list sp_components;
|
||||
|
||||
pthread_mutex_t *sp_mutex; /* Mutex for protecting modification of
|
||||
st_targets and delivery.
|
||||
This needs to be created elsewhere */
|
||||
} streaming_pad_t;
|
||||
|
||||
|
||||
/**
|
||||
* A streaming target receives data
|
||||
*/
|
||||
typedef struct streaming_target {
|
||||
LIST_ENTRY(streaming_target) st_link;
|
||||
streaming_pad_t *st_pad; /* Source we are linked to */
|
||||
|
||||
pthread_mutex_t st_mutex; /* Protects sp_queue */
|
||||
pthread_cond_t st_cond; /* Condvar for signalling new
|
||||
packets */
|
||||
|
||||
struct th_pktref_queue st_queue;
|
||||
|
||||
} streaming_target_t;
|
||||
|
||||
|
||||
/*
|
||||
* Video4linux adapter
|
||||
|
@ -268,10 +323,14 @@ typedef void (pid_section_callback_t)(struct th_transport *t,
|
|||
uint8_t *section, int section_len);
|
||||
|
||||
/*
|
||||
* Stream, one media component for a transport
|
||||
* Stream, one media component for a transport.
|
||||
*
|
||||
* XXX: This should be renamed to 'elementary_stream' or something
|
||||
*/
|
||||
typedef struct th_stream {
|
||||
LIST_ENTRY(th_stream) st_link;
|
||||
|
||||
streaming_component_t st_sc;
|
||||
|
||||
uint16_t st_pid;
|
||||
uint8_t st_cc; /* Last CC */
|
||||
uint8_t st_cc_valid; /* Is CC valid at all? */
|
||||
|
@ -279,9 +338,7 @@ typedef struct th_stream {
|
|||
avgstat_t st_cc_errors;
|
||||
avgstat_t st_rate;
|
||||
|
||||
tv_streamtype_t st_type;
|
||||
int st_demuxer_fd;
|
||||
int st_index;
|
||||
int st_peak_presentation_delay; /* Max seen diff. of DTS and PTS */
|
||||
|
||||
struct psi_section *st_section;
|
||||
|
@ -338,8 +395,6 @@ typedef struct th_stream {
|
|||
|
||||
uint16_t st_caid;
|
||||
|
||||
char st_lang[4]; /* ISO 639 3-letter language code */
|
||||
|
||||
/* Remuxing information */
|
||||
AVRational st_tb;
|
||||
|
||||
|
@ -589,19 +644,6 @@ typedef struct th_transport {
|
|||
pthread_mutex_t tht_stream_mutex;
|
||||
|
||||
|
||||
/**
|
||||
* Condition variable to wakeup transport streaming thread.
|
||||
*
|
||||
* Currently unused (All streaming is executed on the source
|
||||
* thread)
|
||||
*/
|
||||
pthread_cond_t tht_stream_cond;
|
||||
|
||||
/**
|
||||
* List of all streams
|
||||
*/
|
||||
struct th_stream_list tht_streams;
|
||||
|
||||
/**
|
||||
* For simple streaming sources (such as video4linux) keeping
|
||||
* track of the video and audio stream is convenient.
|
||||
|
@ -653,6 +695,14 @@ typedef struct th_transport {
|
|||
*/
|
||||
int tht_pmt_seen;
|
||||
|
||||
|
||||
/**
|
||||
* Delivery pad, this is were we finally deliver all streaming output
|
||||
*/
|
||||
|
||||
streaming_pad_t tht_streaming_pad;
|
||||
|
||||
|
||||
} th_transport_t;
|
||||
|
||||
|
||||
|
@ -839,7 +889,7 @@ typedef struct tt_decoder {
|
|||
|
||||
char *utf8toprintable(const char *in);
|
||||
char *utf8tofilename(const char *in);
|
||||
const char *htstvstreamtype2txt(tv_streamtype_t s);
|
||||
const char *streaming_component_type2txt(streaming_component_type_t s);
|
||||
|
||||
static inline unsigned int tvh_strhash(const char *s, unsigned int mod)
|
||||
{
|
||||
|
@ -879,4 +929,15 @@ getclock_hires(void)
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
extern time_t dispatch_clock;
|
||||
extern int startupcounter;
|
||||
extern struct th_transport_list all_transports;
|
||||
extern struct channel_tree channel_name_tree;
|
||||
extern struct th_subscription_list subscriptions;
|
||||
|
||||
struct th_transport;
|
||||
struct th_stream;
|
||||
|
||||
#endif /* TV_HEAD_H */
|
||||
|
|
|
@ -500,6 +500,8 @@ extjs_dvbadapter(http_connection_t *hc, const char *remain, void *opaque)
|
|||
static htsmsg_t *
|
||||
build_transport_msg(th_transport_t *t)
|
||||
{
|
||||
streaming_pad_t *sp = &t->tht_streaming_pad;
|
||||
streaming_component_t *sc;
|
||||
htsmsg_t *r = htsmsg_create();
|
||||
th_stream_t *st;
|
||||
|
||||
|
@ -522,15 +524,17 @@ build_transport_msg(th_transport_t *t)
|
|||
subtitles[0] = 0;
|
||||
scrambling[0] = 0;
|
||||
|
||||
LIST_FOREACH(st, &t->tht_streams, st_link) {
|
||||
switch(st->st_type) {
|
||||
case HTSTV_TELETEXT:
|
||||
case HTSTV_SUBTITLES:
|
||||
case HTSTV_PAT:
|
||||
case HTSTV_PMT:
|
||||
LIST_FOREACH(sc, &sp->sp_components, sc_link) {
|
||||
st = (th_stream_t *)sc;
|
||||
|
||||
switch(sc->sc_type) {
|
||||
case SCT_TELETEXT:
|
||||
case SCT_SUBTITLES:
|
||||
case SCT_PAT:
|
||||
case SCT_PMT:
|
||||
break;
|
||||
|
||||
case HTSTV_MPEG2VIDEO:
|
||||
case SCT_MPEG2VIDEO:
|
||||
snprintf(video + strlen(video), sizeof(video) - strlen(video),
|
||||
"%sMPEG-2 (PID:%d", strlen(video) > 0 ? ", " : "",
|
||||
st->st_pid);
|
||||
|
@ -546,33 +550,33 @@ build_transport_msg(th_transport_t *t)
|
|||
|
||||
break;
|
||||
|
||||
case HTSTV_H264:
|
||||
case SCT_H264:
|
||||
snprintf(video + strlen(video), sizeof(video) - strlen(video),
|
||||
"%sH.264 (PID:%d", strlen(video) > 0 ? ", " : "",
|
||||
st->st_pid);
|
||||
goto video;
|
||||
|
||||
case HTSTV_MPEG2AUDIO:
|
||||
case SCT_MPEG2AUDIO:
|
||||
snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio),
|
||||
"%sMPEG-2 (PID:%d", strlen(audio) > 0 ? ", " : "",
|
||||
st->st_pid);
|
||||
audio:
|
||||
if(st->st_lang[0]) {
|
||||
if(sc->sc_lang[0]) {
|
||||
snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio),
|
||||
", languange: \"%s\")", st->st_lang);
|
||||
", languange: \"%s\")", sc->sc_lang);
|
||||
} else {
|
||||
snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio),
|
||||
")");
|
||||
}
|
||||
break;
|
||||
|
||||
case HTSTV_AC3:
|
||||
case SCT_AC3:
|
||||
snprintf(audio + strlen(audio), sizeof(audio) - strlen(audio),
|
||||
"%sAC3 (PID:%d", strlen(audio) > 0 ? ", " : "",
|
||||
st->st_pid);
|
||||
goto audio;
|
||||
|
||||
case HTSTV_CA:
|
||||
case SCT_CA:
|
||||
snprintf(scrambling + strlen(scrambling),
|
||||
sizeof(scrambling) - strlen(scrambling),
|
||||
"%s%s", strlen(scrambling) > 0 ? ", " : "",
|
||||
|
|
Loading…
Add table
Reference in a new issue