[FFmpeg-devel] [PATCH 5/5] [RFC] libavcodec/ffv1enc: Support storing LSB raw
Michael Niedermayer
michael at niedermayer.cc
Thu Oct 10 23:45:28 EEST 2024
This makes a 16bit RGB raw sample 25% faster at a 2% loss of compression with rawlsb=4
Please test and comment, especially if you are an archivist caring about compression and speed
Id like to know if this is a direction (that is trading compression against speed) that
is wanted
Note, this only implements the encoder side, you cannot decode this ATM, its only for testing
compression and speed
Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
---
libavcodec/ffv1.h | 1 +
libavcodec/ffv1enc.c | 135 +++++++++++++++++++++++++++++++---
libavcodec/ffv1enc_template.c | 8 ++
3 files changed, 134 insertions(+), 10 deletions(-)
diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h
index b98f0b36855..0a8790fdb1b 100644
--- a/libavcodec/ffv1.h
+++ b/libavcodec/ffv1.h
@@ -136,6 +136,7 @@ typedef struct FFV1Context {
int intra;
int key_frame_ok;
int context_model;
+ int rawlsb;
int bits_per_raw_sample;
int packed_at_lsb;
diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
index 30d8073c8d4..ef139d0f4e7 100644
--- a/libavcodec/ffv1enc.c
+++ b/libavcodec/ffv1enc.c
@@ -290,17 +290,17 @@ static int encode_plane(FFV1Context *f, FFV1SliceContext *sc,
sample[1][ w]= sample[1][w-1];
if (f->bits_per_raw_sample <= 8) {
for (x = 0; x < w; x++)
- sample[0][x] = src[x * pixel_stride + stride * y];
+ sample[0][x] = src[x * pixel_stride + stride * y] >> f->rawlsb;
if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, 8, ac, pass1)) < 0)
return ret;
} else {
if (f->packed_at_lsb) {
for (x = 0; x < w; x++) {
- sample[0][x] = ((uint16_t*)(src + stride*y))[x];
+ sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> f->rawlsb;
}
} else {
for (x = 0; x < w; x++) {
- sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> (16 - f->bits_per_raw_sample);
+ sample[0][x] = ((uint16_t*)(src + stride*y))[x] >> (16 - f->bits_per_raw_sample + f->rawlsb);
}
}
if((ret = encode_line(f, sc, f->avctx, w, sample, plane_index, f->bits_per_raw_sample, ac, pass1)) < 0)
@@ -310,6 +310,82 @@ static int encode_plane(FFV1Context *f, FFV1SliceContext *sc,
return 0;
}
+static int encode_plane_rawlsb(FFV1Context *f, FFV1SliceContext *sc,
+ const uint8_t *src, int w, int h,
+ int stride, int plane_index, int pixel_stride)
+{
+ int x, y;
+ unsigned masklsb = (1 << f->rawlsb) - 1;
+ PutBitContext *pb = &sc->pb;
+
+ for (y = 0; y < h; y++) {
+ if (f->bits_per_raw_sample <= 8) {
+ for (x = 0; x < w; x++)
+ put_bits(pb, f->rawlsb, src[x * pixel_stride + stride * y] & masklsb);
+ } else {
+ if (f->packed_at_lsb) {
+ for (x = 0; x < w; x++)
+ put_bits(pb, f->rawlsb, ((uint16_t*)(src + stride*y))[x] & masklsb);
+ } else {
+ for (x = 0; x < w; x++)
+ put_bits(pb, f->rawlsb, (((uint16_t*)(src + stride*y))[x] >> (16 - f->bits_per_raw_sample)) & masklsb);
+ }
+ }
+ }
+ return 0;
+}
+
+static int encode_rgb_frame_rawlsb(FFV1Context *f, FFV1SliceContext *sc,
+ const uint8_t *src[4],
+ int w, int h, const int stride[4])
+{
+ unsigned masklsb = (1 << f->rawlsb) - 1;
+ PutBitContext *pb = &sc->pb;
+ int x, y;
+ int lbd = f->bits_per_raw_sample <= 8;
+ int packed = !src[1];
+ int transparency = f->transparency;
+ int packed_size = (3 + transparency)*2;
+
+ for (y = 0; y < h; y++) {
+ for (x = 0; x < w; x++) {
+ int b, g, r, av_uninit(a);
+ if (lbd) {
+ unsigned v = *((const uint32_t*)(src[0] + x*4 + stride[0]*y));
+ b = v & 0xFF;
+ g = (v >> 8) & 0xFF;
+ r = (v >> 16) & 0xFF;
+ a = v >> 24;
+ } else if (packed) {
+ const uint16_t *p = ((const uint16_t*)(src[0] + x*packed_size + stride[0]*y));
+ r = p[0];
+ g = p[1];
+ b = p[2];
+ if (transparency)
+ a = p[3];
+ } else 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));
+ }
+
+ put_bits(pb, f->rawlsb, r & masklsb);
+ put_bits(pb, f->rawlsb, g & masklsb);
+ put_bits(pb, f->rawlsb, b & masklsb);
+ if (transparency)
+ put_bits(pb, f->rawlsb, a & masklsb);
+ }
+ }
+ return 0;
+}
+
+
static void write_quant_table(RangeCoder *c, int16_t *quant_table)
{
int last = 0;
@@ -564,6 +640,9 @@ static av_cold int encode_init(AVCodecContext *avctx)
if (s->ec == 2)
s->version = FFMAX(s->version, 4);
+ if (s->rawlsb)
+ s->version = FFMAX(s->version, 4);
+
if ((s->version == 2 || s->version>3) && avctx->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
av_log(avctx, AV_LOG_ERROR, "Version 2 or 4 needed for requested features but version 2 or 4 is experimental and not enabled\n");
return AVERROR_INVALIDDATA;
@@ -716,6 +795,11 @@ static av_cold int encode_init(AVCodecContext *avctx)
}
}
+ if (s->rawlsb > s->bits_per_raw_sample) {
+ av_log(avctx, AV_LOG_ERROR, "too many raw lsb\n");
+ return AVERROR(EINVAL);
+ }
+
if (s->ac == AC_RANGE_CUSTOM_TAB) {
for (i = 1; i < 256; i++)
s->state_transition[i] = ver2_state[i];
@@ -958,6 +1042,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, f->rawlsb, 0);
}
}
@@ -1113,13 +1198,6 @@ retry:
ret = encode_rgb_frame(f, sc, planes, width, height, p->linesize);
}
- if (f->ac != AC_GOLOMB_RICE) {
- sc->ac_byte_count = ff_rac_terminate(&sc->c, 1);
- } else {
- flush_put_bits(&sc->pb); // FIXME: nicer padding
- sc->ac_byte_count += put_bytes_output(&sc->pb);
- }
-
if (ret < 0) {
av_assert0(sc->slice_coding_mode == 0);
if (f->version < 4 || !f->ac) {
@@ -1132,6 +1210,41 @@ retry:
goto retry;
}
+ if (f->ac != AC_GOLOMB_RICE) {
+ sc->ac_byte_count = ff_rac_terminate(&sc->c, 1);
+ init_put_bits(&sc->pb,
+ sc->c.bytestream_start + sc->ac_byte_count,
+ sc->c.bytestream_end - sc->c.bytestream_start - sc->ac_byte_count);
+ }
+
+ if (f->rawlsb) {
+ if (f->colorspace == 0 && c->pix_fmt != AV_PIX_FMT_YA8) {
+ const int chroma_width = AV_CEIL_RSHIFT(width, f->chroma_h_shift);
+ const int chroma_height = AV_CEIL_RSHIFT(height, f->chroma_v_shift);
+ const int cx = x >> f->chroma_h_shift;
+ const int cy = y >> f->chroma_v_shift;
+
+ encode_plane_rawlsb(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1);
+
+ if (f->chroma_planes) {
+ encode_plane_rawlsb(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1);
+ encode_plane_rawlsb(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1);
+ }
+ if (f->transparency)
+ encode_plane_rawlsb(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 1);
+ } else if (c->pix_fmt == AV_PIX_FMT_YA8) {
+ encode_plane_rawlsb(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2);
+ encode_plane_rawlsb(f, sc, p->data[0] + 1 + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2);
+ } else {
+ encode_rgb_frame_rawlsb(f, sc, planes, width, height, p->linesize);
+ }
+ }
+
+ if (f->ac == AC_GOLOMB_RICE || f->rawlsb) {
+ flush_put_bits(&sc->pb); // FIXME: nicer padding
+ sc->ac_byte_count += put_bytes_output(&sc->pb);
+ }
+
return 0;
}
@@ -1289,6 +1402,8 @@ static const AVOption options[] = {
{ .i64 = 1 }, INT_MIN, INT_MAX, VE, .unit = "coder" },
{ "context", "Context model", OFFSET(context_model), AV_OPT_TYPE_INT,
{ .i64 = 0 }, 0, 1, VE },
+ { "rawlsb", "number of LSBs stored RAW", OFFSET(rawlsb), AV_OPT_TYPE_INT,
+ { .i64 = 0 }, 0, 16, VE },
{ NULL }
};
diff --git a/libavcodec/ffv1enc_template.c b/libavcodec/ffv1enc_template.c
index bc14926ab95..6e0ae10a15d 100644
--- a/libavcodec/ffv1enc_template.c
+++ b/libavcodec/ffv1enc_template.c
@@ -180,6 +180,14 @@ static int RENAME(encode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc,
r = *((const uint16_t *)(src[2] + x*2 + stride[2]*y));
}
+ if (f->rawlsb) {
+ r >>= f->rawlsb;
+ g >>= f->rawlsb;
+ b >>= f->rawlsb;
+ if (transparency)
+ a >>= f->rawlsb;
+ }
+
if (sc->slice_coding_mode != 1) {
b -= g;
r -= g;
--
2.47.0
More information about the ffmpeg-devel
mailing list