[FFmpeg-devel] [PATCH] avcodec/ffv1: Support slice coding mode 1 with golomb rice
Michael Niedermayer
michael at niedermayer.cc
Sat Oct 26 01:47:19 EEST 2024
On Fri, Oct 25, 2024 at 04:24:04AM +0200, Lynne via ffmpeg-devel wrote:
> On 25/10/2024 03:57, Michael Niedermayer wrote:
> > Sponsored-by: Sovereign Tech Fund
> > Signed-off-by: Michael Niedermayer <michael at niedermayer.cc>
> > ---
> > libavcodec/ffv1dec.c | 20 ++++++++++----------
> > libavcodec/ffv1dec_template.c | 3 +++
> > libavcodec/ffv1enc.c | 23 ++++++++++++-----------
> > 3 files changed, 25 insertions(+), 21 deletions(-)
> >
> > diff --git a/libavcodec/ffv1dec.c b/libavcodec/ffv1dec.c
> > index ac8cc8a31dc..de5abfe9b41 100644
> > --- a/libavcodec/ffv1dec.c
> > +++ b/libavcodec/ffv1dec.c
> > @@ -120,9 +120,8 @@ static int is_input_end(RangeCoder *c, GetBitContext *gb, int ac)
> > static int decode_plane(FFV1Context *f, FFV1SliceContext *sc,
> > GetBitContext *gb,
> > uint8_t *src, int w, int h, int stride, int plane_index,
> > - int pixel_stride)
> > + int pixel_stride, int ac)
> > {
> > - const int ac = f->ac;
> > int x, y;
> > int16_t *sample[2];
> > sample[0] = sc->sample_buffer + 3;
> > @@ -273,6 +272,7 @@ static int decode_slice(AVCodecContext *c, void *arg)
> > AVFrame * const p = f->picture.f;
> > const int si = sc - f->slices;
> > GetBitContext gb;
> > + int ac = f->ac || sc->slice_coding_mode == 1;
> > if (!(p->flags & AV_FRAME_FLAG_KEY) && f->last_picture.f)
> > ff_progress_frame_await(&f->last_picture, si);
> > @@ -305,7 +305,7 @@ static int decode_slice(AVCodecContext *c, void *arg)
> > x = sc->slice_x;
> > y = sc->slice_y;
> > - if (f->ac == AC_GOLOMB_RICE) {
> > + if (ac == AC_GOLOMB_RICE) {
> > if (f->version == 3 && f->micro_version > 1 || f->version > 3)
> > get_rac(&sc->c, (uint8_t[]) { 129 });
> > sc->ac_byte_count = f->version > 2 || (!x && !y) ? sc->c.bytestream - sc->c.bytestream_start - 1 : 0;
> > @@ -320,17 +320,17 @@ static int decode_slice(AVCodecContext *c, void *arg)
> > 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;
> > - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1);
> > + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1, ac);
> > if (f->chroma_planes) {
> > - decode_plane(f, sc, &gb, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1);
> > - decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1);
> > + decode_plane(f, sc, &gb, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1, ac);
> > + decode_plane(f, sc, &gb, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1, ac);
> > }
> > if (f->transparency)
> > - decode_plane(f, sc, &gb, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2, 1);
> > + decode_plane(f, sc, &gb, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], (f->version >= 4 && !f->chroma_planes) ? 1 : 2, 1, ac);
> > } else if (f->colorspace == 0) {
> > - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 2);
> > - decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + 1, width, height, p->linesize[0], 1, 2);
> > + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] , width, height, p->linesize[0], 0, 2, ac);
> > + decode_plane(f, sc, &gb, p->data[0] + ps*x + y*p->linesize[0] + 1, width, height, p->linesize[0], 1, 2, ac);
> > } else if (f->use32bit) {
> > uint8_t *planes[4] = { p->data[0] + ps * x + y * p->linesize[0],
> > p->data[1] + ps * x + y * p->linesize[1],
> > @@ -344,7 +344,7 @@ static int decode_slice(AVCodecContext *c, void *arg)
> > p->data[3] + ps * x + y * p->linesize[3] };
> > decode_rgb_frame(f, sc, &gb, planes, width, height, p->linesize);
> > }
> > - if (f->ac != AC_GOLOMB_RICE && f->version > 2) {
> > + if (ac != AC_GOLOMB_RICE && f->version > 2) {
> > int v;
> > get_rac(&sc->c, (uint8_t[]) { 129 });
> > v = sc->c.bytestream_end - sc->c.bytestream - 2 - 5*!!f->ec;
> > diff --git a/libavcodec/ffv1dec_template.c b/libavcodec/ffv1dec_template.c
> > index 2da6bd935dc..e983d1ba648 100644
> > --- a/libavcodec/ffv1dec_template.c
> > +++ b/libavcodec/ffv1dec_template.c
> > @@ -143,6 +143,9 @@ static int RENAME(decode_rgb_frame)(FFV1Context *f, FFV1SliceContext *sc,
> > int transparency = f->transparency;
> > int ac = f->ac;
> > + if (sc->slice_coding_mode == 1)
> > + ac = 1;
> > +
> > for (x = 0; x < 4; x++) {
> > sample[x][0] = RENAME(sc->sample_buffer) + x * 2 * (w + 6) + 3;
> > sample[x][1] = RENAME(sc->sample_buffer) + (x * 2 + 1) * (w + 6) + 3;
> > diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c
> > index a32059886c0..547fb598d6d 100644
> > --- a/libavcodec/ffv1enc.c
> > +++ b/libavcodec/ffv1enc.c
> > @@ -271,10 +271,9 @@ static inline void put_vlc_symbol(PutBitContext *pb, VlcState *const state,
> > static int encode_plane(FFV1Context *f, FFV1SliceContext *sc,
> > const uint8_t *src, int w, int h,
> > - int stride, int plane_index, int pixel_stride)
> > + int stride, int plane_index, int pixel_stride, int ac)
> > {
> > int x, y, i, ret;
> > - const int ac = f->ac;
> > const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1);
> > const int ring_size = f->context_model ? 3 : 2;
> > int16_t *sample[3];
> > @@ -1068,6 +1067,7 @@ static int encode_slice(AVCodecContext *c, void *arg)
> > p->data[1] ? p->data[1] + ps*x + y*p->linesize[1] : NULL,
> > p->data[2] ? p->data[2] + ps*x + y*p->linesize[2] : NULL,
> > p->data[3] ? p->data[3] + ps*x + y*p->linesize[3] : NULL};
> > + int ac = f->ac;
> > sc->slice_coding_mode = 0;
> > if (f->version > 3 && f->colorspace == 1) {
> > @@ -1083,7 +1083,7 @@ retry:
> > if (f->version > 2) {
> > encode_slice_header(f, sc);
> > }
> > - if (f->ac == AC_GOLOMB_RICE) {
> > + if (ac == AC_GOLOMB_RICE) {
> > sc->ac_byte_count = f->version > 2 || (!x && !y) ? ff_rac_terminate(&sc->c, f->version > 2) : 0;
> > init_put_bits(&sc->pb,
> > sc->c.bytestream_start + sc->ac_byte_count,
> > @@ -1096,24 +1096,24 @@ retry:
> > const int cx = x >> f->chroma_h_shift;
> > const int cy = y >> f->chroma_v_shift;
> > - ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1);
> > + ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 1, ac);
> > if (f->chroma_planes) {
> > - ret |= encode_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1);
> > - ret |= encode_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1);
> > + ret |= encode_plane(f, sc, p->data[1] + ps*cx+cy*p->linesize[1], chroma_width, chroma_height, p->linesize[1], 1, 1, ac);
> > + ret |= encode_plane(f, sc, p->data[2] + ps*cx+cy*p->linesize[2], chroma_width, chroma_height, p->linesize[2], 1, 1, ac);
> > }
> > if (f->transparency)
> > - ret |= encode_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 1);
> > + ret |= encode_plane(f, sc, p->data[3] + ps*x + y*p->linesize[3], width, height, p->linesize[3], 2, 1, ac);
> > } else if (c->pix_fmt == AV_PIX_FMT_YA8) {
> > - ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2);
> > - ret |= encode_plane(f, sc, p->data[0] + 1 + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2);
> > + ret = encode_plane(f, sc, p->data[0] + ps*x + y*p->linesize[0], width, height, p->linesize[0], 0, 2, ac);
> > + ret |= encode_plane(f, sc, p->data[0] + 1 + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 2, ac);
> > } else if (f->use32bit) {
> > ret = encode_rgb_frame32(f, sc, planes, width, height, p->linesize);
> > } else {
> > ret = encode_rgb_frame(f, sc, planes, width, height, p->linesize);
> > }
> > - if (f->ac != AC_GOLOMB_RICE) {
> > + if (ac != AC_GOLOMB_RICE) {
> > sc->ac_byte_count = ff_rac_terminate(&sc->c, 1);
> > } else {
> > flush_put_bits(&sc->pb); // FIXME: nicer padding
> > @@ -1122,11 +1122,12 @@ retry:
> > if (ret < 0) {
> > av_assert0(sc->slice_coding_mode == 0);
> > - if (f->version < 4 || !f->ac) {
> > + if (f->version < 4) {
> > av_log(c, AV_LOG_ERROR, "Buffer too small\n");
> > return ret;
> > }
> > av_log(c, AV_LOG_DEBUG, "Coding slice as PCM\n");
> > + ac = 1;
> > sc->slice_coding_mode = 1;
> > sc->c = c_bak;
> > goto retry;
>
> Is there a reason to support this with Golomb? Being a fallback-only mode
> for range coding, I don't think there's much point in supporting Golomb
> coding for it.
The reason behind slice_coding_mode is to ensure that the maximum size
of the bitstream can be bound in a reasonable way.
This will allows decoders and encoders to use a known and limited amount of
memory.
This is of course not a problem with normal videos but one could
craft a video that pushes each context state to one side and then
follows that up with crafted data where each is opposit thus generating
the worst case. Its a bigger issue for the range coder than golomb, yes
thx
[...]
--
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB
Those who are too smart to engage in politics are punished by being
governed by those who are dumber. -- Plato
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <https://ffmpeg.org/pipermail/ffmpeg-devel/attachments/20241026/dedcbcfd/attachment.sig>
More information about the ffmpeg-devel
mailing list