FFmpeg  4.4.4
ttmlenc.c
Go to the documentation of this file.
1 /*
2  * TTML subtitle encoder
3  * Copyright (c) 2020 24i
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 /**
23  * @file
24  * TTML subtitle encoder
25  * @see https://www.w3.org/TR/ttml1/
26  * @see https://www.w3.org/TR/ttml2/
27  * @see https://www.w3.org/TR/ttml-imsc/rec
28  */
29 
30 #include "avcodec.h"
31 #include "internal.h"
32 #include "libavutil/avstring.h"
33 #include "libavutil/bprint.h"
34 #include "libavutil/internal.h"
35 #include "ass_split.h"
36 #include "ass.h"
37 #include "ttmlenc.h"
38 
39 typedef struct {
42  AVBPrint buffer;
43 } TTMLContext;
44 
45 static void ttml_text_cb(void *priv, const char *text, int len)
46 {
47  TTMLContext *s = priv;
48  AVBPrint cur_line = { 0 };
49  AVBPrint *buffer = &s->buffer;
50 
52 
53  av_bprint_append_data(&cur_line, text, len);
54  if (!av_bprint_is_complete(&cur_line)) {
55  av_log(s->avctx, AV_LOG_ERROR,
56  "Failed to move the current subtitle dialog to AVBPrint!\n");
57  av_bprint_finalize(&cur_line, NULL);
58  return;
59  }
60 
61 
63  0);
64 
65  av_bprint_finalize(&cur_line, NULL);
66 }
67 
68 static void ttml_new_line_cb(void *priv, int forced)
69 {
70  TTMLContext *s = priv;
71 
72  av_bprintf(&s->buffer, "<br/>");
73 }
74 
76  .text = ttml_text_cb,
77  .new_line = ttml_new_line_cb,
78 };
79 
80 static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf,
81  int bufsize, const AVSubtitle *sub)
82 {
83  TTMLContext *s = avctx->priv_data;
84  ASSDialog *dialog;
85  int i;
86 
87  av_bprint_clear(&s->buffer);
88 
89  for (i=0; i<sub->num_rects; i++) {
90  const char *ass = sub->rects[i]->ass;
91 
92  if (sub->rects[i]->type != SUBTITLE_ASS) {
93  av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n");
94  return AVERROR(EINVAL);
95  }
96 
97 #if FF_API_ASS_TIMING
98  if (!strncmp(ass, "Dialogue: ", 10)) {
99  int num;
100  dialog = ff_ass_split_dialog(s->ass_ctx, ass, 0, &num);
101 
102  for (; dialog && num--; dialog++) {
104  dialog->text);
105  int log_level = (ret != AVERROR_INVALIDDATA ||
106  avctx->err_recognition & AV_EF_EXPLODE) ?
108 
109  if (ret < 0) {
110  av_log(avctx, log_level,
111  "Splitting received ASS dialog failed: %s\n",
112  av_err2str(ret));
113 
114  if (log_level == AV_LOG_ERROR)
115  return ret;
116  }
117  }
118  } else {
119 #endif
120  dialog = ff_ass_split_dialog2(s->ass_ctx, ass);
121  if (!dialog)
122  return AVERROR(ENOMEM);
123 
124  {
126  dialog->text);
127  int log_level = (ret != AVERROR_INVALIDDATA ||
128  avctx->err_recognition & AV_EF_EXPLODE) ?
130 
131  if (ret < 0) {
132  av_log(avctx, log_level,
133  "Splitting received ASS dialog text %s failed: %s\n",
134  dialog->text,
135  av_err2str(ret));
136 
137  if (log_level == AV_LOG_ERROR) {
138  ff_ass_free_dialog(&dialog);
139  return ret;
140  }
141  }
142 
143  ff_ass_free_dialog(&dialog);
144  }
145 #if FF_API_ASS_TIMING
146  }
147 #endif
148  }
149 
150  if (!av_bprint_is_complete(&s->buffer))
151  return AVERROR(ENOMEM);
152  if (!s->buffer.len)
153  return 0;
154 
155  // force null-termination, so in case our destination buffer is
156  // too small, the return value is larger than bufsize minus null.
157  if (av_strlcpy(buf, s->buffer.str, bufsize) > bufsize - 1) {
158  av_log(avctx, AV_LOG_ERROR, "Buffer too small for TTML event.\n");
160  }
161 
162  return s->buffer.len;
163 }
164 
166 {
167  TTMLContext *s = avctx->priv_data;
168 
169  ff_ass_split_free(s->ass_ctx);
170 
171  av_bprint_finalize(&s->buffer, NULL);
172 
173  return 0;
174 }
175 
177 {
178  TTMLContext *s = avctx->priv_data;
179 
180  s->avctx = avctx;
181 
182  if (!(s->ass_ctx = ff_ass_split(avctx->subtitle_header))) {
183  return AVERROR_INVALIDDATA;
184  }
185 
188  return AVERROR(ENOMEM);
189  }
190 
192  memcpy(avctx->extradata, TTMLENC_EXTRADATA_SIGNATURE,
194 
196 
197  return 0;
198 }
199 
201  .name = "ttml",
202  .long_name = NULL_IF_CONFIG_SMALL("TTML subtitle"),
203  .type = AVMEDIA_TYPE_SUBTITLE,
204  .id = AV_CODEC_ID_TTML,
205  .priv_data_size = sizeof(TTMLContext),
207  .encode_sub = ttml_encode_frame,
208  .close = ttml_encode_close,
209  .caps_internal = FF_CODEC_CAP_INIT_CLEANUP,
210 };
ASSDialog * ff_ass_split_dialog2(ASSSplitContext *ctx, const char *buf)
Split one ASS Dialogue line from a string buffer.
Definition: ass_split.c:444
void ff_ass_free_dialog(ASSDialog **dialogp)
Free a dialogue obtained from ff_ass_split_dialog2().
Definition: ass_split.c:432
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:413
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:494
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
void ff_ass_split_free(ASSSplitContext *ctx)
Free all the memory allocated for an ASSSplitContext.
Definition: ass_split.c:481
#define av_cold
Definition: attributes.h:88
uint8_t
Libavcodec external API header.
#define AV_EF_EXPLODE
abort decoding on minor error detection
Definition: avcodec.h:1656
static av_cold int init(AVCodecContext *avctx)
Definition: avrndec.c:31
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition: bprint.c:94
void av_bprint_escape(AVBPrint *dstbuf, const char *src, const char *special_chars, enum AVEscapeMode mode, int flags)
Escape the content in src and append it to dstbuf.
Definition: bprint.c:265
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition: bprint.c:69
int av_bprint_finalize(AVBPrint *buf, char **ret_str)
Finalize a print buffer.
Definition: bprint.c:235
void av_bprint_append_data(AVBPrint *buf, const char *data, unsigned size)
Append data to a print buffer.
Definition: bprint.c:158
void av_bprint_clear(AVBPrint *buf)
Reset the string to "" but keep internal allocated data.
Definition: bprint.c:227
#define AV_BPRINT_SIZE_UNLIMITED
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition: bprint.h:185
#define s(width, name)
Definition: cbs_vp9.c:257
#define NULL
Definition: coverity.c:32
static float sub(float src0, float src1)
void(* text)(void *priv, const char *text, int len)
Definition: ass_split.h:159
@ SUBTITLE_ASS
Formatted text, the ass field must be set by the decoder and is authoritative.
Definition: avcodec.h:2682
@ AV_CODEC_ID_TTML
Definition: codec_id.h:548
#define AV_INPUT_BUFFER_PADDING_SIZE
Required number of additionally allocated bytes at the end of the input bitstream for decoding.
Definition: avcodec.h:215
#define AVERROR_BUFFER_TOO_SMALL
Buffer too small.
Definition: error.h:51
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition: error.h:59
#define av_err2str(errnum)
Convenience macro, the return value should be used only directly in function arguments but never stan...
Definition: error.h:119
#define AVERROR(e)
Definition: error.h:43
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:200
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:194
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
@ AVMEDIA_TYPE_SUBTITLE
Definition: avutil.h:204
size_t av_strlcpy(char *dst, const char *src, size_t size)
Copy the string src to dst, but no more than size - 1 bytes, and null-terminate dst.
Definition: avstring.c:83
@ AV_ESCAPE_MODE_XML
Use XML non-markup character data escaping.
Definition: avstring.h:327
int i
Definition: input.c:407
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
Definition: internal.h:49
static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf, int bufsize, const AVSubtitle *sub)
Definition: ttmlenc.c:80
static const ASSCodesCallbacks ttml_callbacks
Definition: ttmlenc.c:75
static av_cold int ttml_encode_close(AVCodecContext *avctx)
Definition: ttmlenc.c:165
static av_cold int ttml_encode_init(AVCodecContext *avctx)
Definition: ttmlenc.c:176
AVCodec ff_ttml_encoder
Definition: ttmlenc.c:200
static void ttml_text_cb(void *priv, const char *text, int len)
Definition: ttmlenc.c:45
static void ttml_new_line_cb(void *priv, int forced)
Definition: ttmlenc.c:68
common internal API header
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition: internal.h:117
static char buffer[20]
Definition: seek.c:32
Set of callback functions corresponding to each override codes that can be encountered in a "Dialogue...
Definition: ass_split.h:154
fields extracted from the [Events] section
Definition: ass_split.h:71
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
This struct can be casted to ASS to access to the split data.
Definition: ass_split.c:197
main external API structure.
Definition: avcodec.h:536
uint8_t * subtitle_header
Header containing style information for text subtitles.
Definition: avcodec.h:2016
uint8_t * extradata
some codecs need / can use extradata like Huffman tables.
Definition: avcodec.h:637
int extradata_size
Definition: avcodec.h:638
void * priv_data
Definition: avcodec.h:563
int err_recognition
Error recognition; may misdetect some more or less valid parts as errors.
Definition: avcodec.h:1645
AVCodec.
Definition: codec.h:197
const char * name
Name of the codec implementation.
Definition: codec.h:204
AVCodecContext * avctx
Definition: ttmlenc.c:40
AVBPrint buffer
Definition: ttmlenc.c:42
ASSSplitContext * ass_ctx
Definition: ttmlenc.c:41
#define av_log(a,...)
#define TTMLENC_EXTRADATA_SIGNATURE
Definition: ttmlenc.h:25
#define TTMLENC_EXTRADATA_SIGNATURE_SIZE
Definition: ttmlenc.h:26
int len