[FFmpeg-cvslog] libzvbi-teletextdec: split dvb packet to slices

Marton Balint git at videolan.org
Sun Mar 9 03:26:44 CET 2014


ffmpeg | branch: master | Marton Balint <cus at passwd.hu> | Sat Mar  1 02:10:15 2014 +0100| [085ca7dcdbf9ab6c23e3a5397b1f6d4aa23f763d] | committer: Marton Balint

libzvbi-teletextdec: split dvb packet to slices

Instead of using the demux function of libzvbi to split the packet to slices
(vbi lines), lets do it ourselves.

- eliminates the 1 frame delay between page input and output
- handles non-ascending line numbers more gracefully
- enables us to return error codes on some invalid packets instead of silently
  ignoring them

Signed-off-by: Marton Balint <cus at passwd.hu>

> http://git.videolan.org/gitweb.cgi/ffmpeg.git/?a=commit;h=085ca7dcdbf9ab6c23e3a5397b1f6d4aa23f763d
---

 libavcodec/libzvbi-teletextdec.c |   86 ++++++++++++++++++++++++--------------
 1 file changed, 54 insertions(+), 32 deletions(-)

diff --git a/libavcodec/libzvbi-teletextdec.c b/libavcodec/libzvbi-teletextdec.c
index 2b1be82..32475b1 100644
--- a/libavcodec/libzvbi-teletextdec.c
+++ b/libavcodec/libzvbi-teletextdec.c
@@ -37,6 +37,7 @@
 #define MAX_BUFFERED_PAGES 25
 #define BITMAP_CHAR_WIDTH  12
 #define BITMAP_CHAR_HEIGHT 10
+#define MAX_SLICES 64
 
 typedef struct TeletextPage
 {
@@ -65,11 +66,10 @@ typedef struct TeletextContext
     int             handler_ret;
 
     vbi_decoder *   vbi;
-    vbi_dvb_demux * dx;
 #ifdef DEBUG
     vbi_export *    ex;
 #endif
-    vbi_sliced      sliced[64];
+    vbi_sliced      sliced[MAX_SLICES];
 } TeletextContext;
 
 static int chop_spaces_utf8(const unsigned char* t, int len)
@@ -358,15 +358,46 @@ static void handler(vbi_event *ev, void *user_data)
     vbi_unref_page(&page);
 }
 
