Message ID | 20220917170843.308894-1-scott.the.elm@gmail.com |
---|---|
State | New |
Headers | show |
Series | [FFmpeg-devel] mpegts: identify and demux DSMCC-B/MHEG streams | expand |
Context | Check | Description |
---|---|---|
yinshiyou/make_loongarch64 | success | Make finished |
yinshiyou/make_fate_loongarch64 | success | Make fate finished |
andriy/make_x86 | success | Make finished |
andriy/make_fate_x86 | success | Make fate finished |
Ping for review. On 9/17/22 13:08, Scott Theisen wrote: > These changes are from MythTV. > --- > > The `AV_CODEC_ID`s are probably in the wrong place since these are > data codecs, but that is where they are In MythTV. > > There was also a related change to libavformat/demux.c's > avformat_find_stream_info() trying to optimize it for MHEG streams, > but it is unnecessary and was causing FATE to fail. > > libavcodec/codec_desc.c | 12 +++ > libavcodec/codec_id.h | 6 ++ > libavformat/avformat.h | 5 + > libavformat/mpegts.c | 199 +++++++++++++++++++++++++++++++++++++++- > libavformat/mpegts.h | 17 ++++ > 5 files changed, 237 insertions(+), 2 deletions(-) > > diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c > index 648c518b3c..0e54087863 100644 > --- a/libavcodec/codec_desc.c > +++ b/libavcodec/codec_desc.c > @@ -3488,6 +3488,18 @@ static const AVCodecDescriptor codec_descriptors[] = { > .props = AV_CODEC_PROP_TEXT_SUB, > .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), > }, > + { > + .id = AV_CODEC_ID_DVB_VBI, > + .type = AVMEDIA_TYPE_DATA, > + .name = "dvb_vbi", > + .long_name = NULL_IF_CONFIG_SMALL("dvb teletext"), > + }, > + { > + .id = AV_CODEC_ID_DSMCC_B, > + .type = AVMEDIA_TYPE_DATA, > + .name = "dsmcc_b", > + .long_name = NULL_IF_CONFIG_SMALL("DSMCC B"), > + }, > > /* other kind of codecs and pseudo-codecs */ > { > diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h > index bc8226ff07..7e2198a800 100644 > --- a/libavcodec/codec_id.h > +++ b/libavcodec/codec_id.h > @@ -559,6 +559,12 @@ enum AVCodecID { > AV_CODEC_ID_TTML, > AV_CODEC_ID_ARIB_CAPTION, > > + /* teletext codecs */ > + AV_CODEC_ID_DVB_VBI, > + > + /* DSMCC codec */ > + AV_CODEC_ID_DSMCC_B, > + > /* other specific kind of codecs (generally used for attachments) */ > AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. > AV_CODEC_ID_TTF = 0x18000, > diff --git a/libavformat/avformat.h b/libavformat/avformat.h > index 9d46875cce..664a1afa61 100644 > --- a/libavformat/avformat.h > +++ b/libavformat/avformat.h > @@ -1117,6 +1117,11 @@ typedef struct AVStream { > * > */ > int pts_wrap_bits; > + > + /* MHEG support */ > + int component_tag; ///< Component tag given in PMT > + int carousel_id; > + int data_id; > } AVStream; > > struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); > diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c > index 8a3436f2be..be8edd9e62 100644 > --- a/libavformat/mpegts.c > +++ b/libavformat/mpegts.c > @@ -46,6 +46,15 @@ > #include <iconv.h> > #endif > > +typedef struct SectionContext { > + int pid; > + int stream_type; > + int new_packet; > + MpegTSContext *ts; > + AVFormatContext *stream; > + AVStream *st; > +} SectionContext; > + > /* maximum size in which we look for synchronization if > * synchronization is lost */ > #define MAX_RESYNC_SIZE 65536 > @@ -412,6 +421,8 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid) > return !used && discarded; > } > > +static void mpegts_push_section(MpegTSFilter *filter, const uint8_t *section, int section_len); > + > /** > * Assemble PES packets out of TS packets, and then call the "section_cb" > * function when they are complete. > @@ -438,6 +449,11 @@ static void write_section_data(MpegTSContext *ts, MpegTSFilter *tss1, > tss->section_index += len; > } > > + if (tss->section_cb == mpegts_push_section) { > + SectionContext *sect = tss->opaque; > + sect->new_packet = 1; > + } > + > offset = 0; > cur_section_buf = tss->section_buf; > while (cur_section_buf - tss->section_buf < MAX_SECTION_SIZE && cur_section_buf[0] != 0xff) { > @@ -798,6 +814,7 @@ static const StreamType ISO_types[] = { > { 0x02, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, > { 0x03, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, > { 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, > + { 0x0b, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DSMCC_B }, /* DVB_CAROUSEL_ID */ > { 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC }, > { 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 }, > /* Makito encoder sets stream type 0x11 for AAC, > @@ -882,11 +899,20 @@ static const StreamType DESC_types[] = { > { 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */ > { 0x7a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC-3 descriptor */ > { 0x7b, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, > + { 0x13, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DSMCC_B }, /* DVB_CAROUSEL_ID */ > + { 0x45, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DVB_VBI }, /* DVB_VBI_DATA_ID */ > + { 0x46, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DVB_VBI }, /* DVB_VBI_TELETEXT_ID */ //FixMe type subtilte > { 0x56, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_TELETEXT }, > { 0x59, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_SUBTITLE }, /* subtitling descriptor */ > { 0 }, > }; > > +/* component tags */ > +static const StreamType COMPONENT_TAG_types[] = { > + { 0x0a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, > + { 0x52, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, > +}; > + > static void mpegts_find_stream_type(AVStream *st, > uint32_t stream_type, > const StreamType *types) > @@ -1979,7 +2005,13 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type > memcpy(extradata, *pp, 4); /* composition_page_id and ancillary_page_id */ > extradata += 5; > > - *pp += 4; > + { > + int comp_page = get16(pp, desc_end); > + int anc_page = get16(pp, desc_end); > + int sub_id = (anc_page << 16) | comp_page; > + if (sub_id && (st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE)) > + st->carousel_id = sub_id; > + } > } > > language[i * 4 - 1] = 0; > @@ -2023,8 +2055,45 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type > sti->request_probe = 50; > } > break; > + case DVB_BROADCAST_ID: > + st->data_id = get16(pp, desc_end); > + break; > + case DVB_CAROUSEL_ID: > + { > + int carId = 0; > + carId = get8(pp, desc_end); > + carId = (carId << 8) | get8(pp, desc_end); > + carId = (carId << 8) | get8(pp, desc_end); > + carId = (carId << 8) | get8(pp, desc_end); > + st->carousel_id = carId; > + } > + break; > case 0x52: /* stream identifier descriptor */ > sti->stream_identifier = 1 + get8(pp, desc_end); > + st->component_tag = sti->stream_identifier - 1; > + // DVB_DATA_STREAM: > + /* Audio and video are sometimes encoded in private streams labelled with > + * a component tag. */ > +#if 0 > + if (st->codecpar->codec_id == AV_CODEC_ID_NONE && > + desc_count == 1 && > + stream_type == STREAM_TYPE_PRIVATE_DATA) > + mpegts_find_stream_type(st, st->component_tag, > + COMPONENT_TAG_types); > +#endif > + break; > + case DVB_VBI_TELETEXT_ID: > + language[0] = get8(pp, desc_end); > + language[1] = get8(pp, desc_end); > + language[2] = get8(pp, desc_end); > + language[3] = 0; > + > + /* dvbci->txt_type = */ i = (get8(pp, desc_end)) >> 3; // not exported, defeat compiler -Wunused-value > + if (language[0]) > + av_dict_set(&st->metadata, "language", language, 0); > + break; > + case DVB_VBI_DATA_ID: > + // dvbci->vbi_data = 1; //not parsing the data service descriptors > break; > case METADATA_DESCRIPTOR: > if (get16(pp, desc_end) == 0xFFFF) > @@ -2307,6 +2376,34 @@ static int is_pes_stream(int stream_type, uint32_t prog_reg_desc) > (stream_type == 0x86 && prog_reg_desc == AV_RL32("CUEI")) ); > } > > +static SectionContext *add_section_stream(MpegTSContext *ts, int pid, int stream_type) > +{ > + MpegTSFilter *tss = ts->pids[pid]; > + SectionContext *sect = 0; > + if (tss) { /* filter already exists */ > + /* kill it, and start a new stream */ > + mpegts_close_filter(ts, tss); > + } > + > + /* create a SECTION context */ > + if (!(sect=av_mallocz(sizeof(SectionContext)))) { > + av_log(ts, AV_LOG_ERROR, "Error: av_mallocz() failed in add_section_stream"); > + return 0; > + } > + sect->ts = ts; > + sect->stream = ts->stream; > + sect->pid = pid; > + sect->stream_type = stream_type; > + tss = mpegts_open_section_filter(ts, pid, mpegts_push_section, sect, 1); > + if (!tss) { > + av_free(sect); > + av_log(ts, AV_LOG_ERROR, "Error: unable to open mpegts Section filter in add_section_stream"); > + return 0; > + } > + > + return sect; > +} > + > static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) > { > MpegTSContext *ts = filter->u.section_filter.opaque; > @@ -2425,7 +2522,56 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len > stream_identifier = parse_stream_identifier_desc(p, p_end) + 1; > > /* now create stream */ > - if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { > + if (stream_type == STREAM_TYPE_DSMCC_B) > + { > + SectionContext *sect = NULL; > + int idx = -1; > + > + if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_SECTION && > + ts->pids[pid]->u.section_filter.section_cb == mpegts_push_section) { > + // u.section_filter.opaque may be the MpegTSContext, so test the section_cb > + sect = (SectionContext*) ts->pids[pid]->u.section_filter.opaque; > + } > + if (!sect) { > + sect = add_section_stream(ts, pid, stream_type); > + } > + if (!sect) > + { > + av_log(ts, AV_LOG_ERROR, "mpegts_add_stream: " > + "error creating Section context for pid 0x%x with type %i\n", > + pid, stream_type); > + goto out; > + } > + > + idx = ff_find_stream_index(ts->stream, pid); > + if (idx >= 0) { > + st = ts->stream->streams[idx]; > + av_log(ts, AV_LOG_DEBUG, "mpegts_add_stream: " > + "reusing stream #%d, has id 0x%x and codec %s, type %s at 0x%p\n", > + st->index, st->id, avcodec_get_name(st->codecpar->codec_id), > + av_get_media_type_string(st->codecpar->codec_type), st); > + } > + if (!st) { > + st = avformat_new_stream(sect->stream, NULL); > + } > + if (!st) { > + goto out; > + } > + sect->st = st; > + sect->st->id = sect->pid; > + > + avpriv_set_pts_info(sect->st, 33, 1, 90000); > + > + sect->st->codecpar->codec_type = AVMEDIA_TYPE_DATA; > + sect->st->codecpar->codec_id = AV_CODEC_ID_DSMCC_B; > + sect->st->priv_data = sect; > + ffstream(sect->st)->need_parsing = AVSTREAM_PARSE_NONE; > + > + av_log(ts, AV_LOG_DEBUG, "mpegts_add_stream: " > + "stream #%d, has id 0x%x and codec %s, type %s at 0x%p\n", > + st->index, st->id, avcodec_get_name(st->codecpar->codec_id), > + av_get_media_type_string(st->codecpar->codec_type), st); > + } else if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { > pes = ts->pids[pid]->u.pes_filter.opaque; > if (ts->merge_pmt_versions && !pes->st) { > st = find_matching_stream(ts, pid, h->id, stream_identifier, i, &old_program); > @@ -2527,6 +2673,55 @@ out: > av_free(mp4_descr[i].dec_config_descr); > } > > +/* mpegts_push_section: return one or more tables. The tables may not completely fill > + the packet and there may be stuffing bytes at the end. > + This is complicated because a single TS packet may result in several tables being > + produced. We may have a "start" bit indicating, in effect, the end of a table but > + the rest of the TS packet after the start may be filled with one or more small tables. > +*/ > +static void mpegts_push_section(MpegTSFilter *filter, const uint8_t *section, int section_len) > +{ > + SectionContext *sect = filter->u.section_filter.opaque; > + MpegTSContext *ts = sect->ts; > + SectionHeader header; > + AVPacket *pkt = ts->pkt; > + const uint8_t *p = section, *p_end = section + section_len - 4; > + > + if (parse_section_header(&header, &p, p_end) < 0) > + { > + av_log(ts, AV_LOG_DEBUG, "Unable to parse header\n"); > + return; > + } > + > + if (sect->new_packet && pkt && sect->st && pkt->size == -1) { > + int pktLen = section_len + 184; /* Add enough for a complete TS payload. */ > + sect->new_packet = 0; > + av_packet_unref(pkt); > + if (av_new_packet(pkt, pktLen) == 0) { > + memcpy(pkt->data, section, section_len); > + memset(pkt->data+section_len, 0xff, pktLen-section_len); > + pkt->stream_index = sect->st->index; > + ts->stop_parse = 1; > + } > + } else if (pkt->data) { /* We've already added at least one table. */ > + uint8_t *data = pkt->data; > + int space = pkt->size; > + int table_size = 0; > + while (space > 3 + table_size) { > + table_size = (((data[1] & 0xf) << 8) | data[2]) + 3; > + if (table_size < space) { > + space -= table_size; > + data += table_size; > + } /* Otherwise we've got filler. */ > + } > + if (space < section_len) { > + av_log(ts, AV_LOG_DEBUG, "Insufficient space for additional packet\n"); > + return; > + } > + memcpy(data, section, section_len); > + } > +} > + > static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) > { > MpegTSContext *ts = filter->u.section_filter.opaque; > diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h > index a48f14e768..6f57af7786 100644 > --- a/libavformat/mpegts.h > +++ b/libavformat/mpegts.h > @@ -122,6 +122,7 @@ > #define STREAM_TYPE_AUDIO_MPEG2 0x04 > #define STREAM_TYPE_PRIVATE_SECTION 0x05 > #define STREAM_TYPE_PRIVATE_DATA 0x06 > +#define STREAM_TYPE_DSMCC_B 0x0b > #define STREAM_TYPE_AUDIO_AAC 0x0f > #define STREAM_TYPE_AUDIO_AAC_LATM 0x11 > #define STREAM_TYPE_VIDEO_MPEG4 0x10 > @@ -139,6 +140,22 @@ > #define STREAM_TYPE_AUDIO_TRUEHD 0x83 > #define STREAM_TYPE_AUDIO_EAC3 0x87 > > +#define STREAM_TYPE_AUDIO_MISC_DTS 0x8a > +#define STREAM_TYPE_AUDIO_HDMV_AC3_PLUS 0x84 > +#define STREAM_TYPE_AUDIO_HDMV_DTS_HD 0x85 > +#define STREAM_TYPE_AUDIO_HDMV_DTS_HD_MASTER 0x86 > + > +#define STREAM_TYPE_SUBTITLE_DVB 0x100 > +#define STREAM_TYPE_VBI_DVB 0x101 > + > +#define DVB_CAROUSEL_ID 0x13 > +#define DVB_VBI_DATA_ID 0x45 > +#define DVB_VBI_TELETEXT_ID 0x46 > +#define DVB_TELETEXT_ID 0x56 > +#define DVB_SUBT_DESCID 0x59 > +#define DVB_BROADCAST_ID 0x66 > +#define DVB_DATA_STREAM 0x52 > + > /* ISO/IEC 13818-1 Table 2-22 */ > #define STREAM_ID_PROGRAM_STREAM_MAP 0xbc > #define STREAM_ID_PRIVATE_STREAM_1 0xbd
Ping for review. Thanks in advance, Scott Theisen On 11/13/22 18:19, Scott Theisen wrote: > Ping for review. > > On 9/17/22 13:08, Scott Theisen wrote: >> These changes are from MythTV. >> --- >> >> The `AV_CODEC_ID`s are probably in the wrong place since these are >> data codecs, but that is where they are In MythTV. >> >> There was also a related change to libavformat/demux.c's >> avformat_find_stream_info() trying to optimize it for MHEG streams, >> but it is unnecessary and was causing FATE to fail. >> >> libavcodec/codec_desc.c | 12 +++ >> libavcodec/codec_id.h | 6 ++ >> libavformat/avformat.h | 5 + >> libavformat/mpegts.c | 199 +++++++++++++++++++++++++++++++++++++++- >> libavformat/mpegts.h | 17 ++++ >> 5 files changed, 237 insertions(+), 2 deletions(-) >> >> diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c >> index 648c518b3c..0e54087863 100644 >> --- a/libavcodec/codec_desc.c >> +++ b/libavcodec/codec_desc.c >> @@ -3488,6 +3488,18 @@ static const AVCodecDescriptor >> codec_descriptors[] = { >> .props = AV_CODEC_PROP_TEXT_SUB, >> .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), >> }, >> + { >> + .id = AV_CODEC_ID_DVB_VBI, >> + .type = AVMEDIA_TYPE_DATA, >> + .name = "dvb_vbi", >> + .long_name = NULL_IF_CONFIG_SMALL("dvb teletext"), >> + }, >> + { >> + .id = AV_CODEC_ID_DSMCC_B, >> + .type = AVMEDIA_TYPE_DATA, >> + .name = "dsmcc_b", >> + .long_name = NULL_IF_CONFIG_SMALL("DSMCC B"), >> + }, >> /* other kind of codecs and pseudo-codecs */ >> { >> diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h >> index bc8226ff07..7e2198a800 100644 >> --- a/libavcodec/codec_id.h >> +++ b/libavcodec/codec_id.h >> @@ -559,6 +559,12 @@ enum AVCodecID { >> AV_CODEC_ID_TTML, >> AV_CODEC_ID_ARIB_CAPTION, >> + /* teletext codecs */ >> + AV_CODEC_ID_DVB_VBI, >> + >> + /* DSMCC codec */ >> + AV_CODEC_ID_DSMCC_B, >> + >> /* other specific kind of codecs (generally used for >> attachments) */ >> AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID >> pointing at the start of various fake codecs. >> AV_CODEC_ID_TTF = 0x18000, >> diff --git a/libavformat/avformat.h b/libavformat/avformat.h >> index 9d46875cce..664a1afa61 100644 >> --- a/libavformat/avformat.h >> +++ b/libavformat/avformat.h >> @@ -1117,6 +1117,11 @@ typedef struct AVStream { >> * >> */ >> int pts_wrap_bits; >> + >> + /* MHEG support */ >> + int component_tag; ///< Component tag given in PMT >> + int carousel_id; >> + int data_id; >> } AVStream; >> struct AVCodecParserContext *av_stream_get_parser(const AVStream >> *s); >> diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c >> index 8a3436f2be..be8edd9e62 100644 >> --- a/libavformat/mpegts.c >> +++ b/libavformat/mpegts.c >> @@ -46,6 +46,15 @@ >> #include <iconv.h> >> #endif >> +typedef struct SectionContext { >> + int pid; >> + int stream_type; >> + int new_packet; >> + MpegTSContext *ts; >> + AVFormatContext *stream; >> + AVStream *st; >> +} SectionContext; >> + >> /* maximum size in which we look for synchronization if >> * synchronization is lost */ >> #define MAX_RESYNC_SIZE 65536 >> @@ -412,6 +421,8 @@ static int discard_pid(MpegTSContext *ts, >> unsigned int pid) >> return !used && discarded; >> } >> +static void mpegts_push_section(MpegTSFilter *filter, const >> uint8_t *section, int section_len); >> + >> /** >> * Assemble PES packets out of TS packets, and then call the >> "section_cb" >> * function when they are complete. >> @@ -438,6 +449,11 @@ static void write_section_data(MpegTSContext >> *ts, MpegTSFilter *tss1, >> tss->section_index += len; >> } >> + if (tss->section_cb == mpegts_push_section) { >> + SectionContext *sect = tss->opaque; >> + sect->new_packet = 1; >> + } >> + >> offset = 0; >> cur_section_buf = tss->section_buf; >> while (cur_section_buf - tss->section_buf < MAX_SECTION_SIZE && >> cur_section_buf[0] != 0xff) { >> @@ -798,6 +814,7 @@ static const StreamType ISO_types[] = { >> { 0x02, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, >> { 0x03, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, >> { 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, >> + { 0x0b, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DSMCC_B }, /* >> DVB_CAROUSEL_ID */ >> { 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC }, >> { 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 }, >> /* Makito encoder sets stream type 0x11 for AAC, >> @@ -882,11 +899,20 @@ static const StreamType DESC_types[] = { >> { 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* >> AC-3 descriptor */ >> { 0x7a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* >> E-AC-3 descriptor */ >> { 0x7b, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, >> + { 0x13, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DSMCC_B }, /* >> DVB_CAROUSEL_ID */ >> + { 0x45, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DVB_VBI }, /* >> DVB_VBI_DATA_ID */ >> + { 0x46, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DVB_VBI }, /* >> DVB_VBI_TELETEXT_ID */ //FixMe type subtilte >> { 0x56, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_TELETEXT }, >> { 0x59, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_SUBTITLE }, /* >> subtitling descriptor */ >> { 0 }, >> }; >> +/* component tags */ >> +static const StreamType COMPONENT_TAG_types[] = { >> + { 0x0a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, >> + { 0x52, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, >> +}; >> + >> static void mpegts_find_stream_type(AVStream *st, >> uint32_t stream_type, >> const StreamType *types) >> @@ -1979,7 +2005,13 @@ int ff_parse_mpeg2_descriptor(AVFormatContext >> *fc, AVStream *st, int stream_type >> memcpy(extradata, *pp, 4); /* >> composition_page_id and ancillary_page_id */ >> extradata += 5; >> - *pp += 4; >> + { >> + int comp_page = get16(pp, desc_end); >> + int anc_page = get16(pp, desc_end); >> + int sub_id = (anc_page << 16) | comp_page; >> + if (sub_id && (st->codecpar->codec_id == >> AV_CODEC_ID_DVB_SUBTITLE)) >> + st->carousel_id = sub_id; >> + } >> } >> language[i * 4 - 1] = 0; >> @@ -2023,8 +2055,45 @@ int ff_parse_mpeg2_descriptor(AVFormatContext >> *fc, AVStream *st, int stream_type >> sti->request_probe = 50; >> } >> break; >> + case DVB_BROADCAST_ID: >> + st->data_id = get16(pp, desc_end); >> + break; >> + case DVB_CAROUSEL_ID: >> + { >> + int carId = 0; >> + carId = get8(pp, desc_end); >> + carId = (carId << 8) | get8(pp, desc_end); >> + carId = (carId << 8) | get8(pp, desc_end); >> + carId = (carId << 8) | get8(pp, desc_end); >> + st->carousel_id = carId; >> + } >> + break; >> case 0x52: /* stream identifier descriptor */ >> sti->stream_identifier = 1 + get8(pp, desc_end); >> + st->component_tag = sti->stream_identifier - 1; >> + // DVB_DATA_STREAM: >> + /* Audio and video are sometimes encoded in private streams >> labelled with >> + * a component tag. */ >> +#if 0 >> + if (st->codecpar->codec_id == AV_CODEC_ID_NONE && >> + desc_count == 1 && >> + stream_type == STREAM_TYPE_PRIVATE_DATA) >> + mpegts_find_stream_type(st, st->component_tag, >> + COMPONENT_TAG_types); >> +#endif >> + break; >> + case DVB_VBI_TELETEXT_ID: >> + language[0] = get8(pp, desc_end); >> + language[1] = get8(pp, desc_end); >> + language[2] = get8(pp, desc_end); >> + language[3] = 0; >> + >> + /* dvbci->txt_type = */ i = (get8(pp, desc_end)) >> 3; // >> not exported, defeat compiler -Wunused-value >> + if (language[0]) >> + av_dict_set(&st->metadata, "language", language, 0); >> + break; >> + case DVB_VBI_DATA_ID: >> + // dvbci->vbi_data = 1; //not parsing the data service >> descriptors >> break; >> case METADATA_DESCRIPTOR: >> if (get16(pp, desc_end) == 0xFFFF) >> @@ -2307,6 +2376,34 @@ static int is_pes_stream(int stream_type, >> uint32_t prog_reg_desc) >> (stream_type == 0x86 && prog_reg_desc == >> AV_RL32("CUEI")) ); >> } >> +static SectionContext *add_section_stream(MpegTSContext *ts, int >> pid, int stream_type) >> +{ >> + MpegTSFilter *tss = ts->pids[pid]; >> + SectionContext *sect = 0; >> + if (tss) { /* filter already exists */ >> + /* kill it, and start a new stream */ >> + mpegts_close_filter(ts, tss); >> + } >> + >> + /* create a SECTION context */ >> + if (!(sect=av_mallocz(sizeof(SectionContext)))) { >> + av_log(ts, AV_LOG_ERROR, "Error: av_mallocz() failed in >> add_section_stream"); >> + return 0; >> + } >> + sect->ts = ts; >> + sect->stream = ts->stream; >> + sect->pid = pid; >> + sect->stream_type = stream_type; >> + tss = mpegts_open_section_filter(ts, pid, mpegts_push_section, >> sect, 1); >> + if (!tss) { >> + av_free(sect); >> + av_log(ts, AV_LOG_ERROR, "Error: unable to open mpegts >> Section filter in add_section_stream"); >> + return 0; >> + } >> + >> + return sect; >> +} >> + >> static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, >> int section_len) >> { >> MpegTSContext *ts = filter->u.section_filter.opaque; >> @@ -2425,7 +2522,56 @@ static void pmt_cb(MpegTSFilter *filter, const >> uint8_t *section, int section_len >> stream_identifier = parse_stream_identifier_desc(p, p_end) >> + 1; >> /* now create stream */ >> - if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { >> + if (stream_type == STREAM_TYPE_DSMCC_B) >> + { >> + SectionContext *sect = NULL; >> + int idx = -1; >> + >> + if (ts->pids[pid] && ts->pids[pid]->type == >> MPEGTS_SECTION && >> + ts->pids[pid]->u.section_filter.section_cb == mpegts_push_section) { >> + // u.section_filter.opaque may be the MpegTSContext, >> so test the section_cb >> + sect = (SectionContext*) >> ts->pids[pid]->u.section_filter.opaque; >> + } >> + if (!sect) { >> + sect = add_section_stream(ts, pid, stream_type); >> + } >> + if (!sect) >> + { >> + av_log(ts, AV_LOG_ERROR, "mpegts_add_stream: " >> + "error creating Section context for pid 0x%x >> with type %i\n", >> + pid, stream_type); >> + goto out; >> + } >> + >> + idx = ff_find_stream_index(ts->stream, pid); >> + if (idx >= 0) { >> + st = ts->stream->streams[idx]; >> + av_log(ts, AV_LOG_DEBUG, "mpegts_add_stream: " >> + "reusing stream #%d, has id 0x%x and codec %s, >> type %s at 0x%p\n", >> + st->index, st->id, >> avcodec_get_name(st->codecpar->codec_id), >> + av_get_media_type_string(st->codecpar->codec_type), st); >> + } >> + if (!st) { >> + st = avformat_new_stream(sect->stream, NULL); >> + } >> + if (!st) { >> + goto out; >> + } >> + sect->st = st; >> + sect->st->id = sect->pid; >> + >> + avpriv_set_pts_info(sect->st, 33, 1, 90000); >> + >> + sect->st->codecpar->codec_type = AVMEDIA_TYPE_DATA; >> + sect->st->codecpar->codec_id = AV_CODEC_ID_DSMCC_B; >> + sect->st->priv_data = sect; >> + ffstream(sect->st)->need_parsing = AVSTREAM_PARSE_NONE; >> + >> + av_log(ts, AV_LOG_DEBUG, "mpegts_add_stream: " >> + "stream #%d, has id 0x%x and codec %s, type %s at >> 0x%p\n", >> + st->index, st->id, >> avcodec_get_name(st->codecpar->codec_id), >> + av_get_media_type_string(st->codecpar->codec_type), st); >> + } else if (ts->pids[pid] && ts->pids[pid]->type == >> MPEGTS_PES) { >> pes = ts->pids[pid]->u.pes_filter.opaque; >> if (ts->merge_pmt_versions && !pes->st) { >> st = find_matching_stream(ts, pid, h->id, >> stream_identifier, i, &old_program); >> @@ -2527,6 +2673,55 @@ out: >> av_free(mp4_descr[i].dec_config_descr); >> } >> +/* mpegts_push_section: return one or more tables. The tables may >> not completely fill >> + the packet and there may be stuffing bytes at the end. >> + This is complicated because a single TS packet may result in >> several tables being >> + produced. We may have a "start" bit indicating, in effect, the >> end of a table but >> + the rest of the TS packet after the start may be filled with one >> or more small tables. >> +*/ >> +static void mpegts_push_section(MpegTSFilter *filter, const uint8_t >> *section, int section_len) >> +{ >> + SectionContext *sect = filter->u.section_filter.opaque; >> + MpegTSContext *ts = sect->ts; >> + SectionHeader header; >> + AVPacket *pkt = ts->pkt; >> + const uint8_t *p = section, *p_end = section + section_len - 4; >> + >> + if (parse_section_header(&header, &p, p_end) < 0) >> + { >> + av_log(ts, AV_LOG_DEBUG, "Unable to parse header\n"); >> + return; >> + } >> + >> + if (sect->new_packet && pkt && sect->st && pkt->size == -1) { >> + int pktLen = section_len + 184; /* Add enough for a complete >> TS payload. */ >> + sect->new_packet = 0; >> + av_packet_unref(pkt); >> + if (av_new_packet(pkt, pktLen) == 0) { >> + memcpy(pkt->data, section, section_len); >> + memset(pkt->data+section_len, 0xff, pktLen-section_len); >> + pkt->stream_index = sect->st->index; >> + ts->stop_parse = 1; >> + } >> + } else if (pkt->data) { /* We've already added at least one >> table. */ >> + uint8_t *data = pkt->data; >> + int space = pkt->size; >> + int table_size = 0; >> + while (space > 3 + table_size) { >> + table_size = (((data[1] & 0xf) << 8) | data[2]) + 3; >> + if (table_size < space) { >> + space -= table_size; >> + data += table_size; >> + } /* Otherwise we've got filler. */ >> + } >> + if (space < section_len) { >> + av_log(ts, AV_LOG_DEBUG, "Insufficient space for >> additional packet\n"); >> + return; >> + } >> + memcpy(data, section, section_len); >> + } >> +} >> + >> static void pat_cb(MpegTSFilter *filter, const uint8_t *section, >> int section_len) >> { >> MpegTSContext *ts = filter->u.section_filter.opaque; >> diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h >> index a48f14e768..6f57af7786 100644 >> --- a/libavformat/mpegts.h >> +++ b/libavformat/mpegts.h >> @@ -122,6 +122,7 @@ >> #define STREAM_TYPE_AUDIO_MPEG2 0x04 >> #define STREAM_TYPE_PRIVATE_SECTION 0x05 >> #define STREAM_TYPE_PRIVATE_DATA 0x06 >> +#define STREAM_TYPE_DSMCC_B 0x0b >> #define STREAM_TYPE_AUDIO_AAC 0x0f >> #define STREAM_TYPE_AUDIO_AAC_LATM 0x11 >> #define STREAM_TYPE_VIDEO_MPEG4 0x10 >> @@ -139,6 +140,22 @@ >> #define STREAM_TYPE_AUDIO_TRUEHD 0x83 >> #define STREAM_TYPE_AUDIO_EAC3 0x87 >> +#define STREAM_TYPE_AUDIO_MISC_DTS 0x8a >> +#define STREAM_TYPE_AUDIO_HDMV_AC3_PLUS 0x84 >> +#define STREAM_TYPE_AUDIO_HDMV_DTS_HD 0x85 >> +#define STREAM_TYPE_AUDIO_HDMV_DTS_HD_MASTER 0x86 >> + >> +#define STREAM_TYPE_SUBTITLE_DVB 0x100 >> +#define STREAM_TYPE_VBI_DVB 0x101 >> + >> +#define DVB_CAROUSEL_ID 0x13 >> +#define DVB_VBI_DATA_ID 0x45 >> +#define DVB_VBI_TELETEXT_ID 0x46 >> +#define DVB_TELETEXT_ID 0x56 >> +#define DVB_SUBT_DESCID 0x59 >> +#define DVB_BROADCAST_ID 0x66 >> +#define DVB_DATA_STREAM 0x52 >> + >> /* ISO/IEC 13818-1 Table 2-22 */ >> #define STREAM_ID_PROGRAM_STREAM_MAP 0xbc >> #define STREAM_ID_PRIVATE_STREAM_1 0xbd >
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 648c518b3c..0e54087863 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3488,6 +3488,18 @@ static const AVCodecDescriptor codec_descriptors[] = { .props = AV_CODEC_PROP_TEXT_SUB, .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), }, + { + .id = AV_CODEC_ID_DVB_VBI, + .type = AVMEDIA_TYPE_DATA, + .name = "dvb_vbi", + .long_name = NULL_IF_CONFIG_SMALL("dvb teletext"), + }, + { + .id = AV_CODEC_ID_DSMCC_B, + .type = AVMEDIA_TYPE_DATA, + .name = "dsmcc_b", + .long_name = NULL_IF_CONFIG_SMALL("DSMCC B"), + }, /* other kind of codecs and pseudo-codecs */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index bc8226ff07..7e2198a800 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -559,6 +559,12 @@ enum AVCodecID { AV_CODEC_ID_TTML, AV_CODEC_ID_ARIB_CAPTION, + /* teletext codecs */ + AV_CODEC_ID_DVB_VBI, + + /* DSMCC codec */ + AV_CODEC_ID_DSMCC_B, + /* other specific kind of codecs (generally used for attachments) */ AV_CODEC_ID_FIRST_UNKNOWN = 0x18000, ///< A dummy ID pointing at the start of various fake codecs. AV_CODEC_ID_TTF = 0x18000, diff --git a/libavformat/avformat.h b/libavformat/avformat.h index 9d46875cce..664a1afa61 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -1117,6 +1117,11 @@ typedef struct AVStream { * */ int pts_wrap_bits; + + /* MHEG support */ + int component_tag; ///< Component tag given in PMT + int carousel_id; + int data_id; } AVStream; struct AVCodecParserContext *av_stream_get_parser(const AVStream *s); diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index 8a3436f2be..be8edd9e62 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -46,6 +46,15 @@ #include <iconv.h> #endif +typedef struct SectionContext { + int pid; + int stream_type; + int new_packet; + MpegTSContext *ts; + AVFormatContext *stream; + AVStream *st; +} SectionContext; + /* maximum size in which we look for synchronization if * synchronization is lost */ #define MAX_RESYNC_SIZE 65536 @@ -412,6 +421,8 @@ static int discard_pid(MpegTSContext *ts, unsigned int pid) return !used && discarded; } +static void mpegts_push_section(MpegTSFilter *filter, const uint8_t *section, int section_len); + /** * Assemble PES packets out of TS packets, and then call the "section_cb" * function when they are complete. @@ -438,6 +449,11 @@ static void write_section_data(MpegTSContext *ts, MpegTSFilter *tss1, tss->section_index += len; } + if (tss->section_cb == mpegts_push_section) { + SectionContext *sect = tss->opaque; + sect->new_packet = 1; + } + offset = 0; cur_section_buf = tss->section_buf; while (cur_section_buf - tss->section_buf < MAX_SECTION_SIZE && cur_section_buf[0] != 0xff) { @@ -798,6 +814,7 @@ static const StreamType ISO_types[] = { { 0x02, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, { 0x03, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, { 0x04, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, + { 0x0b, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DSMCC_B }, /* DVB_CAROUSEL_ID */ { 0x0f, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC }, { 0x10, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 }, /* Makito encoder sets stream type 0x11 for AAC, @@ -882,11 +899,20 @@ static const StreamType DESC_types[] = { { 0x6a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AC3 }, /* AC-3 descriptor */ { 0x7a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_EAC3 }, /* E-AC-3 descriptor */ { 0x7b, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_DTS }, + { 0x13, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DSMCC_B }, /* DVB_CAROUSEL_ID */ + { 0x45, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DVB_VBI }, /* DVB_VBI_DATA_ID */ + { 0x46, AVMEDIA_TYPE_DATA, AV_CODEC_ID_DVB_VBI }, /* DVB_VBI_TELETEXT_ID */ //FixMe type subtilte { 0x56, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_TELETEXT }, { 0x59, AVMEDIA_TYPE_SUBTITLE, AV_CODEC_ID_DVB_SUBTITLE }, /* subtitling descriptor */ { 0 }, }; +/* component tags */ +static const StreamType COMPONENT_TAG_types[] = { + { 0x0a, AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3 }, + { 0x52, AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO }, +}; + static void mpegts_find_stream_type(AVStream *st, uint32_t stream_type, const StreamType *types) @@ -1979,7 +2005,13 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type memcpy(extradata, *pp, 4); /* composition_page_id and ancillary_page_id */ extradata += 5; - *pp += 4; + { + int comp_page = get16(pp, desc_end); + int anc_page = get16(pp, desc_end); + int sub_id = (anc_page << 16) | comp_page; + if (sub_id && (st->codecpar->codec_id == AV_CODEC_ID_DVB_SUBTITLE)) + st->carousel_id = sub_id; + } } language[i * 4 - 1] = 0; @@ -2023,8 +2055,45 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type sti->request_probe = 50; } break; + case DVB_BROADCAST_ID: + st->data_id = get16(pp, desc_end); + break; + case DVB_CAROUSEL_ID: + { + int carId = 0; + carId = get8(pp, desc_end); + carId = (carId << 8) | get8(pp, desc_end); + carId = (carId << 8) | get8(pp, desc_end); + carId = (carId << 8) | get8(pp, desc_end); + st->carousel_id = carId; + } + break; case 0x52: /* stream identifier descriptor */ sti->stream_identifier = 1 + get8(pp, desc_end); + st->component_tag = sti->stream_identifier - 1; + // DVB_DATA_STREAM: + /* Audio and video are sometimes encoded in private streams labelled with + * a component tag. */ +#if 0 + if (st->codecpar->codec_id == AV_CODEC_ID_NONE && + desc_count == 1 && + stream_type == STREAM_TYPE_PRIVATE_DATA) + mpegts_find_stream_type(st, st->component_tag, + COMPONENT_TAG_types); +#endif + break; + case DVB_VBI_TELETEXT_ID: + language[0] = get8(pp, desc_end); + language[1] = get8(pp, desc_end); + language[2] = get8(pp, desc_end); + language[3] = 0; + + /* dvbci->txt_type = */ i = (get8(pp, desc_end)) >> 3; // not exported, defeat compiler -Wunused-value + if (language[0]) + av_dict_set(&st->metadata, "language", language, 0); + break; + case DVB_VBI_DATA_ID: + // dvbci->vbi_data = 1; //not parsing the data service descriptors break; case METADATA_DESCRIPTOR: if (get16(pp, desc_end) == 0xFFFF) @@ -2307,6 +2376,34 @@ static int is_pes_stream(int stream_type, uint32_t prog_reg_desc) (stream_type == 0x86 && prog_reg_desc == AV_RL32("CUEI")) ); } +static SectionContext *add_section_stream(MpegTSContext *ts, int pid, int stream_type) +{ + MpegTSFilter *tss = ts->pids[pid]; + SectionContext *sect = 0; + if (tss) { /* filter already exists */ + /* kill it, and start a new stream */ + mpegts_close_filter(ts, tss); + } + + /* create a SECTION context */ + if (!(sect=av_mallocz(sizeof(SectionContext)))) { + av_log(ts, AV_LOG_ERROR, "Error: av_mallocz() failed in add_section_stream"); + return 0; + } + sect->ts = ts; + sect->stream = ts->stream; + sect->pid = pid; + sect->stream_type = stream_type; + tss = mpegts_open_section_filter(ts, pid, mpegts_push_section, sect, 1); + if (!tss) { + av_free(sect); + av_log(ts, AV_LOG_ERROR, "Error: unable to open mpegts Section filter in add_section_stream"); + return 0; + } + + return sect; +} + static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { MpegTSContext *ts = filter->u.section_filter.opaque; @@ -2425,7 +2522,56 @@ static void pmt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len stream_identifier = parse_stream_identifier_desc(p, p_end) + 1; /* now create stream */ - if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { + if (stream_type == STREAM_TYPE_DSMCC_B) + { + SectionContext *sect = NULL; + int idx = -1; + + if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_SECTION && + ts->pids[pid]->u.section_filter.section_cb == mpegts_push_section) { + // u.section_filter.opaque may be the MpegTSContext, so test the section_cb + sect = (SectionContext*) ts->pids[pid]->u.section_filter.opaque; + } + if (!sect) { + sect = add_section_stream(ts, pid, stream_type); + } + if (!sect) + { + av_log(ts, AV_LOG_ERROR, "mpegts_add_stream: " + "error creating Section context for pid 0x%x with type %i\n", + pid, stream_type); + goto out; + } + + idx = ff_find_stream_index(ts->stream, pid); + if (idx >= 0) { + st = ts->stream->streams[idx]; + av_log(ts, AV_LOG_DEBUG, "mpegts_add_stream: " + "reusing stream #%d, has id 0x%x and codec %s, type %s at 0x%p\n", + st->index, st->id, avcodec_get_name(st->codecpar->codec_id), + av_get_media_type_string(st->codecpar->codec_type), st); + } + if (!st) { + st = avformat_new_stream(sect->stream, NULL); + } + if (!st) { + goto out; + } + sect->st = st; + sect->st->id = sect->pid; + + avpriv_set_pts_info(sect->st, 33, 1, 90000); + + sect->st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + sect->st->codecpar->codec_id = AV_CODEC_ID_DSMCC_B; + sect->st->priv_data = sect; + ffstream(sect->st)->need_parsing = AVSTREAM_PARSE_NONE; + + av_log(ts, AV_LOG_DEBUG, "mpegts_add_stream: " + "stream #%d, has id 0x%x and codec %s, type %s at 0x%p\n", + st->index, st->id, avcodec_get_name(st->codecpar->codec_id), + av_get_media_type_string(st->codecpar->codec_type), st); + } else if (ts->pids[pid] && ts->pids[pid]->type == MPEGTS_PES) { pes = ts->pids[pid]->u.pes_filter.opaque; if (ts->merge_pmt_versions && !pes->st) { st = find_matching_stream(ts, pid, h->id, stream_identifier, i, &old_program); @@ -2527,6 +2673,55 @@ out: av_free(mp4_descr[i].dec_config_descr); } +/* mpegts_push_section: return one or more tables. The tables may not completely fill + the packet and there may be stuffing bytes at the end. + This is complicated because a single TS packet may result in several tables being + produced. We may have a "start" bit indicating, in effect, the end of a table but + the rest of the TS packet after the start may be filled with one or more small tables. +*/ +static void mpegts_push_section(MpegTSFilter *filter, const uint8_t *section, int section_len) +{ + SectionContext *sect = filter->u.section_filter.opaque; + MpegTSContext *ts = sect->ts; + SectionHeader header; + AVPacket *pkt = ts->pkt; + const uint8_t *p = section, *p_end = section + section_len - 4; + + if (parse_section_header(&header, &p, p_end) < 0) + { + av_log(ts, AV_LOG_DEBUG, "Unable to parse header\n"); + return; + } + + if (sect->new_packet && pkt && sect->st && pkt->size == -1) { + int pktLen = section_len + 184; /* Add enough for a complete TS payload. */ + sect->new_packet = 0; + av_packet_unref(pkt); + if (av_new_packet(pkt, pktLen) == 0) { + memcpy(pkt->data, section, section_len); + memset(pkt->data+section_len, 0xff, pktLen-section_len); + pkt->stream_index = sect->st->index; + ts->stop_parse = 1; + } + } else if (pkt->data) { /* We've already added at least one table. */ + uint8_t *data = pkt->data; + int space = pkt->size; + int table_size = 0; + while (space > 3 + table_size) { + table_size = (((data[1] & 0xf) << 8) | data[2]) + 3; + if (table_size < space) { + space -= table_size; + data += table_size; + } /* Otherwise we've got filler. */ + } + if (space < section_len) { + av_log(ts, AV_LOG_DEBUG, "Insufficient space for additional packet\n"); + return; + } + memcpy(data, section, section_len); + } +} + static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len) { MpegTSContext *ts = filter->u.section_filter.opaque; diff --git a/libavformat/mpegts.h b/libavformat/mpegts.h index a48f14e768..6f57af7786 100644 --- a/libavformat/mpegts.h +++ b/libavformat/mpegts.h @@ -122,6 +122,7 @@ #define STREAM_TYPE_AUDIO_MPEG2 0x04 #define STREAM_TYPE_PRIVATE_SECTION 0x05 #define STREAM_TYPE_PRIVATE_DATA 0x06 +#define STREAM_TYPE_DSMCC_B 0x0b #define STREAM_TYPE_AUDIO_AAC 0x0f #define STREAM_TYPE_AUDIO_AAC_LATM 0x11 #define STREAM_TYPE_VIDEO_MPEG4 0x10 @@ -139,6 +140,22 @@ #define STREAM_TYPE_AUDIO_TRUEHD 0x83 #define STREAM_TYPE_AUDIO_EAC3 0x87 +#define STREAM_TYPE_AUDIO_MISC_DTS 0x8a +#define STREAM_TYPE_AUDIO_HDMV_AC3_PLUS 0x84 +#define STREAM_TYPE_AUDIO_HDMV_DTS_HD 0x85 +#define STREAM_TYPE_AUDIO_HDMV_DTS_HD_MASTER 0x86 + +#define STREAM_TYPE_SUBTITLE_DVB 0x100 +#define STREAM_TYPE_VBI_DVB 0x101 + +#define DVB_CAROUSEL_ID 0x13 +#define DVB_VBI_DATA_ID 0x45 +#define DVB_VBI_TELETEXT_ID 0x46 +#define DVB_TELETEXT_ID 0x56 +#define DVB_SUBT_DESCID 0x59 +#define DVB_BROADCAST_ID 0x66 +#define DVB_DATA_STREAM 0x52 + /* ISO/IEC 13818-1 Table 2-22 */ #define STREAM_ID_PROGRAM_STREAM_MAP 0xbc #define STREAM_ID_PRIVATE_STREAM_1 0xbd