[FFmpeg-devel] [PATCH 2/2] lavc/dvdsub_parser: parse start and end times.

Nicolas George nicolas.george at normalesup.org
Fri Dec 7 17:58:45 CET 2012


Set the packet duration according to the times in it.

Signed-off-by: Nicolas George <nicolas.george at normalesup.org>
---
 libavcodec/dvdsub_parser.c |   51 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)


Without this patch (and the previous one, since otherwise the time base is
not set), ffmpeg -i foo.vob -c copy bar.mkv will not work because the
subtitles packets do not have their duration; mkvalidator considers the file
invalid and mkvmerge does not see the tracks.

As a side note, I would very much like to understand how the PTS is supposed
to work with parsers, since lavf assumes the PTS are in stream time base but
the time base is not available.


diff --git a/libavcodec/dvdsub_parser.c b/libavcodec/dvdsub_parser.c
index e50c339..e451bdc 100644
--- a/libavcodec/dvdsub_parser.c
+++ b/libavcodec/dvdsub_parser.c
@@ -37,6 +37,55 @@ static av_cold int dvdsub_parse_init(AVCodecParserContext *s)
     return 0;
 }
 
+static void parse_duration(AVCodecParserContext *s, AVCodecContext *avctx)
+{
+    DVDSubParseContext *pc = s->priv_data;
+    uint8_t *buf = pc->packet;
+    unsigned buf_size = pc->packet_len;
+    uint8_t *end = buf + buf_size;
+    unsigned hd = 0, offset_size = 2, cmd_pos = 0, new_pos, date, pos, cmd;
+    unsigned time_start = 0, time_end = 0;
+    int64_t ts_start, ts_end;
+    AVRational tb = { 1, 90000 }, ctb = avctx->time_base;
+
+    if (buf_size < 10)
+        return;
+    if (!AV_RB16(buf)) { /* HD, untested */
+        hd = 1;
+        offset_size = 4;
+        cmd_pos += 4;
+    }
+    while (1) {
+        new_pos = hd ? AV_RB32(buf + cmd_pos + 2) : AV_RB16(buf + cmd_pos + 2);
+        if (new_pos <= cmd_pos || new_pos >= buf_size - 2 - offset_size)
+            break;
+        cmd_pos = new_pos;
+        date = AV_RB16(buf + cmd_pos);
+        pos = cmd_pos + 2 + offset_size;
+        while (pos < buf_size) {
+            cmd = buf[pos++];
+            switch (cmd) {
+            case 0x01: time_start = date << 10; break;
+            case 0x02: time_end   = date << 10; break;
+            case 0x00:             break;
+            case 0x03:
+            case 0x04: pos +=   2; break;
+            case 0x05:
+            case 0x85: pos +=   6; break;
+            case 0x06: pos +=   4; break;
+            case 0x86: pos +=   8; break;
+            case 0x83: pos += 768; break;
+            case 0x84: pos += 256; break;
+            default:   pos = buf_size; break;
+            }
+        }
+    }
+    ts_start = av_rescale_q_rnd(time_start, tb, ctb, AV_ROUND_DOWN);
+    ts_end   = av_rescale_q_rnd(time_end,   tb, ctb, AV_ROUND_DOWN);
+    /* FIXME: update pts, but its time base is not available */
+    s->duration = ts_end - ts_start;
+}
+
 static int dvdsub_parse(AVCodecParserContext *s,
                         AVCodecContext *avctx,
                         const uint8_t **poutbuf, int *poutbuf_size,
@@ -61,6 +110,8 @@ static int dvdsub_parse(AVCodecParserContext *s,
                 *poutbuf = pc->packet;
                 *poutbuf_size = pc->packet_len;
                 pc->packet_index = 0;
+                if (avctx->time_base.num && avctx->time_base.den)
+                    parse_duration(s, avctx);
                 return buf_size;
             }
         } else {
-- 
1.7.10.4



More information about the ffmpeg-devel mailing list