From patchwork Fri Feb 2 15:55:12 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Martinez X-Patchwork-Id: 45984 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:1a28:b0:199:de12:6fa6 with SMTP id cj40csp1032677pzb; Fri, 2 Feb 2024 07:55:26 -0800 (PST) X-Google-Smtp-Source: AGHT+IExAbB6bC3dOTu+aCWJNAmYIHDVvuCjoc0q5C8ZfGPl657Djm51FPICJlZIpKLHKflc7+Vz X-Received: by 2002:a17:906:32d0:b0:a37:1e9a:c958 with SMTP id k16-20020a17090632d000b00a371e9ac958mr1155692ejk.22.1706889325952; Fri, 02 Feb 2024 07:55:25 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1706889325; cv=none; d=google.com; s=arc-20160816; b=Ko7rJIEZFzrWI8pok2DyE2uBKy1y+YPeIkrUx8jFHugRinmXMlDEWQs3psjLrbtTNO nJly4K7huEyA0uK6xcqP9+NVVcpuC9tp8DkSo+2W/gaGNLv8a93Vd3SHYM+odpeqpQce J+8Y/e3vPy61/GRkkuNUpbIsmmiS+jwHvx0vShMrsPGWP8pRHN0Y0UQx53u5p8KECZR1 ohc+At9Fin/Hbn2b3zgf6cXqbWgxAsXIhwOWgP4n5O4BkP0/fGMgqpIWNtEyAOBLBGva hK1z5VBr48mDxYojEwEoFpn0Gczmu4fE06zrm4w5AHcWseqA5wENSVwApBNDm2VW2PtF dHBw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:to:from :content-language:user-agent:mime-version:date:message-id :delivered-to; bh=uBJwoR0GLdw2L4+KemUBK0ia0Zs4PwAJU8996g71z1s=; fh=8bLFkykJsqLU6+cX9IXpPITV1NQ0nqkV3XEp0IXy37U=; b=E6CnGvGva1YQ/Y9kPmSQ2jeJlTb9W0gz2oQOvhKlGNlAz13CJ9huharKkeabjWlGmi hnOkb1dB67QFidB24lVHE2QW7BciEMZlaM6c36jsyW3HyVq1Rp8k7kJC973OgRPm8ztn bntdAHZd8zzF5Erq4anCxUSvGEAn2wCTTJuR4c23czYDnR8UoSLzMGvgH/kyFF+MwFuF smMetDOX+hZDqn3I0vsFg1uuk2Pxpvoq8PbtSmczXBzuL9BZvpK0O2Ica7bEAfAk8q5f W71jtwknm8WwjUG8dsQeHIcqBBazMrcovVLvESWetxm6Y9bH5fOjqnz7o55LIQ1z8aIP 0nWA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; 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=mediaarea.net X-Forwarded-Encrypted: i=0; AJvYcCVEX/54GeQcSANbnD8FQjNkxwXYhWQA6XrMPcnSePhgXhh4u7Nf//wBzDvUoQRjWkqSYo5FKefTB0Ox2HD50KRtbgSQFPQwxKs6rKAAmqbDNnsLYMkw36VNXiXr8fTYupZbgnpitmgnZyGd8oKCMRh4aGBlLLCU/SCs4hEmC3b2Ud1fJbzrZCcyHYuJCHmrXDC8xK9u+tMhKGc6PXQKaCTCBiqU2cdUsZ/Qm4i4sPgIdPY4a7OjNMWpqLBEQkM/kvwb6Y9CSogJJTZ8lYbV6M2ubMCfYQX98i5/hcr4TrMBMqTQswHFZehon8rYNp2oDPa33cuuPRTSBO6x3YPmgP0lsgHWmJVPjUCtq+q07hJp/FFXsjNSqrTGENx6g9vCJdWi5Ip67YECaWvg2PTU+U4z4UtMPtl8CwVr1/sqxFwNz7Vln5mSCGtoDTMwvjN2X+WW7ixLqOmaOOPiL04ieoQPbEhAhGhfwDxJ5PhHGzM7pur11dRxehl0nY+YV8DFDVzZCY8FiRSJGh72Ff4qvEeT/iRaAyGptnVKKE3hrSNMTI7Fsr5ayYNuCh6N/irrTtpk4DqFh2q2Lr9fK4OqijF+WhBn4bo/Jzptwja5ug1fSXjX6QtUH+SVWsN+FSqLtCGan2ne8WiiLDbpSRWY2YB2lD8wsA+aZS3fEpfn1L54Nw8NREKRhpZ7VfySk6S/nKPm2rbhha3uPo0MS/ZnjL4t5AHs2sXae4d+GJncUVBDW334droTrRCfpz/P35Iuq+hqhEPcVixagPDz7qj35S1tzJsyjs8kOghXHkgP6kQe7BFZ3rPzx7R0hTYT1iLFKornpgGZeOknXtfP4DBLmc2W0BtxJafHj8efE+DppBZpLaOiajk7UEj4ri402KDzgK8iA/hhBrgtJzyKPV+EG2NAHNZkb2PYU4mErz9cDnzh4v0Y/hDDAOXbruNAbTgaHLDL+c JXk5hV7jiQh7ox4XaA/be/MyODcPzfJCu3/OVQLNwHTmt/KRBrUOXLMk7yaGx1Hpd37Cp/O1gR/Qv6xf0XfnR/1nKklIjezF2JUV1wrZEiYIi8ruPzTXge5WrFVtEFyNO0ZSBgqwXsq40Jdk2AezT9cm8HXzWepD29nP4/Fk0BIRHcsdL6xzhFCzDoHYpTZUHFqJXYvCPws5cbsZQEclCqkxg12a/dtyUCuTcuU6OY+15R601GTbL+3cJWENWzc6nLDIxBJowbs6JdCkkRUO7ZZDKsJggjUf/NlhJ3HQRSewzZpzjsbFDVzOAC83H/iJYlI02obGTcNqgNXJTCf4bi8ypgZ6h1HsyiM3t7c863JhcCPdVYdNjTIHQX8pukEm3pung9otxU3mv6SmKyTyKKcR2SafYxp4htyH1SvcqsIeeTOMPbq675njFpw/+lZuuRlc4cuqxpQCN92QwoFot443H/67x91OXeEkDSv8sWvBKkjSuJDJ8dbo7lAUF9JdPDuT4OU71p1+hXmD/lIOIgOH3NWmH6XgKVU3zcTV3lROkMILjbx1SoSCH6zuDrSAwshh+lclQCnq2NFCnNfHVPBywD4sylT0EM2xJJrNMn Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id w11-20020a17090652cb00b00a30e8b392c4si906342ejn.104.2024.02.02.07.55.25; Fri, 02 Feb 2024 07:55:25 -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; 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=mediaarea.net Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 8873D68D0B4; Fri, 2 Feb 2024 17:55:21 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from 4.mo576.mail-out.ovh.net (4.mo576.mail-out.ovh.net [46.105.42.102]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B792C68CE08 for ; Fri, 2 Feb 2024 17:55:14 +0200 (EET) Received: from director11.ghost.mail-out.ovh.net (unknown [10.109.148.116]) by mo576.mail-out.ovh.net (Postfix) with ESMTP id C4C7D35A46 for ; Fri, 2 Feb 2024 15:55:13 +0000 (UTC) Received: from ghost-submission-6684bf9d7b-6c5fq (unknown [10.108.54.212]) by director11.ghost.mail-out.ovh.net (Postfix) with ESMTPS id EB6571FE8E for ; Fri, 2 Feb 2024 15:55:12 +0000 (UTC) Received: from mediaarea.net ([37.59.142.108]) by ghost-submission-6684bf9d7b-6c5fq with ESMTPSA id mrvvNWAQvWWB/wAAg8iFlQ (envelope-from ) for ; Fri, 02 Feb 2024 15:55:12 +0000 Authentication-Results: garm.ovh; auth=pass (GARM-108S0021103e1ea-58c1-4ce4-ba09-ea82d1e34433, 2C6CCB87BAC13C3A7C35C5FB0FAE638CB3D966E1) smtp.auth=jerome@mediaarea.net X-OVh-ClientIp: 84.143.146.241 Message-ID: Date: Fri, 2 Feb 2024 16:55:12 +0100 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Content-Language: en-US, fr, de-DE From: Jerome Martinez To: FFmpeg development discussions and patches X-Ovh-Tracer-Id: 1180224580676258041 X-VR-SPAMSTATE: OK X-VR-SPAMSCORE: -110 X-VR-SPAMCAUSE: gggruggvucftvghtrhhoucdtuddrgedvkedrfedugedgkeduucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuqfggjfdpvefjgfevmfevgfenuceurghilhhouhhtmecuhedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmnegfrhhlucfvnfffucdlqddutddmnecujfgurheptgfkffggfgfhuffvsehmtderredtvdejnecuhfhrohhmpeflvghrohhmvgcuofgrrhhtihhnvgiiuceojhgvrhhomhgvsehmvgguihgrrghrvggrrdhnvghtqeenucggtffrrghtthgvrhhnpedvffehuedvjefhjeelffeihfetueeitefgleeghfdtfeffteejteeiieetvdeuteenucffohhmrghinhepughighhithhiiigrthhiohhnghhuihguvghlihhnvghsrdhgohhvnecukfhppeduvdejrddtrddtrddupdekgedrudegfedrudegiedrvdeguddpfeejrdehledrudegvddruddtkeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepihhnvghtpeduvdejrddtrddtrddupdhmrghilhhfrhhomhepoehjvghrohhmvgesmhgvughirggrrhgvrgdrnhgvtheqpdhnsggprhgtphhtthhopedupdhrtghpthhtohepfhhfmhhpvghgqdguvghvvghlsehffhhmphgvghdrohhrghdpoffvtefjohhsthepmhhoheejiedpmhhouggvpehsmhhtphhouhht Subject: [FFmpeg-devel] [PATCH] avcodec/jpeg2000dec: support of 2 fields in 1 AVPacket 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: LhprdQ8G+uVv Before this patch, the FFmpeg MXF parser correctly detects content with 2 fields in 1 AVPacket as e.g. interlaced 720x486 but the FFmpeg JPEG 2000 decoder reads the JPEG 2000 SIZ header without understanding that the indicated height is the height of 1 field only so overwrites the frame size info with e.g. 720x243, and also completely discards the second frame, which lead to the decoding of only half of the stored content as "progressive" 720x243 flagged interlaced. Example file: https://www.digitizationguidelines.gov/guidelines/MXF_sampleFiles/RDD48-sample12-gf-jpeg2000-ntsc-4.2.zip Before this patch: Stream #0:0: Video: jpeg2000, yuv422p10le(bottom coded first (swapped)), 720x243, lossless, SAR 9:20 DAR 4:3, 29.97 tbr, 29.97 tbn, 29.97 tbc After this patch: Stream #0:0: Video: jpeg2000, yuv422p10le(bottom coded first (swapped)), 720x486, lossless, SAR 9:10 DAR 4:3, 29.97 fps, 29.97 tbr, 29.97 tbn From 5242971da7d2cf8d8713144e4a7bcc4aa06437c4 Mon Sep 17 00:00:00 2001 From: Jerome Martinez Date: Thu, 1 Feb 2024 17:58:02 +0100 Subject: [PATCH] avcodec/jpeg2000dec: support of 2 fields in 1 AVPacket --- libavcodec/jpeg2000dec.c | 87 +++++++++++++++++++++++++++++++++++++++++++----- libavcodec/jpeg2000dec.h | 5 +++ 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 691cfbd891..d8bfca390e 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -194,6 +194,8 @@ static int get_siz(Jpeg2000DecoderContext *s) int ret; int o_dimx, o_dimy; //original image dimensions. int dimx, dimy; + int previous_width = s->width; + int previous_height = s->height; if (bytestream2_get_bytes_left(&s->g) < 36) { av_log(s->avctx, AV_LOG_ERROR, "Insufficient space for SIZ\n"); @@ -211,7 +213,7 @@ static int get_siz(Jpeg2000DecoderContext *s) s->tile_offset_y = bytestream2_get_be32u(&s->g); // YT0Siz ncomponents = bytestream2_get_be16u(&s->g); // CSiz - if (av_image_check_size2(s->width, s->height, s->avctx->max_pixels, AV_PIX_FMT_NONE, 0, s->avctx)) { + if (av_image_check_size2(s->width, s->height << (s->height >= 0 && s->has_2_fields), s->avctx->max_pixels, AV_PIX_FMT_NONE, 0, s->avctx)) { avpriv_request_sample(s->avctx, "Large Dimensions"); return AVERROR_PATCHWELCOME; } @@ -301,6 +303,19 @@ static int get_siz(Jpeg2000DecoderContext *s) return AVERROR(ENOMEM); } + if (s->has_2_fields) { + s->height <<= 1; + s->image_offset_y <<= 1; + s->tile_offset_y <<= 1; + if (s->is_second_field && (s->width != previous_width || s->height != previous_height)) { + avpriv_request_sample(s->avctx, "Pixel size of the 2 fields of the frame are not same"); + return AVERROR_PATCHWELCOME; + } + if (s->image_offset_y || s->tile_offset_y || (s->tile_height << 1) != s->height) { + av_log(s->avctx, AV_LOG_WARNING, "Decoding of 2 fields having titles in 1 AVPacket was not tested\n"); + } + } + /* compute image size with reduction factor */ o_dimx = ff_jpeg2000_ceildivpow2(s->width - s->image_offset_x, s->reduction_factor); @@ -2001,7 +2016,7 @@ static inline void tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile \ y = tile->comp[compno].coord[1][0] - \ ff_jpeg2000_ceildiv(s->image_offset_y, s->cdy[compno]); \ - line = (PIXEL *)picture->data[plane] + y * (picture->linesize[plane] / sizeof(PIXEL));\ + line = (PIXEL *)picture->data[plane] + (y + (s->is_second_field ^ s->is_bottom_coded_first)) * (picture->linesize[plane] / sizeof(PIXEL));\ for (; y < h; y++) { \ PIXEL *dst; \ \ @@ -2028,7 +2043,7 @@ static inline void tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile dst += pixelsize; \ } \ } \ - line += picture->linesize[plane] / sizeof(PIXEL); \ + line += (picture->linesize[plane] << s->has_2_fields) / sizeof(PIXEL); \ } \ } \ \ @@ -2445,8 +2460,8 @@ static av_cold int jpeg2000_decode_init(AVCodecContext *avctx) return 0; } -static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture, - int *got_frame, AVPacket *avpkt) +static int jpeg2000_decode_frame_picture(AVCodecContext *avctx, AVFrame *picture, + AVPacket *avpkt) { Jpeg2000DecoderContext *s = avctx->priv_data; int ret; @@ -2497,7 +2512,7 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture, } /* get picture buffer */ - if ((ret = ff_thread_get_buffer(avctx, picture, 0)) < 0) + if ((!s->has_2_fields || !s->is_second_field) && (ret = ff_thread_get_buffer(avctx, picture, 0)) < 0) goto end; picture->pict_type = AV_PICTURE_TYPE_I; picture->flags |= AV_FRAME_FLAG_KEY; @@ -2520,8 +2535,6 @@ static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture, jpeg2000_dec_cleanup(s); - *got_frame = 1; - if (s->avctx->pix_fmt == AV_PIX_FMT_PAL8) memcpy(picture->data[1], s->palette, 256 * sizeof(uint32_t)); @@ -2532,6 +2545,64 @@ end: return ret; } +static int jpeg2000_decode_frame(AVCodecContext *avctx, AVFrame *picture, + int *got_frame, AVPacket *avpkt) +{ + Jpeg2000DecoderContext *s = avctx->priv_data; + int picture_1_size = avpkt->size, picture_2_size = 0; + int ret1 = 0, ret2 = 0; + int may_have_2_fields_in_1_packet = 0; + + // find if there are 2 JPEG2000 pictures in a single packet + s->has_2_fields = 0; + s->is_bottom_coded_first = 0; + s->is_second_field = 0; + switch (avctx->field_order) { + case AV_FIELD_TT: + case AV_FIELD_TB: + may_have_2_fields_in_1_packet = 1; + break; + case AV_FIELD_BB: + case AV_FIELD_BT: + may_have_2_fields_in_1_packet = 2; + break; + } + if (may_have_2_fields_in_1_packet) { + for (int i = 0; i < avpkt->size - 4; i++) { + static const unsigned char EOI_SOI[4] = { 0xFF, 0xD9, 0xFF, 0x4F }; + if (!memcmp(avpkt->data + i, EOI_SOI, 4)) { + if (picture_2_size) { + av_log(s->avctx, AV_LOG_WARNING, "EIO SOI sequence found twice, risk of wrong detection\n"); + } else { + picture_1_size = i + 2; + picture_2_size = avpkt->size - picture_1_size; + s->has_2_fields = 1; + s->is_bottom_coded_first = may_have_2_fields_in_1_packet - 1; + } + } + } + } + + // parsing full frame or first picture + avpkt->size -= picture_2_size; + ret1 = jpeg2000_decode_frame_picture(avctx, picture, avpkt); + + // parsing second picture if present + if (picture_2_size) { + avpkt->data += picture_1_size; + avpkt->size = picture_2_size; + s->is_second_field = 1; + ret2 = jpeg2000_decode_frame_picture(avctx, picture, avpkt); + + // reset + avpkt->data -= picture_1_size; + avpkt->size += picture_1_size; + } + + *got_frame = avctx->skip_frame < AVDISCARD_ALL && (ret1 >= 0 || ret2 >= 0); // got_frame is 1 if any of the 2 pictures is fine + return ret1 < 0 ? ret1 : (ret2 < 0 ? ret2 : (ret1 + ret2)); // priority on first field error code +} + #define OFFSET(x) offsetof(Jpeg2000DecoderContext, x) #define VD AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_DECODING_PARAM diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h index d0ca6e7a79..ce42812c48 100644 --- a/libavcodec/jpeg2000dec.h +++ b/libavcodec/jpeg2000dec.h @@ -114,6 +114,11 @@ typedef struct Jpeg2000DecoderContext { /*options parameters*/ int reduction_factor; + + /* field info */ + int8_t has_2_fields; + int8_t is_bottom_coded_first; + int8_t is_second_field; } Jpeg2000DecoderContext; #endif //AVCODEC_JPEG2000DEC_H