[FFmpeg-devel] [PATCH] libavformat/mpegts.c: add: parse EIT descriptors

TADANO Tokumei aimingoff at pc.nifty.jp
Sat Apr 9 18:15:18 EEST 2022


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.

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



More information about the ffmpeg-devel mailing list