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