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.

162 lines
5.0KB

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