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 "libavutil/mem.h"
28 #include "libavutil/common.h"
29 #include "ass_split.h"
30 #include "ass.h"
31 
32 #define STYLE_FLAG_BOLD (1<<0)
33 #define STYLE_FLAG_ITALIC (1<<1)
34 #define STYLE_FLAG_UNDERLINE (1<<2)
35 #define STYLE_RECORD_SIZE 12
36 #define SIZE_ADD 10
37 
38 #define STYL_BOX (1<<0)
39 #define HLIT_BOX (1<<1)
40 #define HCLR_BOX (1<<2)
41 
42 #define av_bprint_append_any(buf, data, size) av_bprint_append_data(buf, ((const char*)data), size)
43 
44 typedef struct {
45  uint16_t style_start;
46  uint16_t style_end;
47  uint8_t style_flag;
48 } StyleBox;
49 
50 typedef struct {
51  uint16_t start;
52  uint16_t end;
53 } HighlightBox;
54 
55 typedef struct {
56  uint32_t color;
58 
59 typedef struct {
61 
63  AVBPrint buffer;
68  int count;
69  uint8_t box_flags;
70  uint16_t style_entries;
71  uint16_t style_fontID;
73  uint32_t style_color;
74  uint16_t text_pos;
76 
77 typedef struct {
78  uint32_t type;
79  void (*encode)(MovTextContext *s, uint32_t tsmb_type);
80 } Box;
81 
83 {
84  int j;
85  if (s->box_flags & STYL_BOX) {
86  for (j = 0; j < s->count; j++) {
87  av_freep(&s->style_attributes[j]);
88  }
90  }
91 }
92 
93 static void encode_styl(MovTextContext *s, uint32_t tsmb_type)
94 {
95  int j;
96  uint32_t tsmb_size;
97  if (s->box_flags & STYL_BOX) {
98  tsmb_size = s->count * STYLE_RECORD_SIZE + SIZE_ADD;
99  tsmb_size = AV_RB32(&tsmb_size);
100  s->style_entries = AV_RB16(&s->count);
101  s->style_fontID = 0x00 | 0x01<<8;
102  s->style_fontsize = 0x12;
103  s->style_color = MKTAG(0xFF, 0xFF, 0xFF, 0xFF);
104  /*The above three attributes are hard coded for now
105  but will come from ASS style in the future*/
106  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
107  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
109  for (j = 0; j < s->count; j++) {
116  }
117  mov_text_cleanup(s);
118  }
119 }
120 
121 static void encode_hlit(MovTextContext *s, uint32_t tsmb_type)
122 {
123  uint32_t tsmb_size;
124  if (s->box_flags & HLIT_BOX) {
125  tsmb_size = 12;
126  tsmb_size = AV_RB32(&tsmb_size);
127  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
128  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
129  av_bprint_append_any(&s->buffer, &s->hlit.start, 2);
130  av_bprint_append_any(&s->buffer, &s->hlit.end, 2);
131  }
132 }
133 
134 static void encode_hclr(MovTextContext *s, uint32_t tsmb_type)
135 {
136  uint32_t tsmb_size;
137  if (s->box_flags & HCLR_BOX) {
138  tsmb_size = 12;
139  tsmb_size = AV_RB32(&tsmb_size);
140  av_bprint_append_any(&s->buffer, &tsmb_size, 4);
141  av_bprint_append_any(&s->buffer, &tsmb_type, 4);
142  av_bprint_append_any(&s->buffer, &s->hclr.color, 4);
143  }
144 }
145 
146 static const Box box_types[] = {
147  { MKTAG('s','t','y','l'), encode_styl },
148  { MKTAG('h','l','i','t'), encode_hlit },
149  { MKTAG('h','c','l','r'), encode_hclr },
150 };
151 
152 const static size_t box_count = FF_ARRAY_ELEMS(box_types);
153 
155 {
156  /*
157  * For now, we'll use a fixed default style. When we add styling
158  * support, this will be generated from the ASS style.
159  */
160  static const uint8_t text_sample_entry[] = {
161  0x00, 0x00, 0x00, 0x00, // uint32_t displayFlags
162  0x01, // int8_t horizontal-justification
163  0xFF, // int8_t vertical-justification
164  0x00, 0x00, 0x00, 0x00, // uint8_t background-color-rgba[4]
165  // BoxRecord {
166  0x00, 0x00, // int16_t top
167  0x00, 0x00, // int16_t left
168  0x00, 0x00, // int16_t bottom
169  0x00, 0x00, // int16_t right
170  // };
171  // StyleRecord {
172  0x00, 0x00, // uint16_t startChar
173  0x00, 0x00, // uint16_t endChar
174  0x00, 0x01, // uint16_t font-ID
175  0x00, // uint8_t face-style-flags
176  0x12, // uint8_t font-size
177  0xFF, 0xFF, 0xFF, 0xFF, // uint8_t text-color-rgba[4]
178  // };
179  // FontTableBox {
180  0x00, 0x00, 0x00, 0x12, // uint32_t size
181  'f', 't', 'a', 'b', // uint8_t name[4]
182  0x00, 0x01, // uint16_t entry-count
183  // FontRecord {
184  0x00, 0x01, // uint16_t font-ID
185  0x05, // uint8_t font-name-length
186  'S', 'e', 'r', 'i', 'f',// uint8_t font[font-name-length]
187  // };
188  // };
189  };
190 
191  MovTextContext *s = avctx->priv_data;
192  s->avctx = avctx;
193 
194  avctx->extradata_size = sizeof text_sample_entry;
196  if (!avctx->extradata)
197  return AVERROR(ENOMEM);
198 
200 
201  memcpy(avctx->extradata, text_sample_entry, avctx->extradata_size);
202 
203  s->ass_ctx = ff_ass_split(avctx->subtitle_header);
204  return s->ass_ctx ? 0 : AVERROR_INVALIDDATA;
205 }
206 
207 static void mov_text_style_cb(void *priv, const char style, int close)
208 {
209  MovTextContext *s = priv;
210  if (!close) {
211  if (!(s->box_flags & STYL_BOX)) { //first style entry
212 
214 
215  if (!s->style_attributes_temp) {
216  av_bprint_clear(&s->buffer);
217  s->box_flags &= ~STYL_BOX;
218  return;
219  }
220 
223  } else {
224  if (s->style_attributes_temp->style_flag) { //break the style record here and start a new one
228  if (!s->style_attributes_temp) {
229  mov_text_cleanup(s);
230  av_bprint_clear(&s->buffer);
231  s->box_flags &= ~STYL_BOX;
232  return;
233  }
234 
237  } else {
240  }
241  }
242  switch (style){
243  case 'b':
245  break;
246  case 'i':
248  break;
249  case 'u':
251  break;
252  }
253  } else if (!s->style_attributes_temp) {
254  av_log(s->avctx, AV_LOG_WARNING, "Ignoring unmatched close tag\n");
255  return;
256  } else {
259 
261 
262  if (!s->style_attributes_temp) {
263  mov_text_cleanup(s);
264  av_bprint_clear(&s->buffer);
265  s->box_flags &= ~STYL_BOX;
266  return;
267  }
268 
270  switch (style){
271  case 'b':
273  break;
274  case 'i':
276  break;
277  case 'u':
279  break;
280  }
281  if (s->style_attributes_temp->style_flag) { //start of new style record
283  }
284  }
285  s->box_flags |= STYL_BOX;
286 }
287 
288 static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color_id)
289 {
290  MovTextContext *s = priv;
291  if (color_id == 2) { //secondary color changes
292  if (s->box_flags & HLIT_BOX) { //close tag
293  s->hlit.end = AV_RB16(&s->text_pos);
294  } else {
295  s->box_flags |= HCLR_BOX;
296  s->box_flags |= HLIT_BOX;
297  s->hlit.start = AV_RB16(&s->text_pos);
298  s->hclr.color = color | (0xFF << 24); //set alpha value to FF
299  }
300  }
301  /* If there are more than one secondary color changes in ASS, take start of
302  first section and end of last section. Movtext allows only one
303  highlight box per sample.
304  */
305 }
306 
307 static void mov_text_text_cb(void *priv, const char *text, int len)
308 {
309  MovTextContext *s = priv;
310  av_bprint_append_data(&s->buffer, text, len);
311  s->text_pos += len;
312 }
313 
314 static void mov_text_new_line_cb(void *priv, int forced)
315 {
316  MovTextContext *s = priv;
317  av_bprint_append_data(&s->buffer, "\n", 1);
318  s->text_pos += 1;
319 }
320 
323  .new_line = mov_text_new_line_cb,
324  .style = mov_text_style_cb,
325  .color = mov_text_color_cb,
326 };
327 
328 static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf,
329  int bufsize, const AVSubtitle *sub)
330 {
331  MovTextContext *s = avctx->priv_data;
332  ASSDialog *dialog;
333  int i, length;
334  size_t j;
335 
336  s->text_pos = 0;
337  s->count = 0;
338  s->box_flags = 0;
339  s->style_entries = 0;
340  for (i = 0; i < sub->num_rects; i++) {
341  const char *ass = sub->rects[i]->ass;
342 
343  if (sub->rects[i]->type != SUBTITLE_ASS) {
344  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
345  return AVERROR(ENOSYS);
346  }
347 
348 #if FF_API_ASS_TIMING
349  if (!strncmp(ass, "Dialogue: ", 10)) {
350  int num;
351  dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
352  for (; dialog && num--; dialog++) {
353  ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
354  }
355  } else {
356 #endif
357  dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
358  if (!dialog)
359  return AVERROR(ENOMEM);
360  ff_ass_split_override_codes(&mov_text_callbacks, s, dialog->text);
361  ff_ass_free_dialog(&dialog);
362 #if FF_API_ASS_TIMING
363  }
364 #endif
365 
366  for (j = 0; j < box_count; j++) {
367  box_types[j].encode(s, box_types[j].type);
368  }
369  }
370 
371  AV_WB16(buf, s->text_pos);
372  buf += 2;
373 
374  if (!av_bprint_is_complete(&s->buffer)) {
375  length = AVERROR(ENOMEM);
376  goto exit;
377  }
378 
379  if (!s->buffer.len) {
380  length = 0;
381  goto exit;
382  }
383 
384  if (s->buffer.len > bufsize - 3) {
385  av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n");
386  length = AVERROR(EINVAL);
387  goto exit;
388  }
389 
390  memcpy(buf, s->buffer.str, s->buffer.len);
391  length = s->buffer.len + 2;
392 
393 exit:
394  av_bprint_clear(&s->buffer);
395  return length;
396 }
397 
399 {
400  MovTextContext *s = avctx->priv_data;
403  return 0;
404 }
405 
407  .name = "mov_text",
408  .long_name = NULL_IF_CONFIG_SMALL("3GPP Timed Text subtitle"),
409  .type = AVMEDIA_TYPE_SUBTITLE,
410  .id = AV_CODEC_ID_MOV_TEXT,
411  .priv_data_size = sizeof(MovTextContext),
413  .encode_sub = mov_text_encode_frame,
414  .close = mov_text_encode_close,
415 };
#define NULL
Definition: coverity.c:32
const char * s
Definition: avisynth_c.h:768
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
fields extracted from the [Events] section
Definition: ass_split.h:71
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:182
Memory handling functions.
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:35
ASSDialog * ff_ass_split_dialog2(ASSSplitContext *ctx, const char *buf)
Split one ASS Dialogue line from a string buffer.
Definition: ass_split.c:442
static const size_t box_count
Definition: movtextenc.c:152
ASSSplitContext * ff_ass_split(const char *buf)
Split a full ASS file or a ASS header from a string buffer and store the split structure in a newly a...
Definition: ass_split.c:374
static av_cold int mov_text_encode_init(AVCodecContext *avctx)
Definition: movtextenc.c:154
unsigned num_rects
Definition: avcodec.h:4123
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:222
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_WB32 unsigned int_TMPL AV_WB24 unsigned int_TMPL AV_RB16
Definition: bytestream.h:87
AVCodec.
Definition: avcodec.h:3730
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
uint16_t style_entries
Definition: movtextdec.c:98
AVSubtitleRect ** rects
Definition: avcodec.h:4124
char * text
actual text which will be displayed as a subtitle, can include style override control codes (see ff_a...
Definition: ass_split.h:82
uint8_t style_fontsize
Definition: movtextenc.c:72
This struct can be casted to ASS to access to the split data.
Definition: ass_split.c:197
uint8_t
#define av_cold
Definition: attributes.h:82
#define av_malloc(s)
void ff_ass_free_dialog(ASSDialog **dialogp)
Free a dialogue obtained from ff_ass_split_dialog2().
Definition: ass_split.c:430
ASSSplitContext * ass_ctx
Definition: movtextenc.c:62
AVBPrint buffer
Definition: movtextenc.c:63
#define STYL_BOX
Definition: movtextenc.c:38
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:1869
int ff_ass_split_override_codes(const ASSCodesCallbacks *callbacks, void *priv, const char *buf)
Split override codes out of a ASS "Dialogue" Text field.
Definition: ass_split.c:492
uint64_t_TMPL AV_WL64 unsigned int_TMPL AV_WL32 unsigned int_TMPL AV_WL24 unsigned int_TMPL AV_WL16 uint64_t_TMPL AV_WB64 unsigned int_TMPL AV_RB32
Definition: bytestream.h:87
static void mov_text_color_cb(void *priv, unsigned int color, unsigned int color_id)
Definition: movtextenc.c:288
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
uint16_t style_fontID
Definition: movtextenc.c:71
static void mov_text_text_cb(void *priv, const char *text, int len)
Definition: movtextenc.c:307
#define AV_WB16(p, v)
Definition: intreadwrite.h:410
HighlightBox hlit
Definition: movtextenc.c:66
ASSDialog * ff_ass_split_dialog(ASSSplitContext *ctx, const char *buf, int cache, int *number)
Split one or several ASS "Dialogue" lines from a string buffer and store them in an already initializ...
Definition: ass_split.c:411
#define av_log(a,...)
uint16_t end
Definition: movtextenc.c:52
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:176
#define STYLE_FLAG_UNDERLINE
Definition: movtextenc.c:34
#define AV_BPRINT_SIZE_UNLIMITED
uint8_t style_flag
Definition: movtextdec.c:70
#define AVERROR(e)
Definition: error.h:43
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
Definition: internal.h:179
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
simple assert() macros that are a bit more flexible than ISO C assert().
GLsizei GLsizei * length
Definition: opengl_enc.c:115
const char * name
Name of the codec implementation.
Definition: avcodec.h:3737
uint32_t color
Definition: movtextenc.c:56
#define STYLE_FLAG_ITALIC
Definition: movtextenc.c:33
static const Box box_types[]
Definition: movtextenc.c:146
static void mov_text_cleanup(MovTextContext *s)
Definition: movtextenc.c:82
uint8_t box_flags
Definition: movtextdec.c:97
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:159
typedef void(APIENTRY *FF_PFNGLACTIVETEXTUREPROC)(GLenum texture)
#define SIZE_ADD
Definition: movtextenc.c:36
void(* encode)(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:79
AVCodecContext * avctx
Definition: movtextenc.c:60
#define HLIT_BOX
Definition: movtextenc.c:39
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:154
AVCodec ff_movtext_encoder
Definition: movtextenc.c:406
StyleBox * style_attributes_temp
Definition: movtextenc.c:65
uint16_t style_start
Definition: movtextdec.c:68
#define FF_ARRAY_ELEMS(a)
static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf, int bufsize, const AVSubtitle *sub)
Definition: movtextenc.c:328
Libavcodec external API header.
static const ASSCodesCallbacks mov_text_callbacks
Definition: movtextenc.c:321
static void encode_hclr(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:134
uint16_t style_end
Definition: movtextdec.c:69
#define STYLE_RECORD_SIZE
Definition: movtextenc.c:35
main external API structure.
Definition: avcodec.h:1754
static int mov_text_encode_close(AVCodecContext *avctx)
Definition: movtextenc.c:398
static void encode(AVCodecContext *ctx, AVFrame *frame, AVPacket *pkt, FILE *output)
Definition: encode_audio.c:95
#define STYLE_FLAG_BOLD
Definition: movtextenc.c:32
void * buf
Definition: avisynth_c.h:690
GLint GLenum type
Definition: opengl_enc.c:105
int extradata_size
Definition: avcodec.h:1870
uint16_t text_pos
Definition: movtextenc.c:74
uint32_t style_color
Definition: movtextenc.c:73
HilightcolorBox hclr
Definition: movtextenc.c:67
StyleBox ** style_attributes
Definition: movtextenc.c:64
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
static void encode_hlit(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:121
common internal and external API header
uint16_t start
Definition: movtextenc.c:51
static void mov_text_new_line_cb(void *priv, int forced)
Definition: movtextenc.c:314
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding...
Definition: avcodec.h:777
static void mov_text_style_cb(void *priv, const char style, int close)
Definition: movtextenc.c:207
void * priv_data
Definition: avcodec.h:1796
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:4079
void av_dynarray_add(void *tab_ptr, int *nb_ptr, void *elem)
Add the pointer to an element to a dynamic array.
Definition: mem.c:294
int len
#define HCLR_BOX
Definition: movtextenc.c:40
#define av_bprint_append_any(buf, data, size)
Definition: movtextenc.c:42
char * ass
0 terminated ASS/SSA compatible event line.
Definition: avcodec.h:4114
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:479
#define av_freep(p)
enum AVSubtitleType type
Definition: avcodec.h:4105
#define MKTAG(a, b, c, d)
Definition: common.h:342
static void encode_styl(MovTextContext *s, uint32_t tsmb_type)
Definition: movtextenc.c:93
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:3387