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.

166 lines
5.2KB

  1. /*
  2. * 3GPP TS 26.245 Timed Text encoder
  3. * Copyright (c) 2012 Philip Langdale <philipl@overt.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 <stdarg.h>
  22. #include "avcodec.h"
  23. #include "libavutil/avassert.h"
  24. #include "libavutil/avstring.h"
  25. #include "libavutil/intreadwrite.h"
  26. #include "ass_split.h"
  27. #include "ass.h"
  28. typedef struct {
  29. ASSSplitContext *ass_ctx;
  30. char buffer[2048];
  31. char *ptr;
  32. char *end;
  33. } MovTextContext;
  34. static av_cold int mov_text_encode_init(AVCodecContext *avctx)
  35. {
  36. /*
  37. * For now, we'll use a fixed default style. When we add styling
  38. * support, this will be generated from the ASS style.
  39. */
  40. static uint8_t text_sample_entry[] = {
  41. 0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
  42. 0x01, // int8_t horizontal-justification
  43. 0xFF, // int8_t vertical-justification
  44. 0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4]
  45. // BoxRecord {
  46. 0x00, 0x00, // int16_t top
  47. 0x00, 0x00, // int16_t left
  48. 0x00, 0x00, // int16_t bottom
  49. 0x00, 0x00, // int16_t right
  50. // };
  51. // StyleRecord {
  52. 0x00, 0x00, // uint16_t startChar
  53. 0x00, 0x00, // uint16_t endChar
  54. 0x00, 0x01, // uint16_t font-ID
  55. 0x00, // uint8_t face-style-flags
  56. 0x12, // uint8_t font-size
  57. 0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4]
  58. // };
  59. // FontTableBox {
  60. 0x00, 0x00, 0x00, 0x12, // uint32_t size
  61. 'f', 't', 'a', 'b', // uint8_t name[4]
  62. 0x00, 0x01, // uint16_t entry-count
  63. // FontRecord {
  64. 0x00, 0x01, // uint16_t font-ID
  65. 0x05, // uint8_t font-name-length
  66. 'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length]
  67. // };
  68. // };
  69. };
  70. MovTextContext *s = avctx->priv_data;
  71. avctx->extradata_size = sizeof text_sample_entry;
  72. avctx->extradata = av_mallocz(avctx->extradata_size);
  73. if (!avctx->extradata)
  74. return AVERROR(ENOMEM);
  75. memcpy(avctx->extradata, text_sample_entry, avctx->extradata_size);
  76. s->ass_ctx = ff_ass_split(avctx->subtitle_header);
  77. return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
  78. }
  79. static void mov_text_text_cb(void *priv, const char *text, int len)
  80. {
  81. MovTextContext *s = priv;
  82. av_assert0(s->end >= s->ptr);
  83. av_strlcpy(s->ptr, text, FFMIN(s->end - s->ptr, len + 1));
  84. s->ptr += FFMIN(s->end - s->ptr, len);
  85. }
  86. static void mov_text_new_line_cb(void *priv, int forced)
  87. {
  88. MovTextContext *s = priv;
  89. av_assert0(s->end >= s->ptr);
  90. av_strlcpy(s->ptr, "\n", FFMIN(s->end - s->ptr, 2));
  91. if (s->end > s->ptr)
  92. s->ptr++;
  93. }
  94. static const ASSCodesCallbacks mov_text_callbacks = {
  95. .text = mov_text_text_cb,
  96. .new_line = mov_text_new_line_cb,
  97. };
  98. static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
  99. int bufsize, const AVSubtitle *sub)
  100. {
  101. MovTextContext *s = avctx->priv_data;
  102. ASSDialog *dialog;
  103. int i, len, num;
  104. s->ptr = s->buffer;
  105. s->end = s->ptr + sizeof(s->buffer);
  106. for (i = 0; i < sub->num_rects; i++) {
  107. if (sub->rects[i]->type != SUBTITLE_ASS) {
  108. av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
  109. return AVERROR(ENOSYS);
  110. }
  111. dialog = ff_ass_split_dialog(s->ass_ctx, sub->rects[i]->ass, 0, &num);
  112. for (; dialog && num--; dialog++) {
  113. ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
  114. }
  115. }
  116. if (s->ptr == s->buffer)
  117. return 0;
  118. AV_WB16(buf, strlen(s->buffer));
  119. buf += 2;
  120. len = av_strlcpy(buf, s->buffer, bufsize - 2);
  121. if (len > bufsize-3) {
  122. av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
  123. return AVERROR(EINVAL);
  124. }
  125. return len + 2;
  126. }
  127. static int mov_text_encode_close(AVCodecContext *avctx)
  128. {
  129. MovTextContext *s = avctx->priv_data;
  130. ff_ass_split_free(s->ass_ctx);
  131. return 0;
  132. }
  133. AVCodec ff_movtext_encoder = {
  134. .name = "mov_text",
  135. .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
  136. .type = AVMEDIA_TYPE_SUBTITLE,
  137. .id = AV_CODEC_ID_MOV_TEXT,
  138. .priv_data_size = sizeof(MovTextContext),
  139. .init = mov_text_encode_init,
  140. .encode_sub = mov_text_encode_frame,
  141. .close = mov_text_encode_close,
  142. };