+static inline int data_identifier_is_teletext(int data_identifier) {
+    /* See EN 301 775 section 4.4.2. */
+    return (data_identifier >= 0x10 && data_identifier <= 0x1F ||
+            data_identifier >= 0x99 && data_identifier <= 0x9B);
+}
+
+static int slice_to_vbi_lines(TeletextContext *ctx, uint8_t* buf, int size)
+{
+    int lines = 0;
+    while (size >= 2 && lines < MAX_SLICES) {
+        int data_unit_id     = buf[0];
+        int data_unit_length = buf[1];
+        if (data_unit_length + 2 > size)
+            return AVERROR_INVALIDDATA;
+        if (data_unit_id == 0x02 || data_unit_id == 0x03) {
+            if (data_unit_length != 0x2c)
+                return AVERROR_INVALIDDATA;
+            else {
+                int line_offset  = buf[2] & 0x1f;
+                int field_parity = buf[2] & 0x20;
+                int i;
+                ctx->sliced[lines].id = VBI_SLICED_TELETEXT_B;
+                ctx->sliced[lines].line = (line_offset > 0 ? (line_offset + (field_parity ? 0 : 313)) : 0);
+                for (i = 0; i < 42; i++)
+                    ctx->sliced[lines].data[i] = vbi_rev8(buf[4 + i]);
+                lines++;
+            }
+        }
+        size -= data_unit_length + 2;
+        buf += data_unit_length + 2;
+    }
+    if (size)
+        av_log(ctx, AV_LOG_WARNING, "%d bytes remained after slicing data\n", size);
+    return lines;
+}
+
 static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *pkt)
 {
     TeletextContext *ctx = avctx->priv_data;
     AVSubtitle      *sub = data;
-    const uint8_t   *buf = pkt->data;
-    int             left = pkt->size;
-    uint8_t         pesheader[45] = {0x00, 0x00, 0x01, 0xbd, 0x00, 0x00, 0x85, 0x80, 0x24, 0x21, 0x00, 0x01, 0x00, 0x01};
-    int             pesheader_size = sizeof(pesheader);
-    const uint8_t   *pesheader_buf = pesheader;
     int             ret = 0;
 
     if (!ctx->vbi) {
@@ -378,40 +409,34 @@ static int teletext_decode_frame(AVCodecContext *avctx, void *data, int *data_si
             return AVERROR(ENOMEM);
         }
     }
-    if (!ctx->dx && (!(ctx->dx = vbi_dvb_pes_demux_new (/* callback */ NULL, NULL))))
-        return AVERROR(ENOMEM);
 
     if (avctx->pkt_timebase.den && pkt->pts != AV_NOPTS_VALUE)
         ctx->pts = av_rescale_q(pkt->pts, avctx->pkt_timebase, AV_TIME_BASE_Q);
 
-    if (left) {
+    if (pkt->size) {
+        int lines;
+        const int full_pes_size = pkt->size + 45; /* PES header is 45 bytes */
+
         // We allow unreasonably big packets, even if the standard only allows a max size of 1472
-        if ((pesheader_size + left) < 184 || (pesheader_size + left) > 65504 || (pesheader_size + left) % 184 != 0)
+        if (full_pes_size < 184 || full_pes_size > 65504 || full_pes_size % 184 != 0)
             return AVERROR_INVALIDDATA;
 
-        memset(pesheader + 14, 0xff, pesheader_size - 14);
-        AV_WB16(pesheader + 4, left + pesheader_size - 6);
-
-        /* PTS is deliberately left as 0 in the PES header, otherwise libzvbi uses
-         * it to detect dropped frames. Unforunatey the guessed packet PTS values
-         * (see mpegts demuxer) are not accurate enough to pass that test. */
-        vbi_dvb_demux_cor(ctx->dx, ctx->sliced, 64, NULL, &pesheader_buf, &pesheader_size);
-
         ctx->handler_ret = pkt->size;
 
-        while (left > 0) {
-            int64_t pts = 0;
-            unsigned int lines = vbi_dvb_demux_cor(ctx->dx, ctx->sliced, 64, &pts, &buf, &left);
-            av_dlog(avctx, "ctx=%p buf_size=%d left=%u lines=%u pts=%f pkt_pts=%f\n",
-                    ctx, pkt->size, left, lines, (double)pts/90000.0, (double)pkt->pts/90000.0);
+        if (data_identifier_is_teletext(*pkt->data)) {
+            if ((lines = slice_to_vbi_lines(ctx, pkt->data + 1, pkt->size - 1)) < 0)
+                return lines;
+            av_dlog(avctx, "ctx=%p buf_size=%d lines=%u pkt_pts=%7.3f\n",
+                    ctx, pkt->size, lines, (double)pkt->pts/90000.0);
             if (lines > 0) {
-#ifdef DEBUGx
+#ifdef DEBUG
                 int i;
-                for(i=0; i<lines; ++i)
-                    av_log(avctx, AV_LOG_DEBUG,
-                           "lines=%d id=%x\n", i, ctx->sliced[i].id);
+                av_log(avctx, AV_LOG_DEBUG, "line numbers:");
+                for(i = 0; i < lines; i++)
+                    av_log(avctx, AV_LOG_DEBUG, " %d", ctx->sliced[i].line);
+                av_log(avctx, AV_LOG_DEBUG, "\n");
 #endif
-                vbi_decode(ctx->vbi, ctx->sliced, lines, (double)pts/90000.0);
+                vbi_decode(ctx->vbi, ctx->sliced, lines, 0.0);
                 ctx->lines_processed += lines;
             }
         }
@@ -474,7 +499,6 @@ static int teletext_init_decoder(AVCodecContext *avctx)
         avctx->height = 25 * BITMAP_CHAR_HEIGHT;
     }
 
-    ctx->dx = NULL;
     ctx->vbi = NULL;
     ctx->pts = AV_NOPTS_VALUE;
 
@@ -497,9 +521,7 @@ static int teletext_close_decoder(AVCodecContext *avctx)
         subtitle_rect_free(&ctx->pages[--ctx->nb_pages].sub_rect);
     av_freep(&ctx->pages);
 
-    vbi_dvb_demux_delete(ctx->dx);
     vbi_decoder_delete(ctx->vbi);
-    ctx->dx = NULL;
     ctx->vbi = NULL;
     ctx->pts = AV_NOPTS_VALUE;
     return 0;



More information about the ffmpeg-cvslog mailing list