From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTP id 3DA1242FA9 for ; Sun, 13 Nov 2022 23:19:15 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A46D268BCD7; Mon, 14 Nov 2022 01:19:12 +0200 (EET) Received: from mail-qt1-f176.google.com (mail-qt1-f176.google.com [209.85.160.176]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id DDF2E68BC55 for ; Mon, 14 Nov 2022 01:19:06 +0200 (EET) Received: by mail-qt1-f176.google.com with SMTP id z6so5958455qtv.5 for ; Sun, 13 Nov 2022 15:19:06 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=content-transfer-encoding:in-reply-to:from:content-language :references:to:subject:user-agent:mime-version:date:message-id:from :to:cc:subject:date:message-id:reply-to; bh=jSiYAGUH0shWMPFf52LtPlpflXXpl7XivRaVyTnlNvg=; b=gDnL+36+JOw+i5Hiqw0jvt5LFfkSxVkbU2Yxp2GXe3rGf3+WlInNweyEkRl83MYrPF YKzyNKux7coiid41hPkf8zDz4ljfKijpGPWRkRskyNR6iYsJN+q+m+ciWZy9DgBMFK6i fsmKBqlXL8TE68nnEgmijiTDuyUuOZb/YclZWEajwxcOOc0ydeYpuLHZqwww4Dowy/Js kYeWbG7XCkXbIgzx+t4Y+2mBEMaAuA2cu+Rte3LZnDfQNOGTZ6tbDgYAwhbc57eEBQK5 KbTcs9yXEQ6/UtksDXwwIh0Gz5jg2PpTE0iWXqJKIrjaKM90FpKFaQHR45Aq7iu8FvGv y3FA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:in-reply-to:from:content-language :references:to:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=jSiYAGUH0shWMPFf52LtPlpflXXpl7XivRaVyTnlNvg=; b=SYM1lJLW8yJ61AQlKBv2nJAERnVjFWCK6AiXfS2v6ksykXjolYZhT2PtdtGMIkC2Uw U5WxdMfRb7qu27xKM/LmF9zD1BF4B2IWMA/c6bhR80dw5+98fJ+J45lUatVh8X46byOY jHzf68NVtSIBx9tq+nhhuPYXNcMcJett6e++4bWKQAEI8BhB3YSfH//i0s/lPthN2Y+k KCsYT8WNcLefpqY0/KiiOz7LZmS1aGaa39RtGfKNN5flyeIZTuMVnJScKpkNaTGpekXt WC3Yb6UQE4bZaeUuEQKCrU1A8RrRG24BwsdHJjpP3tzFWj8/r1tfoVcvdkHFDY0qMHg3 GR0g== X-Gm-Message-State: ANoB5plPvTvnnnmX+CNhMKWfFcdIoWVmESYOosi7UJphJ3VToUeonbIQ 1EVaW1xCvDBzdCYEbQ4qg08EEg7kwi0= X-Google-Smtp-Source: AA0mqf4qhY1BaQYYyxGSzsn/1pSrRBcugMc8G/fb/Uo4ZeQNJ4omR/JUoNuDjQVg8BcRD0+FBdQ1TQ== X-Received: by 2002:ac8:4818:0:b0:3a5:f06:7e8b with SMTP id g24-20020ac84818000000b003a50f067e8bmr10372161qtq.620.1668381544916; Sun, 13 Nov 2022 15:19:04 -0800 (PST) Received: from [192.168.1.13] (pool-72-66-19-106.washdc.fios.verizon.net. [72.66.19.106]) by smtp.gmail.com with ESMTPSA id b13-20020ac86bcd000000b003a57a317c17sm4790775qtt.74.2022.11.13.15.19.03 for (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Sun, 13 Nov 2022 15:19:04 -0800 (PST) Message-ID: <4a032252-705b-b71d-101e-8b1f55b4ec50@gmail.com> Date: Sun, 13 Nov 2022 18:19:03 -0500 MIME-Version: 1.0 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.4.2 To: ffmpeg-devel@ffmpeg.org References: <20220917170843.308894-1-scott.the.elm@gmail.com> Content-Language: en-US From: Scott Theisen In-Reply-To: <20220917170843.308894-1-scott.the.elm@gmail.com> Subject: Re: [FFmpeg-devel] [PATCH] mpegts: identify and demux DSMCC-B/MHEG streams X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii"; Format="flowed" Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" Archived-At: List-Archive: List-Post: 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 > #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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".