[FFmpeg-devel] [PATCH] libavformat/mpegts.c: add: parse EIT descriptors
TADANO Tokumei
aimingoff at pc.nifty.jp
Sun Apr 10 10:49:53 EEST 2022
On 2022/04/10 3:34, Marton Balint wrote:
>
>
> On Sun, 10 Apr 2022, TADANO Tokumei wrote:
>
>> This patch add to parse descriptors on EIT packets.
>> The patch is intended to set information to current program and/or
>> A/V stream.
>> On Japanese ISDB, some important / useful information is provided
>> via EIT only.
>> ref: ARIB STD B10 Table 6-1, Section 6.1, Part 2.
>
> libavformat is a generic A-V demux library, therefore we probably don't want to add full or even partial EIT parsing capabilites to it. EIT is exported as a data stream, the API user can use that to get all EIT related information.
Thanks for your comments.
I have a plan to add EIT parsing capabilities for Japanese ISDB:
* dual-monoral audio stream: Audio component descriptor (0xC4)
libavcodec already has capability to handle Japanese dual-mono audio.
(libavcodec/packet.h, libavcodec/avpacket.c, libavcodec/aacdec_template.c, ...)
However, the information of dual-mono mode is provided via only the EIT descriptor.
Thus, most of application treat the dual-mono audio stream as stereo.
ref: ARIB STD-B10 Part 2, Section 6.2.26
There is no standard way to pass the dual-mono audio information.
My idea is to add side data of AV_PKT_DATA_JP_DUALMONO to the audio stream
(Similar way to DOVI).
To play the dual-mono audio correctly, application have to set (or pass)
AV_PKT_DATA_JP_DUALMONO side data into each audio packet if the stream has
AV_PKT_DATA_JP_DUALMONO side data. (The stream's side data indicates default
mode, and packet's side data should be set user selected mode)
* Language information of ARIB Caption: Data content(s) descriptor (0xC7)
On DVB, similar information is provided by Subtitling descriptor (0x59).
But on ISDB, such information is provided by this EIT descriptor.
ref: ARIB STD-B10 Part 2, Section 6.2.28 and Annex J
ARIB STD-B24 Fascicle 1 Part 3 Chapter 9 Table 9-17
On DVB, most important information for A/V stream are provided by PMT.
But on ISDB, some important information are lacked without parsing EIT.
Regards,
TADANO
> Regards,
> Marton
>
>>
>> This patch only parse short event descriptor (0x4d) and set title
>> information to the program. It may not be useful, but a good example
>> of EIT descriptor common for DVB and ISDB.
>>
>> Note that it only parse EIT for actual and present TS stream as bllow:
>> * Parse EIT table_id 0x4E (actual TS stream) only.
>> ref: DVB Blue Book A038 (EN 300 468) Table 2, Section 5.1.3.
>> * Parse section number 0x00 only.
>> Section number 0x00 is present event.
>> Section number 0x01 is following (i.e., not for present stream).
>> Section number 0x02 or later may contain event for present stream,
>> but it is hard to distinguish and rarely sent.
>> ref: DVB-SI Guidelines (TS 101 211) Section 4.1.4.1.
>> * Find a program associated to the EIT in already initialized
>> AVProgram and Program structures.
>> If no program found, abort to parse the EIT.
>>
>> Since EIT packets may be sent several times for the same program,
>> add 'eit_version' in Program structure and ignore EITs with the
>> same version as previously parsed one.
>>
>> There is a warning: "variable 'language' set but not used" at
>> compilation. It should be resolved by later patches.
>>
>> An sample DVB TS file is found at:
>> https://streams.videolan.org/streams/ts/Teletext/TELETEXTO.ts
>> After aplying this patch, ffprobe TELETEXTO.ts shows tile as:
>> Program 340
>> Metadata:
>> title : NAVY : INVESTIGACIÓN CRIMINAL
>>
>> Many sample ISDB TS files are found at:
>> https://streams.videolan.org/streams/ts/ARIB/japan/
>> Most of TS files show their title by ffprobe, but unrecognizable.
>> It is due to encoding problem of text string.
>> It should be also resolved by future patches.
>>
>> Signed-off-by: TADANO Tokumei <aimingoff at pc.nifty.jp>
>> ---
>> libavformat/mpegts.c | 129 ++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 127 insertions(+), 2 deletions(-)
>>
>> diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c
>> index 49f7735123..8417d71fb3 100644
>> --- a/libavformat/mpegts.c
>> +++ b/libavformat/mpegts.c
>> @@ -123,6 +123,8 @@ struct Program {
>>
>> /** have we found pmt for this program */
>> int pmt_found;
>> +
>> + int eit_version;
>> };
>>
>> struct MpegTSContext {
>> @@ -304,6 +306,7 @@ static void clear_program(struct Program *p)
>> p->nb_pids = 0;
>> p->nb_streams = 0;
>> p->pmt_found = 0;
>> + p->eit_version = -1;
>> }
>>
>> static void clear_programs(MpegTSContext *ts)
>> @@ -2616,8 +2619,12 @@ static void pat_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
>> static void eit_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
>> {
>> MpegTSContext *ts = filter->u.section_filter.opaque;
>> - const uint8_t *p, *p_end;
>> + const uint8_t *p, *p_end, *desc_list_end, *desc_end;
>> SectionHeader h1, *h = &h1;
>> + AVProgram *program;
>> + struct Program *prg;
>> + int desc_len;
>> + char language[252];
>>
>> /*
>> * Sometimes we receive EPG packets but SDT table do not have
>> @@ -2645,6 +2652,7 @@ static void eit_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
>> return;
>>
>> av_log(ts->stream, AV_LOG_TRACE, "EIT: tid received = %.02x\n", h->tid);
>> + hex_dump_debug(ts->stream, section, section_len);
>>
>> /**
>> * Service_id 0xFFFF is reserved, it indicates that the current EIT table
>> @@ -2664,7 +2672,124 @@ static void eit_cb(MpegTSFilter *filter, const uint8_t *section, int section_len
>>
>> new_data_packet(section, section_len, ts->pkt);
>> ts->pkt->stream_index = ts->epg_stream->index;
>> - ts->stop_parse = 1;
>> +
>> + /* parse present event of actual TS stream only */
>> + if (h->tid != EIT_TID)
>> + return;
>> + if (!h->current_next)
>> + return;
>> + if (ts->skip_changes)
>> + return;
>> +
>> + av_log(ts->stream, AV_LOG_TRACE, "sid=0x%x sec_num=%d/%d version=%d\n",
>> + h->id, h->sec_num, h->last_sec_num, h->version);
>> +
>> + /* DVB-SI Guidelines (TS 101 211) 4.1.4.1 */
>> + /* 0x00 indicates present event, 0x01 indicates following event */
>> + /* 0x02 and after is optional */
>> + if (h->sec_num > 0)
>> + return;
>> +
>> + program = NULL;
>> + for (int i = 0; i < ts->stream->nb_programs; i++)
>> + if (ts->stream->programs[i]->id == h->id)
>> + program = ts->stream->programs[i];
>> + if (!program || program->nb_stream_indexes <= 0)
>> + return;
>> +
>> + prg = get_program(ts, h->id);
>> + if (!prg)
>> + return;
>> + if (h->version == prg->eit_version)
>> + return;
>> + prg->eit_version = h->version;
>> +
>> + /* skip ts_id, original_network_id, last_section_no, last_table_id */
>> + if (p + 6 > p_end)
>> + return;
>> + p += 6;
>> +
>> + for (;;) {
>> + int eid, val;
>> +
>> + eid = get16(&p, p_end);
>> + if (eid < 0)
>> + break;
>> + {
>> + int hh, mm, ss, d_hh, d_mm, d_ss, running_status;
>> + val = get16(&p, p_end); /* Date */
>> + if (val < 0)
>> + break;
>> + hh = get8(&p, p_end);
>> + if (hh < 0)
>> + break;
>> + mm = get8(&p, p_end);
>> + if (mm < 0)
>> + break;
>> + ss = get8(&p, p_end);
>> + if (ss < 0)
>> + break;
>> + d_hh = get8(&p, p_end);
>> + if (d_hh < 0)
>> + break;
>> + d_mm = get8(&p, p_end);
>> + if (d_mm < 0)
>> + break;
>> + d_ss = get8(&p, p_end);
>> + if (d_ss < 0)
>> + break;
>> + desc_len = get16(&p, p_end);
>> + if (desc_len < 0)
>> + break;
>> + running_status = (desc_len & 0xe000) >> 5;
>> + av_log(ts->stream, AV_LOG_TRACE,
>> + "eid=0x%04x start %02x:%02x:%02x duration %02x:%02x:%02x running_status=%d\n",
>> + eid, hh, mm, ss, d_hh, d_mm, d_ss, running_status);
>> + }
>> + desc_len &= 0x0fff;
>> + desc_list_end = p + desc_len;
>> + if (desc_list_end > p_end)
>> + break;
>> +
>> + for (;;) {
>> + int desc_tag;
>> +
>> + desc_tag = get8(&p, desc_list_end);
>> + if (desc_tag < 0)
>> + break;
>> + desc_len = get8(&p, desc_list_end);
>> + desc_end = p + desc_len;
>> + if (desc_len < 0 || desc_end > desc_list_end)
>> + break;
>> +
>> + av_log(ts->stream, AV_LOG_DEBUG, "tag: 0x%02x len=%d\n",
>> + desc_tag, desc_len);
>> +
>> + switch (desc_tag) {
>> + case 0x4d: /* short event descriptor */
>> + {
>> + char *txt;
>> +
>> + if (desc_len < 3)
>> + break;
>> + language[0] = get8(&p, desc_end);
>> + language[1] = get8(&p, desc_end);
>> + language[2] = get8(&p, desc_end);
>> + language[3] = '\0';
>> + txt = getstr8(&p, desc_end);
>> + if (!txt)
>> + break;
>> + av_dict_set(&program->metadata, "title", txt, 0);
>> + av_free(txt);
>> + }
>> + break;
>> + default:
>> + break;
>> + }
>> + p = desc_end;
>> + }
>> + p = desc_list_end;
>> + }
>> }
>>
>> static void sdt_cb(MpegTSFilter *filter, const uint8_t *section, int section_len)
>> --
>> 2.30.2
>>
>> _______________________________________________
>> ffmpeg-devel mailing list
>> ffmpeg-devel at ffmpeg.org
>> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>>
>> To unsubscribe, visit link above, or email
>> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".
More information about the ffmpeg-devel
mailing list