summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/demuxers/demux_ts.c268
1 files changed, 195 insertions, 73 deletions
diff --git a/src/demuxers/demux_ts.c b/src/demuxers/demux_ts.c
index a5c715c62..b22f1ffaa 100644
--- a/src/demuxers/demux_ts.c
+++ b/src/demuxers/demux_ts.c
@@ -291,6 +291,7 @@ typedef struct {
buf_element_t *buf;
unsigned int counter;
uint16_t descriptor_tag; /* +0x100 for PES stream IDs (no available TS descriptor tag?) */
+ uint8_t keep; /* used by demux_ts_dynamic_pmt_*() */
int corrupted_pes;
int input_normpos;
@@ -408,6 +409,153 @@ typedef struct {
config_values_t *config;
} demux_ts_class_t;
+/* TJ. dynamic PMT support. The idea is:
+ First, reuse unchanged pids and add new ones.
+ Then, comb out those who are no longer referenced.
+ For example, the Kaffeine dvb frontend preserves original pids but only
+ sends the currently user selected ones, plus matching generated pat/pmt */
+
+static int demux_ts_dynamic_pmt_find (demux_ts_t *this,
+ int pid, int type, unsigned int descriptor_tag) {
+ unsigned int i;
+ demux_ts_media *m;
+ for (i = 0; i < this->media_num; i++) {
+ m = &this->media[i];
+ if ((m->pid == pid) && ((m->type & BUF_MAJOR_MASK) == type)) {
+ /* mark this media decriptor for reuse */
+ m->keep = 1;
+ return i;
+ }
+ }
+ if (i < MAX_PIDS) {
+ /* prepare new media descriptor */
+#ifdef LOG_DYNAMIC_PMT
+ char *name = "";
+ if (type == BUF_VIDEO_BASE) name = "video";
+ else if (type == BUF_AUDIO_BASE) name = "audio";
+ else if (type == BUF_SPU_BASE) name = "subtitle";
+ printf ("demux_ts: new %s pid %d\n", name, pid);
+#endif
+ m = &this->media[i];
+ if (type == BUF_AUDIO_BASE) {
+ /* allocate new audio track as well */
+ if (this->audio_tracks_count >= MAX_AUDIO_TRACKS) {
+ xprintf (this->stream->xine, XINE_VERBOSITY_DEBUG,
+ "demux_ts: too many audio PIDs, ignoring pid %d\n", pid);
+ return -1;
+ }
+ m->type = type | this->audio_tracks_count;
+ this->audio_tracks[this->audio_tracks_count].pid = pid;
+ this->audio_tracks[this->audio_tracks_count].media_index = i;
+ this->audio_tracks_count++;
+ m->fifo = this->stream->audio_fifo;
+ } else {
+ m->type = type;
+ m->fifo = this->stream->video_fifo;
+ }
+ m->pid = pid;
+
+ m->buf = 0;
+ m->counter = INVALID_CC;
+ m->corrupted_pes = 1;
+
+ m->descriptor_tag = descriptor_tag;
+
+ m->keep = 1;
+ this->media_num++;
+ return i;
+ }
+ /* table full */
+ return -1;
+}
+
+static void demux_ts_dynamic_pmt_clean (demux_ts_t *this) {
+ int i, count = 0, tracks = 0, spus = 0;
+ /* densify media table */
+ for (i = 0; i < this->media_num; i++) {
+ demux_ts_media *m = &this->media[i];
+ int type = m->type & BUF_MAJOR_MASK;
+ int chan = m->type & 0xff;
+ if (m->keep) {
+ m->keep = 0;
+ if (type == BUF_VIDEO_BASE) {
+ /* adjust single video link */
+ this->videoMedia = count;
+ } else if (type == BUF_AUDIO_BASE) {
+ /* densify audio track table */
+ this->audio_tracks[chan].media_index = count;
+ if (chan > tracks) {
+ m->type = (m->type & ~0xff) | tracks;
+ this->audio_tracks[tracks] = this->audio_tracks[chan];
+ }
+ tracks++;
+ } else if (type == BUF_SPU_BASE) {
+ /* spu language table has already been rebuilt from scratch.
+ Adjust backlinks only */
+ while ((spus < this->spu_langs_count) && (this->spu_langs[spus].pid == m->pid)) {
+ this->spu_langs[spus].media_index = count;
+ spus++;
+ }
+ }
+ if (i > count) this->media[count] = *m;
+ count++;
+ } else {
+ /* drop this no longer needed media descriptor */
+#ifdef LOG_DYNAMIC_PMT
+ char *name = "";
+ if (type == BUF_VIDEO_BASE) name = "video";
+ else if (type == BUF_AUDIO_BASE) name = "audio";
+ else if (type == BUF_SPU_BASE) name = "subtitle";
+ printf ("demux_ts: dropped %s pid %d\n", name, m->pid);
+#endif
+ if (m->buf) {
+ m->buf->free_buffer (m->buf);
+ m->buf = NULL;
+ }
+ m->pid = INVALID_PID;
+ }
+ }
+ if ((tracks < this->audio_tracks_count) && this->audio_fifo) {
+ /* at least 1 audio track removed, tell audio decoder loop */
+ buf_element_t *b = this->audio_fifo->buffer_pool_alloc (this->audio_fifo);
+ b->type = BUF_CONTROL_RESET_TRACK_MAP;
+ b->decoder_info[1] = -1;
+ this->audio_fifo->put (this->audio_fifo, b);
+#ifdef LOG_DYNAMIC_PMT
+ printf ("demux_ts: new audio track map\n");
+#endif
+ }
+#ifdef LOG_DYNAMIC_PMT
+ printf ("demux_ts: using %d pids, %d audio %d subtitle channels\n", count, tracks, spus);
+#endif
+ /* adjust table sizes */
+ this->media_num = count;
+ this->audio_tracks_count = tracks;
+ /* should really have no effect */
+ this->spu_langs_count = spus;
+}
+
+static void demux_ts_dynamic_pmt_clear (demux_ts_t *this) {
+ unsigned int i;
+ for (i = 0; i < this->media_num; i++) {
+ if (this->media[i].buf) {
+ this->media[i].buf->free_buffer (this->media[i].buf);
+ this->media[i].buf = NULL;
+ }
+ }
+ this->media_num = 0;
+
+ this->videoPid = INVALID_PID;
+ this->audio_tracks_count = 0;
+ this->spu_pid = INVALID_PID;
+ this->spu_langs_count = 0;
+
+ this->pcr_pid = INVALID_PID;
+
+ this->last_pmt_crc = 0;
+}
+
+
static void demux_ts_tbre_reset (demux_ts_t *this) {
if (this->tbre_time <= TBRE_TIME) {
this->tbre_pid = INVALID_PID;
@@ -576,6 +724,9 @@ static void demux_ts_update_spu_channel(demux_ts_t *this)
this->spu_pid = lang->pid;
this->spu_media = lang->media_index;
+ /* multiple spu langs can share same media descriptor */
+ this->media[lang->media_index].type =
+ (this->media[lang->media_index].type & ~0xff) | this->current_spu_channel;
#ifdef TS_LOG
printf("demux_ts: DVBSUB: selecting lang: %s page %ld %ld\n",
lang->desc.lang, lang->desc.comp_page_id, lang->desc.aux_page_id);
@@ -779,11 +930,7 @@ static void demux_ts_parse_pat (demux_ts_t*this, unsigned char *original_pkt,
/* force PMT reparsing when pmt_pid changes */
if (this->pmt_pid[program_count] != pmt_pid) {
this->pmt_pid[program_count] = pmt_pid;
- this->audio_tracks_count = 0;
- this->last_pmt_crc = 0;
- this->videoPid = INVALID_PID;
- this->spu_pid = INVALID_PID;
- this->pcr_pid = INVALID_PID;
+ demux_ts_dynamic_pmt_clear (this);
if (this->pmt[program_count] != NULL) {
free(this->pmt[program_count]);
@@ -1147,29 +1294,6 @@ static void demux_ts_buffer_pes(demux_ts_t*this, unsigned char *ts,
}
}
-/*
- * Create a buffer for a PES stream.
- */
-static void demux_ts_pes_new(demux_ts_t*this,
- unsigned int mediaIndex,
- unsigned int pid,
- fifo_buffer_t *fifo,
- uint16_t descriptor) {
-
- demux_ts_media *m = &this->media[mediaIndex];
-
- /* new PID seen - initialise stuff */
- m->pid = pid;
- m->fifo = fifo;
-
- if (m->buf != NULL) m->buf->free_buffer(m->buf);
- m->buf = NULL;
- m->counter = INVALID_CC;
- m->descriptor_tag = descriptor;
- m->corrupted_pes = 1;
-}
-
-
/* Find the first ISO 639 language descriptor (tag 10) and
* store the 3-char code in dest, nullterminated. If no
* code is found, zero out dest.
@@ -1279,6 +1403,7 @@ static void demux_ts_parse_pmt (demux_ts_t *this,
char *ptr = NULL;
unsigned char len;
unsigned int offset=0;
+ int mi;
/*
* A new section should start with the payload unit start
@@ -1425,7 +1550,6 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
* PMT has changed (e.g. an IPTV streamer that's just changed its source),
* we'll get new PIDs that we should follow.
*/
- this->audio_tracks_count = 0;
this->videoPid = INVALID_PID;
this->spu_pid = INVALID_PID;
@@ -1481,9 +1605,12 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
#ifdef TS_PMT_LOG
printf ("demux_ts: PMT video pid 0x%.4x type %2.2x\n", pid, stream[0]);
#endif
- demux_ts_pes_new(this, this->media_num, pid, this->video_fifo,stream[0]);
- this->videoMedia = this->media_num;
- this->videoPid = pid;
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_VIDEO_BASE, stream[0]);
+ if (mi >= 0) {
+ this->videoMedia = mi;
+ this->videoPid = pid;
+ }
}
break;
@@ -1492,18 +1619,17 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
case ISO_13818_PART7_AUDIO:
case ISO_14496_PART3_AUDIO:
if (this->audio_tracks_count < MAX_AUDIO_TRACKS) {
- if (apid_check(this, pid) < 0) {
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_AUDIO_BASE, stream[0]);
+ if (mi >= 0) {
#ifdef TS_PMT_LOG
- printf ("demux_ts: PMT audio pid 0x%.4x type %2.2x\n", pid, stream[0]);
+ printf ("demux_ts: PMT audio pid 0x%.4x type %2.2x\n", pid, stream[0]);
#endif
- demux_ts_pes_new(this, this->media_num, pid, this->audio_fifo,stream[0]);
- this->audio_tracks[this->audio_tracks_count].pid = pid;
- this->audio_tracks[this->audio_tracks_count].media_index = this->media_num;
- this->media[this->media_num].type = this->audio_tracks_count;
- demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang,
- stream + 5, stream_info_length);
- this->audio_tracks_count++;
+ demux_ts_get_lang_desc (this,
+ this->audio_tracks[this->media[mi].type & 0xff].lang,
+ stream + 5, stream_info_length);
}
+
}
break;
case ISO_13818_PRIVATE:
@@ -1522,28 +1648,21 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
break;
case ISO_13818_PES_PRIVATE:
for (i = 5; i < coded_length; i += stream[i+1] + 2) {
- if (((stream[i] == DESCRIPTOR_AC3) || (stream[i] == DESCRIPTOR_EAC3)) &&
- (this->audio_tracks_count < MAX_AUDIO_TRACKS)) {
- if (apid_check(this, pid) < 0) {
+
+ if ((stream[i] == DESCRIPTOR_AC3) || (stream[i] == DESCRIPTOR_EAC3)) {
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_AUDIO_BASE,
+ stream[i] == DESCRIPTOR_AC3 ? STREAM_AUDIO_AC3 : HDMV_AUDIO_84_EAC3);
+ if (mi >= 0) {
#ifdef TS_PMT_LOG
printf ("demux_ts: PMT AC3 audio pid 0x%.4x type %2.2x\n", pid, stream[0]);
#endif
- if (stream[i] == DESCRIPTOR_AC3)
- demux_ts_pes_new(this, this->media_num, pid,
- this->audio_fifo, STREAM_AUDIO_AC3);
- else
- demux_ts_pes_new(this, this->media_num, pid,
- this->audio_fifo, HDMV_AUDIO_84_EAC3);
-
- this->audio_tracks[this->audio_tracks_count].pid = pid;
- this->audio_tracks[this->audio_tracks_count].media_index = this->media_num;
- this->media[this->media_num].type = this->audio_tracks_count;
- demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang,
- stream + 5, stream_info_length);
- this->audio_tracks_count++;
+ demux_ts_get_lang_desc (this,
+ this->audio_tracks[this->media[mi].type & 0xff].lang,
+ stream + 5, stream_info_length);
break;
}
}
+
/* Teletext */
else if (stream[i] == DESCRIPTOR_TELETEXT)
{
@@ -1561,6 +1680,10 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
else if (stream[i] == DESCRIPTOR_DVBSUB)
{
int pos;
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_SPU_BASE, stream[0]);
+ if (mi < 0) break;
+
for (pos = i + 2;
pos + 8 <= i + 2 + stream[i + 1]
&& this->spu_langs_count < MAX_SPU_LANGS;
@@ -1578,9 +1701,7 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
lang->desc.aux_page_id =
(stream[pos + 6] << 8) | stream[pos + 7];
lang->pid = pid;
- lang->media_index = this->media_num;
- this->media[this->media_num].type = no;
- demux_ts_pes_new(this, this->media_num, pid, this->video_fifo, stream[0]);
+ lang->media_index = mi;
demux_send_special_spu_buf( this, BUF_SPU_DVB, no );
#ifdef TS_LOG
printf("demux_ts: DVBSUB: pid 0x%.4x: %s page %ld %ld type %2.2x\n",
@@ -1615,15 +1736,17 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
break;
}
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_SPU_BASE, stream[0]);
+ if (mi < 0) break;
+
+
demux_ts_spu_lang *lang = &this->spu_langs[this->spu_langs_count];
memset(lang->desc.lang, 0, sizeof(lang->desc.lang));
/*memcpy(lang->desc.lang, &stream[pos], 3);*/
/*lang->desc.lang[3] = 0;*/
lang->pid = pid;
- lang->media_index = this->media_num;
- this->media[this->media_num].type = this->spu_langs_count;
- demux_ts_pes_new(this, this->media_num, pid, this->video_fifo, stream[0]);
+ lang->media_index = mi;
demux_send_special_spu_buf( this, BUF_SPU_HDMV, this->spu_langs_count );
this->spu_langs_count++;
#ifdef TS_PMT_LOG
@@ -1642,8 +1765,10 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
* if is does, we tag this as an audio stream.
* FIXME: This will need expanding if we ever see a DTS or other media format here.
*/
- if ((this->audio_tracks_count < MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) {
- if (apid_check(this,pid) < 0) {
+ if ((this->audio_tracks_count < MAX_AUDIO_TRACKS) && (stream[0] >= 0x80) ) {
+
+ mi = demux_ts_dynamic_pmt_find (this, pid, BUF_AUDIO_BASE, stream[0]);
+ if (mi >= 0) {
uint32_t format_identifier=0;
demux_ts_get_reg_desc(this, &format_identifier,
stream + 5, stream_info_length);
@@ -1652,13 +1777,9 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
( format_identifier == 0) ||
((format_identifier == 0x48444d56 || this->hdmv>0) && stream[0] == HDMV_AUDIO_80_PCM) /* BluRay PCM */) {
- demux_ts_pes_new(this, this->media_num, pid, this->audio_fifo, stream[0]);
- this->audio_tracks[this->audio_tracks_count].pid = pid;
- this->audio_tracks[this->audio_tracks_count].media_index = this->media_num;
- this->media[this->media_num].type = this->audio_tracks_count;
- demux_ts_get_lang_desc(this, this->audio_tracks[this->audio_tracks_count].lang,
- stream + 5, stream_info_length);
- this->audio_tracks_count++;
+ demux_ts_get_lang_desc (this,
+ this->audio_tracks[this->media[mi].type & 0xff].lang,
+ stream + 5, stream_info_length);
break;
}
}
@@ -1674,11 +1795,12 @@ printf("Program Number is %i, looking for %i\n",program_number,this->program_num
}
break;
}
- this->media_num++;
stream += coded_length;
section_length -= coded_length;
}
+ demux_ts_dynamic_pmt_clean (this);
+
/*
* Get the current PCR PID.
*/