From patchwork Thu Apr 29 23:56:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Rheinhardt X-Patchwork-Id: 27501 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a11:4023:0:0:0:0 with SMTP id ky35csp2016960pxb; Thu, 29 Apr 2021 17:01:24 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx+e+n35KElWSqiC7ivK0gEaPKlUAHsjwqdEBJFGEEEWFq3EPJ/UXW4pVK501eavi/T60jx X-Received: by 2002:a17:906:1c83:: with SMTP id g3mr1091478ejh.93.1619740883942; Thu, 29 Apr 2021 17:01:23 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id ca23si75722edb.279.2021.04.29.17.01.23; Thu, 29 Apr 2021 17:01:23 -0700 (PDT) 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=@outlook.com header.s=selector1 header.b="iEEK3wG/"; 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=QUARANTINE dis=NONE) header.from=outlook.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B169668A3B8; Fri, 30 Apr 2021 02:59:32 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from EUR06-DB8-obe.outbound.protection.outlook.com (mail-db8eur06olkn2037.outbound.protection.outlook.com [40.92.51.37]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id EF59C689F4F for ; Fri, 30 Apr 2021 02:59:29 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=C/GrSt5NYeDl/9oD/uB2Pbri1ejqItzH9AQuNnzaxsjSIS1wcqk9ANvh5KKSEMDtfunvDm2BsyC45+cC8o6OI9/5s9ktG0hKj8NOrGs4Za8AUO6iv9+fYJhwJS2/Z5mYPOan/Vv+j2SFLVTkkDTRGi/FM3kLSqOu7TEnysFDPfXrOxPhd8W3Kmo4stMrp0hZgAlBkCy7wZ42NkcDDSk+tj+2FB8M410DL7DHVBRX5c4o5+St9h6U7d208x1qeMHJlOsPeV22M/cdsdxN1j2Yjxw6Yn+oTkH3ZdnGLTrOewdG0X6BSw7g2QfKQNw0k2DFb8hh5LdRmgUKoVhYUZ8oig== 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-SenderADCheck; bh=rJhkp6n6kHEdWzhlq75J8ihYWhIQ1enK+4RJFaxY92s=; b=L+07YpHkKEmVk+UYgCY7zi7OD2CwqdS0+02gu9kLXELY+9+KsDbwzgXeHwR8wPWv/qVUlHRKHmB/PWSJGercjANxJI2Pvx/oOVYAR3vJmBLGjDNvlOMWidtRZDodw3jxUqe5tBmvWeQE8/sAzt2C4IwO0/yJtLj/FVx9mFhFCuPVFd/SokUOry6xJMksKup4S5ddAm8icaxCv8VvcSIPYcludOdp3qifJhc7cZ6J7l2MloIATK4UPjPFRVgMjlD9oRhyAyvbCOl5NvGiyUmojPHpdN5TT/FsrfzzERkuEDfwG5C/hcxBE0fvYEXtotvFBVIqnVRSZVdM2QjKIOtK5w== 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=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=rJhkp6n6kHEdWzhlq75J8ihYWhIQ1enK+4RJFaxY92s=; b=iEEK3wG/hHr0Mkwk+G15fxtZO22y1M8cADpa5TsoEY7Ig6zv1dYthRD3XeFN3cftKu/iDOCy43CaJR/c74EPDT++LOMtuWKOiY24u+o3nMyC5s0deYSuCj7MYQK3XNrU3+OIx01wE3+mkCvObRt5PMMz/RmRDgi0ash45VDpCS6th8M+UESAbnLdRpic5nnZOEl7CDMmEEvb797Xd1OL03+zurMjRI63/gVf7Coffz9JzL/EEkrGkXevEFxSVYzf5Ks1dfuLgbsGds5zRFv0jqnyTlZdNMgI0Qr6nJuyOfu6elerAL4shYKueuIRVwPuBVzvIq86NJyp0JYnz+WaIQ== Received: from AM7EUR06FT055.eop-eur06.prod.protection.outlook.com (2a01:111:e400:fc36::4e) by AM7EUR06HT158.eop-eur06.prod.protection.outlook.com (2a01:111:e400:fc36::490) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4087.27; Thu, 29 Apr 2021 23:59:28 +0000 Received: from HE1PR0301MB2154.eurprd03.prod.outlook.com (2a01:111:e400:fc36::49) by AM7EUR06FT055.mail.protection.outlook.com (2a01:111:e400:fc36::61) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4087.27 via Frontend Transport; Thu, 29 Apr 2021 23:59:28 +0000 X-IncomingTopHeaderMarker: OriginalChecksum:1FE4774B76166EB06E74ECB5A184395BAF2F7DA84D65839E197E5DFCDE97ABE1; UpperCasedChecksum:940ECE74242911017828E949FA244578E38CE2E261A0F874B8D5DB5BEC90A3AA; SizeAsReceived:7606; Count:48 Received: from HE1PR0301MB2154.eurprd03.prod.outlook.com ([fe80::45bb:c44f:2b75:23b7]) by HE1PR0301MB2154.eurprd03.prod.outlook.com ([fe80::45bb:c44f:2b75:23b7%5]) with mapi id 15.20.4065.027; Thu, 29 Apr 2021 23:59:28 +0000 From: Andreas Rheinhardt To: ffmpeg-devel@ffmpeg.org Date: Fri, 30 Apr 2021 01:56:55 +0200 Message-ID: X-Mailer: git-send-email 2.27.0 In-Reply-To: References: X-TMN: [rQtO+Wgrj9FxzeMUmLeYUsiecUaR5GbM] X-ClientProxiedBy: ZR0P278CA0088.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:22::21) To HE1PR0301MB2154.eurprd03.prod.outlook.com (2603:10a6:3:2a::22) X-Microsoft-Original-Message-ID: <20210429235717.2067041-23-andreas.rheinhardt@outlook.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 1 Received: from sblaptop.fritz.box (188.193.248.86) by ZR0P278CA0088.CHEP278.PROD.OUTLOOK.COM (2603:10a6:910:22::21) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.4087.27 via Frontend Transport; Thu, 29 Apr 2021 23:59:28 +0000 X-MS-PublicTrafficType: Email X-IncomingHeaderCount: 48 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-Correlation-Id: fc2125df-7c2b-498d-df9b-08d90b6ad31c X-MS-Exchange-SLBlob-MailProps: q+fD6XS3/UIO6YRda03MtHguxZve2k0PFRWwNVam2X8mGv8oS+krzmVsIOIzxKHRQM8+j6S7rDeuyXZL2YmIcIOFEO0682+dfk9O6lOCQ2jCZ0Ac09r3o8Z14+X/uC2hzN2MbvqaaZQ1wal4bDYeqfrK8EiJ//Ouhw22JnE1DgTZj0u6MEjk9PyZujkfwXRLWi0Wk9uQKdv48CZYeFjKYFXPXgTi6MT3L4Yw1j3CU6ZWFZuE/rq2ullbXiJ7QLP+MhR1U8+xA3lHaDqI1Q5XYuhBfeyq59QckfVPjxH8b4xwFIJJUJPtPtfeD+80iJtaToCtJgm4rTqFCKAXL2qy8GljC45IReL7dnA768fcv2ZU03s8hvjNGmD2c7B5iatqrP/dwtBGoNsi3z/B3PV8osJSBK7FJfoM8iMe77oymESbUezlNoXpMNnpeqjN5LFmESgRI/rjO35359aBXT4mTqfZTtJnRMgHRe7aoo9HdtKT3xW1ceRoG4TAt3emGnxJ9xnlox84R5XuKmx2gLYAaEZLopuJpaGG/vpFqpXrB6u+yU+hIkqLy6RoqtSAMYlnYPtoMXXzVWSQ95fGYOkj8/r2i9giQ2hjeUl+NaxFRXbbuHDYT1jEj0lUgwIg1VkG76jLDRwghAaJ4Yf1eeMe/6tS8pLBXMbZmabhA7fivVbJVBBVy9eFyGGY15TeAVFARbQ0GioTl+kBtOJE5xYPPg== X-MS-TrafficTypeDiagnostic: AM7EUR06HT158: X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: U3Yf09jwH6fVwVwD+ET3g7NYTkrEP9KplksfE7qsQyPgNL93k42sKsvQTSLzmCHnjj9lOVvxIzZoUyHFUEUEvmx6nl+Mw1yH0PSz0kr8uJoPK2iRDG8rzVmEVWGqxjBT3H0DFxFziwlb7sZLatQh2x8ZlDMSnOWF7o+dKQfzQpRoeYLWC50jgmHRm5XHR+RJZl8d8fd7Fj3Z+zR5xhzEj5DHTEoyXJ9DH5UFkNFsW0pYVu+xd3+uLdLFX/QmM6fBv4oJ6z0qBB8q5PdPFoGumWXXFSOrBWB5AkImTdT0Qwsys4C0di9CCWDCVCLOFmGGp1OSc2lcvvg8r7MSTuMTT6lyU7AnUOLsuxvB3ssDvyii/wUvEmk4cBg8dPS8wH+3mZREql53fMh42SUA9eGTpw== X-MS-Exchange-AntiSpam-MessageData: DnInsbFSaUk8bzFcB7uVi4523yDlpUBBPKp0bnQmfANdcS2M/WcBJ504pCzM67kRZ/vKrBu25WzuhA87rf9D0lzhZ5EzEcWqnzkrAke5wo3iZI9IBZz8nVrsdOAM8V9pqKGWZJfXFe8TC0efD397Bw== X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: fc2125df-7c2b-498d-df9b-08d90b6ad31c X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Apr 2021 23:59:28.7658 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-AuthSource: AM7EUR06FT055.eop-eur06.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: Internet X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: AM7EUR06HT158 Subject: [FFmpeg-devel] [PATCH 24/46] avcodec/jpeglsenc: Avoid intermediate buffer, allow user-supplied buffers 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: Andreas Rheinhardt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: wZjA/QcuzntV Up until now, the JPEG-LS encoder allocated a worst-case-sized packet at the beginning of each encode2 call; then it wrote the packet header into its destination buffer and encoded the actual packet data; said data is written into another worst-case-sized buffer, because it needs to be escaped before being written into the packet buffer. Finally, because the packet buffer is worst-case-sized, the generic code copies the actually used part into a fresh buffer. This commit changes this: Allocating the packet and writing the header into it is deferred until the actual data has been encoded and its size is known. This gives a good upper bound for the needed size of the packet buffer (the upper bound might be 1/15 too large) and so one can avoid the implicit intermediate buffer and support user-supplied buffers by using ff_get_encode_buffer(). Signed-off-by: Andreas Rheinhardt --- libavcodec/jpeglsenc.c | 102 ++++++++++++++++++++++++----------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/libavcodec/jpeglsenc.c b/libavcodec/jpeglsenc.c index 17d46c0449..a7bcd78275 100644 --- a/libavcodec/jpeglsenc.c +++ b/libavcodec/jpeglsenc.c @@ -27,6 +27,7 @@ #include "avcodec.h" #include "bytestream.h" +#include "encode.h" #include "get_bits.h" #include "put_bits.h" #include "golomb.h" @@ -283,53 +284,23 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt, const uint8_t *in; uint8_t *last = NULL; JLSState state = { 0 }; - int i, size, ret; + size_t size; + int i, ret, size_in_bits; int comps; - if ((ret = ff_alloc_packet2(avctx, pkt, ctx->size, 0)) < 0) - return ret; - last = av_mallocz(FFABS(p->linesize[0])); if (!last) return AVERROR(ENOMEM); - bytestream2_init_writer(&pb, pkt->data, pkt->size); init_put_bits(&pb2, ctx->buf, ctx->size); - /* write our own JPEG header, can't use mjpeg_picture_header */ comps = ctx->comps; - put_marker_byteu(&pb, SOI); - put_marker_byteu(&pb, SOF48); - bytestream2_put_be16u(&pb, 8 + comps * 3); // header size depends on components - bytestream2_put_byteu(&pb, (avctx->pix_fmt == AV_PIX_FMT_GRAY16) ? 16 : 8); // bpp - bytestream2_put_be16u(&pb, avctx->height); - bytestream2_put_be16u(&pb, avctx->width); - bytestream2_put_byteu(&pb, comps); // components - for (i = 1; i <= comps; i++) { - bytestream2_put_byteu(&pb, i); // component ID - bytestream2_put_byteu(&pb, 0x11); // subsampling: none - bytestream2_put_byteu(&pb, 0); // Tiq, used by JPEG-LS ext - } - - put_marker_byteu(&pb, SOS); - bytestream2_put_be16u(&pb, 6 + comps * 2); - bytestream2_put_byteu(&pb, comps); - for (i = 1; i <= comps; i++) { - bytestream2_put_byteu(&pb, i); // component ID - bytestream2_put_byteu(&pb, 0); // mapping index: none - } - bytestream2_put_byteu(&pb, ctx->pred); - bytestream2_put_byteu(&pb, (comps > 1) ? 1 : 0); // interleaving: 0 - plane, 1 - line - bytestream2_put_byteu(&pb, 0); // point transform: none - /* initialize JPEG-LS state from JPEG parameters */ state.near = ctx->pred; state.bpp = (avctx->pix_fmt == AV_PIX_FMT_GRAY16) ? 16 : 8; ff_jpegls_reset_coding_parameters(&state, 0); ff_jpegls_init_state(&state); - ls_store_lse(&state, &pb); - in = p->data[0]; if (avctx->pix_fmt == AV_PIX_FMT_GRAY8) { int t = 0; @@ -378,17 +349,63 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt, in += p->linesize[0]; } } - - /* the specification says that after doing 0xff escaping unused bits in - * the last byte must be set to 0, so just append 7 "optional" zero bits - * to avoid special-casing. */ + av_free(last); + /* Now the actual image data has been written, which enables us to estimate + * the needed packet size: For every 15 input bits, an escape bit might be + * added below; and if put_bits_count % 15 is >= 8, then another bit might + * be added. + * Furthermore the specification says that after doing 0xff escaping unused + * bits in the last byte must be set to 0, so just append 7 "optional" zero + * bits to avoid special-casing. This also simplifies the size calculation: + * Properly rounding up is now automatically baked-in. */ put_bits(&pb2, 7, 0); - size = put_bits_count(&pb2); + /* Make sure that the bit count + padding is representable in an int; + necessary for put_bits_count() as well as for using a GetBitContext. */ + if (put_bytes_count(&pb2, 0) > INT_MAX / 8 - AV_INPUT_BUFFER_PADDING_SIZE) + return AVERROR(ERANGE); + size_in_bits = put_bits_count(&pb2); flush_put_bits(&pb2); + size = size_in_bits * 2U / 15; + size += 2 + 2 + 2 + 1 + 2 + 2 + 1 + comps * (1 + 1 + 1) + 2 + 2 + 1 + + comps * (1 + 1) + 1 + 1 + 1; /* Header */ + size += 2 + 2 + 1 + 2 + 2 + 2 + 2 + 2; /* LSE */ + size += 2; /* EOI */ + if ((ret = ff_get_encode_buffer(avctx, pkt, size, 0)) < 0) + return ret; + + bytestream2_init_writer(&pb, pkt->data, pkt->size); + + /* write our own JPEG header, can't use mjpeg_picture_header */ + put_marker_byteu(&pb, SOI); + put_marker_byteu(&pb, SOF48); + bytestream2_put_be16u(&pb, 8 + comps * 3); // header size depends on components + bytestream2_put_byteu(&pb, (avctx->pix_fmt == AV_PIX_FMT_GRAY16) ? 16 : 8); // bpp + bytestream2_put_be16u(&pb, avctx->height); + bytestream2_put_be16u(&pb, avctx->width); + bytestream2_put_byteu(&pb, comps); // components + for (i = 1; i <= comps; i++) { + bytestream2_put_byteu(&pb, i); // component ID + bytestream2_put_byteu(&pb, 0x11); // subsampling: none + bytestream2_put_byteu(&pb, 0); // Tiq, used by JPEG-LS ext + } + + put_marker_byteu(&pb, SOS); + bytestream2_put_be16u(&pb, 6 + comps * 2); + bytestream2_put_byteu(&pb, comps); + for (i = 1; i <= comps; i++) { + bytestream2_put_byteu(&pb, i); // component ID + bytestream2_put_byteu(&pb, 0); // mapping index: none + } + bytestream2_put_byteu(&pb, ctx->pred); + bytestream2_put_byteu(&pb, (comps > 1) ? 1 : 0); // interleaving: 0 - plane, 1 - line + bytestream2_put_byteu(&pb, 0); // point transform: none + + ls_store_lse(&state, &pb); + /* do escape coding */ - init_get_bits(&gb, pb2.buf, size); - size -= 7; - while (get_bits_count(&gb) < size) { + init_get_bits(&gb, pb2.buf, size_in_bits); + size_in_bits -= 7; + while (get_bits_count(&gb) < size_in_bits) { int v; v = get_bits(&gb, 8); bytestream2_put_byte(&pb, v); @@ -397,15 +414,14 @@ static int encode_picture_ls(AVCodecContext *avctx, AVPacket *pkt, bytestream2_put_byte(&pb, v); } } - av_freep(&last); /* End of image */ put_marker_byte(&pb, EOI); emms_c(); - pkt->size = bytestream2_tell_p(&pb); pkt->flags |= AV_PKT_FLAG_KEY; + av_shrink_packet(pkt, bytestream2_tell_p(&pb)); *got_packet = 1; return 0; } @@ -468,9 +484,9 @@ const AVCodec ff_jpegls_encoder = { .long_name = NULL_IF_CONFIG_SMALL("JPEG-LS"), .type = AVMEDIA_TYPE_VIDEO, .id = AV_CODEC_ID_JPEGLS, + .capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS, .priv_data_size = sizeof(JPEGLSContext), .priv_class = &jpegls_class, - .capabilities = AV_CODEC_CAP_FRAME_THREADS, .init = encode_jpegls_init, .encode2 = encode_picture_ls, .close = encode_jpegls_close,