* [FFmpeg-devel] [PATCH] avcodec/ffv1: Store slices*planes with the minimum bits needed after remap
@ 2025-04-02 21:13 Michael Niedermayer
2025-04-02 21:31 ` Jerome Martinez
0 siblings, 1 reply; 4+ messages in thread
From: Michael Niedermayer @ 2025-04-02 21:13 UTC (permalink / raw)
To: FFmpeg development discussions and patches
This also means that if a plane*slice has only 1 color nothing
is stored after the remap table
This improves compression as wrap around can be cheaper to reach a
value.
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 | 26 ++++++++++++------------
libavcodec/ffv1enc.c | 13 ++++++++----
libavcodec/ffv1enc_template.c | 9 +++++----
6 files changed, 81 insertions(+), 23 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..fe0e42e7e34 100644
--- a/libavcodec/ffv1dec_template.c
+++ b/libavcodec/ffv1dec_template.c
@@ -138,10 +138,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 +167,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 +189,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..368fd2e148e 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -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..62e222f2498 100644
--- a/libavcodec/ffv1enc_template.c
+++ b/libavcodec/ffv1enc_template.c
@@ -172,11 +172,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 +240,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".
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avcodec/ffv1: Store slices*planes with the minimum bits needed after remap
2025-04-02 21:13 [FFmpeg-devel] [PATCH] avcodec/ffv1: Store slices*planes with the minimum bits needed after remap Michael Niedermayer
@ 2025-04-02 21:31 ` Jerome Martinez
2025-04-03 0:07 ` Michael Niedermayer
0 siblings, 1 reply; 4+ messages in thread
From: Jerome Martinez @ 2025-04-02 21:31 UTC (permalink / raw)
To: ffmpeg-devel
Le 02/04/2025 à 23:13, Michael Niedermayer a écrit :
> [...]
>
> This improves compression as wrap around can be cheaper to reach a
> value.
There is an issue in FFV1 version <=3 with RCT, bit depth of resulting
luminance plane was 1 more than needed (RCT adds 1 bit to chrominance
but not to luminance, but with current spec all planes have 1 additional
bit), preventing in practice the wrap around for luminance, do I
understand well that the remap would mitigate such issue?
I wonder if with remap it would still be interesting to have a specific
code for having luminance without this additional useless bit, or if we
just go with the remap.
Maybe it needs tests (performance impact of remap when not really useful
vs just keeping the right bit depth of luminance? would remap be faster
if we keep the right bit depth of luminance?).
Jérôme
_______________________________________________
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".
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avcodec/ffv1: Store slices*planes with the minimum bits needed after remap
2025-04-02 21:31 ` Jerome Martinez
@ 2025-04-03 0:07 ` Michael Niedermayer
2025-04-03 0:35 ` Michael Niedermayer
0 siblings, 1 reply; 4+ messages in thread
From: Michael Niedermayer @ 2025-04-03 0:07 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 975 bytes --]
Hi Jerome
On Wed, Apr 02, 2025 at 11:31:53PM +0200, Jerome Martinez wrote:
> Le 02/04/2025 à 23:13, Michael Niedermayer a écrit :
> > [...]
> >
> > This improves compression as wrap around can be cheaper to reach a
> > value.
>
>
> There is an issue in FFV1 version <=3 with RCT, bit depth of resulting
> luminance plane was 1 more than needed (RCT adds 1 bit to chrominance but
> not to luminance, but with current spec all planes have 1 additional bit),
> preventing in practice the wrap around for luminance, do I understand well
> that the remap would mitigate such issue?
yes, in fact with version 4 that issue is fixed with this patch without remap too
and its not just the luminance plane, its alpha too
thx
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Its not that you shouldnt use gotos but rather that you should write
readable code and code with gotos often but not always is less readable
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: Type: text/plain, Size: 251 bytes --]
_______________________________________________
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".
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [FFmpeg-devel] [PATCH] avcodec/ffv1: Store slices*planes with the minimum bits needed after remap
2025-04-03 0:07 ` Michael Niedermayer
@ 2025-04-03 0:35 ` Michael Niedermayer
0 siblings, 0 replies; 4+ messages in thread
From: Michael Niedermayer @ 2025-04-03 0:35 UTC (permalink / raw)
To: FFmpeg development discussions and patches
[-- Attachment #1.1: Type: text/plain, Size: 1181 bytes --]
On Thu, Apr 03, 2025 at 02:07:36AM +0200, Michael Niedermayer wrote:
> Hi Jerome
>
> On Wed, Apr 02, 2025 at 11:31:53PM +0200, Jerome Martinez wrote:
> > Le 02/04/2025 à 23:13, Michael Niedermayer a écrit :
> > > [...]
> > >
> > > This improves compression as wrap around can be cheaper to reach a
> > > value.
> >
> >
> > There is an issue in FFV1 version <=3 with RCT, bit depth of resulting
> > luminance plane was 1 more than needed (RCT adds 1 bit to chrominance but
> > not to luminance, but with current spec all planes have 1 additional bit),
> > preventing in practice the wrap around for luminance, do I understand well
> > that the remap would mitigate such issue?
>
> yes, in fact with version 4 that issue is fixed with this patch without remap too
correction, with the v2 i will post in a moment. This one
was missing some hunks
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Breaking DRM is a little like attempting to break through a door even
though the window is wide open and the only thing in the house is a bunch
of things you dont want and which you would get tomorrow for free anyway
[-- Attachment #1.2: signature.asc --]
[-- Type: application/pgp-signature, Size: 195 bytes --]
[-- Attachment #2: Type: text/plain, Size: 251 bytes --]
_______________________________________________
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".
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2025-04-03 0:35 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-04-02 21:13 [FFmpeg-devel] [PATCH] avcodec/ffv1: Store slices*planes with the minimum bits needed after remap Michael Niedermayer
2025-04-02 21:31 ` Jerome Martinez
2025-04-03 0:07 ` Michael Niedermayer
2025-04-03 0:35 ` Michael Niedermayer
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
This inbox may be cloned and mirrored by anyone:
git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git
# If you have public-inbox 1.1+ installed, you may
# initialize and index your mirror using the following commands:
public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \
ffmpegdev@gitmailbox.com
public-inbox-index ffmpegdev
Example config snippet for mirrors.
AGPL code for this site: git clone https://public-inbox.org/public-inbox.git