From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <ffmpeg-devel-bounces@ffmpeg.org> Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by master.gitmailbox.com (Postfix) with ESMTPS id 871F14C2E9 for <ffmpegdev@gitmailbox.com>; Thu, 3 Apr 2025 00:36:46 +0000 (UTC) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 49DA668B1B4; Thu, 3 Apr 2025 03:36:44 +0300 (EEST) Received: from relay2-d.mail.gandi.net (relay2-d.mail.gandi.net [217.70.183.194]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 0E7F168B0A7 for <ffmpeg-devel@ffmpeg.org>; Thu, 3 Apr 2025 03:36:38 +0300 (EEST) Received: by mail.gandi.net (Postfix) with ESMTPSA id 569E743C15 for <ffmpeg-devel@ffmpeg.org>; Thu, 3 Apr 2025 00:36:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=niedermayer.cc; s=gm1; t=1743640597; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=90YqkL8KArop29jYUXUHqwYogjkTw3vbbOkS9G6kqK0=; b=FAi7a4/BglKUB9shlYMzfXBBMjZdEVlWBEXP1rS2vHqgrBUmsX/K37JOQPDr9J8s/GdnGK jPCN2A6MzNh0qzW64GFuGHfrSQbfuojBH3j0Z5GGTA+VygA3f0BS7Rb2iDGG5SzNd+sk+3 SiZy1q54crP/YicxLtzEjOGCJ7YKHbkKHp9Jw0+hSziXmd2a8jPSeHlPwtcLPNFB3lUaMz +sWskPkvlBp4Rs9WUUMcBQ2Te/pvMNAWu4m3xGRhci/PzNaCl/Ih/6lVwtFxV4GmrO1Uas 7zlBkqwaLmMKlauksOpBjwPKqvu0nAyO7B/WWzOSJ2rddZsp075Y+v0UNnGVaw== From: Michael Niedermayer <michael@niedermayer.cc> To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Date: Thu, 3 Apr 2025 02:36:36 +0200 Message-ID: <20250403003636.106191-1-michael@niedermayer.cc> X-Mailer: git-send-email 2.49.0 MIME-Version: 1.0 X-GND-State: clean X-GND-Score: -70 X-GND-Cause: gggruggvucftvghtrhhoucdtuddrgeefvddrtddtgddukeejuddvucetufdoteggodetrfdotffvucfrrhhofhhilhgvmecuifetpfffkfdpucggtfgfnhhsuhgsshgtrhhisggvnecuuegrihhlohhuthemuceftddunecusecvtfgvtghiphhivghnthhsucdlqddutddtmdenfghrlhcuvffnffculdeftddmnecujfgurhephffvufffkffoggfgsedtkeertdertddtnecuhfhrohhmpefoihgthhgrvghlucfpihgvuggvrhhmrgihvghruceomhhitghhrggvlhesnhhivgguvghrmhgrhigvrhdrtggtqeenucggtffrrghtthgvrhhnpefhledvvdehgfettdefueevtdeifffhkeeljeetjeeugfelgfffieduheevvefgvdenucfkphepgedurdeiiedrieejrdduudefnecuvehluhhsthgvrhfuihiivgeptdenucfrrghrrghmpehinhgvthepgedurdeiiedrieejrdduudefpdhhvghloheplhhotggrlhhhohhsthdpmhgrihhlfhhrohhmpehmihgthhgrvghlsehnihgvuggvrhhmrgihvghrrdgttgdpnhgspghrtghpthhtohepuddprhgtphhtthhopehffhhmphgvghdquggvvhgvlhesfhhfmhhpvghgrdhorhhg X-GND-Sasl: michael@niedermayer.cc Subject: [FFmpeg-devel] [PATCH v2] avcodec/ffv1: Store slices*planes with the minimum bits needed after remap X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches <ffmpeg-devel.ffmpeg.org> List-Unsubscribe: <https://ffmpeg.org/mailman/options/ffmpeg-devel>, <mailto:ffmpeg-devel-request@ffmpeg.org?subject=unsubscribe> List-Archive: <https://ffmpeg.org/pipermail/ffmpeg-devel> List-Post: <mailto:ffmpeg-devel@ffmpeg.org> List-Help: <mailto:ffmpeg-devel-request@ffmpeg.org?subject=help> List-Subscribe: <https://ffmpeg.org/mailman/listinfo/ffmpeg-devel>, <mailto:ffmpeg-devel-request@ffmpeg.org?subject=subscribe> Reply-To: FFmpeg development discussions and patches <ffmpeg-devel@ffmpeg.org> Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" <ffmpeg-devel-bounces@ffmpeg.org> Archived-At: <https://master.gitmailbox.com/ffmpegdev/20250403003636.106191-1-michael@niedermayer.cc/> List-Archive: <https://master.gitmailbox.com/ffmpegdev/> List-Post: <mailto:ffmpegdev@gitmailbox.com> This also means that if a plane*slice has only 1 color nothing is stored after the remap table This improves compression, but more tests are needed This also corrects the RCT offset to the exact value after remap not a fixed 65536 Signed-off-by: Michael Niedermayer <michael@niedermayer.cc> --- libavcodec/ffv1.c | 37 +++++++++++++++++++++++++++++++++++ libavcodec/ffv1.h | 2 ++ libavcodec/ffv1dec.c | 17 +++++++++++++--- libavcodec/ffv1dec_template.c | 32 ++++++++++++++++++------------ libavcodec/ffv1enc.c | 15 +++++++++----- libavcodec/ffv1enc_template.c | 12 ++++++++---- 6 files changed, 91 insertions(+), 24 deletions(-) diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c index cff16c5cc76..86fe9455c4c 100644 --- a/libavcodec/ffv1.c +++ b/libavcodec/ffv1.c @@ -219,6 +219,43 @@ void ff_ffv1_clear_slice_state(const FFV1Context *f, FFV1SliceContext *sc) } } +void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, int bits[4], int *offset, int mask[4], int bits_per_raw_sample) +{ + // to simplify we use the remap_count as the symbol range in each plane + if (!sc->remap) { + sc->remap_count[0] = + sc->remap_count[1] = + sc->remap_count[2] = + sc->remap_count[3] = 1 << (bits_per_raw_sample > 0 ? bits_per_raw_sample : 8); + } + + if (sc->remap) + av_assert0(bits_per_raw_sample > 8); //breaks with lbd, needs review if added + + //bits with no RCT + for (int p=0; p<3+f->transparency; p++) { + bits[p] = av_ceil_log2(sc->remap_count[p]); + if (mask) + mask[p] = (1<<bits[p]) - 1; + } + + //RCT + if (sc->slice_coding_mode == 0) { + *offset = sc->remap_count[0]; + + bits[0] = av_ceil_log2(FFMAX3(sc->remap_count[0], sc->remap_count[1], sc->remap_count[2])); + bits[1] = av_ceil_log2(sc->remap_count[0] + sc->remap_count[1]); + bits[2] = av_ceil_log2(sc->remap_count[0] + sc->remap_count[2]); + + //old version coded a bit more than needed + if (f->combined_version < 0x40008) { + bits[0]++; + if(f->transparency) + bits[3]++; + } + } +} + int ff_ffv1_get_symbol(RangeCoder *c, uint8_t *state, int is_signed) { return get_symbol_inline(c, state, is_signed); diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 24cbb694d41..c95508e2844 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -106,6 +106,7 @@ typedef struct FFV1SliceContext { uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; }; }; + int remap_count[4]; uint16_t *bitmap [4]; //float encode uint16_t *fltmap [4]; //halffloat encode & decode @@ -197,6 +198,7 @@ int ff_ffv1_parse_header(FFV1Context *f, RangeCoder *c, uint8_t *state); int ff_ffv1_read_extra_header(FFV1Context *f); int ff_ffv1_read_quant_tables(RangeCoder *c, int16_t quant_table[MAX_CONTEXT_INPUTS][256]); +void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, int bits[4], int offset[1], int mask[4], int bits_per_raw_sample); int ff_ffv1_get_symbol(RangeCoder *c, uint8_t *state, int is_signed); /** diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index ff7935ed722..dc4eeecc87c 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -99,6 +99,16 @@ static int decode_plane(FFV1Context *f, FFV1SliceContext *sc, { int x, y; int16_t *sample[2]; + int bits; + unsigned mask; + + if (sc->remap) { + bits = av_ceil_log2(sc->remap_count[remap_index]); + mask = (1<<bits)-1; + } else { + bits = f->avctx->bits_per_raw_sample; + } + sample[0] = sc->sample_buffer + 3; sample[1] = sc->sample_buffer + w + 6 + 3; @@ -125,18 +135,18 @@ static int decode_plane(FFV1Context *f, FFV1SliceContext *sc, for (x = 0; x < w; x++) src[x*pixel_stride + stride * y] = sample[1][x]; } else { - int ret = decode_line(f, sc, gb, w, sample, plane_index, f->avctx->bits_per_raw_sample, ac); + int ret = decode_line(f, sc, gb, w, sample, plane_index, bits, ac); if (ret < 0) return ret; if (sc->remap) { if (f->packed_at_lsb || f->avctx->bits_per_raw_sample == 16) { for (x = 0; x < w; x++) { - ((uint16_t*)(src + stride*y))[x*pixel_stride] = sc->fltmap[remap_index][sample[1][x] & 0xFFFF]; + ((uint16_t*)(src + stride*y))[x*pixel_stride] = sc->fltmap[remap_index][sample[1][x] & mask]; } } else { for (x = 0; x < w; x++) { - int v = sc->fltmap[remap_index][sample[1][x] & 0xFFFF]; + int v = sc->fltmap[remap_index][sample[1][x] & mask]; ((uint16_t*)(src + stride*y))[x*pixel_stride] = v << (16 - f->avctx->bits_per_raw_sample) | v >> (2 * f->avctx->bits_per_raw_sample - 16); } } @@ -340,6 +350,7 @@ static int decode_remap(FFV1Context *f, FFV1SliceContext *sc) } lu ^= !run; } + sc->remap_count[p] = j; } return 0; } diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index 97116a6dc5b..b88195cfba3 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -36,6 +36,12 @@ RENAME(decode_line)(FFV1Context *f, FFV1SliceContext *sc, int run_mode = 0; int run_index = sc->run_index; + if (bits == 0) { + for (x = 0; x < w; x++) + sample[1][x] = 0; + return 0; + } + if (is_input_end(c, gb, ac)) return AVERROR_INVALIDDATA; @@ -138,10 +144,12 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, int x, y, p; TYPE *sample[4][2]; int lbd = f->avctx->bits_per_raw_sample <= 8; - int bits = f->avctx->bits_per_raw_sample > 0 ? FFMIN(f->avctx->bits_per_raw_sample, 16) : 8; - int offset = 1 << bits; + int bits[4], offset; int transparency = f->transparency; int ac = f->ac; + unsigned mask[4]; + + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, mask, f->avctx->bits_per_raw_sample); if (sc->slice_coding_mode == 1) ac = 1; @@ -165,10 +173,10 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, sample[p][1][-1]= sample[p][0][0 ]; sample[p][0][ w]= sample[p][0][w-1]; - if (lbd && sc->slice_coding_mode == 0) + if (bits[p] == 9) ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, 9, ac); else - ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, bits + (sc->slice_coding_mode != 1), ac); + ret = RENAME(decode_line)(f, sc, gb, w, sample[p], (p + 1)/2, bits[p], ac); if (ret < 0) return ret; } @@ -187,17 +195,17 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, } if (sc->remap) { if (f->avctx->bits_per_raw_sample == 32) { - g = sc->fltmap32[0][g & 0xFFFF]; - b = sc->fltmap32[1][b & 0xFFFF]; - r = sc->fltmap32[2][r & 0xFFFF]; + g = sc->fltmap32[0][g & mask[0]]; + b = sc->fltmap32[1][b & mask[1]]; + r = sc->fltmap32[2][r & mask[2]]; if (transparency) - a = sc->fltmap32[3][a & 0xFFFF]; + a = sc->fltmap32[3][a & mask[3]]; } else { - g = sc->fltmap[0][g & 0xFFFF]; - b = sc->fltmap[1][b & 0xFFFF]; - r = sc->fltmap[2][r & 0xFFFF]; + g = sc->fltmap[0][g & mask[0]]; + b = sc->fltmap[1][b & mask[1]]; + r = sc->fltmap[2][r & mask[2]]; if (transparency) - a = sc->fltmap[3][a & 0xFFFF]; + a = sc->fltmap[3][a & mask[3]]; } } diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index b704cec9f3a..8f61b183eb0 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -433,7 +433,7 @@ static void set_micro_version(FFV1Context *f) if (f->version == 3) { f->micro_version = 4; } else if (f->version == 4) { - f->micro_version = 7; + f->micro_version = 8; } else av_assert0(0); @@ -1216,6 +1216,7 @@ static void encode_histogram_remap(FFV1Context *f, FFV1SliceContext *sc) } if (run) put_symbol(&sc->c, state[lu], run, 0); + sc->remap_count[p] = j; } } @@ -1370,7 +1371,8 @@ static int encode_float32_remap_segment(FFV1SliceContext *sc, mul[ current_mul_index ] *= -1; put_symbol_inline(&rc, state[0][2], mul[ current_mul_index ], 0, NULL, NULL); } - compact_index ++; + if (i < pixel_num) + compact_index ++; } } if (!run || run1final) @@ -1380,6 +1382,8 @@ static int encode_float32_remap_segment(FFV1SliceContext *sc, if (update) { sc->c = rc; + av_assert0(compact_index <= 65535); + sc->remap_count[p] = compact_index + 1; } return get_rac_count(&rc); } @@ -1492,10 +1496,11 @@ static int encode_float32_rgb_frame(FFV1Context *f, FFV1SliceContext *sc, const int ring_size = f->context_model ? 3 : 2; int32_t *sample[4][3]; const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); - int bits = 16; //TODO explain this in the specifciation, we have 32bits in but really encode max 16 - int offset = 1 << bits; + int bits[4], offset; int transparency = f->transparency; + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, NULL, f->bits_per_raw_sample); + sc->run_index = 0; memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * @@ -1532,7 +1537,7 @@ static int encode_float32_rgb_frame(FFV1Context *f, FFV1SliceContext *sc, sample[p][0][-1] = sample[p][1][0 ]; sample[p][1][ w] = sample[p][1][w-1]; ret = encode_line32(f, sc, f->avctx, w, sample[p], (p + 1) / 2, - bits + (sc->slice_coding_mode != 1), ac, pass1); + bits[p], ac, pass1); if (ret < 0) return ret; } diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c index 85d09da99a5..64f3c420c51 100644 --- a/libavcodec/ffv1enc_template.c +++ b/libavcodec/ffv1enc_template.c @@ -35,6 +35,9 @@ RENAME(encode_line)(FFV1Context *f, FFV1SliceContext *sc, int run_count = 0; int run_mode = 0; + if (bits == 0) + return 0; + if (ac != AC_GOLOMB_RICE) { if (c->bytestream_end - c->bytestream < w * 35) { av_log(logctx, AV_LOG_ERROR, "encoded Range Coder frame too large\n"); @@ -172,11 +175,12 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); int lbd = f->bits_per_raw_sample <= 8; int packed = !src[1]; - int bits = f->bits_per_raw_sample > 0 ? f->bits_per_raw_sample : 8; - int offset = 1 << bits; + int bits[4], offset; int transparency = f->transparency; int packed_size = (3 + transparency)*2; + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, NULL, f->bits_per_raw_sample); + sc->run_index = 0; memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * @@ -239,11 +243,11 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, int ret; sample[p][0][-1] = sample[p][1][0 ]; sample[p][1][ w] = sample[p][1][w-1]; - if (lbd && sc->slice_coding_mode == 0) + if (bits[p] == 9) ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, 9, ac, pass1); else ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], (p + 1) / 2, - bits + (sc->slice_coding_mode != 1), ac, pass1); + bits[p], ac, pass1); if (ret < 0) return ret; } -- 2.49.0 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".