* [FFmpeg-devel] [PATCH 1/2] avcodec/ffv1: flip half of float16 and Compactify floats @ 2025-01-18 22:50 Michael Niedermayer 2025-01-18 22:50 ` [FFmpeg-devel] [PATCH 2/2] avcodec/ffv1: Store remap flag per slice Michael Niedermayer 0 siblings, 1 reply; 2+ messages in thread From: Michael Niedermayer @ 2025-01-18 22:50 UTC (permalink / raw) To: FFmpeg development discussions and patches float16 (and more so float32) have many odd values half the values are negative, many are larger than "1.0" and many values are very close to 0. Storing the 16bits as is, looses compression because of the mixture of dense and sparse regions and also many completely unused ones. This simply remaps the 65536 values so no unused values remain This improves compression by about 1.5% for the ACES_OT_VWG_SampleFrames testset (this testset contains all kind of funny values including many images with negative rgb values) The space needed for the map is insignificant compared to the compression gained This patch also flips half the float range as it can be done using the same table. Sponsored-by: Sovereign Tech Fund Signed-off-by: Michael Niedermayer <michael@niedermayer.cc> --- libavcodec/ffv1.h | 1 + libavcodec/ffv1dec_template.c | 21 +++++++++++++++ libavcodec/ffv1enc_template.c | 49 +++++++++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+) diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 2c2df154037..bf49f613a75 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -104,6 +104,7 @@ typedef struct FFV1SliceContext { uint64_t (*rc_stat2[MAX_QUANT_TABLES])[32][2]; }; }; + uint16_t fltmap[4][65536]; } FFV1SliceContext; typedef struct FFV1Context { diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index e983d1ba648..a419aca8584 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -155,6 +155,20 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, memset(RENAME(sc->sample_buffer), 0, 8 * (w + 6) * sizeof(*RENAME(sc->sample_buffer))); + if (f->flt) { + for (int p= 0; p<3 + transparency; p++) { + int j = 0; + int lu = 0; + uint8_t state[2] = {128, 128}; + for (int i= 0; i<65536; i++) { + int u = get_rac(&sc->c, state + lu); + sc->fltmap[p][j] = i ^ ((i&0x8000) ? 0 : 0x7FFF); + j+= u; + lu = u; + } + } + } + for (y = 0; y < h; y++) { for (p = 0; p < 3 + transparency; p++) { int ret; @@ -185,6 +199,13 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, b += g; r += g; } + if (f->flt) { + r = sc->fltmap[0][r]; + g = sc->fltmap[1][g]; + b = sc->fltmap[2][b]; + if (transparency) + a = sc->fltmap[3][a]; + } if (lbd) *((uint32_t*)(src[0] + x*4 + stride[0]*y)) = b + ((unsigned)g<<8) + ((unsigned)r<<16) + ((unsigned)a<<24); diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c index bc14926ab95..0d1b0a28432 100644 --- a/libavcodec/ffv1enc_template.c +++ b/libavcodec/ffv1enc_template.c @@ -148,6 +148,47 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * (w + 6) * sizeof(*RENAME(sc->sample_buffer))); + if (f->flt) { + memset(sc->fltmap, 0, sizeof(sc->fltmap)); + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int b, g, r, av_uninit(a); + + if (sizeof(TYPE) == 4 || transparency) { + g = *((const uint16_t *)(src[0] + x*2 + stride[0]*y)); + b = *((const uint16_t *)(src[1] + x*2 + stride[1]*y)); + r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); + if (transparency) + a = *((const uint16_t *)(src[3] + x*2 + stride[3]*y)); + } else { + b = *((const uint16_t *)(src[0] + x*2 + stride[0]*y)); + g = *((const uint16_t *)(src[1] + x*2 + stride[1]*y)); + r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); + } + + sc->fltmap[0][r] = 1; + sc->fltmap[1][g] = 1; + sc->fltmap[2][b] = 1; + if (transparency) + sc->fltmap[3][a] = 1; + } + } + for (int p= 0; p<3 + transparency; p++) { + int j = 0; + int lu = 0; + uint8_t state[2] = {128, 128}; + for (int i= 0; i<65536; i++) { + int ri = i ^ ((i&0x8000) ? 0 : 0x7FFF); + int u = sc->fltmap[p][ri]; + sc->fltmap[p][ri] = j; + j+= u; + put_rac(&sc->c, state + lu, u); + lu = u; + } + } + } + for (y = 0; y < h; y++) { for (i = 0; i < ring_size; i++) for (p = 0; p < MAX_PLANES; p++) @@ -180,6 +221,14 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); } + if (f->flt) { + r = sc->fltmap[0][r]; + g = sc->fltmap[1][g]; + b = sc->fltmap[2][b]; + if (transparency) + a = sc->fltmap[3][a]; + } + if (sc->slice_coding_mode != 1) { b -= g; r -= g; -- 2.48.1 _______________________________________________ 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] 2+ messages in thread
* [FFmpeg-devel] [PATCH 2/2] avcodec/ffv1: Store remap flag per slice 2025-01-18 22:50 [FFmpeg-devel] [PATCH 1/2] avcodec/ffv1: flip half of float16 and Compactify floats Michael Niedermayer @ 2025-01-18 22:50 ` Michael Niedermayer 0 siblings, 0 replies; 2+ messages in thread From: Michael Niedermayer @ 2025-01-18 22:50 UTC (permalink / raw) To: FFmpeg development discussions and patches This allows switching it on conditionally and also for non float, it may improve compression for RGB data that was paletted or other synthetic images Sponsored-by: Sovereign Tech Fund Signed-off-by: Michael Niedermayer <michael@niedermayer.cc> --- libavcodec/ffv1.h | 1 + libavcodec/ffv1dec.c | 8 ++++++++ libavcodec/ffv1dec_template.c | 4 ++-- libavcodec/ffv1enc.c | 3 +++ libavcodec/ffv1enc_template.c | 4 ++-- 5 files changed, 16 insertions(+), 4 deletions(-) diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index bf49f613a75..3254ae1b56b 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -83,6 +83,7 @@ typedef struct FFV1SliceContext { int slice_coding_mode; int slice_rct_by_coef; int slice_rct_ry_coef; + int remap; // RefStruct reference, array of MAX_PLANES elements PlaneContext *plane; diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c index def95ff411f..db3eedcdc3f 100644 --- a/libavcodec/ffv1dec.c +++ b/libavcodec/ffv1dec.c @@ -248,6 +248,14 @@ static int decode_slice_header(const FFV1Context *f, return AVERROR_INVALIDDATA; } } + if (f->combined_version >= 0x40004) { + sc->remap = get_symbol(c, state, 0); + if (sc->remap > 1 || + sc->remap == 1 && !f->flt) { + av_log(f->avctx, AV_LOG_ERROR, "unsupported remap %d\n", sc->remap); + return AVERROR_INVALIDDATA; + } + } } return 0; diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c index a419aca8584..1fa9933d984 100644 --- a/libavcodec/ffv1dec_template.c +++ b/libavcodec/ffv1dec_template.c @@ -155,7 +155,7 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, memset(RENAME(sc->sample_buffer), 0, 8 * (w + 6) * sizeof(*RENAME(sc->sample_buffer))); - if (f->flt) { + if (sc->remap) { for (int p= 0; p<3 + transparency; p++) { int j = 0; int lu = 0; @@ -199,7 +199,7 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, b += g; r += g; } - if (f->flt) { + if (sc->remap) { r = sc->fltmap[0][r]; g = sc->fltmap[1][g]; b = sc->fltmap[2][b]; diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index 8e9f41fea8f..eba2aab4866 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -946,6 +946,8 @@ static int encode_init_internal(AVCodecContext *avctx) } ff_build_rac_states(&s->slices[j].c, 0.05 * (1LL << 32), 256 - 8); + + s->slices[j].remap = s->flt; } if ((ret = ff_ffv1_init_slices_state(s)) < 0) @@ -1000,6 +1002,7 @@ static void encode_slice_header(FFV1Context *f, FFV1SliceContext *sc) put_symbol(c, state, sc->slice_rct_by_coef, 0); put_symbol(c, state, sc->slice_rct_ry_coef, 0); } + put_symbol(c, state, sc->remap, 0); } } diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c index 0d1b0a28432..4c7cd2e647c 100644 --- a/libavcodec/ffv1enc_template.c +++ b/libavcodec/ffv1enc_template.c @@ -148,7 +148,7 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * (w + 6) * sizeof(*RENAME(sc->sample_buffer))); - if (f->flt) { + if (sc->remap) { memset(sc->fltmap, 0, sizeof(sc->fltmap)); for (y = 0; y < h; y++) { @@ -221,7 +221,7 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc, r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y)); } - if (f->flt) { + if (sc->remap) { r = sc->fltmap[0][r]; g = sc->fltmap[1][g]; b = sc->fltmap[2][b]; -- 2.48.1 _______________________________________________ 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] 2+ messages in thread
end of thread, other threads:[~2025-01-18 22:51 UTC | newest] Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2025-01-18 22:50 [FFmpeg-devel] [PATCH 1/2] avcodec/ffv1: flip half of float16 and Compactify floats Michael Niedermayer 2025-01-18 22:50 ` [FFmpeg-devel] [PATCH 2/2] avcodec/ffv1: Store remap flag per slice 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