From patchwork Fri Dec 10 21:37:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Soft Works X-Patchwork-Id: 32268 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a6b:cd86:0:0:0:0:0 with SMTP id d128csp2372845iog; Fri, 10 Dec 2021 13:38:13 -0800 (PST) X-Google-Smtp-Source: ABdhPJw6rDEC+5LzU3cb4n4ODykjtQFIOD8aLY7h8eXspHLfnZEIjJTI+aiFUj2Z2kitfy6mKYnQ X-Received: by 2002:aa7:c946:: with SMTP id h6mr43181270edt.190.1639172293246; Fri, 10 Dec 2021 13:38:13 -0800 (PST) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id z2si6989063edb.580.2021.12.10.13.38.12; Fri, 10 Dec 2021 13:38:13 -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=@hotmail.com header.s=selector1 header.b=VdX3jfAO; arc=fail (body hash mismatch); 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; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=hotmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id EFBC768AF51; Fri, 10 Dec 2021 23:37:26 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from NAM04-MW2-obe.outbound.protection.outlook.com (mail-mw2nam08olkn2073.outbound.protection.outlook.com [40.92.46.73]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B21BA68AF22 for ; Fri, 10 Dec 2021 23:37:24 +0200 (EET) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=MzAC1DRWdfSeIowvDwTHhA3Uq7HDX2DW8uWmKBMGs20Hq19sxZhHPfvHynhbQGT6xoL0gJJm2IOyqqrra5ddL1p1JUUln7dHZNleAcOrFUF83b3DJfKjTWzZQgvvuOxrbLL1Ur/czNW4D2CsVm3PsdJT3xgTM41bkkn4hhucUH4e3V7VNEfq+DSLQRnMyoBSKtAHmZyF+Ufn9l+YVeLARglgZJmEg7CjMz1I0WO/cxA0IKcI4FWujyEkxCbnuuji0flusHGekpPfWohVXWtUqCleI1UtonL4TNz3uwh9ZdFHWXxyOpwpeM2ATil3zc/76MC6TnQ1I9w2SS022h5nbQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=VGBE3q5uI9oC2UntzDR4VUhSkjkFjJIJPkOkQstqpCQ=; b=G6wmD0TWTARilFox1Yz/1wX9teSKZAc9KdizKmrb1sE6Z4Y1HVuvS2OHXfy59xorVDyNzfCLa8/+gTg2XTG0auLZmiuNj0OzWH65qRK1dgnmI0JAI1b6jplAmnecHmF25SPP13TGOeay2+ama87+ttV5NcMRQEJAgAFrqghGAB+TbZiZCoA/P0qjEX8caxs0pjOWya1pKDl7BHA72Vbis5dLKypJvv69BeUy41xqBhxq7Qkv+FZcEYEHojEoVkiG1m3coFkbZb5aq/shprsWD/AJsv4112Cl5Lb6iSjGRqlsO4mm+p+vv1JJqSfKLq9oWquBb2rgtNenQET4H0K5NQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=hotmail.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=VGBE3q5uI9oC2UntzDR4VUhSkjkFjJIJPkOkQstqpCQ=; b=VdX3jfAOzc0lNqLcDt+BBmnH1OmbRxxle0AhY5RYZW9bm6cOu1IxihPbZwKq8sPtSrJbuX6qSjybUvgqa+pdJzEaouf5dvPqyo3VDXlrp7CUIgNd4USrFLt9ZG+go2oDOxO+XLEDbCSQ3+1XM9Ky2FfcquPDe+z3IQN4/t5325IvOT/0yQYiD+rUuk40m4lGMItoJnIs0F4+7c1vbPy0EtdzOK52xGaD8HQ8LwcG/5C48WpqWWZ2ltx06kd4YyD1wqmpAyuwvUAHv4XaortLH8momU5GFXn65U0OF7ZiQGgDF3yy1lsl1agVdXfnCR+gMgMNedBQdsEJCMnaJsK7kw== Received: from DM8P223MB0365.NAMP223.PROD.OUTLOOK.COM (2603:10b6:8:b::20) by DM8P223MB0397.NAMP223.PROD.OUTLOOK.COM (2603:10b6:8:b::5) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4755.20; Fri, 10 Dec 2021 21:37:19 +0000 Received: from DM8P223MB0365.NAMP223.PROD.OUTLOOK.COM ([fe80::9c8d:fc63:9488:9775]) by DM8P223MB0365.NAMP223.PROD.OUTLOOK.COM ([fe80::9c8d:fc63:9488:9775%7]) with mapi id 15.20.4778.015; Fri, 10 Dec 2021 21:37:19 +0000 From: Soft Works To: "ffmpeg-devel@ffmpeg.org" Thread-Topic: [PATCH v23 06/21] avcodec/subtitles: Migrate subtitle encoders to frame-based API and provide a compatibility shim for the legacy api Thread-Index: AQHX7g4bmCbim8pHOkCpcC6yjam0jA== Date: Fri, 10 Dec 2021 21:37:19 +0000 Message-ID: References: <84c6ba3b99bf387e818d59f2161009ead8fb5767.1639172095.git.softworkz@hotmail.com> <0b41271ed30b530c1d55a9b824fc8bbbbd14fe5e.1639172095.git.softworkz@hotmail.com> <9f2875d043147119351f59b6410d718d170574e1.1639172095.git.softworkz@hotmail.com> <62a926e2d86310039653324bdf2a856f09a0fb46.1639172095.git.softworkz@hotmail.com> In-Reply-To: <62a926e2d86310039653324bdf2a856f09a0fb46.1639172095.git.softworkz@hotmail.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-ms-exchange-messagesentrepresentingtype: 1 x-tmn: [XSZFa7eqrBhu+1m5cIqNXpSrgngEIvY2] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 91db4f8c-39f0-4435-9528-08d9bc253e38 x-ms-traffictypediagnostic: DM8P223MB0397:EE_ x-microsoft-antispam: BCL:0; x-microsoft-antispam-message-info: hIVwQDR0sQ5wyHVTZ4NxY5KrpuN82SUctdgxQ8AD9BVZYcPVN7cUg1W4Oy5hvMYBDhUbD0Osj/fCA3d0oR9ZpNDvApaC+0XB3WZwbGsCXsVpXOT9Msz2Yh1HRF4h6umzzTWXxtX1zEVzQOPwnHtXZiWDQpp5D6P6w6BD2Nt2HM3Z03WV/Vh+8t+HLcgm8V+2G56+usRzzWX1O7pZUNX5r6C+pLM8Kgrg/+PS8AKHYxRfFKDTsdnJL9h+XaL3Es3F7YgTr1WgcOKEvmgT8uyuRK4GE5EuY1LsT3owv8L5PGmrM7ndaqk7qDYwD5QpWbaDNZ9ygla+8lq9ggSTdHcJqQq+eFagctS018EM1qjt6Iwiv+XyBYEySpsrMr1hymvBM8e30R3MsUutsWZUl31sfgG+lEljQOM1kEcYQhx71dtBQ2vIjXU1xduPL1wwwBqH3SWZvykoMqHkIAj4hQWmSAYBqej3NADhmJMvwFtXr4hrJ9Ny/W9S3AVRcrXdkNPVxwYHrZu5gLkIF3LjFJLhTd80hfGvMBeVQItllhcprKADbbc6J46JfhsqAEmFi/UL4JQGP2RZJ4U2iQ3xCJdgig== x-ms-exchange-antispam-messagedata-chunkcount: 1 x-ms-exchange-antispam-messagedata-0: =?utf-8?q?wryeOxnXJB6IJIf4y7tbKVgA3RZm?= =?utf-8?q?VO7v7VA/xPM01GC7CG1X0jUudAnVD5jwgjPi3J3P8Ryqy4V+gLFzWcEx9X73EgadV?= =?utf-8?q?dXpvIwsIfMp50eNkBaPZrq7CMHEGfRSanrU3jVEcOYc1awIHjIsErRayqq4J7edav?= =?utf-8?q?G52dIDkl7Jn0xGXfz0DlZaee8FBWe5sw7brNOeWiHLIHP01twezAsqE7S4v43DX2k?= =?utf-8?q?4ngiTSe3kICNRzYXbVHpIaHDhSBQpx+u8IHUcdaAnpgHfIKmv2YzJMDQv5drk2/EU?= =?utf-8?q?m8jZ9epMTyE47joqx6xU8w7arf0UcxaD7HYGyd/o75mTd+kuWK5KtyMsMpqiQj0aE?= =?utf-8?q?Ld8tA6t0KU+t4+BT7MRIMwxBJsFgQX1gjsPaj/5Y8mVzN30leLSR7yq0A8XbC4QVh?= =?utf-8?q?NDggTBA8LkUZ8cIscsbuSod7VWkM2Bd83vZ65VbEWRqD1tQJCxI2lkRT9RIHsNmMv?= =?utf-8?q?FSBjRVslTv6mPj3pcorrs8zASptAGsqTX66k8esxDiXk4wTT3cIu9rtaSbpLkj4DT?= =?utf-8?q?m6WBIBJDSUFqlfEFO/T0YDD/IlA9372ecz9ayYYS89Lke/OJca58awXKM5ISbPtBz?= =?utf-8?q?jTnRQISjOH77I6aRGcME3FqS+tttsfpF6I0sZ+TBtxZmbb5DMRoM9oIVmUlIRxaTJ?= =?utf-8?q?2wrCp51AVaUpB557oYohtf+yqAzLFLEZtI/MK6YaVO49KantqqJe2Kk2Yo+xrydhx?= =?utf-8?q?ggPbNuMe6xCh2HUxkukzGjw4lK6i02VkunXJfXYl4lsb2pdQn7zfUrQ7X2TisgSRX?= =?utf-8?q?6OIS6SP6SjpXuDhJaviENoP8kVWg0O/XrrURUcg3KxAqeN1PDQjINqo0YxRoJSLEv?= =?utf-8?q?CkJVgnmpTn41QS9YT7tdmOUsZd8YS6MOJDqI+9u/Ab8c5MUyA92n7ZHZ05OfGng0p?= =?utf-8?q?IWeiq5sVNGG8z/sZA0pXXvjWw0NVez1g1PLEpCxU9Ydw=3D=3D?= MIME-Version: 1.0 X-OriginatorOrg: sct-15-20-4755-11-msonline-outlook-1ff67.templateTenant X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-AuthSource: DM8P223MB0365.NAMP223.PROD.OUTLOOK.COM X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-CrossTenant-Network-Message-Id: 91db4f8c-39f0-4435-9528-08d9bc253e38 X-MS-Exchange-CrossTenant-originalarrivaltime: 10 Dec 2021 21:37:19.2337 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-rms-persistedconsumerorg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM8P223MB0397 Subject: [FFmpeg-devel] [PATCH v23 06/21] avcodec/subtitles: Migrate subtitle encoders to frame-based API and provide a compatibility shim for the legacy api 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 Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: QHtDy1RipbEz Signed-off-by: softworkz --- libavcodec/assenc.c | 90 +++++++++++++++++++++-------- libavcodec/avcodec.h | 5 +- libavcodec/dvbsubenc.c | 96 +++++++++++++++++-------------- libavcodec/dvdsubenc.c | 100 +++++++++++++++++++-------------- libavcodec/encode.c | 63 ++++++++++++++++++++- libavcodec/movtextenc.c | 112 +++++++++++++++++++++++++++---------- libavcodec/srtenc.c | 104 ++++++++++++++++++++++------------ libavcodec/tests/avcodec.c | 2 - libavcodec/ttmlenc.c | 98 ++++++++++++++++++++++++-------- libavcodec/webvttenc.c | 82 +++++++++++++++++++-------- libavcodec/xsubenc.c | 87 +++++++++++++++++----------- 11 files changed, 584 insertions(+), 255 deletions(-) diff --git a/libavcodec/assenc.c b/libavcodec/assenc.c index b0e475834b..94601bba68 100644 --- a/libavcodec/assenc.c +++ b/libavcodec/assenc.c @@ -22,48 +22,92 @@ #include #include "avcodec.h" +#include "encode.h" #include "libavutil/ass_internal.h" #include "internal.h" #include "libavutil/avstring.h" #include "libavutil/internal.h" #include "libavutil/mem.h" +static void check_write_header(AVCodecContext* avctx, const AVFrame* frame) +{ + if (avctx->extradata_size) + return; + + if (frame->subtitle_header && frame->subtitle_header->size > 0) { + const char* subtitle_header = (char*)frame->subtitle_header->data; + avctx->extradata_size = strlen(subtitle_header); + avctx->extradata = av_mallocz(frame->subtitle_header->size + 1); + memcpy(avctx->extradata, subtitle_header, avctx->extradata_size); + avctx->extradata[avctx->extradata_size] = 0; + } + + if (!avctx->extradata_size) { + const char* subtitle_header = avpriv_ass_get_subtitle_header_default(0); + if (!subtitle_header) + return; + + avctx->extradata_size = strlen(subtitle_header); + avctx->extradata = av_mallocz(avctx->extradata_size + 1); + memcpy(avctx->extradata, subtitle_header, avctx->extradata_size); + avctx->extradata[avctx->extradata_size] = 0; + av_freep(&subtitle_header); + } +} + static av_cold int ass_encode_init(AVCodecContext *avctx) { - avctx->extradata = av_malloc(avctx->subtitle_header_size + 1); - if (!avctx->extradata) - return AVERROR(ENOMEM); - memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size); - avctx->extradata_size = avctx->subtitle_header_size; - avctx->extradata[avctx->extradata_size] = 0; + if (avctx->subtitle_header_size) { + avctx->extradata = av_malloc(avctx->subtitle_header_size + 1); + if (!avctx->extradata) + return AVERROR(ENOMEM); + memcpy(avctx->extradata, avctx->subtitle_header, avctx->subtitle_header_size); + avctx->extradata_size = avctx->subtitle_header_size; + avctx->extradata[avctx->extradata_size] = 0; + } + return 0; } -static int ass_encode_frame(AVCodecContext *avctx, - unsigned char *buf, int bufsize, - const AVSubtitle *sub) +static int ass_encode_frame(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { - int i, len, total_len = 0; + int ret; + size_t req_len = 0, total_len = 0; + + check_write_header(avctx, frame); - for (i=0; inum_rects; i++) { - const char *ass = sub->rects[i]->ass; + for (unsigned i = 0; i < frame->num_subtitle_areas; i++) { + const char *ass = frame->subtitle_areas[i]->ass; - if (sub->rects[i]->type != SUBTITLE_ASS) { - av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); + if (frame->subtitle_areas[i]->type != AV_SUBTITLE_FMT_ASS) { + av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n"); return AVERROR(EINVAL); } - len = av_strlcpy(buf+total_len, ass, bufsize-total_len); + if (ass) + req_len += strlen(ass); + } - if (len > bufsize-total_len-1) { - av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); - return AVERROR_BUFFER_TOO_SMALL; - } + ret = ff_get_encode_buffer(avctx, avpkt, req_len + 1, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; + } - total_len += len; + for (unsigned i = 0; i < frame->num_subtitle_areas; i++) { + const char *ass = frame->subtitle_areas[i]->ass; + + if (ass) { + size_t len = av_strlcpy((char *)avpkt->data + total_len, ass, avpkt->size - total_len); + total_len += len; + } } - return total_len; + avpkt->size = total_len; + *got_packet = total_len > 0; + + return 0; } #if CONFIG_SSA_ENCODER @@ -73,7 +117,7 @@ const AVCodec ff_ssa_encoder = { .type = AVMEDIA_TYPE_SUBTITLE, .id = AV_CODEC_ID_ASS, .init = ass_encode_init, - .encode_sub = ass_encode_frame, + .encode2 = ass_encode_frame, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; #endif @@ -85,7 +129,7 @@ const AVCodec ff_ass_encoder = { .type = AVMEDIA_TYPE_SUBTITLE, .id = AV_CODEC_ID_ASS, .init = ass_encode_init, - .encode_sub = ass_encode_frame, + .encode2 = ass_encode_frame, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; #endif diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 3e734d3003..3f25fda708 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -2997,10 +2997,13 @@ void av_parser_close(AVCodecParserContext *s); * @{ */ + /** + * @deprecated Use @ref avcodec_encode_subtitle2() instead. + */ +attribute_deprecated int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVSubtitle *sub); - /** * @} */ diff --git a/libavcodec/dvbsubenc.c b/libavcodec/dvbsubenc.c index 322fc27cb4..3b5a76daa7 100644 --- a/libavcodec/dvbsubenc.c +++ b/libavcodec/dvbsubenc.c @@ -20,6 +20,7 @@ */ #include "avcodec.h" #include "bytestream.h" +#include "encode.h" #include "libavutil/colorspace.h" typedef struct DVBSubtitleContext { @@ -268,21 +269,29 @@ static int dvb_encode_rle8(uint8_t **pq, int buf_size, return len; } -static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, - const AVSubtitle *h) +static int dvbsub_encode(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { DVBSubtitleContext *s = avctx->priv_data; uint8_t *q, *pseg_len; int page_id, region_id, clut_id, object_id, i, bpp_index, page_state; - - - q = outbuf; + size_t buf_size; + int ret; page_id = 1; - if (h->num_rects && !h->rects) + if (frame->num_subtitle_areas && !frame->subtitle_areas) return AVERROR(EINVAL); + ret = ff_get_encode_buffer(avctx, avpkt, 1024 * 1024, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; + } + + buf_size = avpkt->size; + q = avpkt->data; + if (avctx->width > 0 && avctx->height > 0) { if (buf_size < 11) return AVERROR_BUFFER_TOO_SMALL; @@ -301,7 +310,7 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, /* page composition segment */ - if (buf_size < 8 + h->num_rects * 6) + if (buf_size < 8 + frame->num_subtitle_areas * 6) return AVERROR_BUFFER_TOO_SMALL; *q++ = 0x0f; /* sync_byte */ *q++ = 0x10; /* segment_type */ @@ -313,30 +322,30 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, /* page_version = 0 + page_state */ *q++ = (s->object_version << 4) | (page_state << 2) | 3; - for (region_id = 0; region_id < h->num_rects; region_id++) { + for (region_id = 0; region_id < frame->num_subtitle_areas; region_id++) { *q++ = region_id; *q++ = 0xff; /* reserved */ - bytestream_put_be16(&q, h->rects[region_id]->x); /* left pos */ - bytestream_put_be16(&q, h->rects[region_id]->y); /* top pos */ + bytestream_put_be16(&q, frame->subtitle_areas[region_id]->x); /* left pos */ + bytestream_put_be16(&q, frame->subtitle_areas[region_id]->y); /* top pos */ } bytestream_put_be16(&pseg_len, q - pseg_len - 2); - buf_size -= 8 + h->num_rects * 6; + buf_size -= 8 + frame->num_subtitle_areas * 6; - if (h->num_rects) { - for (clut_id = 0; clut_id < h->num_rects; clut_id++) { - if (buf_size < 6 + h->rects[clut_id]->nb_colors * 6) + if (frame->num_subtitle_areas) { + for (clut_id = 0; clut_id < frame->num_subtitle_areas; clut_id++) { + if (buf_size < 6 + frame->subtitle_areas[clut_id]->nb_colors * 6) return AVERROR_BUFFER_TOO_SMALL; /* CLUT segment */ - if (h->rects[clut_id]->nb_colors <= 4) { + if (frame->subtitle_areas[clut_id]->nb_colors <= 4) { /* 2 bpp, some decoders do not support it correctly */ bpp_index = 0; - } else if (h->rects[clut_id]->nb_colors <= 16) { + } else if (frame->subtitle_areas[clut_id]->nb_colors <= 16) { /* 4 bpp, standard encoding */ bpp_index = 1; - } else if (h->rects[clut_id]->nb_colors <= 256) { + } else if (frame->subtitle_areas[clut_id]->nb_colors <= 256) { /* 8 bpp, standard encoding */ bpp_index = 2; } else { @@ -353,12 +362,12 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, *q++ = clut_id; *q++ = (0 << 4) | 0xf; /* version = 0 */ - for(i = 0; i < h->rects[clut_id]->nb_colors; i++) { + for(i = 0; i < frame->subtitle_areas[clut_id]->nb_colors; i++) { *q++ = i; /* clut_entry_id */ *q++ = (1 << (7 - bpp_index)) | (0xf << 1) | 1; /* 2 bits/pixel full range */ { int a, r, g, b; - uint32_t x= ((uint32_t*)h->rects[clut_id]->data[1])[i]; + uint32_t x= ((uint32_t*)frame->subtitle_areas[clut_id]->pal)[i]; a = (x >> 24) & 0xff; r = (x >> 16) & 0xff; g = (x >> 8) & 0xff; @@ -372,22 +381,22 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, } bytestream_put_be16(&pseg_len, q - pseg_len - 2); - buf_size -= 6 + h->rects[clut_id]->nb_colors * 6; + buf_size -= 6 + frame->subtitle_areas[clut_id]->nb_colors * 6; } - if (buf_size < h->num_rects * 22) + if (buf_size < frame->num_subtitle_areas * 22) return AVERROR_BUFFER_TOO_SMALL; - for (region_id = 0; region_id < h->num_rects; region_id++) { + for (region_id = 0; region_id < frame->num_subtitle_areas; region_id++) { /* region composition segment */ - if (h->rects[region_id]->nb_colors <= 4) { + if (frame->subtitle_areas[region_id]->nb_colors <= 4) { /* 2 bpp, some decoders do not support it correctly */ bpp_index = 0; - } else if (h->rects[region_id]->nb_colors <= 16) { + } else if (frame->subtitle_areas[region_id]->nb_colors <= 16) { /* 4 bpp, standard encoding */ bpp_index = 1; - } else if (h->rects[region_id]->nb_colors <= 256) { + } else if (frame->subtitle_areas[region_id]->nb_colors <= 256) { /* 8 bpp, standard encoding */ bpp_index = 2; } else { @@ -401,8 +410,8 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, q += 2; /* segment length */ *q++ = region_id; *q++ = (s->object_version << 4) | (0 << 3) | 0x07; /* version , no fill */ - bytestream_put_be16(&q, h->rects[region_id]->w); /* region width */ - bytestream_put_be16(&q, h->rects[region_id]->h); /* region height */ + bytestream_put_be16(&q, frame->subtitle_areas[region_id]->w); /* region width */ + bytestream_put_be16(&q, frame->subtitle_areas[region_id]->h); /* region height */ *q++ = ((1 + bpp_index) << 5) | ((1 + bpp_index) << 2) | 0x03; *q++ = region_id; /* clut_id == region_id */ *q++ = 0; /* 8 bit fill colors */ @@ -416,9 +425,9 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, bytestream_put_be16(&pseg_len, q - pseg_len - 2); } - buf_size -= h->num_rects * 22; + buf_size -= frame->num_subtitle_areas * 22; - for (object_id = 0; object_id < h->num_rects; object_id++) { + for (object_id = 0; object_id < frame->num_subtitle_areas; object_id++) { int (*dvb_encode_rle)(uint8_t **pq, int buf_size, const uint8_t *bitmap, int linesize, int w, int h); @@ -427,13 +436,13 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, return AVERROR_BUFFER_TOO_SMALL; /* bpp_index maths */ - if (h->rects[object_id]->nb_colors <= 4) { + if (frame->subtitle_areas[object_id]->nb_colors <= 4) { /* 2 bpp, some decoders do not support it correctly */ dvb_encode_rle = dvb_encode_rle2; - } else if (h->rects[object_id]->nb_colors <= 16) { + } else if (frame->subtitle_areas[object_id]->nb_colors <= 16) { /* 4 bpp, standard encoding */ dvb_encode_rle = dvb_encode_rle4; - } else if (h->rects[object_id]->nb_colors <= 256) { + } else if (frame->subtitle_areas[object_id]->nb_colors <= 256) { /* 8 bpp, standard encoding */ dvb_encode_rle = dvb_encode_rle8; } else { @@ -463,19 +472,19 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, top_ptr = q; ret = dvb_encode_rle(&q, buf_size, - h->rects[object_id]->data[0], - h->rects[object_id]->w * 2, - h->rects[object_id]->w, - h->rects[object_id]->h >> 1); + frame->subtitle_areas[object_id]->buf[0]->data, + frame->subtitle_areas[object_id]->w * 2, + frame->subtitle_areas[object_id]->w, + frame->subtitle_areas[object_id]->h >> 1); if (ret < 0) return ret; buf_size -= ret; bottom_ptr = q; ret = dvb_encode_rle(&q, buf_size, - h->rects[object_id]->data[0] + h->rects[object_id]->w, - h->rects[object_id]->w * 2, - h->rects[object_id]->w, - h->rects[object_id]->h >> 1); + frame->subtitle_areas[object_id]->buf[0]->data + frame->subtitle_areas[object_id]->w, + frame->subtitle_areas[object_id]->w * 2, + frame->subtitle_areas[object_id]->w, + frame->subtitle_areas[object_id]->h >> 1); if (ret < 0) return ret; buf_size -= ret; @@ -502,7 +511,10 @@ static int dvbsub_encode(AVCodecContext *avctx, uint8_t *outbuf, int buf_size, buf_size -= 6; s->object_version = (s->object_version + 1) & 0xf; - return q - outbuf; + avpkt->size = q - avpkt->data; + *got_packet = 1; + + return 0; } const AVCodec ff_dvbsub_encoder = { @@ -511,5 +523,5 @@ const AVCodec ff_dvbsub_encoder = { .type = AVMEDIA_TYPE_SUBTITLE, .id = AV_CODEC_ID_DVB_SUBTITLE, .priv_data_size = sizeof(DVBSubtitleContext), - .encode_sub = dvbsub_encode, + .encode2 = dvbsub_encode, }; diff --git a/libavcodec/dvdsubenc.c b/libavcodec/dvdsubenc.c index ff4fbed39d..4916410fc8 100644 --- a/libavcodec/dvdsubenc.c +++ b/libavcodec/dvdsubenc.c @@ -20,6 +20,7 @@ */ #include "avcodec.h" #include "bytestream.h" +#include "encode.h" #include "internal.h" #include "libavutil/avassert.h" #include "libavutil/bprint.h" @@ -114,15 +115,14 @@ static int color_distance(uint32_t a, uint32_t b) * Count colors used in a rectangle, quantizing alpha and grouping by * nearest global palette entry. */ -static void count_colors(AVCodecContext *avctx, unsigned hits[33], - const AVSubtitleRect *r) +static void count_colors(const AVCodecContext *avctx, unsigned hits[33], + const AVSubtitleArea *r) { DVDSubtitleContext *dvdc = avctx->priv_data; unsigned count[256] = { 0 }; - uint32_t *palette = (uint32_t *)r->data[1]; uint32_t color; int x, y, i, j, match, d, best_d, av_uninit(best_j); - uint8_t *p = r->data[0]; + uint8_t *p = r->buf[0]->data; for (y = 0; y < r->h; y++) { for (x = 0; x < r->w; x++) @@ -132,7 +132,7 @@ static void count_colors(AVCodecContext *avctx, unsigned hits[33], for (i = 0; i < 256; i++) { if (!count[i]) /* avoid useless search */ continue; - color = palette[i]; + color = r->pal[i]; /* 0: transparent, 1-16: semi-transparent, 17-33 opaque */ match = color < 0x33000000 ? 0 : color < 0xCC000000 ? 1 : 17; if (match) { @@ -232,13 +232,13 @@ static void build_color_map(AVCodecContext *avctx, int cmap[], } } -static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[]) +static void copy_rectangle(AVSubtitleArea*dst, AVSubtitleArea *src, int cmap[]) { int x, y; uint8_t *p, *q; - p = src->data[0]; - q = dst->data[0] + (src->x - dst->x) + + p = src->buf[0]->data; + q = dst->buf[0]->data + (src->x - dst->x) + (src->y - dst->y) * dst->linesize[0]; for (y = 0; y < src->h; y++) { for (x = 0; x < src->w; x++) @@ -248,51 +248,56 @@ static void copy_rectangle(AVSubtitleRect *dst, AVSubtitleRect *src, int cmap[]) } } -static int encode_dvd_subtitles(AVCodecContext *avctx, - uint8_t *outbuf, int outbuf_size, - const AVSubtitle *h) +static int encode_dvd_subtitles(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { DVDSubtitleContext *dvdc = avctx->priv_data; uint8_t *q, *qq; int offset1, offset2; - int i, rects = h->num_rects, ret; + int ret = 0; + unsigned i, rects = frame->num_subtitle_areas; unsigned global_palette_hits[33] = { 0 }; int cmap[256]; int out_palette[4]; int out_alpha[4]; - AVSubtitleRect vrect; - uint8_t *vrect_data = NULL; + AVSubtitleArea vrect; + uint8_t* vrect_data = NULL, *outbuf; int x2, y2; int forced = 0; + int outbuf_size; - if (rects == 0 || !h->rects) + if (rects == 0) + return 0; + + if (!frame->subtitle_areas) return AVERROR(EINVAL); + for (i = 0; i < rects; i++) - if (h->rects[i]->type != SUBTITLE_BITMAP) { + if (frame->subtitle_areas[i]->type != SUBTITLE_BITMAP) { av_log(avctx, AV_LOG_ERROR, "Bitmap subtitle required\n"); return AVERROR(EINVAL); } /* Mark this subtitle forced if any of the rectangles is forced. */ for (i = 0; i < rects; i++) - if ((h->rects[i]->flags & AV_SUBTITLE_FLAG_FORCED) != 0) { + if ((frame->subtitle_areas[i]->flags & AV_SUBTITLE_FLAG_FORCED) != 0) { forced = 1; break; } - vrect = *h->rects[0]; + vrect = *frame->subtitle_areas[0]; if (rects > 1) { /* DVD subtitles can have only one rectangle: build a virtual rectangle containing all actual rectangles. The data of the rectangles will be copied later, when the palette is decided, because the rectangles may have different palettes. */ - int xmin = h->rects[0]->x, xmax = xmin + h->rects[0]->w; - int ymin = h->rects[0]->y, ymax = ymin + h->rects[0]->h; + int xmin = frame->subtitle_areas[0]->x, xmax = xmin + frame->subtitle_areas[0]->w; + int ymin = frame->subtitle_areas[0]->y, ymax = ymin + frame->subtitle_areas[0]->h; for (i = 1; i < rects; i++) { - xmin = FFMIN(xmin, h->rects[i]->x); - ymin = FFMIN(ymin, h->rects[i]->y); - xmax = FFMAX(xmax, h->rects[i]->x + h->rects[i]->w); - ymax = FFMAX(ymax, h->rects[i]->y + h->rects[i]->h); + xmin = FFMIN(xmin, frame->subtitle_areas[i]->x); + ymin = FFMIN(ymin, frame->subtitle_areas[i]->y); + xmax = FFMAX(xmax, frame->subtitle_areas[i]->x + frame->subtitle_areas[i]->w); + ymax = FFMAX(ymax, frame->subtitle_areas[i]->y + frame->subtitle_areas[i]->h); } vrect.x = xmin; vrect.y = ymin; @@ -304,27 +309,29 @@ static int encode_dvd_subtitles(AVCodecContext *avctx, /* Count pixels outside the virtual rectangle as transparent */ global_palette_hits[0] = vrect.w * vrect.h; for (i = 0; i < rects; i++) - global_palette_hits[0] -= h->rects[i]->w * h->rects[i]->h; + global_palette_hits[0] -= frame->subtitle_areas[i]->w * frame->subtitle_areas[i]->h; } for (i = 0; i < rects; i++) - count_colors(avctx, global_palette_hits, h->rects[i]); + count_colors(avctx, global_palette_hits, frame->subtitle_areas[i]); select_palette(avctx, out_palette, out_alpha, global_palette_hits); if (rects > 1) { - if (!(vrect_data = av_calloc(vrect.w, vrect.h))) + + vrect.buf[0] = av_buffer_allocz((size_t)vrect.w * vrect.h); + if (!vrect.buf[0]) return AVERROR(ENOMEM); - vrect.data [0] = vrect_data; + vrect.linesize[0] = vrect.w; for (i = 0; i < rects; i++) { - build_color_map(avctx, cmap, (uint32_t *)h->rects[i]->data[1], + build_color_map(avctx, cmap, frame->subtitle_areas[i]->pal, out_palette, out_alpha); - copy_rectangle(&vrect, h->rects[i], cmap); + copy_rectangle(&vrect, frame->subtitle_areas[i], cmap); } for (i = 0; i < 4; i++) cmap[i] = i; } else { - build_color_map(avctx, cmap, (uint32_t *)h->rects[0]->data[1], + build_color_map(avctx, cmap, frame->subtitle_areas[0]->pal, out_palette, out_alpha); } @@ -335,6 +342,16 @@ static int encode_dvd_subtitles(AVCodecContext *avctx, out_palette[i], out_alpha[i] >> 4); av_log(avctx, AV_LOG_DEBUG, "\n"); + + ret = ff_get_encode_buffer(avctx, avpkt, 4 + vrect.w * vrect.h / 2 + 17 + 21, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; + } + + outbuf_size = avpkt->size; + outbuf = avpkt->data; + // encode data block q = outbuf + 4; offset1 = q - outbuf; @@ -344,10 +361,10 @@ static int encode_dvd_subtitles(AVCodecContext *avctx, ret = AVERROR_BUFFER_TOO_SMALL; goto fail; } - dvd_encode_rle(&q, vrect.data[0], vrect.w * 2, + dvd_encode_rle(&q, vrect.buf[0]->data, vrect.w * 2, vrect.w, (vrect.h + 1) >> 1, cmap); offset2 = q - outbuf; - dvd_encode_rle(&q, vrect.data[0] + vrect.w, vrect.w * 2, + dvd_encode_rle(&q, vrect.buf[0]->data + vrect.w, vrect.w * 2, vrect.w, vrect.h >> 1, cmap); if (dvdc->even_rows_fix && (vrect.h & 1)) { @@ -362,7 +379,7 @@ static int encode_dvd_subtitles(AVCodecContext *avctx, bytestream_put_be16(&qq, q - outbuf); // send start display command - bytestream_put_be16(&q, (h->start_display_time*90) >> 10); + bytestream_put_be16(&q, (frame->subtitle_start_time * 90) >> 10); bytestream_put_be16(&q, (q - outbuf) /*- 2 */ + 8 + 12 + 2); *q++ = 0x03; // palette - 4 nibbles *q++ = (out_palette[3] << 4) | out_palette[2]; @@ -394,7 +411,7 @@ static int encode_dvd_subtitles(AVCodecContext *avctx, *q++ = 0xff; // terminating command // send stop display command last - bytestream_put_be16(&q, (h->end_display_time*90) >> 10); + bytestream_put_be16(&q, (frame->subtitle_end_time*90) >> 10); bytestream_put_be16(&q, (q - outbuf) - 2 /*+ 4*/); *q++ = 0x02; // set end *q++ = 0xff; // terminating command @@ -403,7 +420,9 @@ static int encode_dvd_subtitles(AVCodecContext *avctx, bytestream_put_be16(&qq, q - outbuf); av_log(NULL, AV_LOG_DEBUG, "subtitle_packet size=%"PTRDIFF_SPECIFIER"\n", q - outbuf); - ret = q - outbuf; + avpkt->size = q - outbuf; + ret = 0; + *got_packet = 1; fail: av_free(vrect_data); @@ -467,14 +486,13 @@ static int dvdsub_init(AVCodecContext *avctx) return 0; } -static int dvdsub_encode(AVCodecContext *avctx, - unsigned char *buf, int buf_size, - const AVSubtitle *sub) +static int dvdsub_encode(struct AVCodecContext* avctx, struct AVPacket* avpkt, + const struct AVFrame* frame, int* got_packet) { //DVDSubtitleContext *s = avctx->priv_data; int ret; - ret = encode_dvd_subtitles(avctx, buf, buf_size, sub); + ret = encode_dvd_subtitles(avctx, avpkt, frame, got_packet); return ret; } @@ -499,7 +517,7 @@ const AVCodec ff_dvdsub_encoder = { .type = AVMEDIA_TYPE_SUBTITLE, .id = AV_CODEC_ID_DVD_SUBTITLE, .init = dvdsub_init, - .encode_sub = dvdsub_encode, + .encode2 = dvdsub_encode, .priv_class = &dvdsubenc_class, .priv_data_size = sizeof(DVDSubtitleContext), .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, diff --git a/libavcodec/encode.c b/libavcodec/encode.c index dd25cf999b..8c915cab1d 100644 --- a/libavcodec/encode.c +++ b/libavcodec/encode.c @@ -140,17 +140,76 @@ fail: return ret; } +/** + * \brief + * \param avctx + * \param buf q + * \param buf_size + * \param sub + * \return + */ int avcodec_encode_subtitle(AVCodecContext *avctx, uint8_t *buf, int buf_size, const AVSubtitle *sub) { - int ret; + int ret = 0, got_packet = 0; + AVFrame *frame = NULL; + AVPacket* avpkt = NULL; + if (sub->start_display_time) { av_log(avctx, AV_LOG_ERROR, "start_display_time must be 0.\n"); return -1; } - ret = avctx->codec->encode_sub(avctx, buf, buf_size, sub); + memset(buf, 0, buf_size); + // Create a temporary frame for calling the regular api: + frame = av_frame_alloc(); + if (!frame) { + ret = AVERROR(ENOMEM); + goto exit; + } + + frame->format = sub->format; + frame->type = AVMEDIA_TYPE_SUBTITLE; + ret = av_frame_get_buffer2(frame, 0); + if (ret < 0) + goto exit; + + // Create a temporary packet + avpkt = av_packet_alloc(); + if (!avpkt) { + ret = AVERROR(ENOMEM); + goto exit; + } + + // Copy legacy subtitle data to temp frame + ret = ff_frame_put_subtitle(frame, sub); + if (ret < 0) + goto exit; + + if (frame->subtitle_start_time) { + av_log(avctx, AV_LOG_ERROR, "start_display_time must be 0.\n"); + ret = AVERROR_INVALIDDATA; + goto exit; + } + + ret = avctx->codec->encode2(avctx, avpkt, frame, &got_packet); + avctx->frame_number++; + + if (got_packet) { + if (avpkt->size > buf_size) { + ret = AVERROR_BUFFER_TOO_SMALL; + goto exit; + } + + memcpy(buf, avpkt->data, avpkt->size); + ret = avpkt->size; + } + +exit: + + av_packet_free(&avpkt); + av_frame_free(&frame); return ret; } diff --git a/libavcodec/movtextenc.c b/libavcodec/movtextenc.c index 5b23deeedd..25ba0fac0a 100644 --- a/libavcodec/movtextenc.c +++ b/libavcodec/movtextenc.c @@ -29,6 +29,7 @@ #include "libavutil/ass_split_internal.h" #include "libavutil/ass_internal.h" #include "bytestream.h" +#include "encode.h" #include "internal.h" #define STYLE_FLAG_BOLD (1<<0) @@ -73,6 +74,7 @@ typedef struct { AVCodecContext *avctx; ASSSplitContext *ass_ctx; + int is_default_ass_context; ASSStyle *ass_dialog_style; StyleBox *style_attributes; unsigned count; @@ -329,7 +331,7 @@ static av_cold int mov_text_encode_init(AVCodecContext *avctx) av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED); - s->ass_ctx = avpriv_ass_split(avctx->subtitle_header); + s->ass_ctx = avpriv_ass_split((char*)avctx->subtitle_header); if (!s->ass_ctx) return AVERROR_INVALIDDATA; ret = encode_sample_description(avctx); @@ -631,56 +633,108 @@ static const ASSCodesCallbacks mov_text_callbacks = { .end = mov_text_end_cb, }; -static int mov_text_encode_frame(AVCodecContext *avctx, unsigned char *buf, - int bufsize, const AVSubtitle *sub) +static void ensure_ass_context(AVCodecContext* avctx, const AVFrame* frame) +{ + MovTextContext* s = avctx->priv_data; + int ret; + + if (s->ass_ctx && !s->is_default_ass_context) + // We already have a (non-default context) + return; + + if (!frame->num_subtitle_areas) + // Don't need ass context for processing empty subtitle frames + return; + + // The frame has content, so we need to set up a context + if (frame->subtitle_header && frame->subtitle_header->size > 0) { + const char* subtitle_header = (char*)frame->subtitle_header->data; + avpriv_ass_split_free(s->ass_ctx); + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 0; + } + else if (!s->ass_ctx) { + char* subtitle_header = avpriv_ass_get_subtitle_header_default(0); + if (!subtitle_header) + return; + + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 1; + av_free(subtitle_header); + } + + if (s->ass_ctx && !avctx->extradata_size) { + ret = encode_sample_description(avctx); + if (ret < 0) + av_log(avctx, AV_LOG_ERROR, "Error during encode_sample_description().\n"); + } +} + +static int mov_text_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet) { MovTextContext *s = avctx->priv_data; ASSDialog *dialog; - int i, length; + int i, ret = 0; + size_t j; + uint8_t* buf; + + ensure_ass_context(avctx, frame); + s->text_pos = 0; s->count = 0; s->box_flags = 0; av_bprint_clear(&s->buffer); - for (i = 0; i < sub->num_rects; i++) { - const char *ass = sub->rects[i]->ass; + for (i = 0; i < frame->num_subtitle_areas; i++) { + const char *ass = frame->subtitle_areas[i]->ass; - if (sub->rects[i]->type != SUBTITLE_ASS) { - av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); + if (frame->subtitle_areas[i]->type != AV_SUBTITLE_FMT_ASS) { + av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n"); return AVERROR(EINVAL); } - dialog = avpriv_ass_split_dialog(s->ass_ctx, ass); - if (!dialog) - return AVERROR(ENOMEM); - mov_text_dialog(s, dialog); - avpriv_ass_split_override_codes(&mov_text_callbacks, s, dialog->text); - avpriv_ass_free_dialog(&dialog); + if (ass) { + dialog = avpriv_ass_split_dialog(s->ass_ctx, ass); + if (!dialog) + return AVERROR(ENOMEM); + mov_text_dialog(s, dialog); + avpriv_ass_split_override_codes(&mov_text_callbacks, s, dialog->text); + avpriv_ass_free_dialog(&dialog); + + for (j = 0; j < box_count; j++) { + box_types[j].encode(s); + } + } } - if (s->buffer.len > UINT16_MAX) - return AVERROR(ERANGE); - AV_WB16(buf, s->buffer.len); - buf += 2; + if (!av_bprint_is_complete(&s->buffer)) { + return AVERROR(ENOMEM); + } - for (size_t j = 0; j < box_count; j++) - box_types[j].encode(s); + ret = ff_get_encode_buffer(avctx, avpkt, s->buffer.len + 3, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; + } - if (!av_bprint_is_complete(&s->buffer)) - return AVERROR(ENOMEM); + buf = avpkt->data; - if (!s->buffer.len) - return 0; + AV_WB16(buf, s->buffer.len); + buf += 2; - if (s->buffer.len > bufsize - 3) { + if (s->buffer.len > avpkt->size - 3) { av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); - return AVERROR_BUFFER_TOO_SMALL; + ret = AVERROR_BUFFER_TOO_SMALL; + goto exit; } memcpy(buf, s->buffer.str, s->buffer.len); - length = s->buffer.len + 2; + avpkt->size = s->buffer.len + 2; + *got_packet = 1; - return length; +exit: + return ret; } #define OFFSET(x) offsetof(MovTextContext, x) @@ -705,7 +759,7 @@ const AVCodec ff_movtext_encoder = { .priv_data_size = sizeof(MovTextContext), .priv_class = &mov_text_encoder_class, .init = mov_text_encode_init, - .encode_sub = mov_text_encode_frame, + .encode2 = mov_text_encode_frame, .close = mov_text_encode_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/srtenc.c b/libavcodec/srtenc.c index a7c5fccefe..9b661da54d 100644 --- a/libavcodec/srtenc.c +++ b/libavcodec/srtenc.c @@ -21,6 +21,7 @@ #include #include "avcodec.h" +#include "encode.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/ass_split_internal.h" @@ -33,6 +34,7 @@ typedef struct { AVCodecContext *avctx; ASSSplitContext *ass_ctx; + int is_default_ass_context; AVBPrint buffer; char stack[SRT_STACK_SIZE]; int stack_ptr; @@ -130,14 +132,13 @@ static void srt_style_apply(SRTContext *s, const char *style) } } - static av_cold int srt_encode_init(AVCodecContext *avctx) { SRTContext *s = avctx->priv_data; s->avctx = avctx; - s->ass_ctx = avpriv_ass_split(avctx->subtitle_header); + s->ass_ctx = avpriv_ass_split((char *)avctx->subtitle_header); av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED); - return s->ass_ctx ? 0 : AVERROR_INVALIDDATA; + return 0; } static void srt_text_cb(void *priv, const char *text, int len) @@ -227,58 +228,91 @@ static const ASSCodesCallbacks text_callbacks = { .new_line = srt_new_line_cb, }; -static int encode_frame(AVCodecContext *avctx, - unsigned char *buf, int bufsize, const AVSubtitle *sub, - const ASSCodesCallbacks *cb) +static void ensure_ass_context(SRTContext* s, const AVFrame* frame) +{ + if (s->ass_ctx && !s->is_default_ass_context) + // We already have a (non-default context) + return; + + if (!frame->num_subtitle_areas) + // Don't need ass context for processing empty subtitle frames + return; + + // The frame has content, so we need to set up a context + if (frame->subtitle_header && frame->subtitle_header->size > 0) { + const char* subtitle_header = (char*)frame->subtitle_header->data; + avpriv_ass_split_free(s->ass_ctx); + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 0; + } + else if (!s->ass_ctx) { + char* subtitle_header = avpriv_ass_get_subtitle_header_default(0); + if (!subtitle_header) + return; + + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 1; + av_free(subtitle_header); + } +} + +static int encode_frame(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet, const ASSCodesCallbacks* cb) { SRTContext *s = avctx->priv_data; ASSDialog *dialog; - int i; + int i, ret; + + ensure_ass_context(s, frame); av_bprint_clear(&s->buffer); - for (i=0; inum_rects; i++) { - const char *ass = sub->rects[i]->ass; + for (i=0; i< frame->num_subtitle_areas; i++) { + const char *ass = frame->subtitle_areas[i]->ass; - if (sub->rects[i]->type != SUBTITLE_ASS) { - av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); + if (frame->subtitle_areas[i]->type != AV_SUBTITLE_FMT_ASS) { + av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n"); return AVERROR(EINVAL); } - dialog = avpriv_ass_split_dialog(s->ass_ctx, ass); - if (!dialog) - return AVERROR(ENOMEM); - s->alignment_applied = 0; - if (avctx->codec_id == AV_CODEC_ID_SUBRIP) - srt_style_apply(s, dialog->style); - avpriv_ass_split_override_codes(cb, s, dialog->text); - avpriv_ass_free_dialog(&dialog); + if (ass) { + dialog = avpriv_ass_split_dialog(s->ass_ctx, ass); + if (!dialog) + return AVERROR(ENOMEM); + s->alignment_applied = 0; + if (avctx->codec_id == AV_CODEC_ID_SUBRIP) + srt_style_apply(s, dialog->style); + avpriv_ass_split_override_codes(cb, s, dialog->text); + avpriv_ass_free_dialog(&dialog); + } } if (!av_bprint_is_complete(&s->buffer)) return AVERROR(ENOMEM); - if (!s->buffer.len) - return 0; - if (s->buffer.len > bufsize) { - av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); - return AVERROR_BUFFER_TOO_SMALL; + ret = ff_get_encode_buffer(avctx, avpkt, s->buffer.len + 1, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; } - memcpy(buf, s->buffer.str, s->buffer.len); - return s->buffer.len; + memcpy(avpkt->data, s->buffer.str, s->buffer.len); + avpkt->size = s->buffer.len; + *got_packet = 1; + + return 0; } -static int srt_encode_frame(AVCodecContext *avctx, - unsigned char *buf, int bufsize, const AVSubtitle *sub) +static int srt_encode_frame(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { - return encode_frame(avctx, buf, bufsize, sub, &srt_callbacks); + return encode_frame(avctx, avpkt, frame, got_packet, &srt_callbacks); } -static int text_encode_frame(AVCodecContext *avctx, - unsigned char *buf, int bufsize, const AVSubtitle *sub) +static int text_encode_frame(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { - return encode_frame(avctx, buf, bufsize, sub, &text_callbacks); + return encode_frame(avctx, avpkt, frame, got_packet, &text_callbacks); } static int srt_encode_close(AVCodecContext *avctx) @@ -298,7 +332,7 @@ const AVCodec ff_srt_encoder = { .id = AV_CODEC_ID_SUBRIP, .priv_data_size = sizeof(SRTContext), .init = srt_encode_init, - .encode_sub = srt_encode_frame, + .encode2 = srt_encode_frame, .close = srt_encode_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; @@ -312,7 +346,7 @@ const AVCodec ff_subrip_encoder = { .id = AV_CODEC_ID_SUBRIP, .priv_data_size = sizeof(SRTContext), .init = srt_encode_init, - .encode_sub = srt_encode_frame, + .encode2 = srt_encode_frame, .close = srt_encode_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; @@ -326,7 +360,7 @@ const AVCodec ff_text_encoder = { .id = AV_CODEC_ID_TEXT, .priv_data_size = sizeof(SRTContext), .init = srt_encode_init, - .encode_sub = text_encode_frame, + .encode2 = text_encode_frame, .close = srt_encode_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; diff --git a/libavcodec/tests/avcodec.c b/libavcodec/tests/avcodec.c index 5d0ff9432c..bd979b2184 100644 --- a/libavcodec/tests/avcodec.c +++ b/libavcodec/tests/avcodec.c @@ -107,8 +107,6 @@ int main(void){ continue; } if (is_encoder) { - if (codec->type == AVMEDIA_TYPE_SUBTITLE ^ !!codec->encode_sub) - ERR("Encoder %s is both subtitle encoder and not subtitle encoder."); if (!!codec->encode_sub + !!codec->encode2 + !!codec->receive_packet != 1) ERR("Encoder %s does not implement exactly one encode API.\n"); if (codec->update_thread_context || codec->update_thread_context_for_user || codec->bsfs) diff --git a/libavcodec/ttmlenc.c b/libavcodec/ttmlenc.c index 083f2dd67a..011b7aa753 100644 --- a/libavcodec/ttmlenc.c +++ b/libavcodec/ttmlenc.c @@ -33,11 +33,17 @@ #include "libavutil/bprint.h" #include "libavutil/internal.h" #include "libavutil/ass_split_internal.h" +#include "libavutil/ass_internal.h" #include "ttmlenc.h" +#include "encode.h" + + typedef struct { AVCodecContext *avctx; ASSSplitContext *ass_ctx; + int is_default_ass_context; + int extradata_written; AVBPrint buffer; } TTMLContext; @@ -76,24 +82,68 @@ static const ASSCodesCallbacks ttml_callbacks = { .new_line = ttml_new_line_cb, }; -static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf, - int bufsize, const AVSubtitle *sub) +static int ttml_write_header_content(AVCodecContext* avctx); + +static void ensure_ass_context(AVCodecContext* avctx, const AVFrame* frame) +{ + TTMLContext* s = avctx->priv_data; + int ret; + + if (s->ass_ctx && !s->is_default_ass_context) + // We already have a (non-default context) + return; + + if (!frame->num_subtitle_areas) + // Don't need ass context for processing empty subtitle frames + return; + + // The frame has content, so we need to set up a context + if (frame->subtitle_header && frame->subtitle_header->size > 0) { + const char* subtitle_header = (char*)frame->subtitle_header->data; + avpriv_ass_split_free(s->ass_ctx); + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 0; + } + else if (!s->ass_ctx) { + char* subtitle_header = avpriv_ass_get_subtitle_header_default(0); + if (!subtitle_header) + return; + + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 1; + av_free(subtitle_header); + } + + if (s->ass_ctx && !s->extradata_written) { + s->extradata_written = 1; + if ((ret = ttml_write_header_content(avctx)) < 0) { + av_log(avctx, AV_LOG_ERROR, "Error writing header content.\n"); + } + } +} + +static int ttml_encode_frame(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { TTMLContext *s = avctx->priv_data; ASSDialog *dialog; - int i; + int i, ret; + + ensure_ass_context(avctx, frame); av_bprint_clear(&s->buffer); - for (i=0; inum_rects; i++) { - const char *ass = sub->rects[i]->ass; - int ret; + for (i=0; i< frame->num_subtitle_areas; i++) { + const char *ass = frame->subtitle_areas[i]->ass; - if (sub->rects[i]->type != SUBTITLE_ASS) { - av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); + if (frame->subtitle_areas[i]->type != AV_SUBTITLE_FMT_ASS) { + av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n"); return AVERROR(EINVAL); } + if (!ass) + continue; + dialog = avpriv_ass_split_dialog(s->ass_ctx, ass); if (!dialog) return AVERROR(ENOMEM); @@ -130,17 +180,19 @@ static int ttml_encode_frame(AVCodecContext *avctx, uint8_t *buf, if (!av_bprint_is_complete(&s->buffer)) return AVERROR(ENOMEM); - if (!s->buffer.len) - return 0; - - // force null-termination, so in case our destination buffer is - // too small, the return value is larger than bufsize minus null. - if (av_strlcpy(buf, s->buffer.str, bufsize) > bufsize - 1) { - av_log(avctx, AV_LOG_ERROR, "Buffer too small for TTML event.\n"); - return AVERROR_BUFFER_TOO_SMALL; + + ret = ff_get_encode_buffer(avctx, avpkt, s->buffer.len + 3, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; } - return s->buffer.len; + av_strlcpy(avpkt->data, s->buffer.str, avpkt->size); + + avpkt->size = s->buffer.len; + *got_packet = 1; + + return 0; } static av_cold int ttml_encode_close(AVCodecContext *avctx) @@ -370,13 +422,13 @@ static av_cold int ttml_encode_init(AVCodecContext *avctx) s->avctx = avctx; av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED); + s->ass_ctx = avpriv_ass_split((char*)avctx->subtitle_header); - if (!(s->ass_ctx = avpriv_ass_split(avctx->subtitle_header))) { - return AVERROR_INVALIDDATA; - } + if (s->ass_ctx) { + if (ret = ttml_write_header_content(avctx) < 0) + return ret; - if ((ret = ttml_write_header_content(avctx)) < 0) { - return ret; + s->extradata_written = 1; } return 0; @@ -389,7 +441,7 @@ const AVCodec ff_ttml_encoder = { .id = AV_CODEC_ID_TTML, .priv_data_size = sizeof(TTMLContext), .init = ttml_encode_init, - .encode_sub = ttml_encode_frame, + .encode2 = ttml_encode_frame, .close = ttml_encode_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE | FF_CODEC_CAP_INIT_CLEANUP, }; diff --git a/libavcodec/webvttenc.c b/libavcodec/webvttenc.c index 761099b69a..43dace6575 100644 --- a/libavcodec/webvttenc.c +++ b/libavcodec/webvttenc.c @@ -22,6 +22,7 @@ #include #include "avcodec.h" +#include "encode.h" #include "libavutil/avstring.h" #include "libavutil/bprint.h" #include "libavutil/ass_split_internal.h" @@ -32,6 +33,7 @@ typedef struct { AVCodecContext *avctx; ASSSplitContext *ass_ctx; + int is_default_ass_context; AVBPrint buffer; unsigned timestamp_end; int count; @@ -155,43 +157,77 @@ static const ASSCodesCallbacks webvtt_callbacks = { .end = webvtt_end_cb, }; -static int webvtt_encode_frame(AVCodecContext *avctx, - unsigned char *buf, int bufsize, const AVSubtitle *sub) +static void ensure_ass_context(WebVTTContext* s, const AVFrame* frame) +{ + if (s->ass_ctx && !s->is_default_ass_context) + // We already have a (non-default context) + return; + + if (!frame->num_subtitle_areas) + // Don't need ass context for processing empty subtitle frames + return; + + // The frame has content, so we need to set up a context + if (frame->subtitle_header && frame->subtitle_header->size > 0) { + avpriv_ass_split_free(s->ass_ctx); + const char* subtitle_header = (char*)frame->subtitle_header->data; + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 0; + } + else if (!s->ass_ctx) { + char* subtitle_header = avpriv_ass_get_subtitle_header_default(0); + if (!subtitle_header) + return; + + s->ass_ctx = avpriv_ass_split(subtitle_header); + s->is_default_ass_context = 1; + av_free(subtitle_header); + } +} + +static int webvtt_encode_frame(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { WebVTTContext *s = avctx->priv_data; ASSDialog *dialog; - int i; + int ret, i; + + ensure_ass_context(s, frame); av_bprint_clear(&s->buffer); - for (i=0; inum_rects; i++) { - const char *ass = sub->rects[i]->ass; + for (i=0; i< frame->num_subtitle_areas; i++) { + const char *ass = frame->subtitle_areas[i]->ass; - if (sub->rects[i]->type != SUBTITLE_ASS) { - av_log(avctx, AV_LOG_ERROR, "Only SUBTITLE_ASS type supported.\n"); + if (frame->subtitle_areas[i]->type != AV_SUBTITLE_FMT_ASS) { + av_log(avctx, AV_LOG_ERROR, "Only AV_SUBTITLE_FMT_ASS type supported.\n"); return AVERROR(EINVAL); } - dialog = avpriv_ass_split_dialog(s->ass_ctx, ass); - if (!dialog) - return AVERROR(ENOMEM); - webvtt_style_apply(s, dialog->style); - avpriv_ass_split_override_codes(&webvtt_callbacks, s, dialog->text); - avpriv_ass_free_dialog(&dialog); + if (ass) { + dialog = avpriv_ass_split_dialog(s->ass_ctx, ass); + if (!dialog) + return AVERROR(ENOMEM); + webvtt_style_apply(s, dialog->style); + avpriv_ass_split_override_codes(&webvtt_callbacks, s, dialog->text); + avpriv_ass_free_dialog(&dialog); + } } if (!av_bprint_is_complete(&s->buffer)) return AVERROR(ENOMEM); - if (!s->buffer.len) - return 0; - if (s->buffer.len > bufsize) { - av_log(avctx, AV_LOG_ERROR, "Buffer too small for ASS event.\n"); - return AVERROR_BUFFER_TOO_SMALL; + ret = ff_get_encode_buffer(avctx, avpkt, s->buffer.len + 1, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; } - memcpy(buf, s->buffer.str, s->buffer.len); - return s->buffer.len; + memcpy(avpkt->data, s->buffer.str, s->buffer.len); + avpkt->size = s->buffer.len; + *got_packet = s->buffer.len > 0; + + return 0; } static int webvtt_encode_close(AVCodecContext *avctx) @@ -206,9 +242,9 @@ static av_cold int webvtt_encode_init(AVCodecContext *avctx) { WebVTTContext *s = avctx->priv_data; s->avctx = avctx; - s->ass_ctx = avpriv_ass_split(avctx->subtitle_header); + s->ass_ctx = avpriv_ass_split((char*)avctx->subtitle_header); av_bprint_init(&s->buffer, 0, AV_BPRINT_SIZE_UNLIMITED); - return s->ass_ctx ? 0 : AVERROR_INVALIDDATA; + return 0; } const AVCodec ff_webvtt_encoder = { @@ -218,7 +254,7 @@ const AVCodec ff_webvtt_encoder = { .id = AV_CODEC_ID_WEBVTT, .priv_data_size = sizeof(WebVTTContext), .init = webvtt_encode_init, - .encode_sub = webvtt_encode_frame, + .encode2 = webvtt_encode_frame, .close = webvtt_encode_close, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, }; diff --git a/libavcodec/xsubenc.c b/libavcodec/xsubenc.c index 03d0dc2d86..52fc7044da 100644 --- a/libavcodec/xsubenc.c +++ b/libavcodec/xsubenc.c @@ -22,6 +22,7 @@ #include "avcodec.h" #include "bytestream.h" +#include "encode.h" #include "internal.h" #include "put_bits.h" @@ -111,39 +112,55 @@ static int make_tc(uint64_t ms, int *tc) return ms > 99; } -static int xsub_encode(AVCodecContext *avctx, unsigned char *buf, - int bufsize, const AVSubtitle *h) +static int xsub_encode(AVCodecContext* avctx, AVPacket* avpkt, + const AVFrame* frame, int* got_packet) { - uint64_t startTime = h->pts / 1000; // FIXME: need better solution... - uint64_t endTime = startTime + h->end_display_time - h->start_display_time; + const uint64_t startTime = frame->subtitle_pts / 1000; // FIXME: need better solution... + const uint64_t endTime = startTime + frame->subtitle_end_time - frame->subtitle_start_time; int start_tc[4], end_tc[4]; - uint8_t *hdr = buf + 27; // Point behind the timestamp + uint8_t *hdr; uint8_t *rlelenptr; uint16_t width, height; - int i; + int i, ret; PutBitContext pb; + uint8_t* buf; + int64_t req_size; - if (bufsize < 27 + 7*2 + 4*3) { - av_log(avctx, AV_LOG_ERROR, "Buffer too small for XSUB header.\n"); - return AVERROR_BUFFER_TOO_SMALL; + if (!frame->num_subtitle_areas) { + // Don't encode empty sub events + return 0; } + // Estimate size (timestamp 27, header 7*2 + 4*3, padding 10) + req_size = 27 + 7*2 + 4*3 + 10; + req_size += frame->subtitle_areas[0]->linesize[0] * frame->subtitle_areas[0]->h; + req_size += 256; // Palette + + ret = ff_get_encode_buffer(avctx, avpkt, req_size, 0); + if (ret < 0) { + av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n"); + return ret; + } + + buf = avpkt->data; + hdr = avpkt->data + 27; // Point behind the timestamp + // TODO: support multiple rects - if (h->num_rects != 1) - av_log(avctx, AV_LOG_WARNING, "Only single rects supported (%d in subtitle.)\n", h->num_rects); + if (frame->num_subtitle_areas != 1) + av_log(avctx, AV_LOG_WARNING, "Only single rects supported (%d in subtitle.)\n", frame->num_subtitle_areas); // TODO: render text-based subtitles into bitmaps - if (!h->rects[0]->data[0] || !h->rects[0]->data[1]) { + if (!frame->subtitle_areas[0]->buf[0]->data || !frame->subtitle_areas[0]->pal) { av_log(avctx, AV_LOG_WARNING, "No subtitle bitmap available.\n"); return AVERROR(EINVAL); } // TODO: color reduction, similar to dvdsub encoder - if (h->rects[0]->nb_colors > 4) - av_log(avctx, AV_LOG_WARNING, "No more than 4 subtitle colors supported (%d found.)\n", h->rects[0]->nb_colors); + if (frame->subtitle_areas[0]->nb_colors > 4) + av_log(avctx, AV_LOG_WARNING, "No more than 4 subtitle colors supported (%d found.)\n", frame->subtitle_areas[0]->nb_colors); // TODO: Palette swapping if color zero is not transparent - if (((uint32_t *)h->rects[0]->data[1])[0] & 0xff000000) + if (((uint32_t *)frame->subtitle_areas[0]->pal)[0] & 0xff000000) av_log(avctx, AV_LOG_WARNING, "Color index 0 is not transparent. Transparency will be messed up.\n"); if (make_tc(startTime, start_tc) || make_tc(endTime, end_tc)) { @@ -151,7 +168,7 @@ static int xsub_encode(AVCodecContext *avctx, unsigned char *buf, return AVERROR(EINVAL); } - snprintf(buf, 28, + snprintf((char *)avpkt->data, 28, "[%02d:%02d:%02d.%03d-%02d:%02d:%02d.%03d]", start_tc[3], start_tc[2], start_tc[1], start_tc[0], end_tc[3], end_tc[2], end_tc[1], end_tc[0]); @@ -160,45 +177,47 @@ static int xsub_encode(AVCodecContext *avctx, unsigned char *buf, // 2 pixels required on either side of subtitle. // Possibly due to limitations of hardware renderers. // TODO: check if the bitmap is already padded - width = FFALIGN(h->rects[0]->w, 2) + PADDING * 2; - height = FFALIGN(h->rects[0]->h, 2); + width = FFALIGN(frame->subtitle_areas[0]->w, 2) + PADDING * 2; + height = FFALIGN(frame->subtitle_areas[0]->h, 2); bytestream_put_le16(&hdr, width); bytestream_put_le16(&hdr, height); - bytestream_put_le16(&hdr, h->rects[0]->x); - bytestream_put_le16(&hdr, h->rects[0]->y); - bytestream_put_le16(&hdr, h->rects[0]->x + width -1); - bytestream_put_le16(&hdr, h->rects[0]->y + height -1); + bytestream_put_le16(&hdr, frame->subtitle_areas[0]->x); + bytestream_put_le16(&hdr, frame->subtitle_areas[0]->y); + bytestream_put_le16(&hdr, frame->subtitle_areas[0]->x + width -1); + bytestream_put_le16(&hdr, frame->subtitle_areas[0]->y + height -1); rlelenptr = hdr; // Will store length of first field here later. hdr+=2; // Palette for (i=0; i<4; i++) - bytestream_put_be24(&hdr, ((uint32_t *)h->rects[0]->data[1])[i]); + bytestream_put_be24(&hdr, ((uint32_t *)frame->subtitle_areas[0]->pal)[i]); // Bitmap // RLE buffer. Reserve 2 bytes for possible padding after the last row. - init_put_bits(&pb, hdr, bufsize - (hdr - buf) - 2); - if (xsub_encode_rle(&pb, h->rects[0]->data[0], - h->rects[0]->linesize[0] * 2, - h->rects[0]->w, (h->rects[0]->h + 1) >> 1)) + init_put_bits(&pb, hdr, avpkt->size - (hdr - buf) - 2); + if (xsub_encode_rle(&pb, frame->subtitle_areas[0]->buf[0]->data, + frame->subtitle_areas[0]->linesize[0] * 2, + frame->subtitle_areas[0]->w, (frame->subtitle_areas[0]->h + 1) >> 1)) return AVERROR_BUFFER_TOO_SMALL; bytestream_put_le16(&rlelenptr, put_bytes_count(&pb, 0)); // Length of first field - if (xsub_encode_rle(&pb, h->rects[0]->data[0] + h->rects[0]->linesize[0], - h->rects[0]->linesize[0] * 2, - h->rects[0]->w, h->rects[0]->h >> 1)) + if (xsub_encode_rle(&pb, frame->subtitle_areas[0]->buf[0]->data + frame->subtitle_areas[0]->linesize[0], + frame->subtitle_areas[0]->linesize[0] * 2, + frame->subtitle_areas[0]->w, frame->subtitle_areas[0]->h >> 1)) return AVERROR_BUFFER_TOO_SMALL; // Enforce total height to be a multiple of 2 - if (h->rects[0]->h & 1) { - put_xsub_rle(&pb, h->rects[0]->w, PADDING_COLOR); + if (frame->subtitle_areas[0]->h & 1) { + put_xsub_rle(&pb, frame->subtitle_areas[0]->w, PADDING_COLOR); } flush_put_bits(&pb); - return hdr - buf + put_bytes_output(&pb); + avpkt->size = hdr - buf + put_bytes_output(&pb); + *got_packet = 1; + return 0; } static av_cold int xsub_encoder_init(AVCodecContext *avctx) @@ -217,6 +236,6 @@ const AVCodec ff_xsub_encoder = { .type = AVMEDIA_TYPE_SUBTITLE, .id = AV_CODEC_ID_XSUB, .init = xsub_encoder_init, - .encode_sub = xsub_encode, + .encode2 = xsub_encode, .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, };