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.

367 lines
11KB

  1. /*
  2. * TED Talks captions format decoder
  3. * Copyright (c) 2012 Nicolas George
  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/bprint.h"
  22. #include "libavutil/log.h"
  23. #include "libavutil/opt.h"
  24. #include "avformat.h"
  25. #include "internal.h"
  26. #include "subtitles.h"
  27. typedef struct {
  28. AVClass *class;
  29. int64_t start_time;
  30. FFDemuxSubtitlesQueue subs;
  31. } TEDCaptionsDemuxer;
  32. static const AVOption tedcaptions_options[] = {
  33. { "start_time", "set the start time (offset) of the subtitles, in ms",
  34. offsetof(TEDCaptionsDemuxer, start_time), FF_OPT_TYPE_INT64,
  35. { .i64 = 15000 }, INT64_MIN, INT64_MAX,
  36. AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM },
  37. { NULL },
  38. };
  39. static const AVClass tedcaptions_demuxer_class = {
  40. .class_name = "tedcaptions_demuxer",
  41. .item_name = av_default_item_name,
  42. .option = tedcaptions_options,
  43. .version = LIBAVUTIL_VERSION_INT,
  44. };
  45. #define BETWEEN(a, amin, amax) ((unsigned)((a) - (amin)) <= (amax) - (amin))
  46. #define HEX_DIGIT_TEST(c) (BETWEEN(c, '0', '9') || BETWEEN((c) | 32, 'a', 'z'))
  47. #define HEX_DIGIT_VAL(c) ((c) <= '9' ? (c) - '0' : ((c) | 32) - 'a' + 10)
  48. #define ERR_CODE(c) (c < 0 ? c : AVERROR_INVALIDDATA)
  49. static void av_bprint_utf8(AVBPrint *bp, unsigned c)
  50. {
  51. int bytes, i;
  52. if (c <= 0x7F) {
  53. av_bprint_chars(bp, c, 1);
  54. return;
  55. }
  56. bytes = (av_log2(c) - 2) / 5;
  57. av_bprint_chars(bp, (c >> (bytes * 6)) | ((0xFF80 >> bytes) & 0xFF), 1);
  58. for (i = bytes - 1; i >= 0; i--)
  59. av_bprint_chars(bp, ((c >> (i * 6)) & 0x3F) | 0x80, 1);
  60. }
  61. static void next_byte(AVIOContext *pb, int *cur_byte)
  62. {
  63. uint8_t b;
  64. int ret = avio_read(pb, &b, 1);
  65. *cur_byte = ret > 0 ? b : ret == 0 ? AVERROR_EOF : ret;
  66. }
  67. static void skip_spaces(AVIOContext *pb, int *cur_byte)
  68. {
  69. while (*cur_byte == ' ' || *cur_byte == '\t' ||
  70. *cur_byte == '\n' || *cur_byte == '\r')
  71. next_byte(pb, cur_byte);
  72. }
  73. static int expect_byte(AVIOContext *pb, int *cur_byte, uint8_t c)
  74. {
  75. skip_spaces(pb, cur_byte);
  76. if (*cur_byte != c)
  77. return ERR_CODE(*cur_byte);
  78. next_byte(pb, cur_byte);
  79. return 0;
  80. }
  81. static int parse_string(AVIOContext *pb, int *cur_byte, AVBPrint *bp, int full)
  82. {
  83. int ret;
  84. av_bprint_init(bp, 0, full ? -1 : 1);
  85. ret = expect_byte(pb, cur_byte, '"');
  86. if (ret < 0)
  87. goto fail;
  88. while (*cur_byte > 0 && *cur_byte != '"') {
  89. if (*cur_byte == '\\') {
  90. next_byte(pb, cur_byte);
  91. if (*cur_byte < 0) {
  92. ret = AVERROR_INVALIDDATA;
  93. goto fail;
  94. }
  95. if ((*cur_byte | 32) == 'u') {
  96. unsigned chr = 0, i;
  97. for (i = 0; i < 4; i++) {
  98. next_byte(pb, cur_byte);
  99. if (!HEX_DIGIT_TEST(*cur_byte)) {
  100. ret = ERR_CODE(*cur_byte);
  101. goto fail;
  102. }
  103. chr = chr * 16 + HEX_DIGIT_VAL(*cur_byte);
  104. }
  105. av_bprint_utf8(bp, chr);
  106. } else {
  107. av_bprint_chars(bp, *cur_byte, 1);
  108. }
  109. } else {
  110. av_bprint_chars(bp, *cur_byte, 1);
  111. }
  112. next_byte(pb, cur_byte);
  113. }
  114. ret = expect_byte(pb, cur_byte, '"');
  115. if (ret < 0)
  116. goto fail;
  117. if (full && !av_bprint_is_complete(bp)) {
  118. ret = AVERROR(ENOMEM);
  119. goto fail;
  120. }
  121. return 0;
  122. fail:
  123. av_bprint_finalize(bp, NULL);
  124. return ret;
  125. }
  126. static int parse_label(AVIOContext *pb, int *cur_byte, AVBPrint *bp)
  127. {
  128. int ret;
  129. ret = parse_string(pb, cur_byte, bp, 0);
  130. if (ret < 0)
  131. return ret;
  132. ret = expect_byte(pb, cur_byte, ':');
  133. if (ret < 0)
  134. return ret;
  135. return 0;
  136. }
  137. static int parse_boolean(AVIOContext *pb, int *cur_byte, int *result)
  138. {
  139. static const char * const text[] = { "false", "true" };
  140. const char *p;
  141. int i;
  142. skip_spaces(pb, cur_byte);
  143. for (i = 0; i < 2; i++) {
  144. p = text[i];
  145. if (*cur_byte != *p)
  146. continue;
  147. for (; *p; p++, next_byte(pb, cur_byte))
  148. if (*cur_byte != *p)
  149. return AVERROR_INVALIDDATA;
  150. if (BETWEEN(*cur_byte | 32, 'a', 'z'))
  151. return AVERROR_INVALIDDATA;
  152. *result = i;
  153. return 0;
  154. }
  155. return AVERROR_INVALIDDATA;
  156. }
  157. static int parse_int(AVIOContext *pb, int *cur_byte, int64_t *result)
  158. {
  159. int64_t val = 0;
  160. skip_spaces(pb, cur_byte);
  161. if ((unsigned)*cur_byte - '0' > 9)
  162. return AVERROR_INVALIDDATA;
  163. while (BETWEEN(*cur_byte, '0', '9')) {
  164. val = val * 10 + (*cur_byte - '0');
  165. next_byte(pb, cur_byte);
  166. }
  167. *result = val;
  168. return 0;
  169. }
  170. static int parse_file(AVIOContext *pb, FFDemuxSubtitlesQueue *subs)
  171. {
  172. int ret, cur_byte, start_of_par;
  173. AVBPrint label, content;
  174. int64_t pos, start, duration;
  175. AVPacket *pkt;
  176. next_byte(pb, &cur_byte);
  177. ret = expect_byte(pb, &cur_byte, '{');
  178. if (ret < 0)
  179. return AVERROR_INVALIDDATA;
  180. ret = parse_label(pb, &cur_byte, &label);
  181. if (ret < 0 || strcmp(label.str, "captions"))
  182. return AVERROR_INVALIDDATA;
  183. ret = expect_byte(pb, &cur_byte, '[');
  184. if (ret < 0)
  185. return AVERROR_INVALIDDATA;
  186. while (1) {
  187. content.size = 0;
  188. start = duration = AV_NOPTS_VALUE;
  189. ret = expect_byte(pb, &cur_byte, '{');
  190. if (ret < 0)
  191. return ret;
  192. pos = avio_tell(pb) - 1;
  193. while (1) {
  194. ret = parse_label(pb, &cur_byte, &label);
  195. if (ret < 0)
  196. return ret;
  197. if (!strcmp(label.str, "startOfParagraph")) {
  198. ret = parse_boolean(pb, &cur_byte, &start_of_par);
  199. if (ret < 0)
  200. return ret;
  201. } else if (!strcmp(label.str, "content")) {
  202. ret = parse_string(pb, &cur_byte, &content, 1);
  203. if (ret < 0)
  204. return ret;
  205. } else if (!strcmp(label.str, "startTime")) {
  206. ret = parse_int(pb, &cur_byte, &start);
  207. if (ret < 0)
  208. return ret;
  209. } else if (!strcmp(label.str, "duration")) {
  210. ret = parse_int(pb, &cur_byte, &duration);
  211. if (ret < 0)
  212. return ret;
  213. } else {
  214. return AVERROR_INVALIDDATA;
  215. }
  216. skip_spaces(pb, &cur_byte);
  217. if (cur_byte != ',')
  218. break;
  219. next_byte(pb, &cur_byte);
  220. }
  221. ret = expect_byte(pb, &cur_byte, '}');
  222. if (ret < 0)
  223. return ret;
  224. if (!content.size || start == AV_NOPTS_VALUE ||
  225. duration == AV_NOPTS_VALUE)
  226. return AVERROR_INVALIDDATA;
  227. pkt = ff_subtitles_queue_insert(subs, content.str, content.len, 0);
  228. if (!pkt)
  229. return AVERROR(ENOMEM);
  230. pkt->pos = pos;
  231. pkt->pts = start;
  232. pkt->duration = duration;
  233. av_bprint_finalize(&content, NULL);
  234. skip_spaces(pb, &cur_byte);
  235. if (cur_byte != ',')
  236. break;
  237. next_byte(pb, &cur_byte);
  238. }
  239. ret = expect_byte(pb, &cur_byte, ']');
  240. if (ret < 0)
  241. return ret;
  242. ret = expect_byte(pb, &cur_byte, '}');
  243. if (ret < 0)
  244. return ret;
  245. skip_spaces(pb, &cur_byte);
  246. if (cur_byte != AVERROR_EOF)
  247. return ERR_CODE(cur_byte);
  248. return 0;
  249. }
  250. static av_cold int tedcaptions_read_header(AVFormatContext *avf)
  251. {
  252. TEDCaptionsDemuxer *tc = avf->priv_data;
  253. AVStream *st;
  254. int ret, i;
  255. AVPacket *last;
  256. ret = parse_file(avf->pb, &tc->subs);
  257. if (ret < 0) {
  258. if (ret == AVERROR_INVALIDDATA)
  259. av_log(avf, AV_LOG_ERROR, "Syntax error near offset %"PRId64".\n",
  260. avio_tell(avf->pb));
  261. ff_subtitles_queue_clean(&tc->subs);
  262. return ret;
  263. }
  264. ff_subtitles_queue_finalize(&tc->subs);
  265. for (i = 0; i < tc->subs.nb_subs; i++)
  266. tc->subs.subs[i].pts += tc->start_time;
  267. last = &tc->subs.subs[tc->subs.nb_subs - 1];
  268. st = avformat_new_stream(avf, NULL);
  269. if (!st)
  270. return AVERROR(ENOMEM);
  271. st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
  272. st->codec->codec_id = AV_CODEC_ID_TEXT;
  273. avpriv_set_pts_info(st, 64, 1, 1000);
  274. st->probe_packets = 0;
  275. st->start_time = 0;
  276. st->duration = last->pts + last->duration;
  277. st->cur_dts = 0;
  278. return 0;
  279. }
  280. static int tedcaptions_read_packet(AVFormatContext *avf, AVPacket *packet)
  281. {
  282. TEDCaptionsDemuxer *tc = avf->priv_data;
  283. return ff_subtitles_queue_read_packet(&tc->subs, packet);
  284. }
  285. static int tedcaptions_read_close(AVFormatContext *avf)
  286. {
  287. TEDCaptionsDemuxer *tc = avf->priv_data;
  288. ff_subtitles_queue_clean(&tc->subs);
  289. return 0;
  290. }
  291. static av_cold int tedcaptions_read_probe(AVProbeData *p)
  292. {
  293. static const char *const tags[] = {
  294. "\"captions\"", "\"duration\"", "\"content\"",
  295. "\"startOfParagraph\"", "\"startTime\"",
  296. };
  297. unsigned i, count = 0;
  298. const char *t;
  299. if (p->buf[strspn(p->buf, " \t\r\n")] != '{')
  300. return 0;
  301. for (i = 0; i < FF_ARRAY_ELEMS(tags); i++) {
  302. if (!(t = strstr(p->buf, tags[i])))
  303. continue;
  304. t += strlen(tags[i]);
  305. t += strspn(t, " \t\r\n");
  306. if (*t == ':')
  307. count++;
  308. }
  309. return count == FF_ARRAY_ELEMS(tags) ? AVPROBE_SCORE_MAX :
  310. count ? AVPROBE_SCORE_EXTENSION : 0;
  311. }
  312. static int tedcaptions_read_seek(AVFormatContext *avf, int stream_index,
  313. int64_t min_ts, int64_t ts, int64_t max_ts,
  314. int flags)
  315. {
  316. TEDCaptionsDemuxer *tc = avf->priv_data;
  317. return ff_subtitles_queue_seek(&tc->subs, avf, stream_index,
  318. min_ts, ts, max_ts, flags);
  319. }
  320. AVInputFormat ff_tedcaptions_demuxer = {
  321. .name = "tedcaptions",
  322. .long_name = NULL_IF_CONFIG_SMALL("TED Talks captions"),
  323. .priv_data_size = sizeof(TEDCaptionsDemuxer),
  324. .priv_class = &tedcaptions_demuxer_class,
  325. .read_header = tedcaptions_read_header,
  326. .read_packet = tedcaptions_read_packet,
  327. .read_close = tedcaptions_read_close,
  328. .read_probe = tedcaptions_read_probe,
  329. .read_seek2 = tedcaptions_read_seek,
  330. };