annotate ffmpeg/libavcodec/srtdec.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents 6840f77b83aa
children
rev   line source
yading@10 1 /*
yading@10 2 * SubRip subtitle decoder
yading@10 3 * Copyright (c) 2010 Aurelien Jacobs <aurel@gnuage.org>
yading@10 4 *
yading@10 5 * This file is part of FFmpeg.
yading@10 6 *
yading@10 7 * FFmpeg is free software; you can redistribute it and/or
yading@10 8 * modify it under the terms of the GNU Lesser General Public
yading@10 9 * License as published by the Free Software Foundation; either
yading@10 10 * version 2.1 of the License, or (at your option) any later version.
yading@10 11 *
yading@10 12 * FFmpeg is distributed in the hope that it will be useful,
yading@10 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
yading@10 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
yading@10 15 * Lesser General Public License for more details.
yading@10 16 *
yading@10 17 * You should have received a copy of the GNU Lesser General Public
yading@10 18 * License along with FFmpeg; if not, write to the Free Software
yading@10 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
yading@10 20 */
yading@10 21
yading@10 22 #include "libavutil/avstring.h"
yading@10 23 #include "libavutil/common.h"
yading@10 24 #include "libavutil/intreadwrite.h"
yading@10 25 #include "libavutil/parseutils.h"
yading@10 26 #include "avcodec.h"
yading@10 27 #include "ass.h"
yading@10 28
yading@10 29 static int html_color_parse(AVCodecContext *avctx, const char *str)
yading@10 30 {
yading@10 31 uint8_t rgba[4];
yading@10 32 if (av_parse_color(rgba, str, strcspn(str, "\" >"), avctx) < 0)
yading@10 33 return -1;
yading@10 34 return rgba[0] | rgba[1] << 8 | rgba[2] << 16;
yading@10 35 }
yading@10 36
yading@10 37 enum {
yading@10 38 PARAM_UNKNOWN = -1,
yading@10 39 PARAM_SIZE,
yading@10 40 PARAM_COLOR,
yading@10 41 PARAM_FACE,
yading@10 42 PARAM_NUMBER
yading@10 43 };
yading@10 44
yading@10 45 typedef struct {
yading@10 46 char tag[128];
yading@10 47 char param[PARAM_NUMBER][128];
yading@10 48 } SrtStack;
yading@10 49
yading@10 50 static const char *srt_to_ass(AVCodecContext *avctx, char *out, char *out_end,
yading@10 51 const char *in, int x1, int y1, int x2, int y2)
yading@10 52 {
yading@10 53 char *param, buffer[128], tmp[128];
yading@10 54 int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0;
yading@10 55 SrtStack stack[16];
yading@10 56
yading@10 57 stack[0].tag[0] = 0;
yading@10 58 strcpy(stack[0].param[PARAM_SIZE], "{\\fs}");
yading@10 59 strcpy(stack[0].param[PARAM_COLOR], "{\\c}");
yading@10 60 strcpy(stack[0].param[PARAM_FACE], "{\\fn}");
yading@10 61
yading@10 62 if (x1 >= 0 && y1 >= 0) {
yading@10 63 if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1))
yading@10 64 snprintf(out, out_end-out,
yading@10 65 "{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2);
yading@10 66 else
yading@10 67 snprintf(out, out_end-out, "{\\an1}{\\pos(%d,%d)}", x1, y1);
yading@10 68 out += strlen(out);
yading@10 69 }
yading@10 70
yading@10 71 for (; out < out_end && !end && *in; in++) {
yading@10 72 switch (*in) {
yading@10 73 case '\r':
yading@10 74 break;
yading@10 75 case '\n':
yading@10 76 if (line_start) {
yading@10 77 end = 1;
yading@10 78 break;
yading@10 79 }
yading@10 80 while (out[-1] == ' ')
yading@10 81 out--;
yading@10 82 snprintf(out, out_end-out, "\\N");
yading@10 83 if(out<out_end) out += strlen(out);
yading@10 84 line_start = 1;
yading@10 85 break;
yading@10 86 case ' ':
yading@10 87 if (!line_start)
yading@10 88 *out++ = *in;
yading@10 89 break;
yading@10 90 case '{': /* skip all {\xxx} substrings except for {\an%d}
yading@10 91 and all microdvd like styles such as {Y:xxx} */
yading@10 92 len = 0;
yading@10 93 an += sscanf(in, "{\\an%*1u}%n", &len) >= 0 && len > 0;
yading@10 94 if ((an != 1 && (len = 0, sscanf(in, "{\\%*[^}]}%n", &len) >= 0 && len > 0)) ||
yading@10 95 (len = 0, sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n", &len) >= 0 && len > 0)) {
yading@10 96 in += len - 1;
yading@10 97 } else
yading@10 98 *out++ = *in;
yading@10 99 break;
yading@10 100 case '<':
yading@10 101 tag_close = in[1] == '/';
yading@10 102 len = 0;
yading@10 103 if (sscanf(in+tag_close+1, "%127[^>]>%n", buffer, &len) >= 1 && len > 0) {
yading@10 104 if ((param = strchr(buffer, ' ')))
yading@10 105 *param++ = 0;
yading@10 106 if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) ||
yading@10 107 ( tag_close && sptr > 0 && !strcmp(stack[sptr-1].tag, buffer))) {
yading@10 108 int i, j, unknown = 0;
yading@10 109 in += len + tag_close;
yading@10 110 if (!tag_close)
yading@10 111 memset(stack+sptr, 0, sizeof(*stack));
yading@10 112 if (!strcmp(buffer, "font")) {
yading@10 113 if (tag_close) {
yading@10 114 for (i=PARAM_NUMBER-1; i>=0; i--)
yading@10 115 if (stack[sptr-1].param[i][0])
yading@10 116 for (j=sptr-2; j>=0; j--)
yading@10 117 if (stack[j].param[i][0]) {
yading@10 118 snprintf(out, out_end-out,
yading@10 119 "%s", stack[j].param[i]);
yading@10 120 if(out<out_end) out += strlen(out);
yading@10 121 break;
yading@10 122 }
yading@10 123 } else {
yading@10 124 while (param) {
yading@10 125 if (!strncmp(param, "size=", 5)) {
yading@10 126 unsigned font_size;
yading@10 127 param += 5 + (param[5] == '"');
yading@10 128 if (sscanf(param, "%u", &font_size) == 1) {
yading@10 129 snprintf(stack[sptr].param[PARAM_SIZE],
yading@10 130 sizeof(stack[0].param[PARAM_SIZE]),
yading@10 131 "{\\fs%u}", font_size);
yading@10 132 }
yading@10 133 } else if (!strncmp(param, "color=", 6)) {
yading@10 134 param += 6 + (param[6] == '"');
yading@10 135 snprintf(stack[sptr].param[PARAM_COLOR],
yading@10 136 sizeof(stack[0].param[PARAM_COLOR]),
yading@10 137 "{\\c&H%X&}",
yading@10 138 html_color_parse(avctx, param));
yading@10 139 } else if (!strncmp(param, "face=", 5)) {
yading@10 140 param += 5 + (param[5] == '"');
yading@10 141 len = strcspn(param,
yading@10 142 param[-1] == '"' ? "\"" :" ");
yading@10 143 av_strlcpy(tmp, param,
yading@10 144 FFMIN(sizeof(tmp), len+1));
yading@10 145 param += len;
yading@10 146 snprintf(stack[sptr].param[PARAM_FACE],
yading@10 147 sizeof(stack[0].param[PARAM_FACE]),
yading@10 148 "{\\fn%s}", tmp);
yading@10 149 }
yading@10 150 if ((param = strchr(param, ' ')))
yading@10 151 param++;
yading@10 152 }
yading@10 153 for (i=0; i<PARAM_NUMBER; i++)
yading@10 154 if (stack[sptr].param[i][0]) {
yading@10 155 snprintf(out, out_end-out,
yading@10 156 "%s", stack[sptr].param[i]);
yading@10 157 if(out<out_end) out += strlen(out);
yading@10 158 }
yading@10 159 }
yading@10 160 } else if (!buffer[1] && strspn(buffer, "bisu") == 1) {
yading@10 161 snprintf(out, out_end-out,
yading@10 162 "{\\%c%d}", buffer[0], !tag_close);
yading@10 163 if(out<out_end) out += strlen(out);
yading@10 164 } else {
yading@10 165 unknown = 1;
yading@10 166 snprintf(tmp, sizeof(tmp), "</%s>", buffer);
yading@10 167 }
yading@10 168 if (tag_close) {
yading@10 169 sptr--;
yading@10 170 } else if (unknown && !strstr(in, tmp)) {
yading@10 171 in -= len + tag_close;
yading@10 172 *out++ = *in;
yading@10 173 } else
yading@10 174 av_strlcpy(stack[sptr++].tag, buffer,
yading@10 175 sizeof(stack[0].tag));
yading@10 176 break;
yading@10 177 }
yading@10 178 }
yading@10 179 default:
yading@10 180 *out++ = *in;
yading@10 181 break;
yading@10 182 }
yading@10 183 if (*in != ' ' && *in != '\r' && *in != '\n')
yading@10 184 line_start = 0;
yading@10 185 }
yading@10 186
yading@10 187 out = FFMIN(out, out_end-3);
yading@10 188 while (!strncmp(out-2, "\\N", 2))
yading@10 189 out -= 2;
yading@10 190 while (out[-1] == ' ')
yading@10 191 out--;
yading@10 192 snprintf(out, out_end-out, "\r\n");
yading@10 193 return in;
yading@10 194 }
yading@10 195
yading@10 196 static const char *read_ts(const char *buf, int *ts_start, int *ts_end,
yading@10 197 int *x1, int *y1, int *x2, int *y2)
yading@10 198 {
yading@10 199 int i, hs, ms, ss, he, me, se;
yading@10 200
yading@10 201 for (i=0; i<2; i++) {
yading@10 202 /* try to read timestamps in either the first or second line */
yading@10 203 int c = sscanf(buf, "%d:%2d:%2d%*1[,.]%3d --> %d:%2d:%2d%*1[,.]%3d"
yading@10 204 "%*[ ]X1:%u X2:%u Y1:%u Y2:%u",
yading@10 205 &hs, &ms, &ss, ts_start, &he, &me, &se, ts_end,
yading@10 206 x1, x2, y1, y2);
yading@10 207 buf += strcspn(buf, "\n") + 1;
yading@10 208 if (c >= 8) {
yading@10 209 *ts_start = 100*(ss + 60*(ms + 60*hs)) + *ts_start/10;
yading@10 210 *ts_end = 100*(se + 60*(me + 60*he)) + *ts_end /10;
yading@10 211 return buf;
yading@10 212 }
yading@10 213 }
yading@10 214 return NULL;
yading@10 215 }
yading@10 216
yading@10 217 static int srt_decode_frame(AVCodecContext *avctx,
yading@10 218 void *data, int *got_sub_ptr, AVPacket *avpkt)
yading@10 219 {
yading@10 220 AVSubtitle *sub = data;
yading@10 221 int ts_start, ts_end, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
yading@10 222 char buffer[2048];
yading@10 223 const char *ptr = avpkt->data;
yading@10 224 const char *end = avpkt->data + avpkt->size;
yading@10 225 int size;
yading@10 226 const uint8_t *p = av_packet_get_side_data(avpkt, AV_PKT_DATA_SUBTITLE_POSITION, &size);
yading@10 227
yading@10 228 if (p && size == 16) {
yading@10 229 x1 = AV_RL32(p );
yading@10 230 y1 = AV_RL32(p + 4);
yading@10 231 x2 = AV_RL32(p + 8);
yading@10 232 y2 = AV_RL32(p + 12);
yading@10 233 }
yading@10 234
yading@10 235 if (avpkt->size <= 0)
yading@10 236 return avpkt->size;
yading@10 237
yading@10 238 while (ptr < end && *ptr) {
yading@10 239 if (avctx->codec->id == AV_CODEC_ID_SRT) {
yading@10 240 ptr = read_ts(ptr, &ts_start, &ts_end, &x1, &y1, &x2, &y2);
yading@10 241 if (!ptr)
yading@10 242 break;
yading@10 243 } else {
yading@10 244 // Do final divide-by-10 outside rescale to force rounding down.
yading@10 245 ts_start = av_rescale_q(avpkt->pts,
yading@10 246 avctx->time_base,
yading@10 247 (AVRational){1,100});
yading@10 248 ts_end = av_rescale_q(avpkt->pts + avpkt->duration,
yading@10 249 avctx->time_base,
yading@10 250 (AVRational){1,100});
yading@10 251 }
yading@10 252 ptr = srt_to_ass(avctx, buffer, buffer+sizeof(buffer), ptr,
yading@10 253 x1, y1, x2, y2);
yading@10 254 ff_ass_add_rect(sub, buffer, ts_start, ts_end-ts_start, 0);
yading@10 255 }
yading@10 256
yading@10 257 *got_sub_ptr = sub->num_rects > 0;
yading@10 258 return avpkt->size;
yading@10 259 }
yading@10 260
yading@10 261 #if CONFIG_SRT_DECODER
yading@10 262 /* deprecated decoder */
yading@10 263 AVCodec ff_srt_decoder = {
yading@10 264 .name = "srt",
yading@10 265 .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle with embedded timing"),
yading@10 266 .type = AVMEDIA_TYPE_SUBTITLE,
yading@10 267 .id = AV_CODEC_ID_SRT,
yading@10 268 .init = ff_ass_subtitle_header_default,
yading@10 269 .decode = srt_decode_frame,
yading@10 270 };
yading@10 271 #endif
yading@10 272
yading@10 273 #if CONFIG_SUBRIP_DECODER
yading@10 274 AVCodec ff_subrip_decoder = {
yading@10 275 .name = "subrip",
yading@10 276 .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
yading@10 277 .type = AVMEDIA_TYPE_SUBTITLE,
yading@10 278 .id = AV_CODEC_ID_SUBRIP,
yading@10 279 .init = ff_ass_subtitle_header_default,
yading@10 280 .decode = srt_decode_frame,
yading@10 281 };
yading@10 282 #endif