diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/demuxers/demux_ts.c | 268 |
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. */ |