FFmpeg
Loading...
Searching...
No Matches
libaribb24.c
Go to the documentation of this file.
1/*
2 * ARIB STD-B24 caption decoder using the libaribb24 library
3 * Copyright (c) 2019 Jan Ekström
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 "avcodec.h"
23#include "libavcodec/ass.h"
24#include "codec_internal.h"
25#include "libavutil/log.h"
26#include "libavutil/mem.h"
27#include "libavutil/opt.h"
28
29#include <aribb24/aribb24.h>
30#include <aribb24/parser.h>
31#include <aribb24/decoder.h>
32
33typedef struct Libaribb24Context {
34 AVClass *class;
35
36 arib_instance_t *lib_instance;
37 arib_parser_t *parser;
38 arib_decoder_t *decoder;
39
41
43 unsigned int aribb24_skip_ruby;
44
47
48static unsigned int get_profile_font_size(AVCodecContext *avctx)
49{
50 Libaribb24Context *b24 = avctx->priv_data;
51 int profile = avctx->profile;
52
55
56 switch (profile) {
58 return 36;
60 return 18;
61 default:
62 return 0;
63 }
64}
65
66static void libaribb24_log(void *p, const char *msg)
67{
68 av_log((AVCodecContext *)p, AV_LOG_INFO, "%s\n", msg);
69}
70
72{
73 Libaribb24Context *b24 = avctx->priv_data;
74 unsigned int plane_width = 0;
75 unsigned int plane_height = 0;
76 unsigned int font_size = 0;
77 int profile = avctx->profile;
78
81
82 switch (profile) {
84 plane_width = 960;
85 plane_height = 540;
86 break;
88 plane_width = 320;
89 plane_height = 180;
90 break;
91 default:
92 av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set!\n");
93 return AVERROR(EINVAL);
94 }
95
96 font_size = get_profile_font_size(avctx);
97
99 "[Script Info]\n"
100 "; Script generated by FFmpeg/Lavc%s\n"
101 "ScriptType: v4.00+\n"
102 "PlayResX: %d\n"
103 "PlayResY: %d\n"
104 "\n"
105 "[V4+ Styles]\n"
106
107 /* ASSv4 header */
108 "Format: Name, "
109 "Fontname, Fontsize, "
110 "PrimaryColour, SecondaryColour, OutlineColour, BackColour, "
111 "Bold, Italic, Underline, StrikeOut, "
112 "ScaleX, ScaleY, "
113 "Spacing, Angle, "
114 "BorderStyle, Outline, Shadow, "
115 "Alignment, MarginL, MarginR, MarginV, "
116 "Encoding\n"
117
118 "Style: "
119 "Default," /* Name */
120 "%s,%d," /* Font{name,size} */
121 "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */
122 "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */
123 "100,100," /* Scale{X,Y} */
124 "0,0," /* Spacing, Angle */
125 "%d,1,0," /* BorderStyle, Outline, Shadow */
126 "%d,10,10,10," /* Alignment, Margin[LRV] */
127 "0\n" /* Encoding */
128
129 "\n"
130 "[Events]\n"
131 "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\n",
133 plane_width, plane_height,
138
139 if (!avctx->subtitle_header)
140 return AVERROR(ENOMEM);
141
142 avctx->subtitle_header_size = strlen(avctx->subtitle_header);
143
144 return 0;
145}
146
148{
149 Libaribb24Context *b24 = avctx->priv_data;
150 void(* arib_dec_init)(arib_decoder_t* decoder) = NULL;
151 int ret;
152 int profile = avctx->profile;
153
154 if (!(b24->lib_instance = arib_instance_new(avctx))) {
155 av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24!\n");
156 return AVERROR_EXTERNAL;
157 }
158
159 if (b24->aribb24_base_path) {
160 av_log(avctx, AV_LOG_INFO, "Setting the libaribb24 base path to '%s'\n",
161 b24->aribb24_base_path);
162 arib_set_base_path(b24->lib_instance, b24->aribb24_base_path);
163 }
164
165 arib_register_messages_callback(b24->lib_instance, libaribb24_log);
166
167 if (!(b24->parser = arib_get_parser(b24->lib_instance))) {
168 av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24 PES parser!\n");
169 return AVERROR_EXTERNAL;
170 }
171 if (!(b24->decoder = arib_get_decoder(b24->lib_instance))) {
172 av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribb24 decoder!\n");
173 return AVERROR_EXTERNAL;
174 }
175
178
179 switch (profile) {
181 arib_dec_init = arib_initialize_decoder_a_profile;
182 break;
184 arib_dec_init = arib_initialize_decoder_c_profile;
185 break;
186 default:
187 av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set!\n");
188 return AVERROR(EINVAL);
189 }
190
191 arib_dec_init(b24->decoder);
192
194 if (ret < 0)
195 return ret;
196
197 return 0;
198}
199
201{
202 Libaribb24Context *b24 = avctx->priv_data;
203
204 if (b24->decoder)
205 arib_finalize_decoder(b24->decoder);
206
207 if (b24->lib_instance)
208 arib_instance_destroy(b24->lib_instance);
209
210 return 0;
211}
212
213#define RGB_TO_BGR(c) (((c) & 0xff) << 16 | ((c) & 0xff00) | (((c) >> 16) & 0xff))
214
216{
217 Libaribb24Context *b24 = avctx->priv_data;
218 const arib_buf_region_t *region = arib_decoder_get_regions(b24->decoder);
219 unsigned int profile_font_size = get_profile_font_size(avctx);
220 AVBPrint buf;
221 int ret = 0;
222
224
225 while (region) {
226 ptrdiff_t region_length = region->p_end - region->p_start;
227 unsigned int ruby_region =
228 region->i_fontheight == (profile_font_size / 2);
229
230 // ASS requires us to make the colors BGR, so we convert here
231 int foreground_bgr_color = RGB_TO_BGR(region->i_foreground_color);
232 int background_bgr_color = RGB_TO_BGR(region->i_background_color);
233
234 if (region_length < 0) {
235 av_log(avctx, AV_LOG_ERROR, "Invalid negative region length!\n");
237 break;
238 }
239
240 if (region_length == 0 || (ruby_region && b24->aribb24_skip_ruby)) {
241 goto next_region;
242 }
243
244 // color and alpha
245 if (foreground_bgr_color != ASS_DEFAULT_COLOR)
246 av_bprintf(&buf, "{\\1c&H%06x&}", foreground_bgr_color);
247
248 if (region->i_foreground_alpha != 0)
249 av_bprintf(&buf, "{\\1a&H%02x&}", region->i_foreground_alpha);
250
251 if (background_bgr_color != ASS_DEFAULT_BACK_COLOR)
252 av_bprintf(&buf, "{\\3c&H%06x&}", background_bgr_color);
253
254 if (region->i_background_alpha != 0)
255 av_bprintf(&buf, "{\\3a&H%02x&}", region->i_background_alpha);
256
257 // font size
258 if (region->i_fontwidth != profile_font_size ||
259 region->i_fontheight != profile_font_size) {
260 av_bprintf(&buf, "{\\fscx%"PRId64"\\fscy%"PRId64"}",
261 av_rescale(region->i_fontwidth, 100,
262 profile_font_size),
263 av_rescale(region->i_fontheight, 100,
264 profile_font_size));
265 }
266
267 // TODO: positioning
268
269 av_bprint_append_data(&buf, region->p_start, region_length);
270
271 av_bprintf(&buf, "{\\r}");
272
273next_region:
274 region = region->p_next;
275 }
276
277 if (!av_bprint_is_complete(&buf))
278 ret = AVERROR(ENOMEM);
279
280 if (ret == 0) {
281 av_log(avctx, AV_LOG_DEBUG, "Styled ASS line: %s\n",
282 buf.str);
283
284 sub->format = 1; /* text */
285 ret = ff_ass_add_rect(sub, buf.str, b24->read_order++,
286 0, NULL, NULL);
287 }
288
290
291 return ret;
292}
293
295 int *got_sub_ptr, const AVPacket *pkt)
296{
297 Libaribb24Context *b24 = avctx->priv_data;
298 size_t parsed_data_size = 0;
299 size_t decoded_subtitle_size = 0;
300 const unsigned char *parsed_data = NULL;
301 char *decoded_subtitle = NULL;
302 time_t subtitle_duration = 0;
303 int ret = 0;
304
305 if (pkt->size <= 0)
306 return pkt->size;
307
308 arib_parse_pes(b24->parser, pkt->data, pkt->size);
309
310 parsed_data = arib_parser_get_data(b24->parser,
311 &parsed_data_size);
312 if (!parsed_data || !parsed_data_size) {
313 av_log(avctx, AV_LOG_DEBUG, "No decode'able data was received from "
314 "packet (dts: %"PRId64", pts: %"PRId64").\n",
315 pkt->dts, pkt->pts);
316 return pkt->size;
317 }
318
319 decoded_subtitle_size = parsed_data_size * 4;
320 if (!(decoded_subtitle = av_mallocz(decoded_subtitle_size + 1))) {
321 av_log(avctx, AV_LOG_ERROR,
322 "Failed to allocate buffer for decoded subtitle!\n");
323 return AVERROR(ENOMEM);
324 }
325
326 decoded_subtitle_size = arib_decode_buffer(b24->decoder,
327 parsed_data,
328 parsed_data_size,
329 decoded_subtitle,
330 decoded_subtitle_size);
331
332 subtitle_duration = arib_decoder_get_time(b24->decoder);
333
334 if (avctx->pkt_timebase.num && pkt->pts != AV_NOPTS_VALUE)
335 sub->pts = av_rescale_q(pkt->pts,
337
338 sub->end_display_time = subtitle_duration ?
339 av_rescale_q(subtitle_duration,
341 (AVRational){1, 1000}) :
342 UINT32_MAX;
343
344 av_log(avctx, AV_LOG_DEBUG,
345 "Result: '%s' (size: %zu, pkt_pts: %"PRId64", sub_pts: %"PRId64" "
346 "duration: %"PRIu32", pkt_timebase: %d/%d, time_base: %d/%d')\n",
347 decoded_subtitle ? decoded_subtitle : "<no subtitle>",
348 decoded_subtitle_size,
349 pkt->pts, sub->pts,
350 sub->end_display_time,
351 avctx->pkt_timebase.num, avctx->pkt_timebase.den,
352 avctx->time_base.num, avctx->time_base.den);
353
354 if (decoded_subtitle)
355 ret = libaribb24_handle_regions(avctx, sub);
356
357 *got_sub_ptr = sub->num_rects > 0;
358
359 av_free(decoded_subtitle);
360
361 // flush the region buffers, otherwise the linked list keeps getting
362 // longer and longer...
363 arib_finalize_decoder(b24->decoder);
364
365 return ret < 0 ? ret : pkt->size;
366}
367
369{
370 Libaribb24Context *b24 = avctx->priv_data;
371 if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP))
372 b24->read_order = 0;
373}
374
375#define OFFSET(x) offsetof(Libaribb24Context, x)
376#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM
377static const AVOption options[] = {
378 { "aribb24-base-path", "set the base path for the libaribb24 library",
379 OFFSET(aribb24_base_path), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD },
380 { "aribb24-skip-ruby-text", "skip ruby text blocks during decoding",
381 OFFSET(aribb24_skip_ruby), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD },
382 { "default_profile", "default profile to use if not specified in the stream parameters",
383 OFFSET(default_profile), AV_OPT_TYPE_INT, { .i64 = AV_PROFILE_UNKNOWN }, AV_PROFILE_UNKNOWN, AV_PROFILE_ARIB_PROFILE_C, SD, .unit = "profile" },
384 {"a", "Profile A", 0, AV_OPT_TYPE_CONST, {.i64 = AV_PROFILE_ARIB_PROFILE_A}, INT_MIN, INT_MAX, SD, .unit = "profile"},
385 {"c", "Profile C", 0, AV_OPT_TYPE_CONST, {.i64 = AV_PROFILE_ARIB_PROFILE_C}, INT_MIN, INT_MAX, SD, .unit = "profile"},
386 { NULL }
387};
388
389static const AVClass aribb24_class = {
390 .class_name = "libaribb24 decoder",
391 .item_name = av_default_item_name,
392 .option = options,
393 .version = LIBAVUTIL_VERSION_INT,
394};
395
397 .p.name = "libaribb24",
398 CODEC_LONG_NAME("libaribb24 ARIB STD-B24 caption decoder"),
399 .p.type = AVMEDIA_TYPE_SUBTITLE,
401 .p.priv_class = &aribb24_class,
402 .p.wrapper_name = "libaribb24",
404 .priv_data_size = sizeof(Libaribb24Context),
408 .flush = libaribb24_flush,
409};
const FFCodec ff_libaribb24_decoder
Definition libaribb24.c:396
static av_cold void close(AVCodecParserContext *s)
Definition apv_parser.c:197
int ff_ass_add_rect(AVSubtitle *sub, const char *dialog, int readorder, int layer, const char *style, const char *speaker)
Add an ASS dialog to a subtitle.
Definition ass.c:159
#define ASS_DEFAULT_ALIGNMENT
Definition ass.h:42
#define ASS_DEFAULT_COLOR
Definition ass.h:37
#define ASS_DEFAULT_BORDERSTYLE
Definition ass.h:43
#define ASS_DEFAULT_BACK_COLOR
Definition ass.h:38
#define ASS_DEFAULT_FONT
Definition ass.h:35
#define ASS_DEFAULT_BOLD
Definition ass.h:39
#define ASS_DEFAULT_UNDERLINE
Definition ass.h:41
#define ASS_DEFAULT_ITALIC
Definition ass.h:40
Libavcodec external API header.
char * av_asprintf(const char *fmt,...)
Definition avstring.c:115
void av_bprintf(AVBPrint *buf, const char *fmt,...)
Definition bprint.c:122
void av_bprint_init(AVBPrint *buf, unsigned size_init, unsigned size_max)
Definition bprint.c:69
#define AV_BPRINT_SIZE_UNLIMITED
#define SD
#define FF_CODEC_CAP_NOT_INIT_THREADSAFE
The codec is not known to be init-threadsafe (i.e.
#define CODEC_LONG_NAME(str)
#define FF_CODEC_CAP_INIT_CLEANUP
The codec allows calling the close function for deallocation even if the init function returned a fai...
#define FF_CODEC_DECODE_SUB_CB(func)
#define NULL
Definition coverity.c:32
#define AV_PROFILE_ARIB_PROFILE_A
Definition defs.h:191
#define AV_PROFILE_UNKNOWN
Definition defs.h:65
#define AV_PROFILE_ARIB_PROFILE_C
Definition defs.h:192
static AVPacket * pkt
int(* init)(AVBSFContext *ctx)
Definition dts2pts.c:608
@ AV_OPT_TYPE_CONST
Special option type for declaring named constants.
Definition opt.h:298
@ AV_OPT_TYPE_INT
Underlying C type is int.
Definition opt.h:258
@ AV_OPT_TYPE_BOOL
Underlying C type is int.
Definition opt.h:326
@ AV_OPT_TYPE_STRING
Underlying C type is a uint8_t* that is either NULL or points to a C string allocated with the av_mal...
Definition opt.h:275
#define AV_CODEC_FLAG2_RO_FLUSH_NOOP
Do not reset ASS ReadOrder field on flush (subtitles decoding)
Definition avcodec.h:376
#define AV_CODEC_FLAG_BITEXACT
Use only bitexact stuff (except (I)DCT).
Definition avcodec.h:322
@ AV_CODEC_ID_ARIB_CAPTION
Definition codec_id.h:591
static int av_bprint_is_complete(const AVBPrint *buf)
Test if the print buffer is complete (not truncated).
Definition bprint.h:218
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:148
#define AVERROR_EXTERNAL
Generic error in an external library.
Definition error.h:59
#define AVERROR_INVALIDDATA
Invalid data found when processing input.
Definition error.h:61
#define AVERROR(e)
Definition error.h:45
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition log.h:231
#define AV_LOG_INFO
Standard information.
Definition log.h:221
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition log.h:210
const char * av_default_item_name(void *ptr)
Return the context name.
Definition log.c:241
int64_t av_rescale(int64_t a, int64_t b, int64_t c)
Rescale a 64-bit integer with rounding to nearest.
int64_t av_rescale_q(int64_t a, AVRational bq, AVRational cq)
Rescale a 64-bit integer by 2 rational numbers.
@ AVMEDIA_TYPE_SUBTITLE
Definition avutil.h:203
#define AV_NOPTS_VALUE
Undefined timestamp value.
Definition avutil.h:247
#define AV_TIME_BASE_Q
Internal time base represented as fractional value.
Definition avutil.h:263
#define LIBAVUTIL_VERSION_INT
Definition version.h:85
#define AV_STRINGIFY(s)
Definition macros.h:66
#define RGB_TO_BGR(c)
Definition libaribb24.c:213
static void libaribb24_flush(AVCodecContext *avctx)
Definition libaribb24.c:368
static av_cold int libaribb24_init(AVCodecContext *avctx)
Definition libaribb24.c:147
static int libaribb24_generate_ass_header(AVCodecContext *avctx)
Definition libaribb24.c:71
static void libaribb24_log(void *p, const char *msg)
Definition libaribb24.c:66
static av_cold int libaribb24_close(AVCodecContext *avctx)
Definition libaribb24.c:200
static int libaribb24_decode(AVCodecContext *avctx, AVSubtitle *sub, int *got_sub_ptr, const AVPacket *pkt)
Definition libaribb24.c:294
static unsigned int get_profile_font_size(AVCodecContext *avctx)
Definition libaribb24.c:48
static int libaribb24_handle_regions(AVCodecContext *avctx, AVSubtitle *sub)
Definition libaribb24.c:215
#define OFFSET(x)
Definition libaribb24.c:375
static const AVClass aribb24_class
Definition libaribb24.c:389
static const chunk_decoder decoder[8]
Definition dfa.c:331
#define LIBAVCODEC_VERSION
Definition version.h:38
#define av_cold
Definition attributes.h:117
Memory handling functions.
int profile
Definition mxfenc.c:2299
AVOptions.
Describe the class of an AVClass context structure.
Definition log.h:76
main external API structure.
Definition avcodec.h:443
int subtitle_header_size
Header containing style information for text subtitles.
Definition avcodec.h:1743
int flags2
AV_CODEC_FLAG2_*.
Definition avcodec.h:507
AVRational pkt_timebase
Timebase in which pkt_dts/pts and AVPacket.dts/pts are expressed.
Definition avcodec.h:554
int profile
profile
Definition avcodec.h:1636
uint8_t * subtitle_header
Definition avcodec.h:1744
AVRational time_base
This is the fundamental unit of time (in seconds) in terms of which frame timestamps are represented.
Definition avcodec.h:547
int flags
AV_CODEC_FLAG_*.
Definition avcodec.h:500
void * priv_data
Definition avcodec.h:470
AVOption.
Definition opt.h:428
This structure stores compressed data.
Definition packet.h:580
Rational number (pair of numerator and denominator).
Definition rational.h:58
int num
Numerator.
Definition rational.h:59
int den
Denominator.
Definition rational.h:60
uint16_t format
Definition avcodec.h:2088
uint32_t end_display_time
Definition avcodec.h:2090
unsigned num_rects
Definition avcodec.h:2091
int64_t pts
Same as packet pts, in AV_TIME_BASE.
Definition avcodec.h:2093
arib_instance_t * lib_instance
Definition libaribb24.c:36
char * aribb24_base_path
Definition libaribb24.c:42
arib_parser_t * parser
Definition libaribb24.c:37
arib_decoder_t * decoder
Definition libaribb24.c:38
unsigned int aribb24_skip_ruby
Definition libaribb24.c:43
#define av_free(p)
#define av_mallocz(s)
#define av_log(a,...)