From patchwork Thu Aug 1 02:37:24 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Osamu Watanabe X-Patchwork-Id: 50846 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:12d6:0:b0:489:2eb3:e4c4 with SMTP id 205csp865052vqs; Wed, 31 Jul 2024 19:47:00 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCX1qqF4xHuBu+2XKsVzY48tdkV3Qi1GWENm4AI2jmUv+qwdQjaegVnfYL6ya6b901tzRtuzJNp1E5IL9V2KtIzHv6H8MxXnkmikYg== X-Google-Smtp-Source: AGHT+IEC0+qOIbW/WVcqsPi+TBMPRjnBZZ71OITmdW0aDXI2ZTDvrZPneP3gePUqhzkfUdUDVj/C X-Received: by 2002:a17:906:eec5:b0:a77:dafb:2bf9 with SMTP id a640c23a62f3a-a7daf5bec60mr61773366b.49.1722480419778; Wed, 31 Jul 2024 19:46:59 -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 a640c23a62f3a-a7aca9f665esi999139066b.239.2024.07.31.19.46.59; Wed, 31 Jul 2024 19:46:59 -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=@takushoku.onmicrosoft.com header.s=selector2-takushoku-onmicrosoft-com header.b=rXL23G0K; 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 Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A4A3768D932; Thu, 1 Aug 2024 05:37:49 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from TY3P286CU002.outbound.protection.outlook.com (mail-japaneastazon11020124.outbound.protection.outlook.com [52.101.229.124]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2778B68CA8A for ; Thu, 1 Aug 2024 05:37:41 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=pUpt7NAX/RlJaPthHMOUaQjklJyzyvAyktf4gqP12c9S3SKjP7NUEV+ysMFqF1rqsZ0PwJN2/kC68saNfGimcclWAiD/czOmY8reu6oddiZtPPhzoBVwcv9d/uweKMKk7hMDScElJhvoqBTifyRr3tVIiniJOQhgaTAnMtK/zDnJN1g0Lvhfe5aoj9yVF7XBFVxzod9/3Bt0hpBrtUI9ORGoXbZt8YaAnQf4EQZVW65SPG+kSkJfSLhaOV3lH17k2+5qvo0m/zNGOFDg9zzSkTGwhRN9/oXyNlA0N4OGvtPwZ+B1pF/yFN2k7skK6KwVUri06rvtkO8uq1Qh4jCK5Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=WhQ9SxTgQ0EKaU9bOQOAkJVK+HydnY/e/G0iLca+qBw=; b=F96IboTCTAocezzegHL6Ylxqj2WNyf/zrzAc1r+/wtmldbnAx7kZRTJGLBDlgyx2W5nkcduwxabZZzamFW6mDJxcoN36H55Ir9fvxihogAzMCWxh8Xdn9E4rDDgkaSVCz6WsEtySfg9GA6p0BrCCkcwQ2tu9CPZL2AaKY51SEhkBFcCxCML1Yfhj8YFv0Nsn17Wl41oG4EKxi0+vxhtH40NNFOdDSN5r0EDL4+LseY1PPcUBoeef+8i3ku3NA2reya6A9XBoOrozVmwNVZPyv1XFalgJR3HSHU7o1vehiU3sef7CsFaeZQNwOXdfwbSAGVjzjGcSQXtm1DTLhEgurA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=es.takushoku-u.ac.jp; dmarc=pass action=none header.from=es.takushoku-u.ac.jp; dkim=pass header.d=es.takushoku-u.ac.jp; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=takushoku.onmicrosoft.com; s=selector2-takushoku-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=WhQ9SxTgQ0EKaU9bOQOAkJVK+HydnY/e/G0iLca+qBw=; b=rXL23G0KLfkFZClIUaQh8w1HCpHthAXtkIpC3ZBWFr0Lb9Ytdyri+McG2B0gpni6hiN0GoS5hmT3zEJM/70BrEtf+tohMsChIOevPJqNwK/q0q9WkvDoFo3o4cXGpOaaL/TNwCVvjZhw5ZvnYTyIcYPzr/xTfaTj7ywlu6/qMNM= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=es.takushoku-u.ac.jp; Received: from OS0PR01MB6001.jpnprd01.prod.outlook.com (2603:1096:604:b7::12) by TYCPR01MB6032.jpnprd01.prod.outlook.com (2603:1096:400:49::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7807.28; Thu, 1 Aug 2024 02:37:36 +0000 Received: from OS0PR01MB6001.jpnprd01.prod.outlook.com ([fe80::181c:c1f4:9b58:f6cc]) by OS0PR01MB6001.jpnprd01.prod.outlook.com ([fe80::181c:c1f4:9b58:f6cc%3]) with mapi id 15.20.7828.021; Thu, 1 Aug 2024 02:37:36 +0000 From: Osamu Watanabe To: ffmpeg-devel@ffmpeg.org Date: Thu, 1 Aug 2024 11:37:24 +0900 Message-Id: <20240801023726.188191-1-owatanab@es.takushoku-u.ac.jp> X-Mailer: git-send-email 2.34.1 X-ClientProxiedBy: TYWPR01CA0038.jpnprd01.prod.outlook.com (2603:1096:400:17f::8) To OS0PR01MB6001.jpnprd01.prod.outlook.com (2603:1096:604:b7::12) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: OS0PR01MB6001:EE_|TYCPR01MB6032:EE_ X-MS-Office365-Filtering-Correlation-Id: 1fc3c9a7-d4be-454f-3481-08dcb1d2e687 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|366016|52116014|376014|1800799024|41320700013|38350700014; X-Microsoft-Antispam-Message-Info: i9I4zY0yQxefVQy1HawG645TSQkTE7ukOZSzim7yp4t5c1KmvpsDivJcX76suLnVvAgKtU8jWpPzBZWKS8P0v6nGO0hICwQ+CnVLrpp7vcmZr7IU79PeMHcbOlS/Dcups2hth3l5WmAIT430XbN3LbBNbrIeoUSIFXA7uc+MAutgBPz0qr3bg720hB/eRJNe0OzM9eyC6xoICGtZMzMEsP55FNZBVz/TPV5dfpmNzEyT6L5lngYWma6OuFPIujZmccbPeexKn55V2YVkvVeA0axueFWvOGAQ8kpYxfP/hUI0IXfTQ5taXNfyqj7/QiqNUWtgrQljrsUSoh7/VJr0/3d2FWW36o73cB2GRJ5min2orqmNp9L89QovdnR9jB6xPS3xWWPId6jifjoQguClH9U1CDHJ3mzd3UtvuFcYrtHZcgUXTF1MmZcVEv3QJDqykrf6SQh12QpcITHWtOEFri/Fw19B8W9VuERhB/gqykO9VKB38WBnJjWuctXi9zxrkjQlkKuE2ECdN/BnrgrRhbbMefqNhuYUb2acTgc9FwaGOiTe5FhTcN7RnEU6wL8KqVqn8CXMF5VjxxYaLi20wpW49ryV7p3b019rZRXIwBBq2Lct52IUx767+EMHaKQ4zgT/lF59MUxQMeimdhbHynofkUOBQ/z8MBqyoj8LiHuCVsa0GGy08fwfB6j+pvttvLTfAt3uuzAWCBi97YzPXckK2pf3ux8+u+4XdvEte8l6yzNz+lBLr9MekeKuLLkhZ0La1wzrhxGs9CTUX/9gTenoIgaQ2k+M+KlnaCZRplTmd7lqmeNHXnuffEeXOlpgqj+rfsCEBWdRn5o6rTSa72Hm1f0Qz+vLHLUOyRM2pOepQs6FAudlM6d/VRLVAh/fEVKsM1BkyMuIpWx95zjpGQfI9W4TUCxm2/a1viL+FKf7SPUzzkU/yiklknXXhUs3ChVvlQdv5N/S4dHKsV1vEGrkBWw/rdgPKTiPs8X7APzf3Jt9TGwGVrf/viqIRqdo/ZfjyxThmY73gzIKH144n9w2llGfpj8M9AOZ8YH2SwpefUXH29L8dUCzC6if8klob1EDnl4RuT50i1Wt+PbxfWXctnrxAkuEHeZ0GcYKdshgxdrUNy4/8dTH5YqFpDmH+HUk/ojxhAEQzHHM497RQXNpP8h6zWUmGhUakSjUpFYDWt7p002/O5/hvQLp40qo++Z+lthEDJhrEvm4ldn5Rrr0bLNaiUxdflp6Zo3DZt062lsz0JlwR/ll9fbwL0H/KNj7aqpelBqdekFdZIqPzckNDF+A9QUx2lZac2dP4hYhyg+rb89pcMkQgIwsh2xMqpSvbpjAKRpuL051ZCZ3GMm1kpyT3DddSNyXamdPq30IH92ghiYix//75o0cqQsyCqYK4Y7zZQKJ9kUQXp9EzA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:OS0PR01MB6001.jpnprd01.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(52116014)(376014)(1800799024)(41320700013)(38350700014); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: w8b5eDtfcoPMh9tRtZ2auwLLmD+1FNri/u3G7YJy8ofEnMZ06uJfl83oHxLNiNe9KdzeOl6gH5/4sg6QC9qCT8aFh5JcPVdiU9vwxz+nCVhabV7smVcHrOQD1SXTDrMMpMbsp1GmhAPiGEyBsbZcM9DXVNZK6RL+B8rFuAz3OqEEv4FOaNXFnkFPNgM+zXuJvLFssyq/kM+YRdjaawHDmnModuN6hK+zjDu8hKqvKSOE1SpV1HAIOjnKpdxJ3FoMMQNXM4ueCmspgfZpDPQ17KACkpuwS92fguUlLCqfvTDR1i4Trp97WV6IXK+JVlSITFI9HcO2SK32rUMievDswqANUypL+9d+Pp9cQ0TiPuPEOWhykEhDW7yLEoSBsUsuc9i9R9KRqY4MxCZDYJNNAY1k8wRksQtMwr6ChbKbBPKKV+yaOVqxg0MQCvrCl28P+7d6UDi1COGzhqATaOr1/ukf7vDI1V1wX6ZxZSDS9higijHVlmhFd3vgSrHrRwzI88Hg9zUcBzUFRIeg6m80/tJDrw6LLfjD1wE6b8fNZGEsHToOWaN+zU5Uxm8LoksAZ+XjCpqRV2FzemJ6S9A95CkrFjaRfRAG0T4hj/VYp1eD0R7G5mut6kwlNaeh72m9G9ejshjyrAgra65iazHRm8DPN7GYmvx/FQPZuJMFdk02fACyb8nMS3hp8inQPLtVPObZHteciT0mKwxcccwY55jdgb6o3/qkam8uFlTJrd6U1+OoVVEEd3/W41UbiI2ckCyC2Sj8Bc3uzYV0uEcq87dp1+7KWJeXWh913Y3mVL3dfNCcs2e/zin+z+7dkwaAMLF/2AIhMYhJZnELJGsgitlFfL8R9ZcR5n7y/UP+9X8ToGdoCU1RuCcozBemJIhTVLbv0lf/P+hwQpnazjGrXL2nzSqupyipGYssVF1AUhYuxsBsJmyFLqeUyrahEHIbiWKQbsjyZ6KKOq2XSGCSw1X2u7VIQSV3vKaHmPi+jfHcoLqd0sMG6aHKqHhJb8W4ZDG+oLJimFhvDSlafG3efqS7h9TevR75oHUSSS0Y9e0s8mEN74zVxl1scpTLIJBqnH0Y6oe6+SdFHRVCrK5r4bxx839mdF3Y2XvovfvFjCYJSH3MSrxOTzyx2rswPSxYnMDT3DZ9RDjqMWNb1adwWEisy47krEAjhlzEU6fBotPUphNr4drQGcMzT/nmC/F/J9L2bgRzTWYf7FzeIbnY91bIwyUCyN+/0n1hEHik7Jju10NzmglNwYyRho/M6UDnS/I0f1NXdf/ZN2Xk7AqVnuVUqUm8wU5PHkzAOdGUzTxhhUnKDbaj2E5jS8MuKXFWbo/1vtcURFIFQX8vc2IsmDOcVyo6ciaUgZMvvQhsm48xs3jY1DZaqU4965e6Uv8y++1kfuik0T37rQFEBzjDnL7grXN2bu4E47CFbXgMiXX/hizFRU6yho/CjIR/aOpIkbRuTwDL+j4q4pZSeOv44hBbdGv97mY65Sjp4ZL9nWtGGnaqhbsvJlp1KTFDM7E5R+i1ZTkRGGVpeZ+7YyBZUzmt2Tz4gsDjqnk/6oYlvMWeBtYcc0KHgCzn8T04wPBuxve/Y5UcuLUXw83ECwQ1jA== X-OriginatorOrg: es.takushoku-u.ac.jp X-MS-Exchange-CrossTenant-Network-Message-Id: 1fc3c9a7-d4be-454f-3481-08dcb1d2e687 X-MS-Exchange-CrossTenant-AuthSource: OS0PR01MB6001.jpnprd01.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Aug 2024 02:37:35.9567 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 853333e5-13b1-4738-ae04-bfb589cf2665 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: LMvS15kZkdmV8puDzSmRwxKAGZOvtibvJfik49nxM1ElMfsE3x7fpUCxaZuuPykOMskjmGPTb8NwyG2Mx3bU/saN31KqarshFrinh3mmBR8= X-MS-Exchange-Transport-CrossTenantHeadersStamped: TYCPR01MB6032 Subject: [FFmpeg-devel] [PATCH v6 1/3] avcodec/jpeg2000dec: Add support for CAP and CPF markers 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: Osamu Watanabe , pal@sandflow.com Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: Qd3WdglY5pbx This commit adds support for CAP and CPF markers. Decoder will exit when encountering an illegal codestream. It is confirmed that the decoder passes all the test cases in FATE and ISO/IEC 15444-4. The subject was wrong in the v5 set of patches. The v6 corrects it. Signed-off-by: Osamu Watanabe --- libavcodec/jpeg2000.h | 8 +++ libavcodec/jpeg2000dec.c | 128 ++++++++++++++++++++++++++++++++++++++- libavcodec/jpeg2000dec.h | 7 +++ 3 files changed, 142 insertions(+), 1 deletion(-) diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index d004c08f10..4bdc38df7c 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -37,12 +37,14 @@ enum Jpeg2000Markers { JPEG2000_SOC = 0xff4f, // start of codestream + JPEG2000_CAP = 0xff50, // extended capabilities JPEG2000_SIZ = 0xff51, // image and tile size JPEG2000_COD, // coding style default JPEG2000_COC, // coding style component JPEG2000_TLM = 0xff55, // tile-part length, main header JPEG2000_PLM = 0xff57, // packet length, main header JPEG2000_PLT, // packet length, tile-part header + JPEG2000_CPF, // corresponding profile JPEG2000_QCD = 0xff5c, // quantization default JPEG2000_QCC, // quantization component JPEG2000_RGN, // region of interest @@ -58,6 +60,12 @@ enum Jpeg2000Markers { JPEG2000_EOC = 0xffd9, // end of codestream }; +enum JPEG2000_Ccap15_b14_15_params { + HTJ2K_HTONLY = 0, // HTONLY, bit 14 and 15 are 0 + HTJ2K_HTDECLARED, // HTDECLARED, bit 14 = 1 and bit 15 = 0 + HTJ2K_MIXED = 3, // MIXED, bit 14 and 15 are 1 +}; + #define JPEG2000_SOP_FIXED_BYTES 0xFF910004 #define JPEG2000_SOP_BYTE_LENGTH 6 diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 091931b1ff..a1f82389fa 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -408,6 +408,73 @@ static int get_siz(Jpeg2000DecoderContext *s) s->avctx->bits_per_raw_sample = s->precision; return 0; } +/* get extended capabilities (CAP) marker segment */ +static int get_cap(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) +{ + uint32_t Pcap; + uint16_t Ccap_i[32] = { 0 }; + uint16_t Ccap_15; + uint8_t P; + + if (bytestream2_get_bytes_left(&s->g) < 6) { + av_log(s->avctx, AV_LOG_ERROR, "Insufficient space for CAP\n"); + return AVERROR_INVALIDDATA; + } + + Pcap = bytestream2_get_be32u(&s->g); + s->isHT = (Pcap >> (31 - (15 - 1))) & 1; + for (int i = 0; i < 32; i++) { + if ((Pcap >> (31 - i)) & 1) + Ccap_i[i] = bytestream2_get_be16u(&s->g); + } + Ccap_15 = Ccap_i[14]; + if (s->isHT == 1) { + av_log(s->avctx, AV_LOG_INFO, "This is an HTJ2K codestream.\n"); + // Bits 14-15 + switch ((Ccap_15 >> 14) & 0x3) { + case 0x3: + s->Ccap15_b14_15 = HTJ2K_MIXED; + break; + case 0x1: + s->Ccap15_b14_15 = HTJ2K_HTDECLARED; + break; + case 0x0: + s->Ccap15_b14_15 = HTJ2K_HTONLY; + break; + default: + av_log(s->avctx, AV_LOG_ERROR, "Unknown CCap value.\n"); + return AVERROR(EINVAL); + break; + } + // Bit 13 + if ((Ccap_15 >> 13) & 1) { + av_log(s->avctx, AV_LOG_ERROR, "MULTIHT set is not supported.\n"); + return AVERROR_PATCHWELCOME; + } + // Bit 12 + s->Ccap15_b12 = (Ccap_15 >> 12) & 1; + // Bit 11 + s->Ccap15_b11 = (Ccap_15 >> 11) & 1; + // Bit 5 + s->Ccap15_b05 = (Ccap_15 >> 5) & 1; + // Bit 0-4 + P = Ccap_15 & 0x1F; + if (!P) + s->HT_MAGB = 8; + else if (P < 20) + s->HT_MAGB = P + 8; + else if (P < 31) + s->HT_MAGB = 4 * (P - 19) + 27; + else + s->HT_MAGB = 74; + + if (s->HT_MAGB > 31) { + av_log(s->avctx, AV_LOG_ERROR, "Available internal precision is exceeded (MAGB> 31).\n"); + return AVERROR_PATCHWELCOME; + } + } + return 0; +} /* get common part for COD and COC segments */ static int get_cox(Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c) @@ -802,6 +869,15 @@ static int read_crg(Jpeg2000DecoderContext *s, int n) bytestream2_skip(&s->g, n - 2); return 0; } + +static int read_cpf(Jpeg2000DecoderContext *s, int n) +{ + if (bytestream2_get_bytes_left(&s->g) < (n - 2)) + return AVERROR_INVALIDDATA; + bytestream2_skip(&s->g, n - 2); + return 0; +} + /* Tile-part lengths: see ISO 15444-1:2002, section A.7.1 * Used to know the number of tile parts and lengths. * There may be multiple TLMs in the header. @@ -965,6 +1041,14 @@ static int init_tile(Jpeg2000DecoderContext *s, int tileno) comp->roi_shift = s->roi_shift[compno]; if (!codsty->init) return AVERROR_INVALIDDATA; + if (s->isHT && (!s->Ccap15_b05) && (!codsty->transform)) { + av_log(s->avctx, AV_LOG_ERROR, "Transformation = 0 (lossy DWT) is found in HTREV HT set\n"); + return AVERROR_INVALIDDATA; + } + if (s->isHT && s->Ccap15_b14_15 != (codsty->cblk_style >> 6) && s->Ccap15_b14_15 != HTJ2K_HTONLY) { + av_log(s->avctx, AV_LOG_ERROR, "SPcod/SPcoc value does not match bit 14-15 values of Ccap15\n"); + return AVERROR_INVALIDDATA; + } if (ret = ff_jpeg2000_init_component(comp, codsty, qntsty, s->cbps[compno], s->cdx[compno], s->cdy[compno], s->avctx)) @@ -2187,22 +2271,57 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) if (!s->tile) s->numXtiles = s->numYtiles = 0; break; + case JPEG2000_CAP: + if (!s->ncomponents) { + av_log(s->avctx, AV_LOG_ERROR, "CAP marker segment shall come after SIZ\n"); + return AVERROR_INVALIDDATA; + } + ret = get_cap(s, codsty); + break; case JPEG2000_COC: + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + av_log(s->avctx, AV_LOG_ERROR, "COC marker is found in HOMOGENEOUS HT set\n"); + return AVERROR_INVALIDDATA; + } ret = get_coc(s, codsty, properties); break; case JPEG2000_COD: + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + av_log(s->avctx, AV_LOG_ERROR, "COD marker is found in HOMOGENEOUS HT set\n"); + return AVERROR_INVALIDDATA; + } ret = get_cod(s, codsty, properties); break; case JPEG2000_RGN: + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + av_log(s->avctx, AV_LOG_ERROR, "RGB marker is found in HOMOGENEOUS HT set\n"); + return AVERROR_INVALIDDATA; + } ret = get_rgn(s, len); + if ((!s->Ccap15_b12) && s->isHT) { + av_log(s->avctx, AV_LOG_ERROR, "RGN marker is found in RGNFREE HT set\n"); + return AVERROR_INVALIDDATA; + } break; case JPEG2000_QCC: + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + av_log(s->avctx, AV_LOG_ERROR, "QCC marker is found in HOMOGENEOUS HT set\n"); + return AVERROR_INVALIDDATA; + } ret = get_qcc(s, len, qntsty, properties); break; case JPEG2000_QCD: + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + av_log(s->avctx, AV_LOG_ERROR, "QCD marker is found in HOMOGENEOUS HT set\n"); + return AVERROR_INVALIDDATA; + } ret = get_qcd(s, len, qntsty, properties); break; case JPEG2000_POC: + if (s->in_tile_headers == 1 && s->isHT && (!s->Ccap15_b11)) { + av_log(s->avctx, AV_LOG_ERROR, "POC marker is found in HOMOGENEOUS HT set\n"); + return AVERROR_INVALIDDATA; + } ret = get_poc(s, len, poc); break; case JPEG2000_SOT: @@ -2252,9 +2371,16 @@ static int jpeg2000_read_main_headers(Jpeg2000DecoderContext *s) "Cannot have both PPT and PPM marker.\n"); return AVERROR_INVALIDDATA; } - + if ((!s->Ccap15_b11) && s->isHT) { + av_log(s->avctx, AV_LOG_ERROR, "PPT marker is found in HOMOGENEOUS HT set\n"); + return AVERROR_INVALIDDATA; + } ret = get_ppt(s, len); break; + case JPEG2000_CPF: + // Corresponding profile marker + ret = read_cpf(s, len); + break; default: av_log(s->avctx, AV_LOG_ERROR, "unsupported marker 0x%.4"PRIX16" at pos 0x%X\n", diff --git a/libavcodec/jpeg2000dec.h b/libavcodec/jpeg2000dec.h index d0ca6e7a79..326a572722 100644 --- a/libavcodec/jpeg2000dec.h +++ b/libavcodec/jpeg2000dec.h @@ -112,6 +112,13 @@ typedef struct Jpeg2000DecoderContext { Jpeg2000Tile *tile; Jpeg2000DSPContext dsp; + uint8_t isHT; // HTJ2K? + uint8_t Ccap15_b14_15; // HTONLY(= 0) or HTDECLARED(= 1) or MIXED(= 3) ? + uint8_t Ccap15_b12; // RGNFREE(= 0) or RGN(= 1)? + uint8_t Ccap15_b11; // HOMOGENEOUS(= 0) or HETEROGENEOUS(= 1) ? + uint8_t Ccap15_b05; // HTREV(= 0) or HTIRV(= 1) ? + uint8_t HT_MAGB; // MAGB value + /*options parameters*/ int reduction_factor; } Jpeg2000DecoderContext; From patchwork Thu Aug 1 02:37:25 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Osamu Watanabe X-Patchwork-Id: 50847 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:12d6:0:b0:489:2eb3:e4c4 with SMTP id 205csp865065vqs; Wed, 31 Jul 2024 19:47:01 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCWApflpK4HlJgzva4Wu3hkcs/ra7QvJvtaKVSRIgTj+VT8y3jG4vtgS6htziFfHwRajGwSh2YavYRFx9v28uDAO4R9kOrpgksvFYg== X-Google-Smtp-Source: AGHT+IE7r5uzEgWF/z6tqSlu3zwTcxzab59sYO9F7eOeYXv3s9as8tdB2ghwRBwymH9pBzXtAkAs X-Received: by 2002:a05:651c:1714:b0:2ef:25ab:9881 with SMTP id 38308e7fff4ca-2f1533c4388mr6054121fa.46.1722480420712; Wed, 31 Jul 2024 19:47:00 -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 38308e7fff4ca-2f03d08d576si39414581fa.54.2024.07.31.19.47.00; Wed, 31 Jul 2024 19:47:00 -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=@takushoku.onmicrosoft.com header.s=selector2-takushoku-onmicrosoft-com header.b=lB7X4mUs; 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 Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id F11FC68D951; Thu, 1 Aug 2024 05:37:53 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from TY3P286CU002.outbound.protection.outlook.com (mail-japaneastazon11020124.outbound.protection.outlook.com [52.101.229.124]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0E0F568D94B for ; Thu, 1 Aug 2024 05:37:47 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=CRgw0BsIsTIxLojbH4KnSqLsViwWZx5KdSaBT0hyLPmLsAS6r+G+hFD0IIU4v+C3IJXIUeq8FsdMzkQrJW42CvswiQl1ZxCgRz/xULyONPpBnNOe+GRy2h3Ay5XAY6cayfixl9J3tDs7QUsVYXvStvak8j8cM+PXHqWo/qUgrhccX/vUk61BME9PzAVVCmsyT4KJr7u9Oo+pRmYm2t3PVeRPFUdSixWPZJfTqt/c1B9PhnS+BXC1YZrQnVAag6fpyhONmfr4QPvfT4q764zWA10K6iibVqW7D55IpfEyT0rDBzmhJGvalGZbhzyXa7Ge5yplf1x1GDNPwJZMX9rSBg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=IVjCtgeHQmrqpnWMKS6NOs4MaetbN+QPxyDi4YFLVUY=; b=mNCjsTpOPQx2Vr3BSoxfS3SWvkFEeoDfeqZFh1YM7en4nmYN7t67x7T5Ty2gaLi3irjB3pSHNv8dykQE//WeUDURGK1XV8uEK9Q2KnyBiDyRMGC1AivNFWVJrnw652xBxOQa+bxj8/yHadc79iuVRhKXBpp9OXSThzN0JU9LcRtMDTfmKPQyBj48kpMCeUW1xS/V1SaYNVF2VQ4U+HKMIAmGftJiCZMwnfQ3KL81Di5N3NEwxai1VoirnvQeFSHOLeFwCJd2NRolEeN0GJ8Zu7fcp1+YoMIvYZEu7KykYznXaA83DMqB7rzt4nycW6klzmdasFn9cxJrbF4M7YXfBg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=es.takushoku-u.ac.jp; dmarc=pass action=none header.from=es.takushoku-u.ac.jp; dkim=pass header.d=es.takushoku-u.ac.jp; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=takushoku.onmicrosoft.com; s=selector2-takushoku-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=IVjCtgeHQmrqpnWMKS6NOs4MaetbN+QPxyDi4YFLVUY=; b=lB7X4mUsFzQZdmXqSquvbgK8uMpE7kWWZ3AxG30wUHJdTKzHTMxfxaRbuyIltHqn5eEdxsRdnD56rlh//jleysdK9EwQjNiq1+XI94J2WWKmwAl42Ajlc4yFDaogGb9L9QwYJaxVaaWfstwO8V12MQECJBTKDaCjFZrfPWW9Bvg= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=es.takushoku-u.ac.jp; Received: from OS0PR01MB6001.jpnprd01.prod.outlook.com (2603:1096:604:b7::12) by TYCPR01MB6032.jpnprd01.prod.outlook.com (2603:1096:400:49::11) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7807.28; Thu, 1 Aug 2024 02:37:37 +0000 Received: from OS0PR01MB6001.jpnprd01.prod.outlook.com ([fe80::181c:c1f4:9b58:f6cc]) by OS0PR01MB6001.jpnprd01.prod.outlook.com ([fe80::181c:c1f4:9b58:f6cc%3]) with mapi id 15.20.7828.021; Thu, 1 Aug 2024 02:37:37 +0000 From: Osamu Watanabe To: ffmpeg-devel@ffmpeg.org Date: Thu, 1 Aug 2024 11:37:25 +0900 Message-Id: <20240801023726.188191-2-owatanab@es.takushoku-u.ac.jp> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240801023726.188191-1-owatanab@es.takushoku-u.ac.jp> References: <20240801023726.188191-1-owatanab@es.takushoku-u.ac.jp> X-ClientProxiedBy: TYWP286CA0024.JPNP286.PROD.OUTLOOK.COM (2603:1096:400:262::9) To OS0PR01MB6001.jpnprd01.prod.outlook.com (2603:1096:604:b7::12) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: OS0PR01MB6001:EE_|TYCPR01MB6032:EE_ X-MS-Office365-Filtering-Correlation-Id: 561085a1-d71f-40c6-9127-08dcb1d2e780 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|366016|52116014|376014|1800799024|41320700013|38350700014; X-Microsoft-Antispam-Message-Info: JKjgqEtftdM1R4OA46x6ynECIelDAG5z+0TwdIc6MpMXenY8GRwFMER9RmNVMFzPGdumviEosVgZUBg/FOun4m9VI/PkWsZEQm4Rqssa+UM+ylUdreChivq7VVHOx9n6/voQLYJtWaLkihqnSetsU/hs8cxAW6iQdD6Pp5UtDTQohqTmHJkUD/11QqsJ8f1cup/jOoi9H5SvBPmk4vGjq6Gg79UVLO4l5tWLDQppztboGiw7tNUQWmsfBu8EDOqTBHWg8sHdY/Ct2ZeJ8WstvV9eCOZKwuMfNXuM2ESTqovr66qqYJSVnWLiLb0u6EkfYqAiavyz+WEaoUEVqbZaCzbn5xMxPbFyiSkkoFXGFAome8/QLn2YkFkGPZzPebCdxwKiBbWRsoigwX56YZjtQI12cLqNEBeXbbyAO9mMYI+pPnfcwMPWrj84SLhVgxfYyp504/OIAs8/FVfI3LG0iFR09ZzrCApZIKeky3Az8ewHlJZIVGhYE9uXBfdij/vCRq5wUqJvE8t/GKgfDS9iAD3ApqyBei9zT9cB0Hxzq1FGIMkuakLUb3sWNlzDM5IcFPghidAR4xu9km1s5jaMOwrkWNNCNYo69T6iPnzKllym7ZzZ9/LWZVROgFsBGT9KrmM1fdXUeoLGq7PjKG5ngdSFPhQi0wmEUyl2Rq92KUtdnkqwOcGq9ergzk6ymiswVjpaGM1I4nwL77bF7gFLEOMScaAZ6rjzIwlcjyNoTzJrHD0KMazScPktiWTAhqHSjQgFy22cHHhzbnvHj3sFPM32Nz5QI2pLeyQ+5VnyrYJlJzYfU8pylj77IjUpzeIp5xM18qiSBCMo/99y6kRMcjq9xE9c6Nm6ctwgYg7gnKTd5IdMjuB7GSNIV5r0wTVPJHkMH4PDx95Iav06DXEeGIcwqBPPe2q7HnLF7BnOr7T9vcmor7VWvn11OVjsUiJRisTlis5FkGFHnhgo2c9QfQPZljniXqZ510dxtCTCfJViGd0laY7rtGYLLAdD51iBXoQMD+EOrZoC6iiEZyxcNF2RxhHL3eIJpUv/nNQynT/bCuHWw6stx73IL+JIQVosVAK1TsVmnddiaElfbT+JtU7bqrONmzcbds6ZTniLN1fbgli+RPAN4JvbSks9DU4co6pUz+k5gvZIEDRu1bctnZjK05wSCecaGZ2vncd89vx5ENLYULmeIqV3nhwS5OeMVjnIIA7XljBEChpM+qMX1WeKGQxLHGq/yOyQcbky0dvZa4KcYPQ41tzxCCUzvN8qt/2uTF3lcpuRioYtbFK2hlBoKHSALptIc3it6/1wUHxzVFrMDpcRKGFDI5zOxgKKAutwodkdttFS+37mTgVAvnP+brixIs+psTluYvc5TiWRvLKntkigtbwzNsQDmRO9KypKN4c4E5081+BRGjSunA== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:OS0PR01MB6001.jpnprd01.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(366016)(52116014)(376014)(1800799024)(41320700013)(38350700014); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: hbxX/yVsuBYh1pB31ZqbsQs0XxC7vy6/pqvq0W5isokCx/3zIKsQAyZZ3xy5n6jNaFX4nQ5GcdyVM8d8r3IaC6CHrJyjyNopVSCpq2Aefb4khvikoGUCX99rycBeBoTpk+JfxQ2l09BgQPmJlAzWRdnah1kRwJa4Uuww+k9aAcX/5cOIrz5Xk4d1OaXZAX6S2KkbuvAFVYnoZDr+cBtT3bJHo+CASisFADngVpmAEWkj5PRsYO/z0deLzQ3udQH3+6keKu+2ubic/rsM/hFfh1+Yww9tVBe7Zl9cGLLabQAEJT2HFIYPjQIQ3fUZetYEOCKSZQeWGlnrF5VDR+mHympIzn5vVdJT7cmivJDJmpD8f8+OMGfFG+hCwZhbt1XcL9qrVNNb0+C33AcIzpu8pd5beHMuGgOURUBsqkGnuqKyPrbpEAumeglIM1HX5muJWlheKUiepUbwZ9MI/+tjGnlB/CxspInQ+X+yCkGZLxzOT1k3/hZoNhbPvUMJ/Q3yg3JD0tnofm+czBIpgQXz9HXoQSedMbq0zI19A9UnfxAwxfPOEm3LweG0+qnML3NMyB53+lhl8LnBQkrj85C3pzDWqLVia0Uiq3FuuFZzOdKAQ2tZypgouAB4tdx9WKrGPYC281xDxy4QzqV8i+oSWt7akYDUQ9FftStkC2CPQsjEKUnuPUbTSrCFP02BolbmKl28VweZ2xWF7gHaYUD0R/suuP8x/Spylh8HT+xyXRpXSFh23o53hx+Ja4HtPq8AH2Po4YCoe00N/Cp4QB3uJaZPhiYL6kB/esfImRJacq75lvFva/MqNkoWhtkMFNaHzK3BQEbuRKo2twnfwFs4btPA0fiGkEwb2IxrO1v0nQ9RZADaDH2CSDf5Rd7kbjR5N3MxbXI9KcqLxgsZj2b60Vqrt4az0DYhhNtX3VmIIKQKnoOcqx3QlYhXmYhqJ944JbeCqeJARMEDd+js8EQvDtsgOYz7EML+RsMl8Nh7nz3bKDImAorFdmRUMu8OrPOQOmVV2XVSdfUmELpJ+ninRbh8Xf0cwDwoERvmwbbHO3KhaWxY2VNKb/Es47Dz1RjrFAjPsK5KnGrmE15OYAv+PbkeHW4ElW1GcpR+7kF96wWMSLZSbshTFUkY6Vmsu+9t+qY36oCG4N4ZcM2Egn6IFHoNhvVZiWpgjwxyqUVwLIWPcwMS0oKAZ40e5hAB5qJlQKM4CP7Yxn+U44T2h4YoHdfA4ClJ7PuCkgE86G+nQ/pw1j7JhW6JSOGHnjzbG0PzJniz4UuFPWfFvlqU5s2rPBY1SGV3uNU6ZI1opXKstHpn4MiDqVnCPOctAIbfolrWIedRG45XNuHqsmAMMFaqzSjj5L7B5ZRF8+ggx6fjfwGc/WKb3WOw+vxKuT8AZnkxuL7w50XOqMbCuXfCvVGXtFxVKQ0e2n4EvIgtJWhD0LcmFvOmQbHNblfDb3OFnATe6yVNsGPw2cxWvSHlP2/S+pWeAmgdQidiIbrlRQP/LcP9qRzf+AoUwr/jVOG3LxcpKF1EF6c2yKdlX9cL0FaxBBgyCVDyLbinmdUiLcfZaTdcK+2c5vUii8xDyYAaFPwdMyXLaRDb6e1mUg/mPDV4rw== X-OriginatorOrg: es.takushoku-u.ac.jp X-MS-Exchange-CrossTenant-Network-Message-Id: 561085a1-d71f-40c6-9127-08dcb1d2e780 X-MS-Exchange-CrossTenant-AuthSource: OS0PR01MB6001.jpnprd01.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Aug 2024 02:37:37.5839 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 853333e5-13b1-4738-ae04-bfb589cf2665 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: 5fxftWUUNLAP0l5huBaaWfJD2rD7h5o6FRhP12AVVsELzmu76yOl3ta/Tu38RVhb91WQ516rqTOBW2DqH6I+sstcj6lOHuWkeweMm+HD3d0= X-MS-Exchange-Transport-CrossTenantHeadersStamped: TYCPR01MB6032 Subject: [FFmpeg-devel] [PATCH v6 2/3] avcodec/jpeg2000dec: Add support for placeholder passes 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: Osamu Watanabe , pal@sandflow.com Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: LKpe+Ry9Lz+K This commit adds support for placeholder pass parsing. Signed-off-by: Osamu Watanabe --- libavcodec/jpeg2000.h | 2 + libavcodec/jpeg2000dec.c | 352 +++++++++++++++++++++++++++++-------- libavcodec/jpeg2000htdec.c | 90 +++++----- 3 files changed, 326 insertions(+), 118 deletions(-) diff --git a/libavcodec/jpeg2000.h b/libavcodec/jpeg2000.h index 4bdc38df7c..93221d90ca 100644 --- a/libavcodec/jpeg2000.h +++ b/libavcodec/jpeg2000.h @@ -200,6 +200,8 @@ typedef struct Jpeg2000Cblk { /* specific to HT code-blocks */ int zbp; int pass_lengths[2]; + uint8_t modes; // copy of SPcod/SPcoc field to parse HT-MIXED mode + uint8_t ht_plhd; // are we looking for HT placeholder passes? } Jpeg2000Cblk; // code block typedef struct Jpeg2000Prec { diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index a1f82389fa..00ff9bea6f 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -54,6 +54,15 @@ #define HAD_COC 0x01 #define HAD_QCC 0x02 +// Values of flag for placeholder passes +enum HT_PLHD_STATUS { + HT_PLHD_OFF, + HT_PLHD_ON +}; + +#define HT_MIXED 0x80 // bit 7 of SPcod/SPcoc + + /* get_bits functions for JPEG2000 packet bitstream * It is a get_bit function with a bit-stuffing routine. If the value of the * byte is 0xFF, the next byte includes an extra zero bit stuffed into the MSB. @@ -1160,100 +1169,293 @@ static int jpeg2000_decode_packet(Jpeg2000DecoderContext *s, Jpeg2000Tile *tile, int incl, newpasses, llen; void *tmp; - if (cblk->npasses) - incl = get_bits(s, 1); - else + if (!cblk->incl) { + incl = 0; + cblk->modes = codsty->cblk_style; + if (cblk->modes >= JPEG2000_CTSY_HTJ2K_F) + cblk->ht_plhd = HT_PLHD_ON; + if (layno > 0) + incl = tag_tree_decode(s, prec->cblkincl + cblkno, 0 + 1) == 0; incl = tag_tree_decode(s, prec->cblkincl + cblkno, layno + 1) == layno; - if (!incl) - continue; - else if (incl < 0) - return incl; - - if (!cblk->npasses) { - int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100); - int v = expn[bandno] + numgbits - 1 - zbp; - if (v < 0 || v > 30) { - av_log(s->avctx, AV_LOG_ERROR, - "nonzerobits %d invalid or unsupported\n", v); - return AVERROR_INVALIDDATA; + if (incl) { + int zbp = tag_tree_decode(s, prec->zerobits + cblkno, 100); + int v = expn[bandno] + numgbits - 1 - (zbp - tile->comp->roi_shift); + if (v < 0 || v > 30) { + av_log(s->avctx, AV_LOG_ERROR, + "nonzerobits %d invalid or unsupported\n", v); + return AVERROR_INVALIDDATA; + } + cblk->incl = 1; + cblk->nonzerobits = v; + cblk->zbp = zbp; + cblk->lblock = 3; } - cblk->zbp = zbp; - cblk->nonzerobits = v; - } - if ((newpasses = getnpasses(s)) < 0) - return newpasses; - av_assert2(newpasses > 0); - if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) { - avpriv_request_sample(s->avctx, "Too many passes"); - return AVERROR_PATCHWELCOME; - } - if ((llen = getlblockinc(s)) < 0) - return llen; - if (cblk->lblock + llen + av_log2(newpasses) > 16) { - avpriv_request_sample(s->avctx, - "Block with length beyond 16 bits"); - return AVERROR_PATCHWELCOME; + } else { + incl = get_bits(s, 1); } - cblk->lblock += llen; - - cblk->nb_lengthinc = 0; - cblk->nb_terminationsinc = 0; - av_free(cblk->lengthinc); - cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc)); - if (!cblk->lengthinc) - return AVERROR(ENOMEM); - tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, sizeof(*cblk->data_start)); - if (!tmp) - return AVERROR(ENOMEM); - cblk->data_start = tmp; - do { - int newpasses1 = 0; + if (incl) { + uint8_t bypass_term_threshold = 0; + uint8_t bits_to_read = 0; + uint32_t segment_bytes = 0; + int32_t segment_passes = 0; + uint8_t next_segment_passes = 0; + int32_t href_passes, pass_bound; + uint32_t tmp_length = 0; + int32_t newpasses_copy, npasses_copy; + + if ((newpasses = getnpasses(s)) <= 0) + return newpasses; + if (cblk->npasses + newpasses >= JPEG2000_MAX_PASSES) { + avpriv_request_sample(s->avctx, "Too many passes"); + return AVERROR_PATCHWELCOME; + } + if ((llen = getlblockinc(s)) < 0) + return llen; + if (cblk->lblock + llen + av_log2(newpasses) > 16) { + avpriv_request_sample(s->avctx, + "Block with length beyond 16 bits"); + return AVERROR_PATCHWELCOME; + } + cblk->nb_lengthinc = 0; + cblk->nb_terminationsinc = 0; + av_free(cblk->lengthinc); + cblk->lengthinc = av_calloc(newpasses, sizeof(*cblk->lengthinc)); + if (!cblk->lengthinc) + return AVERROR(ENOMEM); + tmp = av_realloc_array(cblk->data_start, cblk->nb_terminations + newpasses + 1, + sizeof(*cblk->data_start)); + if (!tmp) + return AVERROR(ENOMEM); + cblk->data_start = tmp; + cblk->lblock += llen; + + // Count number of necessary terminations for non HT code block + newpasses_copy = newpasses; + npasses_copy = cblk->npasses; + if (!(cblk->modes & JPEG2000_CTSY_HTJ2K_F)) { + do { + int newpasses1 = 0; + + while (newpasses1 < newpasses_copy) { + newpasses1++; + if (needs_termination(codsty->cblk_style, npasses_copy + newpasses1 - 1)) { + cblk->nb_terminationsinc++; + break; + } + } + npasses_copy += newpasses1; + newpasses_copy -= newpasses1; + } while (newpasses_copy); + } - while (newpasses1 < newpasses) { - newpasses1 ++; - if (needs_termination(codsty->cblk_style, cblk->npasses + newpasses1 - 1)) { - cblk->nb_terminationsinc ++; - break; + if (cblk->ht_plhd) { + href_passes = (cblk->npasses + newpasses - 1) % 3; + segment_passes = newpasses - href_passes; + pass_bound = 2; + bits_to_read = cblk->lblock; + if (segment_passes < 1) { + // No possible HT Cleanup pass here; may have placeholder passes + // or an original J2K block bit-stream (in MIXED mode). + segment_passes = newpasses; + while (pass_bound <= segment_passes) { + bits_to_read++; + pass_bound += pass_bound; + } + segment_bytes = get_bits(s, bits_to_read); + if (segment_bytes) { + if (cblk->modes & HT_MIXED) { + cblk->ht_plhd = HT_PLHD_OFF; + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F)); + } + else { + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + } + } + } else { + while (pass_bound <= segment_passes) { + bits_to_read++; + pass_bound += pass_bound; + } + segment_bytes = get_bits(s, bits_to_read); + if (segment_bytes) { + // No more placeholder passes + if (!(cblk->modes & HT_MIXED)) { + // Must be the first HT Cleanup pass + if (segment_bytes < 2) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + next_segment_passes = 2; + cblk->ht_plhd = HT_PLHD_OFF; + // Write length information for HT CleanUp segment + cblk->pass_lengths[0] = segment_bytes; + } else if (cblk->lblock > 3 && segment_bytes > 1 + && (segment_bytes >> (bits_to_read - 1)) == 0) { + // Must be the first HT Cleanup pass, since length MSB is 0 + next_segment_passes = 2; + cblk->ht_plhd = HT_PLHD_OFF; + // Write length information for HT CleanUp segment + cblk->pass_lengths[0] = segment_bytes; + } else { + // Must have an original (non-HT) block coding pass + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F)); + cblk->ht_plhd = HT_PLHD_OFF; + segment_passes = newpasses; + while (pass_bound <= segment_passes) { + bits_to_read++; + pass_bound += pass_bound; + segment_bytes <<= 1; + segment_bytes += get_bits(s, 1); + } + } + } else { + // Probably parsing placeholder passes, but we need to read an + // extra length bit to verify this, since prior to the first + // HT Cleanup pass, the number of length bits read for a + // contributing code-block is dependent on the number of passes + // being included, as if it were a non-HT code-block. + segment_passes = newpasses; + if (pass_bound <= segment_passes) { + while (1) { + bits_to_read++; + pass_bound += pass_bound; + segment_bytes <<= 1; + segment_bytes += get_bits(s, 1); + if (pass_bound > segment_passes) + break; + } + if (segment_bytes) { + if (cblk->modes & HT_MIXED) { + cblk->modes &= (uint8_t) (~(JPEG2000_CTSY_HTJ2K_F)); + cblk->ht_plhd = HT_PLHD_OFF; + } else { + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + } + } + } + } + } + } else if (cblk->modes & JPEG2000_CTSY_HTJ2K_F) { + // Quality layer commences with a non-initial HT coding pass + if(bits_to_read != 0) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + segment_passes = cblk->npasses % 3; + if (segment_passes == 0) { + // newpasses is a HT Cleanup pass; next segment has refinement passes + segment_passes = 1; + next_segment_passes = 2; + if (segment_bytes == 1) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a HT-codeblock is invalid\n"); + } else { + // newpasses = 1 means npasses is HT SigProp; 2 means newpasses is + // HT MagRef pass + segment_passes = newpasses > 1 ? 3 - segment_passes : 1; + next_segment_passes = 1; + bits_to_read = av_log2(segment_passes); + } + bits_to_read = (uint8_t) (bits_to_read + cblk->lblock); + segment_bytes = get_bits(s, bits_to_read); + // Write length information for HT Refinment segment + cblk->pass_lengths[1] += segment_bytes; + } else if (!(cblk->modes & (JPEG2000_CBLK_TERMALL | JPEG2000_CBLK_BYPASS))) { + // Common case for non-HT code-blocks; we have only one segment + bits_to_read = (uint8_t) cblk->lblock + av_log2((uint8_t) newpasses); + segment_bytes = get_bits(s, bits_to_read); + segment_passes = newpasses; + } else if (cblk->modes & JPEG2000_CBLK_TERMALL) { + // RESTART MODE + bits_to_read = cblk->lblock; + segment_bytes = get_bits(s, bits_to_read); + segment_passes = 1; + next_segment_passes = 1; + } else { + // BYPASS MODE + bypass_term_threshold = 10; + if(bits_to_read != 0) + av_log(s->avctx, AV_LOG_WARNING, "Length information for a codeblock is invalid\n"); + if (cblk->npasses < bypass_term_threshold) { + // May have from 1 to 10 uninterrupted passes before 1st RAW SigProp + segment_passes = bypass_term_threshold - cblk->npasses; + if (segment_passes > newpasses) + segment_passes = newpasses; + while ((2 << bits_to_read) <= segment_passes) + bits_to_read++; + next_segment_passes = 2; + } else if ((cblk->npasses - bypass_term_threshold) % 3 < 2) { + // 0 means newpasses is a RAW SigProp; 1 means newpasses is a RAW MagRef pass + segment_passes = newpasses > 1 ? 2 - (cblk->npasses - bypass_term_threshold) % 3 : 1; + bits_to_read = av_log2(segment_passes); + next_segment_passes = 1; + } else { + // newpasses is an isolated Cleanup pass that precedes a RAW SigProp pass + segment_passes = 1; + next_segment_passes = 2; } + bits_to_read = (uint8_t) (bits_to_read + cblk->lblock); + segment_bytes = get_bits(s, bits_to_read); } - - if (newpasses > 1 && (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F)) { - // Retrieve pass lengths for each pass - int href_passes = (cblk->npasses + newpasses - 1) % 3; - int eb = av_log2(newpasses - href_passes); - int extra_bit = newpasses > 2 ? 1 : 0; - if ((ret = get_bits(s, llen + eb + 3)) < 0) - return ret; - cblk->pass_lengths[0] = ret; - if ((ret = get_bits(s, llen + 3 + extra_bit)) < 0) - return ret; - cblk->pass_lengths[1] = ret; - ret = cblk->pass_lengths[0] + cblk->pass_lengths[1]; + // Update cblk->npasses and write length information + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes); + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes; + + if ((cblk->modes & JPEG2000_CTSY_HTJ2K_F) && cblk->ht_plhd == HT_PLHD_OFF) { + newpasses -= (uint8_t) segment_passes; + while (newpasses > 0) { + segment_passes = newpasses > 1 ? next_segment_passes : 1; + next_segment_passes = (uint8_t) (3 - next_segment_passes); + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes)); + segment_bytes = get_bits(s, bits_to_read); + newpasses -= (uint8_t) (segment_passes); + // This is a FAST Refinement pass + // Write length information for HT Refinement segment + cblk->pass_lengths[1] += segment_bytes; + // Update cblk->npasses and write length information + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes); + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes; + } } else { - if ((ret = get_bits(s, av_log2(newpasses1) + cblk->lblock)) < 0) - return ret; - cblk->pass_lengths[0] = ret; + newpasses -= (uint8_t) (segment_passes); + while (newpasses > 0) { + if (bypass_term_threshold != 0) { + segment_passes = newpasses > 1 ? next_segment_passes : 1; + next_segment_passes = (uint8_t) (3 - next_segment_passes); + bits_to_read = (uint8_t) (cblk->lblock + av_log2(segment_passes)); + } else { + if ((cblk->modes & JPEG2000_CBLK_TERMALL) == 0) + av_log(s->avctx, AV_LOG_WARNING, "Corrupted packet header is found.\n"); + segment_passes = 1; + bits_to_read = cblk->lblock; + } + segment_bytes = get_bits(s, bits_to_read); + newpasses -= (uint8_t) (segment_passes); + + // Update cblk->npasses and write length information + cblk->npasses = (uint8_t) (cblk->npasses + segment_passes); + cblk->lengthinc[cblk->nb_lengthinc++] = segment_bytes; + } } - if (ret > cblk->data_allocated) { - size_t new_size = FFMAX(2*cblk->data_allocated, ret); + + for (int i = 0; i < cblk->nb_lengthinc; ++i) + tmp_length = (tmp_length < cblk->lengthinc[i]) ? cblk->lengthinc[i] : tmp_length; + + if (tmp_length > cblk->data_allocated) { + size_t new_size = FFMAX(2 * cblk->data_allocated, tmp_length); void *new = av_realloc(cblk->data, new_size); if (new) { cblk->data = new; cblk->data_allocated = new_size; } } - if (ret > cblk->data_allocated) { + if (tmp_length > cblk->data_allocated) { avpriv_request_sample(s->avctx, "Block with lengthinc greater than %"SIZE_SPECIFIER"", cblk->data_allocated); return AVERROR_PATCHWELCOME; } - cblk->lengthinc[cblk->nb_lengthinc++] = ret; - cblk->npasses += newpasses1; - newpasses -= newpasses1; - } while(newpasses); + } else { + // This codeblock has no contribution to the current packet + continue; + } } } jpeg2000_flush(s); @@ -1788,7 +1990,7 @@ static int decode_cblk(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *cod Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width, int height, int bandpos, uint8_t roi_shift) { - int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1 + roi_shift; + int passno = cblk->npasses, pass_t = 2, bpno = cblk->nonzerobits - 1; int pass_cnt = 0; int vert_causal_ctx_csty_symbol = codsty->cblk_style & JPEG2000_CBLK_VSC; int term_cnt = 0; @@ -2028,7 +2230,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile Jpeg2000Cblk *cblk = prec->cblk + cblkno; - if (codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) + if (cblk->modes & JPEG2000_CTSY_HTJ2K_F) ret = ff_jpeg2000_decode_htj2k(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], cblk->coord[1][1] - cblk->coord[1][0], diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c index eba0936089..9b473e11d3 100644 --- a/libavcodec/jpeg2000htdec.c +++ b/libavcodec/jpeg2000htdec.c @@ -1032,25 +1032,31 @@ static void jpeg2000_calc_mbr(uint8_t *mbr, const uint16_t i, const uint16_t j, static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s, int width, int height, int stride, int pLSB, int32_t *sample_buf, uint8_t *block_states, - uint8_t *magref_segment, uint32_t magref_length) + uint8_t *magref_segment, uint32_t magref_length, + uint8_t is_causal) { for (int j = j_s; j < j_s + width; j++) { uint32_t mbr_info = 0; for (int i = i_s; i < i_s + height; i++) { - int modify_state, cond; + int modify_state; uint8_t bit; - uint8_t causal_cond = i != (i_s + height - 1); + uint8_t causal_cond = (is_causal == 0) || (i != (i_s + height - 1)); int32_t *sp = &sample_buf[j + (i * (stride))]; uint8_t mbr = 0; - if (jpeg2000_get_state(i, j, stride - 2, HT_SHIFT_SIGMA, block_states) == 0) + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) == 0) jpeg2000_calc_mbr(&mbr, i, j, mbr_info & 0x1EF, causal_cond, block_states, stride); mbr_info >>= 3; - cond = mbr != 0; - bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length); - *sp |= (bit * cond) << pLSB; - sig_prop->bits -= cond; - modify_state = (((1 << HT_SHIFT_REF_IND) | (1 << HT_SHIFT_REF)) * cond) | 1 << HT_SHIFT_SCAN; + + modify_state = block_states[(i + 1) * stride + (j + 1)]; + modify_state |= 1 << HT_SHIFT_SCAN; + if (mbr != 0) { + modify_state |= 1 << HT_SHIFT_REF_IND; + bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length); + modify_state |= bit << HT_SHIFT_REF; + *sp |= bit << pLSB; + *sp |= bit << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) + } jpeg2000_modify_state(i, j, stride, modify_state, block_states); } } @@ -1074,6 +1080,7 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, int last_width; uint16_t i = 0, j = 0; + uint8_t is_causal = cblk->modes & JPEG2000_CBLK_VSC; jpeg2000_init_zero(&sp_dec); @@ -1082,14 +1089,14 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, for (int n2 = 0; n2 < num_h_stripe; n2++) { jpeg2000_process_stripes_block(&sp_dec, i, j, b_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); j += 4; } last_width = width % 4; if (last_width) jpeg2000_process_stripes_block(&sp_dec, i, j, last_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); i += 4; } @@ -1099,20 +1106,20 @@ static void jpeg2000_decode_sigprop_segment(Jpeg2000Cblk *cblk, uint16_t width, for (int n2 = 0; n2 < num_h_stripe; n2++) { jpeg2000_process_stripes_block(&sp_dec, i, j, b_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); j += 4; } last_width = width % 4; if (last_width) jpeg2000_process_stripes_block(&sp_dec, i, j, last_width, b_height, stride, pLSB, sample_buf, block_states, magref_segment, - magref_length); + magref_length, is_causal); } /** * See procedure decodeSigPropMag at Rec. ITU-T T.814, 7.5. */ -static int +static void jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int stride, uint8_t *magref_segment,uint32_t magref_length, uint8_t pLSB, int32_t *sample_buf, uint8_t *block_states) @@ -1152,15 +1159,14 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int } } } - return 1; } int ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, - int width, int height, int magp, uint8_t roi_shift) + int width, int height, int M_b, uint8_t roi_shift) { - uint8_t p0 = 0; // Number of placeholder passes + uint8_t p0 = 0; // 3 * p0 = Number of placeholder passes uint32_t Lcup; // Length of HT cleanup segment uint32_t Lref; // Length of Refinement segment uint32_t Scup; // HT cleanup segment suffix length @@ -1174,7 +1180,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c int z_blk; // Number of ht coding pass - uint8_t empty_passes; + uint8_t num_plhd_passes; // Number of placeholder passes StateVars mag_sgn; // Magnitude and Sign StateVars mel; // Adaptive run-length coding @@ -1190,8 +1196,9 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c uint8_t *block_states = NULL; int32_t n, val; // Post-processing - - int32_t M_b = magp; + const uint32_t mask = UINT32_MAX >> (M_b + 1); // bit mask for ROI detection + + uint8_t num_rempass; const int quad_buf_width = width + 4; const int quad_buf_height = height + 4; @@ -1201,22 +1208,17 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c av_assert0(width * height <= 4096); av_assert0(width * height > 0); - if (roi_shift) - avpriv_report_missing_feature(s->avctx, "ROI shift"); - memset(t1->data, 0, t1->stride * height * sizeof(*t1->data)); memset(t1->flags, 0, t1->stride * (height + 2) * sizeof(*t1->flags)); if (cblk->npasses == 0) return 0; - if (cblk->npasses > 3) - p0 = 0; - else if (cblk->length == 0) - p0 = 1; - - empty_passes = p0 * 3; - z_blk = cblk->npasses - empty_passes; + num_rempass = cblk->npasses % 3; // Number of remainder passes + num_plhd_passes = num_rempass ? cblk->npasses - num_rempass : cblk->npasses - 3; + av_assert0(num_plhd_passes % 3 == 0); + p0 = num_plhd_passes / 3; + z_blk = cblk->npasses - num_plhd_passes; if (z_blk <= 0) return 0; // No passes within this set, continue @@ -1232,6 +1234,7 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c Dcup = cblk->data; Dref = cblk->data + Lcup; // Dref comes after the refinement segment S_blk = p0 + cblk->zbp; + cblk->zbp = S_blk - 1; pLSB = 30 - S_blk; Scup = (Dcup[Lcup - 1] << 4) + (Dcup[Lcup - 2] & 0x0F); @@ -1277,31 +1280,32 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c goto free; } - if (cblk->npasses > 1) + if (z_blk > 1) jpeg2000_decode_sigprop_segment(cblk, width, height, quad_buf_width, Dref, Lref, pLSB - 1, sample_buf, block_states); - if (cblk->npasses > 2) { - - if (Lref < 2){ - av_log(s->avctx,AV_LOG_ERROR,"Invalid magnitude refinement length\n"); - ret = AVERROR_INVALIDDATA; - goto free; - } - if ((ret = jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref, - pLSB - 1, sample_buf, block_states)) < 0) - goto free; - } + if (z_blk > 2) + jpeg2000_decode_magref_segment(width, height, quad_buf_width, Dref, Lref, + pLSB - 1, sample_buf, block_states); pLSB = 31 - M_b; /* Reconstruct the sample values */ for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { + int32_t sign; + n = x + (y * t1->stride); val = sample_buf[x + (y * quad_buf_width)]; + sign = val & INT32_MIN; + val &= INT32_MAX; + /* ROI shift, if necessary */ + if (roi_shift && (((uint32_t)val & ~mask) == 0)) + val <<= roi_shift; /* Convert sign-magnitude to two's complement. */ - val = val >> 31 ? 0x80000000 - val : val; + if (sign) + val = -val; + /* Shift down to 1 bit upper from decimal point for reconstruction value (= 0.5) */ val >>= (pLSB - 1); t1->data[n] = val; } From patchwork Thu Aug 1 02:37:26 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Osamu Watanabe X-Patchwork-Id: 50848 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:12d6:0:b0:489:2eb3:e4c4 with SMTP id 205csp867632vqs; Wed, 31 Jul 2024 19:56:59 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCVGkub/mmRU41iT4YsHT5W1NvJst9hkD/4ilIDoEspeLIkAXclmhnIe1VJM1wB45uMfCb5AawrewTxaKv96xA69rHYslS0sB+C1FA== X-Google-Smtp-Source: AGHT+IERQ+BJC0TqBQOrVy8b+fQntdWdxrore/q5DcI8HgnMpDcJEbd5LQVlV1gi+071zmF91wLE X-Received: by 2002:a17:907:60c8:b0:a7a:acae:340e with SMTP id a640c23a62f3a-a7daf2d15bbmr80673266b.26.1722481018792; Wed, 31 Jul 2024 19:56:58 -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 4fb4d7f45d1cf-5ac650a43bcsi9856191a12.249.2024.07.31.19.56.58; Wed, 31 Jul 2024 19:56:58 -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=@takushoku.onmicrosoft.com header.s=selector2-takushoku-onmicrosoft-com header.b=M4eVBpCH; 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 Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id E561268D949; Thu, 1 Aug 2024 05:37:51 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from TYVP286CU001.outbound.protection.outlook.com (mail-japaneastazon11021075.outbound.protection.outlook.com [52.101.125.75]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id C4DB668D934 for ; Thu, 1 Aug 2024 05:37:44 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=x58cElETXQNSnZghdFzQQHKdJrHf5K4ccSDK5PynPy2EWJ5tz/WLBtT4OYmkq9OVFNAnloB7tJlpfEcXKEvMJLseN+jwP712EjkiwMvWOyzWglFge1l86mrwdiZuUt3mLrkIFWyKJgOFN/CA11kol83MZ8eouZC5KwgslQBcMRb+VeajXQ3rMonwx1fvubA+mrNyhTEcZdDAiDnm0Vo0xbiW+tdJ60jLH0iHCc1FzjaNmfwsYXyRMXwZSzpiPIdmoJ+KzvGQ/G6orC5xmx6/J9OxB6SUffeSkmqo6kQNCmyC2q1IEL+gTq0i0dpYZdLDT8zXk3up2UN2pxQiMVMkUg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; 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=SA0OSyQHYy4rKUNTgzGNjWHp/MMEDp23Oin6pzORJ9w=; b=GZBCFWmG1y0KJ6UBfKuQWa09JhD7fNb+liIGwGTT3PwbHxPl5nFdOKGova4qoe6Y534xR57mjsWE11Y44E/uqdF9XZZ+f0PDh77/svuzsAC4C70wZXKiLb4YNYVYQIOI41GQ0ZTuhA3yXIXJG6gVX5LAITOKxRIpvFKNV3Q1aMV1J+RqLa2CxxN687rpHBZq5kT98FbkdJQlgJRYr7MRH9XI0lRN5jgLmigpOFkFdmbgmIM5kvfV3qeBRgn0U85uiRDvuf898avE/2Wr7nlEK7aFnO4n0k5uvytUga7SQExPCRJE9U7daxu1HNdP53Qi+ppaBnDK6GrCuAycF3uIsw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=es.takushoku-u.ac.jp; dmarc=pass action=none header.from=es.takushoku-u.ac.jp; dkim=pass header.d=es.takushoku-u.ac.jp; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=takushoku.onmicrosoft.com; s=selector2-takushoku-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=SA0OSyQHYy4rKUNTgzGNjWHp/MMEDp23Oin6pzORJ9w=; b=M4eVBpCHJESHa0gO3K4KDj4cZQJFTqfHbVeMiFfzRaVOYNOoaAbc8ojtZe5uklIK0ywDJ/gLsHL4HR00nGsAqxwmYlKNJBieh08yTFeViHDsel/9BVZz+9M9r7rcD9D+qIASOMXFHqt//ETaJcMuK36w0LAZ6xPy27Jp8TiV4xA= Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=es.takushoku-u.ac.jp; Received: from OS0PR01MB6001.jpnprd01.prod.outlook.com (2603:1096:604:b7::12) by OS3PR01MB6934.jpnprd01.prod.outlook.com (2603:1096:604:12d::8) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.7828.22; Thu, 1 Aug 2024 02:37:39 +0000 Received: from OS0PR01MB6001.jpnprd01.prod.outlook.com ([fe80::181c:c1f4:9b58:f6cc]) by OS0PR01MB6001.jpnprd01.prod.outlook.com ([fe80::181c:c1f4:9b58:f6cc%3]) with mapi id 15.20.7828.021; Thu, 1 Aug 2024 02:37:39 +0000 From: Osamu Watanabe To: ffmpeg-devel@ffmpeg.org Date: Thu, 1 Aug 2024 11:37:26 +0900 Message-Id: <20240801023726.188191-3-owatanab@es.takushoku-u.ac.jp> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240801023726.188191-1-owatanab@es.takushoku-u.ac.jp> References: <20240801023726.188191-1-owatanab@es.takushoku-u.ac.jp> X-ClientProxiedBy: TYAPR01CA0041.jpnprd01.prod.outlook.com (2603:1096:404:28::29) To OS0PR01MB6001.jpnprd01.prod.outlook.com (2603:1096:604:b7::12) MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: OS0PR01MB6001:EE_|OS3PR01MB6934:EE_ X-MS-Office365-Filtering-Correlation-Id: 1eb87793-82a0-45c5-5fb7-08dcb1d2e88f X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0; ARA:13230040|1800799024|366016|41320700013|376014|52116014|38350700014; X-Microsoft-Antispam-Message-Info: URXZVyRilsZp4OxkhvwwKyG28p3kVZuR8i+ID1mnWoz8stZixYIuyzyqHYn7LcQnM/r3Z2Ln0jJTRyDkPUvg4uff/BiIsrhYYlh2hYvjeeweJ6a0qYTdk+xGXNvTb/z+RzjKuQKDIsuwXpvzq8/gE66xUUwE5r+vjVAe79UaQ1PX2HTXEKO9nSAks2tJTSGcynmNNSznZrqTa9GISbDEMyAJQ62QcVcP+Cewv4sb54V/PTMDc2YzDKNkVIjZMkfogUFh3+p42eNu2bYXubmWjsvC5EQvYy+GAhI0mFWWptguxTslLu7uQiKZCKYiCYRdoNjxS12pQBSmNDfN/D/bj4K3waiWLzCkqISA/Am8JQ3tY5Bbe439b5U6rVIx8T18ALkT9/Kk9nNf7SqVvEX6AZsQlkq2gQqIMP2uRn0dRoGsC5OBGMMgVBu0mc2EJDt520ocngIOk/oJ+3Zqp9HrfCncMYQQG/1uuv6at6IJXbjK+hy3/RO8QBdMawSV7haR4rRgPRntKzgjbrWRzRVKy2sjLWqf0W9KNsQCfmF/StEK03ZlrWIhkKoESZ2n0Ntkzj1BiDNpDJQ3DlToURqGJDfIK91kKIV4bcR/+ivbCHd6TnaDgMj/QhpOosmyLnJfKqdBGqdlznw/IUZEOeTrzGO6hbSPKMm/GX9onNtf74iw59HRUcLJ2lKbdYY0nDe6FXG/lb75sLjk7CXD34U8SjyYAGX88ytZ0AVfPqeB+kVDfJqXK8Ec6c4CgGP/L+b2NR+/HzD/uigS0azRJM7Ruyy3VETQoPI1oyLl8VzLDNX0Qp7vEJ+4lMOwSayq9zbD6z12A9FLJe0AyKL68BiXKFh1GAOOemlUi3FvuhgyyGEyPdUkVZ0Kz0t8NQ+//eILxaoikMxRjbXSy0bMU+SLB0kWhd1ZYqhQA7mmJiuAFeubZz96lTvyFauN/7KffwDyse5+0C7lIZHIElmfuMqaT8ZB0drXjde5ZSPjq4dgYKxotchq19jxR+bf0CIyDQ+WXHBIQD7fVWziF8ytrRh5SjvqRx+G37VkyVK7Tm7HM7ruNc+FmQ+/7GBb5VJiagfECIHWNya15YUGOXbu2l9qJDJDn0rc1ydhnLA0IptM1YilhI6hF8zuijJaSmvGF5UZMrMmDjAdmn2epw75iDC7f1V7Y+mjRLzefuoIHRCQsdlrdC6YD1GT0s+S73JGMUapUfdkIexZ3lDowwumtXa+p9T9m8BUNQc5UmyE2QmzUmZxscWJ3eRb/ibta9wbaXRrKcjPSys6VbPF7xAcw/fyujYlOWv9u59gnJlvvlyFpIYur9PtrywdIq8aBENPbMM7cyKeBjKkxsAKRQSmG/nSj7WY1hpsIj3vjwCAdL2zRPf6LEAxSKvXV0+z82Hy5NzKBy/xy8dkTJxFjRtg05Am4Q== X-Forefront-Antispam-Report: CIP:255.255.255.255; CTRY:; LANG:en; SCL:1; SRV:; IPV:NLI; SFV:NSPM; H:OS0PR01MB6001.jpnprd01.prod.outlook.com; PTR:; CAT:NONE; SFS:(13230040)(1800799024)(366016)(41320700013)(376014)(52116014)(38350700014); DIR:OUT; SFP:1102; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: +GVHyzsFEx2kQIpl5MUSbtZCXQIs0sjYl0Y7ng0K8rNUDHM+WbiykUi1l6yvpOQkEX0qRJr31/lIbzzOMJWgIckzZn3YhTj6WNNR5K1gFVG2qt8Bhitbe6H6HyWsCL/M0DQ0Gvy9q3KjzaYoX52FBHjfD84h0LluTqBCKb0CzZLWXQduOj2NDzmSBQtwZcsfLAyqIoJz48ytt83Gyl2cwN/Yc9HeX0eTL3jWR5NfH4CInW87IPA4DzXFNXXFRCmSXPQyHAx/Jp/zTAhq4j+D2jrpBMgtC9De+/g7d8KaRtQK6cMcs9ouvQzbUbwzF9S5n292U/76N3h7utpOngWTsna6gtk6M6gxnEQMV5wskeStHTKMw5nWLQilOZc35cu0JTeJ5MrRdh/K6/63ozHPE4ABECOp3T7uiijOsWBPw1JqDjCG2e8zraD8+HDZvvRKV/nQbeBtEmVJEPg/7b2ZAw+gXEraxNdQOFSd1ZBN7xN5kuUicc2T8oPkW7GC2XVQkwX9sIZiixVx8+KWOWGHXkOyufchBKu7JAF5/9kjuRBnZPPwaPi+5YCwMtyd1tAW4GAg0VKSb1GRK+XykFclf0hYg+vvB+2jYjbzCxuKU6mOlKMA0gyDVAZx5Q2TDqqc7U/3fKe/+l+k4D8KmTBG4O0/XF41kB0eMqu6GskLxUj6tpUjPp11mLXPNxFmQjB0vM/SNxg3H96jwl3wJ3CiceA6bm2l1+pVjPrZG21WhQp1MWzh3NoQPrPD/lT4cIDx40PqLeHAEjbmntQJpgVa/7CSTBe5+tD7FWP1ZYGMifzEX0fyEwioanmidipkZdgIbMhEPyInq85RFmKEgP7/ir67P8m98Nab0l6gi9YQIeBZoDQ2QNcDWgrY7lMwUCgCxQTUerO+migO9gy3Or0Kz9zN9PY4cVQc2RzCKTSrijxEexeaHm75PM/Nx35NhVvybnjU8LczSc0q7RRGwfyzRF34cfDz7nhEteKaSEt35spHD/sOueukramcrBkfj+qwTwkMDZKVqzL3P7+YKEnu8KofH0RJ109vEgoqlYSyLCnTNqarj2gUTbTveOd4Y6zWNX2U/4ofDXb24UjAObz8w8jAnIfQsEGuH3EpJIlHjsQDozN+qDHwYNA85XgKO6s4x0nzlEGIrGEncwQOlmq7CeMyg2CvfB+bLtn2TFh1sud8RFzN0mUxbjMXofxgclUrnTYGuKTswvXHyGwL6zjF8/S6Y65tyqCLfcbL50npfH3dI1EGVBgbJyKMzZ9O2oWJNsbSyH/D/Bom4IXb2B4D4cRyAHsc/NFDRL0j1UjcciWu+b7oltMnIEGjPBiSu0Cxi6bdIXOGRKkfHJZGyjNzCciPFXkV2Rdl/TkU89Q8gxLqtHSEpZDZRx6bQYZQQWt7A1TO0dKVrr/J4sGKE0DGpujvXa5GiutLW5rSU98BegxVfmNQX5eXysBzL0gVLImzbZ+VGrrvb9jkWZSG5Va+k219vf+KFsG4OHTvZUuFtipKG6enmivoedwxWIPRMC9oUMqJrWRUQOwNVxmuuE1U4zvC6upKL57WQ1odNQ/e+JpS9hE4JqbYZwSqYMHNCGJybz79y23OXX4qxZZ85P1MrA== X-OriginatorOrg: es.takushoku-u.ac.jp X-MS-Exchange-CrossTenant-Network-Message-Id: 1eb87793-82a0-45c5-5fb7-08dcb1d2e88f X-MS-Exchange-CrossTenant-AuthSource: OS0PR01MB6001.jpnprd01.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Aug 2024 02:37:39.3496 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 853333e5-13b1-4738-ae04-bfb589cf2665 X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: +hlBzDOuRcp6+ZZd/s6zUhWQ6w/Vuy7M2WArbJ6oIZuA/FPY49yrU0JxPQZHRFT7mukIDDzE8lfrLYtkbrgfTWNvHH30hOh03674/MFt8P0= X-MS-Exchange-Transport-CrossTenantHeadersStamped: OS3PR01MB6934 Subject: [FFmpeg-devel] [PATCH v6 3/3] avcodec/jpeg2000dec: Fix HT decoding 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: Osamu Watanabe , pal@sandflow.com Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: BBLOWX3k0rc6 This commit fixes wrong treatment of MAGBP value in Ccap15 and bugs in HT block decoding. Signed-off-by: Osamu Watanabe --- libavcodec/jpeg2000dec.c | 11 +-- libavcodec/jpeg2000htdec.c | 136 ++++++++++++++++++++++--------------- libavcodec/jpeg2000htdec.h | 2 +- 3 files changed, 89 insertions(+), 60 deletions(-) diff --git a/libavcodec/jpeg2000dec.c b/libavcodec/jpeg2000dec.c index 00ff9bea6f..6653fc1ab4 100644 --- a/libavcodec/jpeg2000dec.c +++ b/libavcodec/jpeg2000dec.c @@ -391,6 +391,9 @@ static int get_siz(Jpeg2000DecoderContext *s) } else if (ncomponents == 1 && s->precision == 8) { s->avctx->pix_fmt = AV_PIX_FMT_GRAY8; i = 0; + } else if (ncomponents == 1 && s->precision == 12) { + s->avctx->pix_fmt = AV_PIX_FMT_GRAY16LE; + i = 0; } } @@ -2204,7 +2207,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile Jpeg2000Band *band = rlevel->band + bandno; int cblkno = 0, bandpos; /* See Rec. ITU-T T.800, Equation E-2 */ - int magp = quantsty->expn[subbandno] + quantsty->nguardbits - 1; + int M_b = quantsty->expn[subbandno] + quantsty->nguardbits - 1; bandpos = bandno + (reslevelno > 0); @@ -2212,8 +2215,8 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile band->coord[1][0] == band->coord[1][1]) continue; - if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && magp >= 31) { - avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and magp >= 31"); + if ((codsty->cblk_style & JPEG2000_CTSY_HTJ2K_F) && M_b >= 31) { + avpriv_request_sample(s->avctx, "JPEG2000_CTSY_HTJ2K_F and M_b >= 31"); return AVERROR_PATCHWELCOME; } @@ -2234,7 +2237,7 @@ static inline int tile_codeblocks(const Jpeg2000DecoderContext *s, Jpeg2000Tile ret = ff_jpeg2000_decode_htj2k(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], cblk->coord[1][1] - cblk->coord[1][0], - magp, comp->roi_shift); + M_b, comp->roi_shift); else ret = decode_cblk(s, codsty, &t1, cblk, cblk->coord[0][1] - cblk->coord[0][0], diff --git a/libavcodec/jpeg2000htdec.c b/libavcodec/jpeg2000htdec.c index 9b473e11d3..0296792a6a 100644 --- a/libavcodec/jpeg2000htdec.c +++ b/libavcodec/jpeg2000htdec.c @@ -122,7 +122,7 @@ static void jpeg2000_init_mel(StateVars *s, uint32_t Pcup) static void jpeg2000_init_mag_ref(StateVars *s, uint32_t Lref) { - s->pos = Lref - 2; + s->pos = Lref - 1; s->bits = 0; s->last = 0xFF; s->tmp = 0; @@ -145,9 +145,10 @@ static void jpeg2000_init_mel_decoder(MelDecoderState *mel_state) static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *array) { uint64_t tmp = 0; - int32_t position = buffer->pos - 4; uint32_t new_bits = 32; + buffer->last = array[buffer->pos + 1]; + if (buffer->bits_left >= 32) return 0; // enough data, no need to pull in more bits @@ -157,9 +158,24 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar * the bottom most bits. */ - for(int i = FFMAX(0, position + 1); i <= buffer->pos + 1; i++) - tmp = 256*tmp + array[i]; - + if (buffer->pos >= 3) { // Common case; we have at least 4 bytes available + tmp = array[buffer->pos - 3]; + tmp = (tmp << 8) | array[buffer->pos - 2]; + tmp = (tmp << 8) | array[buffer->pos - 1]; + tmp = (tmp << 8) | array[buffer->pos]; + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection + buffer->pos -= 4; + } else { + if (buffer->pos >= 2) + tmp = array[buffer->pos - 2]; + if (buffer->pos >= 1) + tmp = (tmp << 8) | array[buffer->pos - 1]; + if (buffer->pos >= 0) + tmp = (tmp << 8) | array[buffer->pos]; + buffer->pos = 0; + tmp = (tmp << 8) | buffer->last; // For stuffing bit detection + } + // Now remove any stuffing bits, shifting things down as we go if ((tmp & 0x7FFF000000) > 0x7F8F000000) { tmp &= 0x7FFFFFFFFF; new_bits--; @@ -176,13 +192,11 @@ static int jpeg2000_bitbuf_refill_backwards(StateVars *buffer, const uint8_t *ar tmp = (tmp & 0x0000007FFF) + ((tmp & 0xFFFFFF0000) >> 1); new_bits--; } - - tmp >>= 8; // Remove temporary byte loaded + tmp >>= 8; // Shifts away the extra byte we imported /* Add bits to the MSB of the bit buffer */ buffer->bit_buf |= tmp << buffer->bits_left; buffer->bits_left += new_bits; - buffer->pos = FFMAX(0, position); return 0; } @@ -406,6 +420,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t E[n] = 32 - ff_clz(v[pos][i] | 1); mu_n[n] = (v[pos][i] >> 1) + 1; mu_n[n] <<= pLSB; + mu_n[n] |= (1 << (pLSB - 1)); // Add 0.5 (reconstruction parameter = 1/2) mu_n[n] |= ((uint32_t) (v[pos][i] & 1)) << 31; // sign bit. } } @@ -414,7 +429,7 @@ static void recover_mag_sgn(StateVars *mag_sgn, uint8_t pos, uint16_t q, int32_t static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t length) { int cond = stream->pos < length; - int pos = FFMIN(stream->pos, length); + int pos = FFMIN(stream->pos, length - 1); if (stream->bits == 0) { stream->bits = (stream->tmp == 0xFF) ? 7 : 8; stream->pos += cond; @@ -426,14 +441,22 @@ static int jpeg2000_import_bit(StateVars *stream, const uint8_t *array, uint32_t static int jpeg2000_peek_bit(StateVars *stream, const uint8_t *array, uint32_t length) { + uint8_t bit; + if (stream->bits == 0) { - int cond = stream->pos < length; - int pos = FFMIN(stream->pos, length); - stream->bits = (stream->tmp == 0xFF) ? 7 : 8; - stream->pos += cond; - stream->tmp = cond ? array[pos] : 0xFF; + stream->bits = (stream->last == 0xFF) ? 7 : 8; + if (stream->pos < length) { + stream->tmp = array[stream->pos]; + stream->pos++; + } else { + stream->tmp = 0; + } + stream->last = stream->tmp; } - return (stream->tmp >> stream->bits) & 1; + bit = stream->tmp & 1; + stream->tmp >>= 1; + stream->bits--; + return bit; } static int jpeg2000_decode_mel_sym(MelDecoderState *mel_state, @@ -994,39 +1017,18 @@ static void jpeg2000_calc_mbr(uint8_t *mbr, const uint16_t i, const uint16_t j, const uint32_t mbr_info, uint8_t causal_cond, uint8_t *block_states, int stride) { - int local_mbr = 0; - - local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SIGMA, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_SIGMA, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SIGMA, block_states); - - local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SIGMA, block_states); - local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SIGMA, block_states); - - local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SIGMA, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SIGMA, block_states) * causal_cond; - - local_mbr |= jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 0, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i - 1, j - 1, stride, HT_SHIFT_SCAN, block_states); - local_mbr |= jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i - 1, j + 1, stride, HT_SHIFT_SCAN, block_states); - - local_mbr |= jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 0, j - 1, stride, HT_SHIFT_SCAN, block_states); - local_mbr |= jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 0, j + 1, stride, HT_SHIFT_SCAN, block_states); - - local_mbr |= jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 1, j - 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 1, j + 0, stride, HT_SHIFT_SCAN, block_states) * causal_cond; - local_mbr |= jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_REF, block_states) * - jpeg2000_get_state(i + 1, j + 1, stride, HT_SHIFT_SCAN, block_states) * causal_cond; - - *mbr |= local_mbr; + uint8_t *state_p0 = block_states + i * stride + j; + uint8_t *state_p1 = block_states + (i + 1) * stride + j; + uint8_t *state_p2 = block_states + (i + 2) * stride + j; + + uint8_t mbr0 = state_p0[0] | state_p0[1] | state_p0[2]; + uint8_t mbr1 = state_p1[0] | state_p1[2]; + uint8_t mbr2 = state_p2[0] | state_p2[1] | state_p2[2]; + *mbr = mbr0 | mbr1 | (mbr2 & causal_cond); + *mbr |= (mbr0 >> HT_SHIFT_REF) & (mbr0 >> HT_SHIFT_SCAN); + *mbr |= (mbr1 >> HT_SHIFT_REF) & (mbr1 >> HT_SHIFT_SCAN); + *mbr |= (mbr2 >> HT_SHIFT_REF) & (mbr2 >> HT_SHIFT_SCAN) & causal_cond; + *mbr &= 1; } static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s, @@ -1060,6 +1062,18 @@ static void jpeg2000_process_stripes_block(StateVars *sig_prop, int i_s, int j_s jpeg2000_modify_state(i, j, stride, modify_state, block_states); } } + // decode sign + for (int j = j_s; j < j_s + width; j++) { + for (int i = i_s; i < i_s + height; i++) { + uint8_t bit; + int32_t *sp = &sample_buf[j + (i * (stride))]; + uint8_t *state_p = block_states + (i + 1) * stride + (j + 1); + if ((state_p[0] >> HT_SHIFT_REF) & 1) { + bit = jpeg2000_peek_bit(sig_prop, magref_segment, magref_length); + *sp |= (int32_t)bit << 31; + } + } + } } /** @@ -1130,7 +1144,8 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int uint16_t height = 4; uint16_t i_start = 0; int32_t *sp; - + int32_t bit; + int32_t tmp; jpeg2000_init_mag_ref(&mag_ref, magref_length); for (int n1 = 0; n1 < num_v_stripe; n1++) { @@ -1141,9 +1156,13 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int * Rec. ITU-T T.814, Figure 7. */ sp = &sample_buf[j + i * stride]; - if (jpeg2000_get_state(i, j, width, HT_SHIFT_SIGMA, block_states) != 0) { - jpeg2000_modify_state(i, j, width, 1 << HT_SHIFT_REF_IND, block_states); - *sp |= jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length) << pLSB; + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) { + jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states); + bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length); + tmp = 0xFFFFFFFE | (uint32_t)bit; + tmp <<= pLSB; + sp[0] &= tmp; + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } } } @@ -1153,9 +1172,13 @@ jpeg2000_decode_magref_segment( uint16_t width, uint16_t block_height, const int for (int j = 0; j < width; j++) { for (int i = i_start; i < i_start + height; i++) { sp = &sample_buf[j + i * stride]; - if (jpeg2000_get_state(i, j, width, HT_SHIFT_SIGMA, block_states) != 0) { - jpeg2000_modify_state(i, j, width, 1 << HT_SHIFT_REF_IND, block_states); - *sp |= jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length) << pLSB; + if (jpeg2000_get_state(i, j, stride, HT_SHIFT_SIGMA, block_states) != 0) { + jpeg2000_modify_state(i, j, stride, 1 << HT_SHIFT_REF_IND, block_states); + bit = jpeg2000_import_magref_bit(&mag_ref, magref_segment, magref_length); + tmp = 0xFFFFFFFE | (uint32_t)bit; + tmp <<= pLSB; + sp[0] &= tmp; + sp[0] |= 1 << (pLSB - 1); // Add 0.5 (reconstruction parameter = 1/2) } } } @@ -1233,6 +1256,9 @@ ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *c } Dcup = cblk->data; Dref = cblk->data + Lcup; // Dref comes after the refinement segment + + cblk->data[cblk->length] = 0xFF; // an extra byte for refinement segment (buffer->last) + S_blk = p0 + cblk->zbp; cblk->zbp = S_blk - 1; pLSB = 30 - S_blk; diff --git a/libavcodec/jpeg2000htdec.h b/libavcodec/jpeg2000htdec.h index 572d095c92..8d6919a0de 100644 --- a/libavcodec/jpeg2000htdec.h +++ b/libavcodec/jpeg2000htdec.h @@ -29,6 +29,6 @@ int ff_jpeg2000_decode_htj2k(const Jpeg2000DecoderContext *s, Jpeg2000CodingStyle *codsty, Jpeg2000T1Context *t1, Jpeg2000Cblk *cblk, int width, - int height, int magp, uint8_t roi_shift); + int height, int M_b, uint8_t roi_shift); #endif /* AVCODEC_JPEG2000HTDEC_H */