You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
9.4KB

  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. #include "libavutil/avstring.h"
  22. #include "libavutil/common.h"
  23. #include "libavutil/intreadwrite.h"
  24. #include "libavutil/parseutils.h"
  25. #include "avcodec.h"
  26. #include "ass.h"
  27. static 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. enum {
  35. PARAM_UNKNOWN = -1,
  36. PARAM_SIZE,
  37. PARAM_COLOR,
  38. PARAM_FACE,
  39. PARAM_NUMBER
  40. };
  41. typedef struct {
  42. char tag[128];
  43. char param[PARAM_NUMBER][128];
  44. } SrtStack;
  45. static void rstrip_spaces_buf(AVBPrint *buf)
  46. {
  47. while (buf->len > 0 && buf->str[buf->len - 1] == ' ')
  48. buf->str[--buf->len] = 0;
  49. }
  50. static void srt_to_ass(AVCodecContext *avctx, AVBPrint *dst,
  51. const char *in, int x1, int y1, int x2, int y2)
  52. {
  53. char *param, buffer[128], tmp[128];
  54. int len, tag_close, sptr = 1, line_start = 1, an = 0, end = 0;
  55. SrtStack stack[16];
  56. stack[0].tag[0] = 0;
  57. strcpy(stack[0].param[PARAM_SIZE], "{\\fs}");
  58. strcpy(stack[0].param[PARAM_COLOR], "{\\c}");
  59. strcpy(stack[0].param[PARAM_FACE], "{\\fn}");
  60. if (x1 >= 0 && y1 >= 0) {
  61. if (x2 >= 0 && y2 >= 0 && (x2 != x1 || y2 != y1))
  62. av_bprintf(dst, "{\\an1}{\\move(%d,%d,%d,%d)}", x1, y1, x2, y2);
  63. else
  64. av_bprintf(dst, "{\\an1}{\\pos(%d,%d)}", x1, y1);
  65. }
  66. for (; !end && *in; in++) {
  67. switch (*in) {
  68. case '\r':
  69. break;
  70. case '\n':
  71. if (line_start) {
  72. end = 1;
  73. break;
  74. }
  75. rstrip_spaces_buf(dst);
  76. av_bprintf(dst, "\\N");
  77. line_start = 1;
  78. break;
  79. case ' ':
  80. if (!line_start)
  81. av_bprint_chars(dst, *in, 1);
  82. break;
  83. case '{': /* skip all {\xxx} substrings except for {\an%d}
  84. and all microdvd like styles such as {Y:xxx} */
  85. len = 0;
  86. an += sscanf(in, "{\\an%*1u}%n", &len) >= 0 && len > 0;
  87. if ((an != 1 && (len = 0, sscanf(in, "{\\%*[^}]}%n", &len) >= 0 && len > 0)) ||
  88. (len = 0, sscanf(in, "{%*1[CcFfoPSsYy]:%*[^}]}%n", &len) >= 0 && len > 0)) {
  89. in += len - 1;
  90. } else
  91. av_bprint_chars(dst, *in, 1);
  92. break;
  93. case '<':
  94. tag_close = in[1] == '/';
  95. len = 0;
  96. if (sscanf(in+tag_close+1, "%127[^>]>%n", buffer, &len) >= 1 && len > 0) {
  97. if ((param = strchr(buffer, ' ')))
  98. *param++ = 0;
  99. if ((!tag_close && sptr < FF_ARRAY_ELEMS(stack)) ||
  100. ( tag_close && sptr > 0 && !strcmp(stack[sptr-1].tag, buffer))) {
  101. int i, j, unknown = 0;
  102. in += len + tag_close;
  103. if (!tag_close)
  104. memset(stack+sptr, 0, sizeof(*stack));
  105. if (!strcmp(buffer, "font")) {
  106. if (tag_close) {
  107. for (i=PARAM_NUMBER-1; i>=0; i--)
  108. if (stack[sptr-1].param[i][0])
  109. for (j=sptr-2; j>=0; j--)
  110. if (stack[j].param[i][0]) {
  111. av_bprintf(dst, "%s", stack[j].param[i]);
  112. break;
  113. }
  114. } else {
  115. while (param) {
  116. if (!strncmp(param, "size=", 5)) {
  117. unsigned font_size;
  118. param += 5 + (param[5] == '"');
  119. if (sscanf(param, "%u", &font_size) == 1) {
  120. snprintf(stack[sptr].param[PARAM_SIZE],
  121. sizeof(stack[0].param[PARAM_SIZE]),
  122. "{\\fs%u}", font_size);
  123. }
  124. } else if (!strncmp(param, "color=", 6)) {
  125. param += 6 + (param[6] == '"');
  126. snprintf(stack[sptr].param[PARAM_COLOR],
  127. sizeof(stack[0].param[PARAM_COLOR]),
  128. "{\\c&H%X&}",
  129. html_color_parse(avctx, param));
  130. } else if (!strncmp(param, "face=", 5)) {
  131. param += 5 + (param[5] == '"');
  132. len = strcspn(param,
  133. param[-1] == '"' ? "\"" :" ");
  134. av_strlcpy(tmp, param,
  135. FFMIN(sizeof(tmp), len+1));
  136. param += len;
  137. snprintf(stack[sptr].param[PARAM_FACE],
  138. sizeof(stack[0].param[PARAM_FACE]),
  139. "{\\fn%s}", tmp);
  140. }
  141. if ((param = strchr(param, ' ')))
  142. param++;
  143. }
  144. for (i=0; i<PARAM_NUMBER; i++)
  145. if (stack[sptr].param[i][0])
  146. av_bprintf(dst, "%s", stack[sptr].param[i]);
  147. }
  148. } else if (!buffer[1] && strspn(buffer, "bisu") == 1) {
  149. av_bprintf(dst, "{\\%c%d}", buffer[0], !tag_close);
  150. } else {
  151. unknown = 1;
  152. snprintf(tmp, sizeof(tmp), "</%s>", buffer);
  153. }
  154. if (tag_close) {
  155. sptr--;
  156. } else if (unknown && !strstr(in, tmp)) {
  157. in -= len + tag_close;
  158. av_bprint_chars(dst, *in, 1);
  159. } else
  160. av_strlcpy(stack[sptr++].tag, buffer,
  161. sizeof(stack[0].tag));
  162. break;
  163. }
  164. }
  165. default:
  166. av_bprint_chars(dst, *in, 1);
  167. break;
  168. }
  169. if (*in != ' ' && *in != '\r' && *in != '\n')
  170. line_start = 0;
  171. }
  172. while (dst->len >= 2 && !strncmp(&dst->str[dst->len - 2], "\\N", 2))
  173. dst->len -= 2;
  174. dst->str[dst->len] = 0;
  175. rstrip_spaces_buf(dst);
  176. av_bprintf(dst, "\r\n");
  177. }
  178. static int srt_decode_frame(AVCodecContext *avctx,
  179. void *data, int *got_sub_ptr, AVPacket *avpkt)
  180. {
  181. AVSubtitle *sub = data;
  182. AVBPrint buffer;
  183. int ts_start, ts_end, x1 = -1, y1 = -1, x2 = -1, y2 = -1;
  184. int size, ret;
  185. const uint8_t *p = av_packet_get_side_data(avpkt, AV_PKT_DATA_SUBTITLE_POSITION, &size);
  186. if (p && size == 16) {
  187. x1 = AV_RL32(p );
  188. y1 = AV_RL32(p + 4);
  189. x2 = AV_RL32(p + 8);
  190. y2 = AV_RL32(p + 12);
  191. }
  192. if (avpkt->size <= 0)
  193. return avpkt->size;
  194. av_bprint_init(&buffer, 0, AV_BPRINT_SIZE_UNLIMITED);
  195. // TODO: reindent
  196. // Do final divide-by-10 outside rescale to force rounding down.
  197. ts_start = av_rescale_q(avpkt->pts,
  198. avctx->time_base,
  199. (AVRational){1,100});
  200. ts_end = av_rescale_q(avpkt->pts + avpkt->duration,
  201. avctx->time_base,
  202. (AVRational){1,100});
  203. srt_to_ass(avctx, &buffer, avpkt->data, x1, y1, x2, y2);
  204. ret = ff_ass_add_rect_bprint(sub, &buffer, ts_start, ts_end-ts_start, 0);
  205. av_bprint_finalize(&buffer, NULL);
  206. if (ret < 0)
  207. return ret;
  208. *got_sub_ptr = sub->num_rects > 0;
  209. return avpkt->size;
  210. }
  211. #if CONFIG_SRT_DECODER
  212. /* deprecated decoder */
  213. AVCodec ff_srt_decoder = {
  214. .name = "srt",
  215. .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
  216. .type = AVMEDIA_TYPE_SUBTITLE,
  217. .id = AV_CODEC_ID_SUBRIP,
  218. .init = ff_ass_subtitle_header_default,
  219. .decode = srt_decode_frame,
  220. };
  221. #endif
  222. #if CONFIG_SUBRIP_DECODER
  223. AVCodec ff_subrip_decoder = {
  224. .name = "subrip",
  225. .long_name = NULL_IF_CONFIG_SMALL("SubRip subtitle"),
  226. .type = AVMEDIA_TYPE_SUBTITLE,
  227. .id = AV_CODEC_ID_SUBRIP,
  228. .init = ff_ass_subtitle_header_default,
  229. .decode = srt_decode_frame,
  230. };
  231. #endif