History

add SubRip decoder

Originally committed as revision 26119 to svn://svn.ffmpeg.org/ffmpeg/trunk

Aurelien Jacobs committed 15 years ago

Commit 2c77c901 parent 312056c11 files · +335 −3Browse files

Unified · Split

11 files
  1. Changelog +1 −0
  2. MAINTAINERS +1 −0
  3. doc/general.texi +1 −1
  4. libavcodec/Makefile +1 −0
  5. libavcodec/allcodecs.c +1 −0
  6. libavcodec/ass.c +40 −0
  7. libavcodec/ass.h +45 −0
  8. libavcodec/avcodec.h +2 −2
  9. libavcodec/srtdec.c +240 −0
  10. tests/fate.mak +2 −0
  11. tests/ref/fate/sub-srt +1 −0
Changelog+1−0
@@ -69,6 +69,7 @@ version <next>: · 68 unmodified lines
69- replace the ocv_smooth filter with a more generic ocv filter69- replace the ocv_smooth filter with a more generic ocv filter
70- Windows Televison (WTV) demuxer70- Windows Televison (WTV) demuxer
71- FFmpeg metadata format muxer and demuxer71- FFmpeg metadata format muxer and demuxer
72- SubRip (srt) subtitle decoder
72 73
73 74
74version 0.6:75version 0.6:
MAINTAINERS+1−0
@@ -198,6 +198,7 @@ Codecs: · 197 unmodified lines
198 smc.c Mike Melanson198 smc.c Mike Melanson
199 snow.c Michael Niedermayer, Loren Merritt199 snow.c Michael Niedermayer, Loren Merritt
200 sonic.c Alex Beregszaszi200 sonic.c Alex Beregszaszi
201 srtdec.c Aurelien Jacobs
201 sunrast.c Ivo van Poorten202 sunrast.c Ivo van Poorten
202 svq3.c Michael Niedermayer203 svq3.c Michael Niedermayer
203 targa.c Kostya Shishkov204 targa.c Kostya Shishkov
doc/general.texi+1−1
@@ -694,7 +694,7 @@ performance on systems without hardware floating point support). · 693 unmodified lines
694@item DVB @tab X @tab X @tab X @tab X694@item DVB @tab X @tab X @tab X @tab X
695@item DVD @tab X @tab X @tab X @tab X695@item DVD @tab X @tab X @tab X @tab X
696@item PGS @tab @tab @tab @tab X696@item PGS @tab @tab @tab @tab X
697@item SubRip (SRT) @tab X @tab X697@item SubRip (SRT) @tab X @tab X @tab @tab X
698@item XSUB @tab @tab @tab X @tab X698@item XSUB @tab @tab @tab X @tab X
699@end multitable699@end multitable
700 700
libavcodec/Makefile+1−0
@@ -337,6 +337,7 @@ OBJS-$(CONFIG_SONIC_DECODER) += sonic.o · 336 unmodified lines
337OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o337OBJS-$(CONFIG_SONIC_ENCODER) += sonic.o
338OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o338OBJS-$(CONFIG_SONIC_LS_ENCODER) += sonic.o
339OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o mjpegdec.o mjpeg.o339OBJS-$(CONFIG_SP5X_DECODER) += sp5xdec.o mjpegdec.o mjpeg.o
340OBJS-$(CONFIG_SRT_DECODER) += srtdec.o ass.o
340OBJS-$(CONFIG_SUNRAST_DECODER) += sunrast.o341OBJS-$(CONFIG_SUNRAST_DECODER) += sunrast.o
341OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o h263.o \342OBJS-$(CONFIG_SVQ1_DECODER) += svq1dec.o svq1.o h263.o \
342 mpegvideo.o error_resilience.o343 mpegvideo.o error_resilience.o
libavcodec/allcodecs.c+1−0
@@ -347,6 +347,7 @@ void avcodec_register_all(void) · 346 unmodified lines
347 REGISTER_ENCDEC (DVBSUB, dvbsub);347 REGISTER_ENCDEC (DVBSUB, dvbsub);
348 REGISTER_ENCDEC (DVDSUB, dvdsub);348 REGISTER_ENCDEC (DVDSUB, dvdsub);
349 REGISTER_DECODER (PGSSUB, pgssub);349 REGISTER_DECODER (PGSSUB, pgssub);
350 REGISTER_DECODER (SRT, srt);
350 REGISTER_ENCDEC (XSUB, xsub);351 REGISTER_ENCDEC (XSUB, xsub);
351 352
352 /* external libraries */353 /* external libraries */
libavcodec/ass.c+40−0
@@ -22,6 +22,46 @@ · 21 unmodified lines
22#include "avcodec.h"22#include "avcodec.h"
23#include "ass.h"23#include "ass.h"
24 24
25int ff_ass_subtitle_header(AVCodecContext *avctx,
26 const char *font, int font_size,
27 int color, int back_color,
28 int bold, int italic, int underline,
29 int alignment)
30{
31 char header[512];
32
33 snprintf(header, sizeof(header),
34 "[Script Info]\r\n"
35 "ScriptType: v4.00+\r\n"
36 "\r\n"
37 "[V4+ Styles]\r\n"
38 "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding\r\n"
39 "Style: Default,%s,%d,&H%x,&H%x,&H%x,&H%x,%d,%d,%d,1,1,0,%d,10,10,10,0,0\r\n"
40 "\r\n"
41 "[Events]\r\n"
42 "Format: Layer, Start, End, Text\r\n",
43 font, font_size, color, color, back_color, back_color,
44 -bold, -italic, -underline, alignment);
45
46 avctx->subtitle_header = av_strdup(header);
47 if (!avctx->subtitle_header)
48 return AVERROR(ENOMEM);
49 avctx->subtitle_header_size = strlen(avctx->subtitle_header);
50 return 0;
51}
52
53int ff_ass_subtitle_header_default(AVCodecContext *avctx)
54{
55 return ff_ass_subtitle_header(avctx, ASS_DEFAULT_FONT,
56 ASS_DEFAULT_FONT_SIZE,
57 ASS_DEFAULT_COLOR,
58 ASS_DEFAULT_BACK_COLOR,
59 ASS_DEFAULT_BOLD,
60 ASS_DEFAULT_ITALIC,
61 ASS_DEFAULT_UNDERLINE,
62 ASS_DEFAULT_ALIGNMENT);
63}
64
25void ff_ass_init(AVSubtitle *sub)65void ff_ass_init(AVSubtitle *sub)
26{66{
27 memset(sub, 0, sizeof(*sub));67 memset(sub, 0, sizeof(*sub));
libavcodec/ass.h+45−0
@@ -24,6 +24,51 @@ · 23 unmodified lines
24 24
25#include "avcodec.h"25#include "avcodec.h"
26 26
27/**
28 * Default values for ASS style.
29 * @defgroup ass_default
30 * @{
31 */
32#define ASS_DEFAULT_FONT "Arial"
33#define ASS_DEFAULT_FONT_SIZE 16
34#define ASS_DEFAULT_COLOR 0xffffff
35#define ASS_DEFAULT_BACK_COLOR 0
36#define ASS_DEFAULT_BOLD 0
37#define ASS_DEFAULT_ITALIC 0
38#define ASS_DEFAULT_UNDERLINE 0
39#define ASS_DEFAULT_ALIGNMENT 2
40/** @} */
41
42/**
43 * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS.
44 *
45 * @param avctx pointer to the AVCodecContext
46 * @param font name of the default font face to use
47 * @param font_size default font size to use
48 * @param color default text color to use (ABGR)
49 * @param back_color default background color to use (ABGR)
50 * @param bold 1 for bold text, 0 for normal text
51 * @param italic 1 for italic text, 0 for normal text
52 * @param underline 1 for underline text, 0 for normal text
53 * @param alignment position of the text (left, center, top...), defined after
54 * the layout of the numpad (1-3 sub, 4-6 mid, 7-9 top)
55 * @return >= 0 on success otherwise an error code <0
56 */
57int ff_ass_subtitle_header(AVCodecContext *avctx,
58 const char *font, int font_size,
59 int color, int back_color,
60 int bold, int italic, int underline,
61 int alignment);
62
63/**
64 * Generate a suitable AVCodecContext.subtitle_header for SUBTITLE_ASS
65 * with default style.
66 *
67 * @param avctx pointer to the AVCodecContext
68 * @return >= 0 on success otherwise an error code <0
69 */
70int ff_ass_subtitle_header_default(AVCodecContext *avctx);
71
27/**72/**
28 * Initialize an AVSubtitle structure for use with ff_ass_add_rect().73 * Initialize an AVSubtitle structure for use with ff_ass_add_rect().
29 *74 *
libavcodec/avcodec.h+2−2
@@ -32,8 +32,8 @@ · 31 unmodified lines
32#include "libavutil/cpu.h"32#include "libavutil/cpu.h"
33 33
34#define LIBAVCODEC_VERSION_MAJOR 5234#define LIBAVCODEC_VERSION_MAJOR 52
35#define LIBAVCODEC_VERSION_MINOR 10035#define LIBAVCODEC_VERSION_MINOR 101
36#define LIBAVCODEC_VERSION_MICRO 136#define LIBAVCODEC_VERSION_MICRO 0
37 37
38#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \38#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
39 LIBAVCODEC_VERSION_MINOR, \39 LIBAVCODEC_VERSION_MINOR, \
libavcodec/srtdec.c+240−0
@@ -0,0 +1,240 @@
1/*
2 * SubRip subtitle decoder
3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
4 *
5 * This file is part of FFmpeg.
6 *
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * FFmpeg is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "libavutil/avstring.h"
23#include "libavcore/parseutils.h"
24#include "avcodec.h"
25#include "ass.h"
26
27static int html_color_parse(AVCodecContext *avctx, const char *str)
28{
29 uint8_t rgba[4];
30 if (av_parse_color(rgba, str, strcspn(str, "\" >"), avctx) < 0)
31 return -1;
32 return rgba[0] | rgba[1] << 8 | rgba[2] << 16;
33}
34
35enum {
36 PARAM_UNKNOWN = -1,
37 PARAM_SIZE,
38 PARAM_COLOR,
39 PARAM_FACE,
40 PARAM_NUMBER
41};
42
43typedef struct {
44 char tag[128];
45 char param[PARAM_NUMBER][128];
46} SrtStack;
47
48static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
49 const char *in, int x1, int y1, int x2, int y2)
50{
51 char c, *param, buffer[128], tmp[128];
52 int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0;
53 SrtStack stack[16];
54
55 stack[0].tag[0] = 0;
56 strcpy(stack[0].param[PARAM_SIZE], "{\\fs}");
57 strcpy(stack[0].param[PARAM_COLOR], "{\\c}");
58 strcpy(stack[0].param[PARAM_FACE], "{\\fn}");
59
60 if (x1 >= 0 && y1 >= 0) {
61 if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1))
62 out += snprintf(out, out_end-out,
63 "{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2);
64 else
65 out += snprintf(out, out_end-out, "{\\an1}{\\pos(%d,%d)}", x1, y1);
66 }
67
68 for (; *in && out < out_end && !end; in++) {
69 switch (*in) {
70 case '\r':
71 break;
72 case '\n':
73 if (line_start) {
74 end = 1;
75 break;
76 }
77 while (out[-1] == ' ')
78 out--;
79 out += snprintf(out, out_end-out, "\\N");
80 line_start = 1;
81 break;
82 case ' ':
83 if (!line_start)
84 *out++ = *in;
85 break;
86 case '{': /* skip all {\xxx} substrings except for {\an%d}
87 and all microdvd like styles such as {Y:xxx} */
88 an += sscanf(in, "{\\an%*1u}%c", &c) == 1;
89 if ((an != 1 && sscanf(in, "{\\%*[^}]}%n%c", &len, &c) > 0) ||
90 sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n%c", &len, &c) > 0) {
91 in += len - 1;
92 } else
93 *out++ = *in;
94 break;
95 case '<':
96 tag_close = in[1] == '/';
97 if (sscanf(in+tag_close+1, "%128[^>]>%n%c", buffer, &len,&c) >= 2) {
98 if ((param = strchr(buffer, ' ')))
99 *param++ = 0;
100 if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) ||
101 ( tag_close && sptr > 0 && !strcmp(stack[sptr-1].tag, buffer))) {
102 int i, j, unknown = 0;
103 in += len + tag_close;
104 if (!tag_close)
105 memset(stack+sptr, 0, sizeof(*stack));
106 if (!strcmp(buffer, "font")) {
107 if (tag_close) {
108 for (i=PARAM_NUMBER-1; i>=0; i--)
109 if (stack[sptr-1].param[i][0])
110 for (j=sptr-2; j>=0; j--)
111 if (stack[j].param[i][0]) {
112 out += snprintf(out, out_end-out,
113 stack[j].param[i]);
114 break;
115 }
116 } else {
117 while (param) {
118 if (!strncmp(param, "size=", 5)) {
119 unsigned font_size;
120 param += 5 + (param[5] == '"');
121 if (sscanf(param, "%u", &font_size) == 1) {
122 snprintf(stack[sptr].param[PARAM_SIZE],
123 sizeof(stack[0].param[PARAM_SIZE]),
124 "{\\fs%u}", font_size);
125 }
126 } else if (!strncmp(param, "color=", 6)) {
127 param += 6 + (param[6] == '"');
128 snprintf(stack[sptr].param[PARAM_COLOR],
129 sizeof(stack[0].param[PARAM_COLOR]),
130 "{\\c&H%X&}",
131 html_color_parse(avctx, param));
132 } else if (!strncmp(param, "face=", 5)) {
133 param += 5 + (param[5] == '"');
134 len = strcspn(param,
135 param[-1] == '"' ? "\"" :" ");
136 av_strlcpy(tmp, param,
137 FFMIN(sizeof(tmp), len+1));
138 param += len;
139 snprintf(stack[sptr].param[PARAM_FACE],
140 sizeof(stack[0].param[PARAM_FACE]),
141 "{\\fn%s}", tmp);
142 }
143 if ((param = strchr(param, ' ')))
144 param++;
145 }
146 for (i=0; i<PARAM_NUMBER; i++)
147 if (stack[sptr].param[i][0])
148 out += snprintf(out, out_end-out,
149 stack[sptr].param[i]);
150 }
151 } else if (!buffer[1] && strspn(buffer, "bisu") == 1) {
152 out += snprintf(out, out_end-out,
153 "{\\%c%d}", buffer[0], !tag_close);
154 } else {
155 unknown = 1;
156 snprintf(tmp, sizeof(tmp), "</%s>", buffer);
157 }
158 if (tag_close) {
159 sptr--;
160 } else if (unknown && !strstr(in, tmp)) {
161 in -= len + tag_close;
162 *out++ = *in;
163 } else
164 av_strlcpy(stack[sptr++].tag, buffer,
165 sizeof(stack[0].tag));
166 break;
167 }
168 }
169 default:
170 *out++ = *in;
171 break;
172 }
173 if (*in != ' ' && *in != '\r' && *in != '\n')
174 line_start = 0;
175 }
176
177 out = FFMIN(out, out_end-3);
178 while (!strncmp(out-2, "\\N", 2))
179 out -= 2;
180 while (out[-1] == ' ')
181 out--;
182 out += snprintf(out, out_end-out, "\r\n");
183 return in;
184}
185
186static const char *read_ts(const char *buf, int *ts_start, int *ts_end,
187 int *x1, int *y1, int *x2, int *y2)
188{
189 int i, hs, ms, ss, he, me, se;
190
191 for (i=0; i<2; i++) {
192 /* try to read timestamps in either the first or second line */
193 int c = sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
194 "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
195 &hs, &ms, &ss, ts_start, &he, &me, &se, ts_end,
196 x1, x2, y1, y2);
197 buf += strcspn(buf, "\n") + 1;
198 if (c >= 8) {
199 *ts_start = 100*(ss + 60*(ms + 60*hs)) + *ts_start/10;
200 *ts_end = 100*(se + 60*(me + 60*he)) + *ts_end /10;
201 return buf;
202 }
203 }
204 return NULL;
205}
206
207static int srt_decode_frame(AVCodecContext *avctx,
208 void *data, int *got_sub_ptr, AVPacket *avpkt)
209{
210 AVSubtitle *sub = data;
211 int ts_start, ts_end, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
212 char buffer[2048];
213 const char *ptr = avpkt->data;
214
215 if (avpkt->size <= 0)
216 return avpkt->size;
217
218 ff_ass_init(sub);
219
220 while (*ptr) {
221 ptr = read_ts(ptr, &ts_start, &ts_end, &x1, &y1, &x2, &y2);
222 if (!ptr)
223 break;
224 ptr = srt_to_ass(avctx, buffer, buffer+sizeof(buffer), ptr,
225 x1, y1, x2, y2);
226 ff_ass_add_rect(sub, buffer, ts_start, ts_end, 0);
227 }
228
229 *got_sub_ptr = sub->num_rects > 0;
230 return avpkt->size;
231}
232
233AVCodec srt_decoder = {
234 .name = "srt",
235 .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
236 .type = AVMEDIA_TYPE_SUBTITLE,
237 .id = CODEC_ID_SRT,
238 .init = ff_ass_subtitle_header_default,
239 .decode = srt_decode_frame,
240};
tests/fate.mak+2−0
@@ -282,6 +282,8 @@ FATE_TESTS += fate-smc · 281 unmodified lines
282fate-smc: CMD = framecrc -i $(SAMPLES)/smc/cass_schi.qt -vsync 0 -pix_fmt rgb24282fate-smc: CMD = framecrc -i $(SAMPLES)/smc/cass_schi.qt -vsync 0 -pix_fmt rgb24
283FATE_TESTS += fate-sp5x283FATE_TESTS += fate-sp5x
284fate-sp5x: CMD = framecrc -idct simple -i $(SAMPLES)/sp5x/sp5x_problem.avi284fate-sp5x: CMD = framecrc -idct simple -i $(SAMPLES)/sp5x/sp5x_problem.avi
285FATE_TESTS += fate-sub-srt
286fate-sub-srt: CMD = md5 -i $(SAMPLES)/sub/SubRip_capability_tester.srt -f ass
285FATE_TESTS += fate-sunraster-1bit-raw287FATE_TESTS += fate-sunraster-1bit-raw
286fate-sunraster-1bit-raw: CMD = framecrc -i $(SAMPLES)/sunraster/lena-1bit-raw.sun288fate-sunraster-1bit-raw: CMD = framecrc -i $(SAMPLES)/sunraster/lena-1bit-raw.sun
287FATE_TESTS += fate-sunraster-1bit-rle289FATE_TESTS += fate-sunraster-1bit-rle
tests/ref/fate/sub-srt+1−0
@@ -0,0 +1 @@
103b2a3f7e7e83624c8e4d1b5569df758

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t