Browse code

srt: make the demuxer output SubRip packets.

The SRT format should never have outputted CODEC_ID_SRT packets in the
first place: SRT is a subtitle format containing SubRip text markup
events. The timing information is part of the format, not the codec, and
thus CODEC_ID_SRT should not exist.

Creating packets with the timing information within the payload only
leads to problem (such as remuxing with timing alteration not working),
especially when the SubRip markup is being used in container like
Matroska in addition to this standalone SRT format.

The main reason the timing line was included in those CODEC_ID_SRT
packets is likely because it contained extra information (the event
position) the codec actually needs. This issue is solved by using the
AV_PKT_DATA_SUBTITLE_POSITION side data type.

Clément Bœsch authored on 2012/10/25 07:01:42
Showing 2 changed files
... ...
@@ -21,6 +21,7 @@
21 21
 
22 22
 #include "libavutil/avstring.h"
23 23
 #include "libavutil/common.h"
24
+#include "libavutil/intreadwrite.h"
24 25
 #include "libavutil/parseutils.h"
25 26
 #include "avcodec.h"
26 27
 #include "ass.h"
... ...
@@ -219,6 +220,15 @@ static int srt_decode_frame(AVCodecContext *avctx,
219 219
     char buffer[2048];
220 220
     const char *ptr = avpkt->data;
221 221
     const char *end = avpkt->data + avpkt->size;
222
+    int size;
223
+    const uint8_t *p = av_packet_get_side_data(avpkt, AV_PKT_DATA_SUBTITLE_POSITION, &size);
224
+
225
+    if (p && size == 16) {
226
+        x1 = AV_RL32(p     );
227
+        y1 = AV_RL32(p +  4);
228
+        x2 = AV_RL32(p +  8);
229
+        y2 = AV_RL32(p + 12);
230
+    }
222 231
 
223 232
     if (avpkt->size <= 0)
224 233
         return avpkt->size;
... ...
@@ -247,6 +257,7 @@ static int srt_decode_frame(AVCodecContext *avctx,
247 247
 }
248 248
 
249 249
 #if CONFIG_SRT_DECODER
250
+/* deprecated decoder */
250 251
 AVCodec ff_srt_decoder = {
251 252
     .name         = "srt",
252 253
     .long_name    = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
... ...
@@ -47,26 +47,30 @@ static int srt_read_header(AVFormatContext *s)
47 47
         return AVERROR(ENOMEM);
48 48
     avpriv_set_pts_info(st, 64, 1, 1000);
49 49
     st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
50
-    st->codec->codec_id   = AV_CODEC_ID_SRT;
50
+    st->codec->codec_id   = AV_CODEC_ID_SUBRIP;
51 51
     return 0;
52 52
 }
53 53
 
54
-static int64_t get_pts(const char *buf, int *duration)
54
+static int64_t get_pts(char **buf, int *duration,
55
+                       int32_t *x1, int32_t *y1, int32_t *x2, int32_t *y2)
55 56
 {
56 57
     int i;
57 58
 
58 59
     for (i=0; i<2; i++) {
59 60
         int hh1, mm1, ss1, ms1;
60 61
         int hh2, mm2, ss2, ms2;
61
-        if (sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d",
62
+        if (sscanf(*buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
63
+                   "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
62 64
                    &hh1, &mm1, &ss1, &ms1,
63
-                   &hh2, &mm2, &ss2, &ms2) == 8) {
65
+                   &hh2, &mm2, &ss2, &ms2,
66
+                   x1, x2, y1, y2) >= 8) {
64 67
             int64_t start = (hh1*3600LL + mm1*60LL + ss1) * 1000LL + ms1;
65 68
             int64_t end   = (hh2*3600LL + mm2*60LL + ss2) * 1000LL + ms2;
66 69
             *duration = end - start;
70
+            *buf += strcspn(*buf, "\n") + 1;
67 71
             return start;
68 72
         }
69
-        buf += strcspn(buf, "\n") + 1;
73
+        *buf += strcspn(*buf, "\n") + 1;
70 74
     }
71 75
     return AV_NOPTS_VALUE;
72 76
 }
... ...
@@ -87,11 +91,31 @@ static int srt_read_packet(AVFormatContext *s, AVPacket *pkt)
87 87
         ptr += ff_get_line(s->pb, ptr, sizeof(buffer)+buffer-ptr);
88 88
     } while (!is_eol(*ptr2) && !url_feof(s->pb) && ptr-buffer<sizeof(buffer)-1);
89 89
 
90
-    if (buffer[0] && !(res = av_new_packet(pkt, ptr-buffer))) {
91
-        memcpy(pkt->data, buffer, pkt->size);
92
-        pkt->flags |= AV_PKT_FLAG_KEY;
93
-        pkt->pos = pos;
94
-        pkt->pts = pkt->dts = get_pts(pkt->data, &(pkt->duration));
90
+    if (buffer[0]) {
91
+        int64_t pts;
92
+        int duration;
93
+        const char *end = ptr;
94
+        int32_t x1 = -1, y1 = -1, x2 = -1, y2 = -1;
95
+
96
+        ptr = buffer;
97
+        pts = get_pts(&ptr, &duration, &x1, &y1, &x2, &y2);
98
+        if (pts != AV_NOPTS_VALUE &&
99
+            !(res = av_new_packet(pkt, end - ptr))) {
100
+            memcpy(pkt->data, ptr, pkt->size);
101
+            pkt->flags |= AV_PKT_FLAG_KEY;
102
+            pkt->pos = pos;
103
+            pkt->pts = pkt->dts = pts;
104
+            pkt->duration = duration;
105
+            if (x1 != -1) {
106
+                uint8_t *p = av_packet_new_side_data(pkt, AV_PKT_DATA_SUBTITLE_POSITION, 16);
107
+                if (p) {
108
+                    AV_WL32(p,      x1);
109
+                    AV_WL32(p +  4, y1);
110
+                    AV_WL32(p +  8, x2);
111
+                    AV_WL32(p + 12, y2);
112
+                }
113
+            }
114
+        }
95 115
     }
96 116
     return res;
97 117
 }