From patchwork Thu Feb 23 10:17:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: TADANO Tokumei X-Patchwork-Id: 40472 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:5494:b0:bf:7b3a:fd32 with SMTP id i20csp265195pzk; Thu, 23 Feb 2023 02:18:33 -0800 (PST) X-Google-Smtp-Source: AK7set/O2cAnUV5P8AxXUHiL/ySKE7JG904qDJKRIOI47UDF2CdAWyORxpMJqSo+JzdlRKeMrSjH X-Received: by 2002:a17:906:3b4a:b0:8b1:29ed:e206 with SMTP id h10-20020a1709063b4a00b008b129ede206mr20494276ejf.28.1677147513453; Thu, 23 Feb 2023 02:18:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677147513; cv=none; d=google.com; s=arc-20160816; b=TPQ2kICbsAyUnSNKNPJe6EV+T9PpuSjzxihuJGcok/ayymT24j148R4t8uP/fWt4xX zEGBWnGqcMCcI9esFtP2rS579sQFgKETYPf7hj4RSiQ3DO4jTpZDLgRXbXx+UzWL2Kxf hlOrTglq9OI4BWv7CaCh0cHTW/DhKNW1bsasbmCwHyNtacDDdsOm4soZH+4dQXJqcWyG 0NA1B8EovqoicwvshDHIUqaK96wBs/YyhWMDlgY/wV/FDSPLTKnre00IwOrQG17t7D33 t8JnrJ2GSIHWWaha45dKMrDYZ3B1LPyAwqEuF5bXNZc7PxfP2p1BQMxZGevEVlKwAEes oyZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:dkim-filter:delivered-to; bh=slCMufBBDcZXz7cXYiYNOFUvYywTaZ0bFN/pbewpxyE=; b=jr272xID+Kv9Zjw6fMvCVnvDMT4ARdbHgXr3YgMNNWBblfY5BtL69p96OoPlop75LD CRz8UZBnhMexJnpYWDbvIHQOqTvukiqeozHANwqBMtmIW0vFaTSkLZ1vMIsdmB2IQ5I0 x/1Cjdp7WtRVP2WbboMaaWLRqKAK75abfeXAkl6eXXlICLUU6NhOzdSlBY5cp1C2PKfG 3dZHZ/+4GNDblskYhmxmPXCas22xYobzVHjwDtV9qCPjl3+obJBo25mKRGUXNPqBknnu tlUO937a0EpQKfweqJL+9QrDXBJ8XFq2jXILWGsuUQl10ow6nNpf6xpX+bkPk+G0eT5q 9tKg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=MjSAhR0t; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id u16-20020a170906109000b008d0378ec19dsi15120696eju.487.2023.02.23.02.18.33; Thu, 23 Feb 2023 02:18:33 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=MjSAhR0t; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 71F5568BF58; Thu, 23 Feb 2023 12:18:17 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from conssluserg-02.nifty.com (conssluserg-02.nifty.com [210.131.2.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0B49668BCCE for ; Thu, 23 Feb 2023 12:18:07 +0200 (EET) Received: from osamu-pc.. (M106073025034.v4.enabler.ne.jp [106.73.25.34]) (authenticated) by conssluserg-02.nifty.com with ESMTP id 31NAHtht015305; Thu, 23 Feb 2023 19:18:01 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conssluserg-02.nifty.com 31NAHtht015305 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1677147481; bh=32cnmWxQXehdzd70F69Z9o4pjs5/fA5QfMkIve4FAgw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MjSAhR0tmFL7pfeftWeM9zsUF4YEZdmInTJZjBmkdBEK+8h4A+jX6cg8fUVTQDx7q X39G8t+qJ7gn4/vsQg5rTVwEBgyc9O5X/mK11Mul7RmCeqA3yqB48NL4I31NiL9JFc z2TkLiUv8A4QVk1212aIcz7i3H2UmncDc//JkPuhCIWDLz4Cdx5N6rtmnU8DsWj+9c 1yDd7vq8H/HRxPKwmxr6z8Mufwwv8YNImtkpsJdrWfbLf2C7Iyx8ZftR110uEkP4cC 3VNZT7HP7Jrvw7LTJF1Vy1U7hnf0wEtR6IIADaz3myed/cWxd02oD0Bad7Xh/2JUIA BTBI+4MIGeHhg== X-Nifty-SrcIP: [106.73.25.34] From: TADANO Tokumei To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 Feb 2023 19:17:15 +0900 Message-Id: <20230223101718.562202-2-aimingoff@pc.nifty.jp> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230223101718.562202-1-aimingoff@pc.nifty.jp> References: <20230223101718.562202-1-aimingoff@pc.nifty.jp> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v7 1/4] lavc/libaribcaption.c: add ARIB caption decoder using libaribcaption X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: TADANO Tokumei Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: ZNMZx1kzaDIi This patch add another ARIB caption decoder using libaribcaption external library. Unlike libaribb24, it supports 3 types of subtitle outputs: * text: plain text * ass: ASS formatted text * bitmap: bitmap image Default subtitle type is ass as same as libaribb24. Advantages compared with libaribb24 on ASS subtitle are: * Subtitle positioning. * Multi-rect subtitle: some captions are displayed at different position at a time. * More stability and reproducibility. To compile with this feature: * libaribcaption external library has to be pre-installed. https://github.com/xqq/libaribcaption * configure with `--enable-libaribcaption` option. `--enable-libaribb24` and `--enable-libaribcaption` options are not exclusive. If both enabled, libaribcaption precedes as order listed in `libavcodec/allcodecs.c`. --- configure | 4 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/libaribcaption.c | 1171 +++++++++++++++++++++++++++++++++++ 4 files changed, 1177 insertions(+) create mode 100644 libavcodec/libaribcaption.c diff --git a/configure b/configure index b6616f00b6..a0fe88104c 100755 --- a/configure +++ b/configure @@ -218,6 +218,7 @@ External library support: --enable-lcms2 enable ICC profile support via LittleCMS 2 [no] --enable-libaom enable AV1 video encoding/decoding via libaom [no] --enable-libaribb24 enable ARIB text and caption decoding via libaribb24 [no] + --enable-libaribcaption enable ARIB text and caption decoding via libaribcaption [no] --enable-libass enable libass subtitles rendering, needed for subtitles and ass filter [no] --enable-libbluray enable BluRay reading using libbluray [no] @@ -1805,6 +1806,7 @@ EXTERNAL_LIBRARY_LIST=" ladspa lcms2 libaom + libaribcaption libass libbluray libbs2b @@ -3332,6 +3334,7 @@ libaom_av1_decoder_deps="libaom" libaom_av1_encoder_deps="libaom" libaom_av1_encoder_select="extract_extradata_bsf" libaribb24_decoder_deps="libaribb24" +aribcaption_decoder_deps="libaribcaption" libcelt_decoder_deps="libcelt" libcodec2_decoder_deps="libcodec2" libcodec2_encoder_deps="libcodec2" @@ -6567,6 +6570,7 @@ enabled libaom && require_pkg_config libaom "aom >= 1.0.0" aom/aom_co enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || { enabled gpl && require_pkg_config libaribb24 aribb24 "aribb24/aribb24.h" arib_instance_new; } || die "ERROR: libaribb24 requires version higher than 1.0.3 or --enable-gpl."; } +enabled libaribcaption && require_pkg_config libaribcaption "libaribcaption >= 0.1.0" "aribcaption/aribcaption.h" aribcc_context_alloc enabled lv2 && require_pkg_config lv2 lilv-0 "lilv/lilv.h" lilv_world_new enabled libiec61883 && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883 enabled libass && require_pkg_config libass "libass >= 0.11.0" ass/ass.h ass_library_init diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 389253f5d0..4a84b3ff48 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -1079,6 +1079,7 @@ OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o +OBJS-$(CONFIG_ARIBCAPTION_DECODER) += libaribcaption.o ass.o OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o OBJS-$(CONFIG_LIBCODEC2_DECODER) += libcodec2.o OBJS-$(CONFIG_LIBCODEC2_ENCODER) += libcodec2.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index e593ad19af..74e1c9b904 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -759,6 +759,7 @@ extern const FFCodec ff_pcm_mulaw_at_decoder; extern const FFCodec ff_qdmc_at_decoder; extern const FFCodec ff_qdm2_at_decoder; extern FFCodec ff_libaom_av1_encoder; +extern const FFCodec ff_aribcaption_decoder; extern const FFCodec ff_libaribb24_decoder; extern const FFCodec ff_libcelt_decoder; extern const FFCodec ff_libcodec2_encoder; diff --git a/libavcodec/libaribcaption.c b/libavcodec/libaribcaption.c new file mode 100644 index 0000000000..1c6e65b562 --- /dev/null +++ b/libavcodec/libaribcaption.c @@ -0,0 +1,1171 @@ +/* + * ARIB STD-B24 caption decoder using the libaribcaption library + * Copyright (c) 2022 TADANO Tokumei + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "avcodec.h" +#include "codec_internal.h" +#include "internal.h" +#include "libavcodec/ass.h" +#include "libavutil/avstring.h" +#include "libavutil/avutil.h" +#include "libavutil/thread.h" +#include "libavutil/log.h" +#include "libavutil/opt.h" + +#include + +#if !defined(DEFAULT_FONT_ASS) +# define DEFAULT_FONT_ASS "sans-serif" +#endif + +#define ARIBC_BPRINT_SIZE_INIT 64 +#define ARIBC_BPRINT_SIZE_MAX (8 * 1024) +#define ARIBC_ALPHA_MAX_NUM 4 +#define ARIBC_ALPHA_DEFAULT_FRONT 0xFF +#define ARIBC_ALPHA_DEFAULT_BACK 0x80 + +#define ARIBCC_COLOR_RGB(c) ((c) & 0xFFFFFF) +#define ARIBCC_COLOR_DIFF_RGB(c1,c2) (((c1) ^ (c2)) & 0x00FFFFFF) +#define ARIBCC_COLOR_DIFF_A(c1,c2) (((c1) ^ (c2)) & 0xFF000000) + +#define CLUT_RGBA(r,g,b,a) (((unsigned)(a) << 24) | ((r) << 16) | ((g) << 8) | (b)) +#define CLUT_A(c) (((c) >> 24) & 0xFF) +#define CLUT_R(c) (((c) >> 16) & 0xFF) +#define CLUT_G(c) (((c) >> 8) & 0xFF) +#define CLUT_B(c) ( (c) & 0xFF) + +#define ARIBCC_COLOR_TO_CLUT_RGBA(c,a) (((ARIBCC_COLOR_A(c) ? ARIBCC_COLOR_A(c) : (a)) << 24) | \ + (ARIBCC_COLOR_R(c) << 16) | \ + (ARIBCC_COLOR_G(c) << 8) | \ + (ARIBCC_COLOR_B(c))) + +typedef struct ARIBCaptionContext { + AVClass *class; + AVCodecContext *avctx; + const AVPacket *avpkt; + AVSubtitle *sub; + + aribcc_context_t *context; + aribcc_decoder_t *decoder; + aribcc_renderer_t *renderer; + + int subtitle_type; + int encoding_scheme; + bool ass_single_rect; + char *font; + bool replace_fullwidth_ascii; + bool force_stroke_text; + bool ignore_background; + bool ignore_ruby; + float stroke_width; + bool replace_drcs; + + int64_t pts; + AVRational time_base; + int canvas_width; + int canvas_height; + int plane_width; + int plane_height; + int frame_width; + int frame_height; + int bitmap_plane_width; + int bitmap_plane_height; + int font_size; + int charstyle; + int border_style; + int readorder; + + aribcc_caption_t caption; + aribcc_render_result_t render_result; + uint32_t *clut; + int clut_idx; + int clut_overflow; + uint8_t clut_alpha[ARIBC_ALPHA_MAX_NUM]; +} ARIBCaptionContext; + +static void hex_dump_debug(void *ctx, const char *buf, int buf_size) +{ + int i; + + for (i = 0; i < buf_size; i++) { + ff_dlog(ctx, "%02hhx ", buf[i]); + if (i % 16 == 15) + ff_dlog(ctx, "\n"); + } + if (i % 16) + ff_dlog(ctx, "\n"); +} + +static void logcat_callback(aribcc_loglevel_t level, const char* message, void* userdata) +{ + ARIBCaptionContext *ctx = userdata; + int lvl; + + if (ctx->decoder != NULL) { + switch (level) { + case ARIBCC_LOGLEVEL_ERROR: + lvl = AV_LOG_ERROR; + break; + case ARIBCC_LOGLEVEL_WARNING: + lvl = AV_LOG_WARNING; + break; + default: + lvl = AV_LOG_INFO; + } + + av_log(ctx, lvl, "%s\n", message); + } +} + +static void estimate_video_frame_size(ARIBCaptionContext *ctx) +{ + if (ctx->avctx->width > 0 && ctx->avctx->height > 0) { + /* input video size specified by -canvas_size option */ + ctx->bitmap_plane_width = ctx->avctx->width; + ctx->bitmap_plane_height = ctx->avctx->height; + } else if (ctx->plane_width == 960) { + /* ARIB TR-B14 Fascicle 2 Volume 3 [Section 2] 4.3.1 */ + /* ARIB TR-B14 Fascicle 2 Volume 3 [Section 2] Appendix-4 */ + ctx->bitmap_plane_width = 1440; + ctx->bitmap_plane_height = 1080; + } else { + ctx->bitmap_plane_width = ctx->plane_width; + ctx->bitmap_plane_height = ctx->plane_height; + } + /* Expand either width or height */ + if (ctx->bitmap_plane_height * ctx->plane_width > ctx->bitmap_plane_width * ctx->plane_height) { + ctx->frame_height = ctx->bitmap_plane_height; + ctx->frame_width = ctx->frame_height * ctx->plane_width / ctx->plane_height; + } else { + ctx->frame_width = ctx->bitmap_plane_width; + ctx->frame_height = ctx->frame_width * ctx->plane_height / ctx->plane_width; + } +} + +static void clut_set_alpha(ARIBCaptionContext *ctx, uint8_t a) +{ + int i; + + for (i = 0; i < ARIBC_ALPHA_MAX_NUM; i++) { + if (ctx->clut_alpha[i] == 0) { + ctx->clut_alpha[i] = a; + return; + } + if (ctx->clut_alpha[i] == a) + return; + } + return; +} + +static uint8_t clut_find_nearlest_alpha(ARIBCaptionContext *ctx, uint8_t a) +{ + int i, j, d; + + if (a == 0) + return a; + d = 256; + j = 0; + for (i = 0; i < ARIBC_ALPHA_MAX_NUM; i++) { + if (ctx->clut_alpha[i] == a) + return a; + if (ctx->clut_alpha[i] == 0) + break; + if (abs((int)a - (int)ctx->clut_alpha[i]) < d) { + d = abs((int)a - (int)ctx->clut_alpha[i]); + j = i; + } + } + return ctx->clut_alpha[j]; +} + +static int clut_find(ARIBCaptionContext *ctx, uint32_t rgba) +{ + int i; + + for (i = 0; i < ctx->clut_idx; i++) { + if (ctx->clut[i] == rgba) + return i; + } + return -1; +} + +static inline int clut_color_distance(uint32_t rgba1, uint32_t rgba2) +{ + return abs((int)CLUT_R(rgba1) - (int)CLUT_R(rgba2)) + + abs((int)CLUT_G(rgba1) - (int)CLUT_G(rgba2)) + + abs((int)CLUT_B(rgba1) - (int)CLUT_B(rgba2)); +} + +static uint8_t clut_pick_or_set(ARIBCaptionContext *ctx, int r, int g, int b, int a) +{ + int c, i, d, d_min; + uint32_t rgba; + + a = clut_find_nearlest_alpha(ctx, a); + if (a == 0) + return 0; /* transparent */ + rgba = CLUT_RGBA(r,g,b,a); + + d_min = 256 * 3; + c = 0; + for (i = 0; i < ctx->clut_idx; i++) { + if (ctx->clut[i] == rgba) + return i; + if (CLUT_A(ctx->clut[i]) != a) + continue; + d = clut_color_distance(ctx->clut[i], rgba); + if (d < d_min) { + d_min = d; + c = i; + } + } + if (d_min > 3) { + if (ctx->clut_idx >= AVPALETTE_COUNT) + ctx->clut_overflow++; + else { + c = ctx->clut_idx; + ctx->clut[ctx->clut_idx++] = rgba; + } + } + return c; +} + +/* initialiaze CLUT with each character colors */ +static void clut_init(ARIBCaptionContext *ctx, aribcc_caption_region_t *region) +{ + aribcc_color_t text_color, back_color, stroke_color; + uint32_t rgba; + + ctx->clut[0] = CLUT_RGBA(0,0,0,0); /* transparent */ + ctx->clut_alpha[0] = 0xFF; + ctx->clut_idx = 1; + ctx->clut_overflow = 0; + text_color = region->chars[0].text_color; + back_color = region->chars[0].back_color; + stroke_color = region->chars[0].stroke_color; + rgba = ARIBCC_COLOR_TO_CLUT_RGBA(text_color, ARIBC_ALPHA_DEFAULT_FRONT); + ctx->clut[ctx->clut_idx++] = rgba; + clut_set_alpha(ctx, CLUT_A(rgba)); + rgba = ARIBCC_COLOR_TO_CLUT_RGBA(back_color, ARIBC_ALPHA_DEFAULT_BACK); + ctx->clut[ctx->clut_idx++] = rgba; + clut_set_alpha(ctx, CLUT_A(rgba)); + rgba = ARIBCC_COLOR_TO_CLUT_RGBA(stroke_color, ARIBC_ALPHA_DEFAULT_FRONT); + if (clut_find(ctx, rgba) < 0) { + ctx->clut[ctx->clut_idx++] = rgba; + clut_set_alpha(ctx, CLUT_A(rgba)); + } + + for (int i = 1; i < region->char_count; i++) { + if (region->chars[i].text_color != text_color) { + rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].text_color, + ARIBC_ALPHA_DEFAULT_FRONT); + if (clut_find(ctx, rgba) < 0) { + ctx->clut[ctx->clut_idx++] = rgba; + clut_set_alpha(ctx, CLUT_A(rgba)); + } + } + if (region->chars[i].back_color != back_color) { + rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].back_color, + ARIBC_ALPHA_DEFAULT_BACK); + if (clut_find(ctx, rgba) < 0) { + ctx->clut[ctx->clut_idx++] = rgba; + clut_set_alpha(ctx, CLUT_A(rgba)); + } + } + if (region->chars[i].stroke_color != stroke_color) { + rgba = ARIBCC_COLOR_TO_CLUT_RGBA(region->chars[i].stroke_color, + ARIBC_ALPHA_DEFAULT_FRONT); + if (clut_find(ctx, rgba) < 0) { + if (ctx->clut_idx < AVPALETTE_COUNT) + ctx->clut[ctx->clut_idx++] = rgba; + clut_set_alpha(ctx, CLUT_A(rgba)); + } + } + } +} + +/** + * aribcaption_trans_{bitmap|ass|text}_subtitle() + * + * Transfer decoded subtitle to AVSubtitle with corresponding subtitle type. + * + * @param ctx pointer to the ARIBCaptionContext + * @return > 0 number of rectangles to be displayed + * = 0 no subtitle + * < 0 error code + */ +static int aribcaption_trans_bitmap_subtitle(ARIBCaptionContext *ctx) +{ + int ret = 0; + AVSubtitle *sub = ctx->sub; + int status, rect_idx; + int old_width = ctx->frame_width; + int old_height = ctx->frame_height; + + if (ctx->caption.plane_width > 0 && ctx->caption.plane_height > 0) { + ctx->plane_width = ctx->caption.plane_width; + ctx->plane_height = ctx->caption.plane_height; + } + estimate_video_frame_size(ctx); + if (ctx->frame_width != old_width || ctx->frame_height != old_height) { + ff_dlog(ctx, "canvas: %dx%d plane: %dx%d bitmap: %dx%d frame: %dx%d\n", + ctx->avctx->width, ctx->avctx->height, + ctx->plane_width, ctx->plane_height, + ctx->bitmap_plane_width, ctx->bitmap_plane_height, + ctx->frame_width, ctx->frame_height); + if (!aribcc_renderer_set_frame_size(ctx->renderer, + ctx->frame_width, ctx->frame_height)) { + av_log(ctx, AV_LOG_ERROR, + "aribcc_renderer_set_frame_size() returned with error.\n"); + return AVERROR_EXTERNAL; + } + } + + status = aribcc_renderer_append_caption(ctx->renderer, &ctx->caption); + if (!status) { + av_log(ctx, AV_LOG_ERROR, + "aribcc_renderer_append_caption() returned with error.\n"); + return AVERROR_EXTERNAL; + } + + status = aribcc_renderer_render(ctx->renderer, ctx->pts, &ctx->render_result); + switch (status) { + case ARIBCC_RENDER_STATUS_GOT_IMAGE: + break; + + case ARIBCC_RENDER_STATUS_GOT_IMAGE_UNCHANGED: + aribcc_render_result_cleanup(&ctx->render_result); + ff_dlog(ctx, "got image unchanged\n"); + return 0; + + case ARIBCC_RENDER_STATUS_NO_IMAGE: + ff_dlog(ctx, "no image\n"); + return 0; + + case ARIBCC_RENDER_STATUS_ERROR: + av_log(ctx, AV_LOG_ERROR, + "aribcc_renderer_render() returned with error.\n"); + return AVERROR_EXTERNAL; + + default: + aribcc_render_result_cleanup(&ctx->render_result); + av_log(ctx, AV_LOG_ERROR, + "aribcc_renderer_render() returned unknown status: %d\n", status); + return AVERROR_EXTERNAL; + } + + if (!ctx->render_result.image_count || ctx->render_result.images == NULL) { + aribcc_render_result_cleanup(&ctx->render_result); + ff_dlog(ctx, "no image (%d)\n", ctx->render_result.image_count); + return 0; + } + + sub->format = 0; /* graphic */ + sub->rects = av_calloc(ctx->render_result.image_count, sizeof(*sub->rects)); + if (!sub->rects) { + ret = AVERROR(ENOMEM); + goto fail; + } + for (int i = 0; i < ctx->render_result.image_count; i++) { + sub->rects[i] = av_mallocz(sizeof(*sub->rects[i])); + if (!sub->rects[i]) { + ret = AVERROR(ENOMEM); + goto fail; + } + } + + for (rect_idx = 0; rect_idx < ctx->caption.region_count; rect_idx++) { + AVSubtitleRect *rect = sub->rects[rect_idx]; + aribcc_image_t *image = &ctx->render_result.images[rect_idx]; + int w, h, shrink_height, dst_idx; + + clut_init(ctx, &ctx->caption.regions[rect_idx]); + + rect->w = image->width * ctx->bitmap_plane_width / ctx->frame_width; + rect->h = image->height * ctx->bitmap_plane_height / ctx->frame_height; + rect->data[0] = av_mallocz(rect->w * rect->h); + if (!rect->data[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + if ((image->height != rect->h && image->width != rect->w) || + image->stride < image->width * 4 || + image->stride * image->height > image->bitmap_size) { + av_log(ctx, AV_LOG_ERROR, "Bug: unexpected rendered image: %d(%d)x%d -> %dx%d\n", + image->width, image->stride / 4, image->height, rect->w, rect->h); + ret = AVERROR_EXTERNAL; + goto fail; + } + + shrink_height = image->height != rect->h; + dst_idx = 0; + for (h = 0; h < rect->h; h++) { + for (w = 0; w < rect->w; w++) { + /* Bi-linear interpolation */ + int n, m, idx0, idx1, r, g, b, a; + if (shrink_height) { + int div_a, y0, y1; + div_a = h * ctx->frame_height; + n = ctx->bitmap_plane_height; + y0 = div_a / n; + y1 = FFMIN(y0 + 1, image->height - 1); + m = div_a - n * y0; + idx0 = image->stride * y0 + w * 4; + idx1 = image->stride * y1 + w * 4; + } else { + int div_a, x0, x1; + div_a = w * ctx->frame_width; + n = ctx->bitmap_plane_width; + x0 = div_a / n; + x1 = FFMIN(x0 + 1, image->width - 1); + m = div_a - n * x0; + idx0 = image->stride * h + x0 * 4; + idx1 = image->stride * h + x1 * 4; + } + r = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n; + g = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n; + b = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n; + a = (image->bitmap[idx0++] * (n - m) + image->bitmap[idx1++] * m) / n; + rect->data[0][dst_idx++] = clut_pick_or_set(ctx, r, g, b, a); + } + } + rect->data[1] = av_memdup(ctx->clut, AVPALETTE_SIZE); + if (!rect->data[1]) { + ret = AVERROR(ENOMEM); + goto fail; + } + + if (ctx->avctx->profile == FF_PROFILE_ARIB_PROFILE_C) { + /* ARIB TR-B14 version 3.8 Fascicle 1-(2/2) Volume 3 [Section 4] */ + /* No position information is provided for profile C */ + rect->x = (ctx->frame_width - rect->w) / 2; + rect->y = ctx->frame_height - rect->h * (ctx->caption.region_count - rect_idx); + } else { + rect->x = image->dst_x * ctx->bitmap_plane_width / ctx->frame_width; + rect->y = image->dst_y * ctx->bitmap_plane_height / ctx->frame_height; + } + rect->type = SUBTITLE_BITMAP; + rect->linesize[0] = rect->w; + rect->nb_colors = 256; + + ff_dlog(ctx, "BITMAP subtitle%s (%d,%d) %dx%d -> (%d,%d) %dx%d [%d]: %d colors\n", + (ctx->caption.regions[rect_idx].is_ruby) ? " (ruby)" : "", + image->dst_x, image->dst_y, image->width, image->height, + rect->x, rect->y, rect->w, rect->h, + rect_idx, ctx->clut_idx); + if (ctx->clut_overflow) + av_log(ctx, AV_LOG_WARNING, "CLUT overflow (%d).\n", ctx->clut_overflow); + } + sub->num_rects = rect_idx; + + return rect_idx; + +fail: + if (sub->rects) { + for (int i = 0; i < ctx->caption.region_count; i++) { + if (sub->rects[i]) { + av_freep(&sub->rects[i]->data[0]); + av_freep(&sub->rects[i]->data[1]); + av_freep(&sub->rects[i]); + } + } + av_freep(&sub->rects); + } + sub->num_rects = 0; + + return ret; +} + +static int set_ass_header(ARIBCaptionContext *ctx) +{ + AVCodecContext *avctx = ctx->avctx; + int outline, shadow; + const char *font_name; + const char *fonts = ctx->font; + + if (ctx->border_style == 4) { + outline = 0; + shadow = 4; + } else { + outline = 1; + shadow = 0; + } + if (ctx->force_stroke_text) + outline = (int)(ctx->stroke_width * 4.0 / 3.0); + + if (fonts && *fonts) + font_name = av_get_token(&fonts, ","); + else + font_name = av_strdup(DEFAULT_FONT_ASS); + if (!font_name) + return AVERROR(ENOMEM); + + av_freep(&avctx->subtitle_header); + avctx->subtitle_header = av_asprintf( + "[Script Info]\r\n" + "ScriptType: v4.00+\r\n" + "PlayResX: %d\r\n" + "PlayResY: %d\r\n" + "WrapStyle: 2\r\n" /* 2: no word wrapping */ + "\r\n" + + "[V4+ Styles]\r\n" + "Format: Name, " + "Fontname, Fontsize, " + "PrimaryColour, SecondaryColour, OutlineColour, BackColour, " + "Bold, Italic, Underline, StrikeOut, " + "ScaleX, ScaleY, " + "Spacing, Angle, " + "BorderStyle, Outline, Shadow, " + "Alignment, MarginL, MarginR, MarginV, " + "Encoding\r\n" + + "Style: " + "Default," /* Name */ + "%s,%d," /* Font{name,size} */ + "&H%x,&H%x,&H%x,&H%x," /* {Primary,Secondary,Outline,Back}Colour */ + "%d,%d,%d,0," /* Bold, Italic, Underline, StrikeOut */ + "100,100," /* Scale{X,Y} */ + "0,0," /* Spacing, Angle */ + "%d,%d,%d," /* BorderStyle, Outline, Shadow */ + "%d,10,10,10," /* Alignment, Margin[LRV] */ + "0\r\n" /* Encoding */ + "\r\n" + + "[Events]\r\n" + "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text\r\n", + ctx->plane_width, ctx->plane_height, + font_name, ctx->font_size, + ASS_DEFAULT_COLOR, ASS_DEFAULT_COLOR, + ASS_DEFAULT_BACK_COLOR, ASS_DEFAULT_BACK_COLOR, + -ASS_DEFAULT_BOLD, -ASS_DEFAULT_ITALIC, -ASS_DEFAULT_UNDERLINE, + ctx->border_style, outline, shadow, ASS_DEFAULT_ALIGNMENT); + + av_freep(&font_name); + if (!avctx->subtitle_header) + return AVERROR(ENOMEM); + avctx->subtitle_header_size = strlen(avctx->subtitle_header); + return 0; +} + +static void set_ass_color(AVBPrint *buf, int color_num, + aribcc_color_t new_color, aribcc_color_t old_color) +{ + if (ARIBCC_COLOR_DIFF_RGB(new_color, old_color)) + av_bprintf(buf, "{\\%dc&H%06x&}", color_num, + ARIBCC_COLOR_RGB(new_color)); + if (ARIBCC_COLOR_DIFF_A(new_color, old_color)) + av_bprintf(buf, "{\\%da&H%02x&}", color_num, + 0xFF - ARIBCC_COLOR_A(new_color)); +} + +static int aribcaption_trans_ass_subtitle(ARIBCaptionContext *ctx) +{ + AVSubtitle *sub = ctx->sub; + AVBPrint buf; + bool single_rect = ctx->ass_single_rect; + int ret = 0, rect_idx; + + if (ctx->caption.plane_width > 0 && ctx->caption.plane_height > 0 && + (ctx->caption.plane_width != ctx->plane_width || + ctx->caption.plane_height != ctx->plane_height)) { + ctx->plane_width = ctx->caption.plane_width; + ctx->plane_height = ctx->caption.plane_height; + if ((ret = set_ass_header(ctx)) < 0) + return ret; + } + + /* ARIB TR-B14 version 3.8 Fascicle 1-(2/2) Volume 3 [Section 4] */ + /* No position information is provided for profile C */ + if (ctx->avctx->profile == FF_PROFILE_ARIB_PROFILE_C) + single_rect = true; + + sub->format = 1; /* text */ + if (ctx->caption.region_count == 0) { + /* clear previous caption for indefinite duration */ + ff_ass_add_rect(sub, "", ctx->readorder++, 0, NULL, NULL); + return 1; + } + + av_bprint_init(&buf, ARIBC_BPRINT_SIZE_INIT, ARIBC_BPRINT_SIZE_MAX); + + if (single_rect && ctx->avctx->profile != FF_PROFILE_ARIB_PROFILE_C) { + int x, y, rx, ry; + x = ctx->plane_width; + y = ctx->plane_height; + for (int i = 0; i < ctx->caption.region_count; i++) { + rx = ctx->caption.regions[i].x; + ry = ctx->caption.regions[i].y; + if (rx < x) + x = rx; + if (ry < y) + y = ry; + } + av_bprintf(&buf, "{\\an7}"); + if (y < 0) + y += ctx->plane_height; + if (x > 0 || y > 0) + av_bprintf(&buf, "{\\pos(%d,%d)}", x, y); + } + + rect_idx = 0; + for (int i = 0; i < ctx->caption.region_count; i++) { + aribcc_caption_region_t *region = &ctx->caption.regions[i]; + aribcc_color_t text_color = ARIBCC_MAKE_RGBA(0xFF, 0xFF, 0xFF, + ARIBC_ALPHA_DEFAULT_FRONT); + aribcc_color_t stroke_color = ARIBCC_MAKE_RGBA(0, 0, 0, + ARIBC_ALPHA_DEFAULT_FRONT); + aribcc_color_t back_color = ARIBCC_MAKE_RGBA(0, 0, 0, + ARIBC_ALPHA_DEFAULT_BACK); + aribcc_charstyle_t charstyle = ctx->charstyle; + int char_width = ctx->font_size; + int char_height = ctx->font_size; + int char_horizontal_spacing = 0; + + if (region->is_ruby && ctx->ignore_ruby) + continue; + + if (!single_rect) { + int x = region->x; + int y = region->y; + if (x < 0) + x += ctx->plane_width; + if (y < 0) + y += ctx->plane_height; + av_bprint_clear(&buf); + av_bprintf(&buf, "{\\an7}"); + if (x > 0 || y > 0) + av_bprintf(&buf, "{\\pos(%d,%d)}", x, y); + } + if (region->is_ruby) + av_bprintf(&buf, "{\\fs%d}", char_height / 2); + + for (int j = 0; j < region->char_count; j++) { + aribcc_caption_char_t *ch = ®ion->chars[j]; + + if (ctx->avctx->profile != FF_PROFILE_ARIB_PROFILE_C) { + if (ch->char_horizontal_spacing != char_horizontal_spacing) { + av_bprintf(&buf, "{\\fsp%d}", (region->is_ruby) ? + ch->char_horizontal_spacing / 2 : + ch->char_horizontal_spacing); + char_horizontal_spacing = ch->char_horizontal_spacing; + } + if (ch->char_width != char_width) { + av_bprintf(&buf, "{\\fscx%"PRId64"}", + av_rescale(ch->char_width, 100, ctx->font_size)); + char_width = ch->char_width; + } + if (ch->char_height != char_height) { + av_bprintf(&buf, "{\\fscy%"PRId64"}", + av_rescale(ch->char_height, 100, ctx->font_size)); + char_height = ch->char_height; + } + } + if (ch->style != charstyle) { + aribcc_charstyle_t diff = ch->style ^ charstyle; + if (diff & ARIBCC_CHARSTYLE_STROKE) { + if (charstyle & ARIBCC_CHARSTYLE_STROKE) { + if (ctx->force_stroke_text) + av_bprintf(&buf, "{\\bord%d}", + (int)(ctx->stroke_width * 4.0 / 3.0)); + else + av_bprintf(&buf, "{\\bord0}"); + } else + av_bprintf(&buf, "{\\bord3}"); + } + if (diff & ARIBCC_CHARSTYLE_BOLD) { + if (charstyle & ARIBCC_CHARSTYLE_BOLD) + av_bprintf(&buf, "{\\b0}"); + else + av_bprintf(&buf, "{\\b1}"); + } + if (diff & ARIBCC_CHARSTYLE_ITALIC) { + if (charstyle & ARIBCC_CHARSTYLE_ITALIC) + av_bprintf(&buf, "{\\i0}"); + else + av_bprintf(&buf, "{\\i1}"); + } + if (diff & ARIBCC_CHARSTYLE_UNDERLINE) { + if (charstyle & ARIBCC_CHARSTYLE_UNDERLINE) + av_bprintf(&buf, "{\\u0}"); + else + av_bprintf(&buf, "{\\u1}"); + } + charstyle = ch->style; + } + if (ch->text_color != text_color) { + set_ass_color(&buf, 1, ch->text_color, text_color); + text_color = ch->text_color; + } + if (ch->stroke_color != stroke_color) { + set_ass_color(&buf, 3, ch->stroke_color, stroke_color); + stroke_color = ch->stroke_color; + } + if (ch->back_color != back_color) { + if (ctx->border_style == 4) + set_ass_color(&buf, 4, ch->back_color, back_color); + else + set_ass_color(&buf, 3, ch->back_color, back_color); + back_color = ch->back_color; + } + if (region->chars[j].type == ARIBCC_CHARTYPE_DRCS) + av_bprintf(&buf, "\xe3\x80\x93"); /* Geta Mark */ + else + ff_ass_bprint_text_event(&buf, ch->u8str, strlen(ch->u8str), "", 0); + } + + if (single_rect) { + if (i + 1 < ctx->caption.region_count) + av_bprintf(&buf, "{\\r}\\N"); + ff_dlog(ctx, "ASS subtitle%s (%d,%d) %dx%d [%d]\n", + (region->is_ruby) ? " (ruby)" : "", + region->x, region->y, region->width, region->height, + rect_idx); + } else { + if (!av_bprint_is_complete(&buf)) { + ret = AVERROR(ENOMEM); + goto fail; + } + ff_dlog(ctx, "ASS subtitle%s (%d,%d) %dx%d [%d]: %s\n", + (region->is_ruby) ? " (ruby)" : "", + region->x, region->y, region->width, region->height, + rect_idx, buf.str); + + ret = ff_ass_add_rect(sub, buf.str, ctx->readorder++, 0 , NULL, NULL); + if (ret != 0) + goto fail; + rect_idx++; + } + } + if (single_rect) { + if (!av_bprint_is_complete(&buf)) { + ret = AVERROR(ENOMEM); + goto fail; + } + ff_dlog(ctx, "ASS subtitle: %s\n", buf.str); + + ret = ff_ass_add_rect(sub, buf.str, ctx->readorder++, 0 , NULL, NULL); + if (ret != 0) + goto fail; + rect_idx++; + } + + av_bprint_finalize(&buf, NULL); + return rect_idx; + +fail: + if (sub->rects) { + for (int i = 0; i < ctx->caption.region_count; i++) { + if (sub->rects[i]) { + av_freep(&sub->rects[i]->ass); + av_freep(&sub->rects[i]); + } + } + av_freep(&sub->rects); + } + sub->num_rects = 0; + av_bprint_finalize(&buf, NULL); + + return ret; +} + +static int aribcaption_trans_text_subtitle(ARIBCaptionContext *ctx) +{ + AVSubtitle *sub = ctx->sub; + AVSubtitleRect *rect; + int ret = 0; + const char *text; + + sub->rects = av_calloc(ctx->caption.region_count, sizeof(*sub->rects)); + if (!sub->rects) { + ret = AVERROR(ENOMEM); + goto fail; + } + sub->num_rects = 1; + + sub->rects[0] = av_mallocz(sizeof(*sub->rects[0])); + if (!sub->rects[0]) { + ret = AVERROR(ENOMEM); + goto fail; + } + rect = sub->rects[0]; + + if (ctx->caption.region_count == 0) + text = ""; /* clear previous caption */ + else { + text = ctx->caption.text; + ff_dlog(ctx, "TEXT subtitle: %s\n", text); + } + rect->text = av_strdup(text); + if (!rect->text) { + ret = AVERROR(ENOMEM); + goto fail; + } + + sub->format = 1; /* text */ + rect->type = SUBTITLE_TEXT; + + return 1; + +fail: + if (sub->rects) { + rect = sub->rects[0]; + if (rect) { + av_freep(&rect->text); + av_freep(&rect); + } + av_freep(&sub->rects); + } + sub->num_rects = 0; + + return ret; +} + +static int aribcaption_decode(AVCodecContext *avctx, AVSubtitle *sub, + int *got_sub_ptr, const AVPacket *avpkt) +{ + ARIBCaptionContext *ctx = avctx->priv_data; + int status; + + ff_dlog(ctx, "ARIB caption packet pts=%"PRIx64":\n", avpkt->pts); + if (sub->num_rects) { + avpriv_request_sample(ctx, "Different Version of Segment asked Twice"); + return AVERROR_PATCHWELCOME; + } + hex_dump_debug(ctx, avpkt->data, avpkt->size); + + ctx->sub = sub; + ctx->avpkt = avpkt; + ctx->time_base = avctx->pkt_timebase; + if (ctx->time_base.num <= 0 || ctx->time_base.den <= 0) { + av_log(ctx, AV_LOG_VERBOSE, "No timebase set. assuming 90kHz.\n"); + ctx->time_base = av_make_q(1, 90000); + } + if (avpkt->pts == AV_NOPTS_VALUE) + ctx->pts = ARIBCC_PTS_NOPTS; + else + ctx->pts = av_rescale_q(avpkt->pts, ctx->time_base, (AVRational){1, 1000}); + + status = aribcc_decoder_decode(ctx->decoder, avpkt->data, avpkt->size, + ctx->pts, &ctx->caption); + if (status == ARIBCC_DECODE_STATUS_ERROR) { + av_log(ctx, AV_LOG_ERROR, + "aribcc_decoder_decode() returned with error.\n"); + return AVERROR(EAGAIN); + } + if (status == ARIBCC_DECODE_STATUS_NO_CAPTION) { + ff_dlog(ctx, "No caption.\n"); + return avpkt->size; + } else { + ff_dlog(ctx, "type=%02x, flags=%x, lang=%03x\n", + ctx->caption.type, ctx->caption.flags, ctx->caption.iso6392_language_code); + ff_dlog(ctx, "region count = %d, start=%d.%d, duration=%d.%d\n", + ctx->caption.region_count, + (int)(ctx->caption.pts / 1000), (int)(ctx->caption.pts % 1000), + (int)((ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE) ? + -1 : ctx->caption.wait_duration / 1000), + (int)((ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE) ? + 0 : ctx->caption.wait_duration % 1000)); + } + + switch ((enum AVSubtitleType) ctx->subtitle_type) { + case SUBTITLE_TEXT: + status = aribcaption_trans_text_subtitle(ctx); + break; + + case SUBTITLE_ASS: + status = aribcaption_trans_ass_subtitle(ctx); + break; + + case SUBTITLE_BITMAP: + status = aribcaption_trans_bitmap_subtitle(ctx); + break; + + case SUBTITLE_NONE: + default: + status = 0; + } + + if (status < 0) { + av_log(ctx, AV_LOG_ERROR, "Failed to set Subtitle: %s\n", + av_err2str(status)); + aribcc_caption_cleanup(&ctx->caption); + return status; + } + if (status > 0) { + *got_sub_ptr = 1; + if (ctx->avpkt->pts != AV_NOPTS_VALUE) + sub->pts = av_rescale_q(ctx->avpkt->pts, + ctx->time_base, AV_TIME_BASE_Q); + if (ctx->caption.wait_duration == ARIBCC_DURATION_INDEFINITE) + sub->end_display_time = UINT32_MAX; + else + sub->end_display_time = (uint32_t)ctx->caption.wait_duration; + } + + aribcc_caption_cleanup(&ctx->caption); + return avpkt->size; +} + +static void aribcaption_flush(AVCodecContext *avctx) +{ + ARIBCaptionContext *ctx = avctx->priv_data; + + if (ctx->decoder) + aribcc_decoder_flush(ctx->decoder); + if (ctx->renderer) + aribcc_renderer_flush(ctx->renderer); + if (!(avctx->flags2 & AV_CODEC_FLAG2_RO_FLUSH_NOOP)) + ctx->readorder = 0; +} + +static int aribcaption_close(AVCodecContext *avctx) +{ + ARIBCaptionContext *ctx = avctx->priv_data; + + av_freep(&ctx->clut); + if (ctx->renderer) + aribcc_renderer_free(ctx->renderer); + if (ctx->decoder) + aribcc_decoder_free(ctx->decoder); + if (ctx->context) + aribcc_context_free(ctx->context); + + return 0; +} + +static int aribcaption_init(AVCodecContext *avctx) +{ + ARIBCaptionContext *ctx = avctx->priv_data; + aribcc_profile_t profile; + int ret = 0; + + ctx->avctx = avctx; + + switch (avctx->profile) { + case FF_PROFILE_ARIB_PROFILE_A: + profile = ARIBCC_PROFILE_A; + /* assume 960x540 at initial state */ + ctx->plane_width = 960; + ctx->plane_height = 540; + ctx->font_size = 36; + break; + case FF_PROFILE_ARIB_PROFILE_C: + profile = ARIBCC_PROFILE_C; + ctx->plane_width = 320; + ctx->plane_height = 180; + ctx->font_size = 16; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unknown or unsupported profile set.\n"); + return AVERROR(EINVAL); + } + /* determine BorderStyle of ASS header */ + if (ctx->ignore_background) + ctx->border_style = 1; + else + ctx->border_style = 4; + ctx->charstyle = ARIBCC_CHARSTYLE_DEFAULT; + if (ctx->force_stroke_text || ctx->ignore_background) + ctx->charstyle |= ARIBCC_CHARSTYLE_STROKE; + + if (!(ctx->context = aribcc_context_alloc())) { + av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption context.\n"); + return AVERROR_EXTERNAL; + } + aribcc_context_set_logcat_callback(ctx->context, logcat_callback, avctx); + if (!(ctx->decoder = aribcc_decoder_alloc(ctx->context))) { + av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption decoder.\n"); + return AVERROR_EXTERNAL; + } + if (!aribcc_decoder_initialize(ctx->decoder, + (enum aribcc_encoding_scheme_t) ctx->encoding_scheme, + ARIBCC_CAPTIONTYPE_CAPTION, + profile, + ARIBCC_LANGUAGEID_FIRST)) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribcaption decoder.\n"); + return AVERROR_EXTERNAL; + } + aribcc_decoder_set_replace_msz_fullwidth_ascii(ctx->decoder, + ctx->replace_fullwidth_ascii); + + /* Similar behavior as ffmpeg tool to set canvas size */ + if (ctx->canvas_width > 0 && ctx->canvas_height > 0 && + (ctx->avctx->width == 0 || ctx->avctx->height == 0)) { + ctx->avctx->width = ctx->canvas_width; + ctx->avctx->height = ctx->canvas_height; + } + + switch ((enum AVSubtitleType) ctx->subtitle_type) { + case SUBTITLE_ASS: + ret = set_ass_header(ctx); + if (ret != 0) { + av_log(avctx, AV_LOG_ERROR, "Failed to set ASS header: %s\n", + av_err2str(ret)); + return ret; + } + break; + + case SUBTITLE_BITMAP: + if(!(ctx->renderer = aribcc_renderer_alloc(ctx->context))) { + av_log(avctx, AV_LOG_ERROR, "Failed to alloc libaribcaption renderer.\n"); + return AVERROR_EXTERNAL; + } + if(!aribcc_renderer_initialize(ctx->renderer, + ARIBCC_CAPTIONTYPE_CAPTION, + ARIBCC_FONTPROVIDER_TYPE_AUTO, + ARIBCC_TEXTRENDERER_TYPE_AUTO)) { + av_log(avctx, AV_LOG_ERROR, "Failed to initialize libaribcaption renderer.\n"); + return AVERROR_EXTERNAL; + } + estimate_video_frame_size(ctx); + ff_dlog(ctx, "canvas: %dx%d plane: %dx%d bitmap: %dx%d frame: %dx%d\n", + ctx->avctx->width, ctx->avctx->height, + ctx->plane_width, ctx->plane_height, + ctx->bitmap_plane_width, ctx->bitmap_plane_height, + ctx->frame_width, ctx->frame_height); + if (!aribcc_renderer_set_frame_size(ctx->renderer, + ctx->frame_width, ctx->frame_height)) { + av_log(ctx, AV_LOG_ERROR, + "aribcc_renderer_set_frame_size() returned with error.\n"); + return AVERROR_EXTERNAL; + } + + if (!(ctx->clut = av_mallocz(AVPALETTE_SIZE))) + return AVERROR(ENOMEM); + + aribcc_renderer_set_storage_policy(ctx->renderer, ARIBCC_CAPTION_STORAGE_POLICY_MINIMUM, 0); + aribcc_renderer_set_replace_drcs(ctx->renderer, ctx->replace_drcs); + aribcc_renderer_set_force_stroke_text(ctx->renderer, ctx->force_stroke_text); + aribcc_renderer_set_force_no_background(ctx->renderer, ctx->ignore_background); + aribcc_renderer_set_force_no_ruby(ctx->renderer, ctx->ignore_ruby); + aribcc_renderer_set_stroke_width(ctx->renderer, ctx->stroke_width); + if (ctx->font) { + int is_nomem = 0; + size_t count = 0; + const char **font_families = NULL; + const char *fonts = ctx->font; + + while (*fonts) { + const char **ff = av_realloc_array(font_families, count + 1, sizeof(*font_families)); + if (!ff) { + is_nomem = 1; + break; + } else { + font_families = ff; + ff[count++] = av_get_token(&fonts, ","); + if (!ff[count - 1]) { + is_nomem = 1; + break; + } else if (*fonts) + fonts++; + } + } + if (!is_nomem && count) + aribcc_renderer_set_default_font_family(ctx->renderer, font_families, count, true); + while (count) + av_freep(&font_families[--count]); + av_freep(&font_families); + if (is_nomem) + return AVERROR(ENOMEM); + } + break; + + case SUBTITLE_TEXT: + case SUBTITLE_NONE: + default: + /* do nothing */ ; + } + + ctx->readorder = 0; + + return 0; +} + +#if !defined(ASS_SINGLE_RECT) +# define ASS_SINGLE_RECT 0 +#endif + +#define OFFSET(x) offsetof(ARIBCaptionContext, x) +#define SD AV_OPT_FLAG_SUBTITLE_PARAM | AV_OPT_FLAG_DECODING_PARAM +static const AVOption options[] = { + { "sub_type", "subtitle rendering type", + OFFSET(subtitle_type), AV_OPT_TYPE_INT, + { .i64 = SUBTITLE_ASS }, SUBTITLE_NONE, SUBTITLE_ASS, SD, "type" }, + { "none", "do nothing", 0, AV_OPT_TYPE_CONST, + { .i64 = SUBTITLE_NONE }, .flags = SD, .unit = "type" }, + { "bitmap", "bitmap rendering", 0, AV_OPT_TYPE_CONST, + { .i64 = SUBTITLE_BITMAP }, .flags = SD, .unit = "type" }, + { "text", "plain text", 0, AV_OPT_TYPE_CONST, + { .i64 = SUBTITLE_TEXT }, .flags = SD, .unit = "type" }, + { "ass", "formatted text", 0, AV_OPT_TYPE_CONST, + { .i64 = SUBTITLE_ASS }, .flags = SD, .unit = "type" }, + { "caption_encoding", "encoding scheme of subtitle text", + OFFSET(encoding_scheme), AV_OPT_TYPE_INT, { .i64 = ARIBCC_ENCODING_SCHEME_AUTO }, + ARIBCC_ENCODING_SCHEME_AUTO, ARIBCC_ENCODING_SCHEME_ABNT_NBR_15606_1_LATIN, SD, "encoding" }, + { "auto", "automatically detect encoding scheme", 0, AV_OPT_TYPE_CONST, + { .i64 = ARIBCC_ENCODING_SCHEME_AUTO }, .flags = SD, .unit = "encoding" }, + { "jis", "8bit-char JIS encoding (Japanese ISDB captions)", 0, AV_OPT_TYPE_CONST, + { .i64 = ARIBCC_ENCODING_SCHEME_ARIB_STD_B24_JIS }, .flags = SD, .unit = "encoding" }, + { "utf8", "UTF-8 encoding (Philippines ISDB-T captions)", 0, AV_OPT_TYPE_CONST, + { .i64 = ARIBCC_ENCODING_SCHEME_ARIB_STD_B24_UTF8 }, .flags = SD, .unit = "encoding" }, + { "latin", "latin characters (SBTVD / ISDB-Tb captions used in South America)", 0, AV_OPT_TYPE_CONST, + { .i64 = ARIBCC_ENCODING_SCHEME_ABNT_NBR_15606_1_LATIN }, .flags = SD, .unit = "encoding" }, + { "ass_single_rect", "workaround of ASS subtitle for players which can't handle multi-rectangle [ass]", + OFFSET(ass_single_rect), AV_OPT_TYPE_BOOL, { .i64 = ASS_SINGLE_RECT }, 0, 1, SD }, + { "font", "comma-separated font family [ass, bitmap]", + OFFSET(font), AV_OPT_TYPE_STRING, { .str = NULL }, 0, 0, SD }, + { "replace_fullwidth_ascii", "replace MSZ fullwidth alphanumerics with halfwidth alphanumerics [ass, bitmap]", + OFFSET(replace_fullwidth_ascii), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD }, + { "force_outline_text", "always render characters with outline [(ass), bitmap]", + OFFSET(force_stroke_text), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD }, + { "ignore_background", "ignore rendering caption background [(ass), bitmap]", + OFFSET(ignore_background), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD }, + { "ignore_ruby", "ignore ruby-like characters [ass, bitmap]", + OFFSET(ignore_ruby), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, SD }, + { "outline_width", "outline width of text [(ass), bitmap]", + OFFSET(stroke_width), AV_OPT_TYPE_FLOAT, { .dbl = 1.5 }, 0.0, 3.0, SD }, + { "replace_drcs", "replace known DRCS [bitmap]", + OFFSET(replace_drcs), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, SD }, + {"canvas_size", "set input video size (WxH or abbreviation) [bitmap]", + OFFSET(canvas_width), AV_OPT_TYPE_IMAGE_SIZE, { .str = NULL }, 0, INT_MAX, SD }, + { NULL } +}; + +static const AVClass aribcaption_class = { + .class_name = "aribcaption decoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +const FFCodec ff_aribcaption_decoder = { + .p.name = "aribcaption", + .p.long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption decoder"), + .p.type = AVMEDIA_TYPE_SUBTITLE, + .p.id = AV_CODEC_ID_ARIB_CAPTION, + .priv_data_size = sizeof(ARIBCaptionContext), + .init = aribcaption_init, + .close = aribcaption_close, + FF_CODEC_DECODE_SUB_CB(aribcaption_decode), + .flush = aribcaption_flush, + .p.priv_class = &aribcaption_class, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; From patchwork Thu Feb 23 10:17:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: TADANO Tokumei X-Patchwork-Id: 40473 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:5494:b0:bf:7b3a:fd32 with SMTP id i20csp265276pzk; Thu, 23 Feb 2023 02:18:43 -0800 (PST) X-Google-Smtp-Source: AK7set8/UnNv5qntu1/zK9v3B5Kw9pvsY7/TgmUpnubJiwwP44H1FzjNcnmSrUUJATnG/g1BAR6p X-Received: by 2002:aa7:d048:0:b0:4ab:554:37ea with SMTP id n8-20020aa7d048000000b004ab055437eamr10673400edo.4.1677147523759; Thu, 23 Feb 2023 02:18:43 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677147523; cv=none; d=google.com; s=arc-20160816; b=CFbIHTcqxX44zRqkvlPUAC0TUNfup67v3n95A+akaBkrX8PCwqGiL6XWZsno9Qm1jD mSqDzUG1H6UHrGgWBB2x7fyx6/d2b7POBGYOShWiRPKCUkKdLSr2TyoR1oMOlWcfvuzJ DCrvK3svHutVTYTzreV2ODUvtY1kxmCFqOWU1yPQa6coyTYN+FuAgnjS3KiyCiPChy0d eVoKReS2b3DZ7jvhpxD3MD4dldsLTMnqsazvcPOV4JEH2k8/L3md3t6sXYxYiGJwidt5 pN+krF05I2gVVgd71AfaVA63vCRB2DAwjtVmkFHsUQJYb4yNIlBSPot0YDElGO9NqfHy mWFg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:dkim-filter:delivered-to; bh=fum46+7J0tt36J6wTvbx29An7dmmaoBqXyBXDzcgvXk=; b=O0zQE55N7xDEOP4pUd5xFX1juhA8Bvzwa4bte/nF7jqPjW9ghAd3YUvOFmPzBQppvy s5hR4x3joIF+bsOXiR8RzTKmI1hLf3B7J+bst9kZdf7Fu2LFbRGI5NfPw5AlmrWF0inv LMxd1M81/HBgSEX47FfHaltVw66UajD7KoeGCMEqmPJcvevWTxo+tpQUIt6q6+lo5TxM 44Cy35a4BS5LRcG1zJ4SJAiIy2UgBs8bDQ8V98L0Pkr1FfiO6IHgYuAHFz08JhGWy1Tg YTTMWx9Y+nlrBywcXfzLCF6DOzP3ToPNyT5NurncoG1yk19TYKvi7EaI2AUT6O4HPnZR bOGQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=qzcUtfdd; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id m17-20020aa7c491000000b004aaa653a74asi6277496edq.596.2023.02.23.02.18.43; Thu, 23 Feb 2023 02:18:43 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=qzcUtfdd; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 7C29168C0E6; Thu, 23 Feb 2023 12:18:32 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from conssluserg-02.nifty.com (conssluserg-02.nifty.com [210.131.2.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B065D68C0DB for ; Thu, 23 Feb 2023 12:18:25 +0200 (EET) Received: from osamu-pc.. (M106073025034.v4.enabler.ne.jp [106.73.25.34]) (authenticated) by conssluserg-02.nifty.com with ESMTP id 31NAHthv015305; Thu, 23 Feb 2023 19:18:04 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conssluserg-02.nifty.com 31NAHthv015305 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1677147485; bh=v13cEGOk37dCYVoHQALvruWonxAc4SDVijA0QjjkCNo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qzcUtfdd9YscosywclyQd5cpVc0Iz2Gz8P8fol3ENRHoMm2+vTZp07lkfzW60Mm+n ihaIvcGnfLvzGvjpeQl3QcKMaMRxUGwt750y7pACyGT2ONdi062N0rMJdSDbqYPK7O 0B5Gli3pAy5TLNoiXvJRuAvCCUhbez7B4DwrIkmZ/uTa4uiAz6e8pP8RYi8/tGcng8 mTEeMvvfPdErOlxyB50ofuAaIaw4+5UvSU4ZOjrdLvjc9EtMU0C8cCKn0BtOjfqUoA nAhJFW+w4i3MfG6GhqBrSNeOEWwEAxn3PZ73uqoYjpUTBWTUhTaSCb26EwO6KveqVw e9M6d1xSaY3eg== X-Nifty-SrcIP: [106.73.25.34] From: TADANO Tokumei To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 Feb 2023 19:17:16 +0900 Message-Id: <20230223101718.562202-3-aimingoff@pc.nifty.jp> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230223101718.562202-1-aimingoff@pc.nifty.jp> References: <20230223101718.562202-1-aimingoff@pc.nifty.jp> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v7 2/4] lavc/codec_desc.c: remove AV_CODEC_PROP_TEXT_SUB property X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: TADANO Tokumei Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: ERIdIU5Vp9vC To support bitmap type of subtitles, remove AV_CODEC_PROP_TEXT_SUB property from codec descriptor for AV_CODEC_ID_ARIB_CAPTION. It is similar way to `libavcodec/libzvbi-teletextdec.c` (AV_CODEC_ID_DVB_TELETEXT). Instead, each subtitle decoder has to specify subtitile format. `libavcodec/libaribb24.c` uses same AV_CODEC_ID_ARIB_CAPTION and expects AV_CODEC_PROP_TEXT_SUB is defined. Thus add a line to specify text format subtitle. --- libavcodec/codec_desc.c | 1 - libavcodec/libaribb24.c | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 199f62df15..22b7f3c7f9 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3548,7 +3548,6 @@ static const AVCodecDescriptor codec_descriptors[] = { .type = AVMEDIA_TYPE_SUBTITLE, .name = "arib_caption", .long_name = NULL_IF_CONFIG_SMALL("ARIB STD-B24 caption"), - .props = AV_CODEC_PROP_TEXT_SUB, .profiles = NULL_IF_CONFIG_SMALL(ff_arib_caption_profiles), }, diff --git a/libavcodec/libaribb24.c b/libavcodec/libaribb24.c index 8ccf3c4b5d..e3e244be99 100644 --- a/libavcodec/libaribb24.c +++ b/libavcodec/libaribb24.c @@ -291,6 +291,7 @@ next_region: av_log(avctx, AV_LOG_DEBUG, "Styled ASS line: %s\n", buf.str); + sub->format = 1; /* text */ ret = ff_ass_add_rect(sub, buf.str, b24->read_order++, 0, NULL, NULL); } From patchwork Thu Feb 23 10:17:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: TADANO Tokumei X-Patchwork-Id: 40475 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:5494:b0:bf:7b3a:fd32 with SMTP id i20csp265473pzk; Thu, 23 Feb 2023 02:19:03 -0800 (PST) X-Google-Smtp-Source: AK7set+OemZfJb2x0C6eKbggyeTXIZcQNgBauIID79YxdmUy2IOk0lPjmFdbQDQD3B3srpHlJCK+ X-Received: by 2002:aa7:da06:0:b0:4aa:da7c:4c5c with SMTP id r6-20020aa7da06000000b004aada7c4c5cmr10648816eds.34.1677147543179; Thu, 23 Feb 2023 02:19:03 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677147543; cv=none; d=google.com; s=arc-20160816; b=CJ/Uap8nU7ZvtbQFP7Kuij7J0ahtCRKxq1wKBGvsoEc/O24HvC4VA/QfqtD0OhAig/ /PPeToZiGDRoA1fGhwFpKMjEnjnpucSeukT1SYHdI754PW/NhW5+GTe0TYsGo73uMAhX S7l4bP3Co9ZZhLUaf5qD5miw8by4CQw2pQkyac+UxrJo9N+s7rvshtFpCDMFDTeDXM5j OJxtbsAqot5UxH9uBOD4KEwrUEQ4gitKddoDUTswYmQ6FpUeZbC42UtLwdbvXDc/71cg BYALhi7u/KzxOoYVn6OqSuEPpypYJrxeQOSE/dnyb6+3uHWPxgkxdoorWqm/aEDmCWdf eUgA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:dkim-filter:delivered-to; bh=qrl0Bo1xRaiAslpjbvoMjJwBbv6IUhEqfjL+JaMXE54=; b=KhfakofYxt0lTBI6NeJfkLRc1QQJNM/RDvUXXI+IZKYMcCfnmxJPyVnZyYEDAHrVfQ +TnSzhpqVAbmUS25D+AcxvXi14SU+kZLd4a735FK/S4JVL8TnlCRcj+TRPlxZOxNwncG nScc1HmI0inF7dEmFqPZQYlq5R/wmhlZ2S/wz6fmun0MEIMCTOWyeDa2eyPJUWUPO4fU zXjScx8HzcnagVPdf2jhSAerfurH9X5ha4mmxoPn3GJqcfiRv5EdTawzKte3DrokS0+A NcX1bDP9rfEbtE1aFgQMyCxkAzLpdSSQulVVFUVtTZaVoF9etWHHvSe787aIm/cD+VEl MPQg== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b="S/yAAFff"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id v28-20020aa7cd5c000000b004aad23a85a6si14820104edw.81.2023.02.23.02.19.02; Thu, 23 Feb 2023 02:19:03 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b="S/yAAFff"; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 3680C68C0EE; Thu, 23 Feb 2023 12:18:34 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from conssluserg-02.nifty.com (conssluserg-02.nifty.com [210.131.2.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id D0E8E68C0DC for ; Thu, 23 Feb 2023 12:18:25 +0200 (EET) Received: from osamu-pc.. (M106073025034.v4.enabler.ne.jp [106.73.25.34]) (authenticated) by conssluserg-02.nifty.com with ESMTP id 31NAHthx015305; Thu, 23 Feb 2023 19:18:07 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conssluserg-02.nifty.com 31NAHthx015305 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1677147487; bh=29yOFh3CFpr/FLAE3Us62rnyzRmjUEiJq27F2o8t+MU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=S/yAAFffd8Pg+DwxT5qX2BZxRoE+wGY8mP+9SfbC2zz2EEzufvNJnTANyrvOciafq l8WsbntBQpmbNajTpYWGaWE9YBZ+R5Tr/zXiVFI0f1VDGMpl5OEUzcZXETUOQCrREa Bfi5Aok/xQMexI3cZI1gNN56Pe/RiSias4+7NjW5CBveHGnA4IeUXs3wpVkAXf5u0W wFDPSDIWUR++6Z7EzaQs7NL9tz0Lp33KwrQUj46g/1XYpKWUAKwSUJUQMoKAIGsJs/ Dih0p6tygP1/yyBeHodEkuAQ7U+phCHVeohkGuKBsWK3O7SJQ+qpAqIq2IxXwf7O1M c5X9FhPwU3N6g== X-Nifty-SrcIP: [106.73.25.34] From: TADANO Tokumei To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 Feb 2023 19:17:17 +0900 Message-Id: <20230223101718.562202-4-aimingoff@pc.nifty.jp> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230223101718.562202-1-aimingoff@pc.nifty.jp> References: <20230223101718.562202-1-aimingoff@pc.nifty.jp> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v7 3/4] lavf/mpegts.c: set some properties for ARIB caption X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: TADANO Tokumei Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: MpI+M8mTkxK/ Some additional properties are set for ARIB caption. * need_parsing = 0 ARIB caption doesn't require any parser. This avoids "parser not found" warning message. * need_context_update = 1 When any profiles are changed, set this flag to notify. --- libavformat/mpegts.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libavformat/mpegts.c b/libavformat/mpegts.c index d97702fcd7..a0e5eb75b6 100644 --- a/libavformat/mpegts.c +++ b/libavformat/mpegts.c @@ -2175,8 +2175,12 @@ int ff_parse_mpeg2_descriptor(AVFormatContext *fc, AVStream *st, int stream_type st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; st->codecpar->codec_id = AV_CODEC_ID_ARIB_CAPTION; - st->codecpar->profile = picked_profile; + if (st->codecpar->profile != picked_profile) { + st->codecpar->profile = picked_profile; + sti->need_context_update = 1; + } sti->request_probe = 0; + sti->need_parsing = 0; } break; case 0xb0: /* DOVI video stream descriptor */ From patchwork Thu Feb 23 10:17:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: TADANO Tokumei X-Patchwork-Id: 40474 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:5494:b0:bf:7b3a:fd32 with SMTP id i20csp265382pzk; Thu, 23 Feb 2023 02:18:53 -0800 (PST) X-Google-Smtp-Source: AK7set/YsWRQf1TRFqioUJ3i7tvvzoZq6arw1/VP6nmyOJccgN4mdu3rH4PwMSVOF1JGni8/rOsB X-Received: by 2002:a17:907:ea2:b0:888:b764:54e5 with SMTP id ho34-20020a1709070ea200b00888b76454e5mr24622864ejc.71.1677147533705; Thu, 23 Feb 2023 02:18:53 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1677147533; cv=none; d=google.com; s=arc-20160816; b=V/ju6A4aav3SuVOj4TxT6hbqu3MMFrbmG32XgVThqD7brV34l3IsoS8eb+Y7G/jU1L wV7F/cQ0QKVqbFjDWz2dkIC0B0wqWTZ5EMeXqWGhYsfu2haIEHcXKl7deE5LD4BugHuk R+mSDHDsFPOq3fWSkmait8+wgDogVqv5Qmit1bGEEz9UiR0llazE7q3kAjfQOYbJN28v fKWGBEku3oIy3oEU8OnFEH8+w7taoNaT87YA1O/TE6kP0ujVp66XvMYEA5PXC02mj+Qb flv+5QzUX8UFMTl+qYvbmHdTS1np86oRJ7WQ1+3W/NvRYKZoo0GJlVckdQFfD8Ct+Xi8 GSPw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc:reply-to :list-subscribe:list-help:list-post:list-archive:list-unsubscribe :list-id:precedence:subject:mime-version:references:in-reply-to :message-id:date:to:from:dkim-signature:dkim-filter:delivered-to; bh=60A+XG5LjYVC/SURC3I64vwaVh79y247orccbZHndWU=; b=zgGWt+cLQo+55feCfvu4ejmvZjVwhO0aoiJG1KINIPwlI84hlUP8cH9gZWboc+nR03 OjKNbqodsQ+evh/X2EPA8JWUlpJTHPvTUtpZUSE5JB66c0A7XJ6V+gwaetk/m+LjFad8 pQElpEIzvQeySDn1SwKaJD2bWTEeYgGJMV1AqVrb7s3fbaLcLg2THQgnMhMqepfRUBJ2 1YQTfjjr1BzAy0LxpLu7P7Ux3QTkxAeP5pqxX/Frr2/HLMu6szEI0fLPxr+HPdhHcGu0 xqVCiNmmsnx49UZnfsLKYwP9+Ft+MpK2nYVnorNE4sOxVL5LjatwEoqyCi4bWcRFYL7C QMHQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=IyTAsbas; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id vr2-20020a170907a50200b008eb27de203csi3108784ejc.183.2023.02.23.02.18.53; Thu, 23 Feb 2023 02:18:53 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@nifty.com header.s=dec2015msa header.b=IyTAsbas; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 5501F68C0E2; Thu, 23 Feb 2023 12:18:33 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from conssluserg-02.nifty.com (conssluserg-02.nifty.com [210.131.2.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id BA14768C0CC for ; Thu, 23 Feb 2023 12:18:25 +0200 (EET) Received: from osamu-pc.. (M106073025034.v4.enabler.ne.jp [106.73.25.34]) (authenticated) by conssluserg-02.nifty.com with ESMTP id 31NAHti1015305; Thu, 23 Feb 2023 19:18:09 +0900 DKIM-Filter: OpenDKIM Filter v2.10.3 conssluserg-02.nifty.com 31NAHti1015305 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=nifty.com; s=dec2015msa; t=1677147489; bh=6aEnUw2iqYg0PhywopEaTXYPts89pvRUSTVTtHb21Zg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IyTAsbasy4lEcl7L4yYlxFr/dZSSXuKe0fhDplgoZz36z5ldVlMEnDtcv4nSO6oy6 8UxgiNyzrn2JG3JknZ7Y397uRN9CtEmfeW8jU4Qpur2nCfRWDFMzkxrCuuhsh3dA04 VB0dpVgTt0/1WAwn1dredxMYp/93g4EjxR20kEYywF9GM+mf/3tPOkJRJsBmna1Y+8 3AzzBbsfbZGxObPhQXNDMFrD6bXWghFi5dUWj0zRYydIoPJ1WQ5I4moFf2o9BEFF8A EpLPwW1QjH2T3u6PADQSIUXZYEORmV0pKmGsbNoIAr8tGbCjkZ3PbgbQHF/OmdPh9S NWVOI7LSA0BMQ== X-Nifty-SrcIP: [106.73.25.34] From: TADANO Tokumei To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 Feb 2023 19:17:18 +0900 Message-Id: <20230223101718.562202-5-aimingoff@pc.nifty.jp> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20230223101718.562202-1-aimingoff@pc.nifty.jp> References: <20230223101718.562202-1-aimingoff@pc.nifty.jp> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v7 4/4] doc/decoders.texi: add document of aribcaption decoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: TADANO Tokumei Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: pl1tIkK21XrT --- doc/decoders.texi | 150 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 150 insertions(+) diff --git a/doc/decoders.texi b/doc/decoders.texi index 5ba85cf9b1..4888735016 100644 --- a/doc/decoders.texi +++ b/doc/decoders.texi @@ -353,6 +353,156 @@ Enabled by default. @end table +@section aribcaption + +Yet another ARIB STD-B24 caption decoder using external @dfn{libaribcaption} +library. + +Implements profiles A and C of the Japanse ARIB STD-B24 standard, +Brazilian ABNT NBR 15606-1, and Philippines version of ISDB-T. + +Requires the presence of the libaribcaption headers and library +(@url{https://github.com/xqq/libaribcaption}) during configuration. +You need to explicitly configure the build with @code{--enable-libaribcaption}. +If both @dfn{libaribb24} and @dfn{aribcaption} are enabled, @dfn{aribcaption} +decoder precedes. + +@subsection aribcaption Decoder Options + +@table @option + +@item -sub_type @var{subtitle_type} +Specifies the format of the decoded subtitles. + +@table @samp +@item bitmap +Graphical image. +@item ass +ASS formatted text. +@item text +Simple text based output without formatting. +@end table + +The default is @dfn{ass} as same as @dfn{libaribb24} decoder. +Some present players (e.g., @dfn{mpv}) expect ASS format for ARIB caption. + +@item -caption_encoding @var{encoding_scheme} +Specifies the encoding scheme of input subtitle text. + +@table @samp +@item auto +Automatically detect text encoding. +@item jis +8bit-char JIS encoding defined in ARIB STD B24. +This encoding used in Japan for ISDB captions. +@item utf8 +UTF-8 encoding defined in ARIB STD B24. +This encoding is used in Philippines for ISDB-T captions. +@item latin +Latin character encoding defined in ABNT NBR 15606-1. +This encoding is used in South America for SBTVD / ISDB-Tb captions. +@end table + +The default is @dfn{ass} as same as @dfn{libaribb24} decoder. +Some present players (e.g., @dfn{mpv}) expect ASS format for ARIB caption. + +@item -font @var{font_name[,font_name2,...]} +Specify comma-separated list of font family names to be used for @dfn{bitmap} +or @dfn{ass} type subtitle rendering. +Only first font name is used for @dfn{ass} type subtitle. + +If not specified, use internaly defined default font family. + +@item -ass_single_rect @var{boolean} +ARIB STD-B24 specifies that some captions may be displayed at different +positions at a time (multi-rectangle subtitle). +Since some players (e.g., old @dfn{mpv}) can't handle multiple ASS rectangles +in a single AVSubtitle, or multiple ASS rectangles of indeterminate duration +with the same start timestamp, this option can change the behavior so that +all the texts are displayed in a single ASS rectangle. + +The default is @var{false}. + +If your player cannot handle AVSubtitles with multiple ASS rectangles properly, +set this option to @var{true} or define @env{ASS_SINGLE_RECT=1} to change +default behavior at compilation. + +@item -replace_fullwidth_ascii @var{boolean} +Specify whether to replace MSZ (Middle Size, half width) fullwidth +alphanumerics with halfwidth alphanumerics. + +The default is @var{true}. + +@item -force_outline_text @var{boolean} +Specify whether always render outline text for all characters regardless of +the indication by charactor style. + +The default is @var{false}. + +@item -outline_width @var{number} (0.0 - 3.0) +Specify width for outline text, in dots (relative). + +The default is @var{1.5}. + +@item -ignore_background @var{boolean} +Specify whether to ignore background color rendering. + +The default is @var{false}. + +@item -ignore_ruby @var{boolean} +Specify whether to ignore rendering for ruby-like (furigana) characters. + +The default is @var{false}. + +@item -replace_drcs @var{boolean} +Specify whether to render replaced DRCS characters as Unicode characters. + +The default is @var{true}. + +@item -canvas_size @var{image_size} +Specify the resolution of the canvas to render subtitles to; usually, this +should be frame size of input video. +This only applies when @code{-subtitle_type} is set to @var{bitmap}. + +The aribcaption decoder assumes input frame size for bitmap rendering as below: +@enumerate +@item +PROFILE_A : 1440 x 1080 with SAR (PAR) 4:3 +@item +PROFILE_C : 320 x 180 with SAR (PAR) 1:1 +@end enumerate + +If actual frame size of input video does not match above assumption, +the rendered captions may be distorted. +To make the captions undistorted, add @code{-canvas_size} option to specify +actual input video size. + +Note that the @code{-canvas_size} option is not required for video with +different size but same aspect ratio. +In such cases, the caption will be stretched or shrunk to actual video size +if @code{-canvas_size} option is not specified. +If @code{-canvas_size} option is specified with different size, +the caption will be stretched or shrunk as specified size with calculated SAR. + +@end table + +@subsection aribcaption decoder usage examples + +Display MPEG-TS file with ARIB subtitle by @code{ffplay} tool: +@example +ffplay -sub_type bitmap MPEG.TS +@end example + +Display MPEG-TS file with input frame size 1920x1080 by @code{ffplay} tool: +@example +ffplay -sub_type bitmap -canvas_size 1920x1080 MPEG.TS +@end example + +Embed ARIB subtitle in transcoded video: +@example +ffmpeg -sub_type bitmap -i src.m2t -filter_complex "[0:v][0:s]overlay" -vcodec h264 dest.mp4 +@end example + @section dvbsub @subsection Options