This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit d62686b50fa69ae338507501bb2a53dbb7539045 Author: Lynne <[email protected]> AuthorDate: Tue Mar 17 13:37:39 2026 +0100 Commit: Lynne <[email protected]> CommitDate: Sun May 31 20:03:57 2026 +0900 ffv1enc: implement Bayer pixel format encoding Sponsored-by: Sovereign Tech Fund --- libavcodec/ffv1.c | 6 ++- libavcodec/ffv1.h | 2 + libavcodec/ffv1enc.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 110 insertions(+), 8 deletions(-) diff --git a/libavcodec/ffv1.c b/libavcodec/ffv1.c index 812989a892..1dcb7be28d 100644 --- a/libavcodec/ffv1.c +++ b/libavcodec/ffv1.c @@ -126,6 +126,8 @@ int ff_need_new_slices(int width, int num_h_slices, int chroma_shift) { int ff_slice_coord(const FFV1Context *f, int width, int sx, int num_h_slices, int chroma_shift) { int mpw = 1<<chroma_shift; + if (f->bayer) + mpw = FFMAX(mpw, 2); int awidth = FFALIGN(width, mpw); if (f->combined_version <= 0x40002) @@ -233,7 +235,7 @@ void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, 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++) { + for (int p=0; p<3+f->transparency+f->bayer; p++) { bits[p] = av_ceil_log2(sc->remap_count[p]); if (mask) mask[p] = (1<<bits[p]) - 1; @@ -246,6 +248,8 @@ void ff_ffv1_compute_bits_per_plane(const FFV1Context *f, FFV1SliceContext *sc, 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]); + if (f->bayer) + bits[3] = av_ceil_log2(sc->remap_count[0] + sc->remap_count[3]); //old version coded a bit more than needed if (f->combined_version < 0x40008) { diff --git a/libavcodec/ffv1.h b/libavcodec/ffv1.h index 8a48e8e682..012b92ec21 100644 --- a/libavcodec/ffv1.h +++ b/libavcodec/ffv1.h @@ -153,6 +153,8 @@ typedef struct FFV1Context { int flt; int remap_mode; int remap_optimizer; + int bayer; + int bayer_order; /* 0 = RGGB (only supported value for now) */ int maxsize_warned; int use32bit; diff --git a/libavcodec/ffv1enc.c b/libavcodec/ffv1enc.c index cd346495f7..5e5974c035 100644 --- a/libavcodec/ffv1enc.c +++ b/libavcodec/ffv1enc.c @@ -435,7 +435,7 @@ static void set_micro_version(FFV1Context *f) if (f->version == 3) { f->micro_version = 4; } else if (f->version == 4) { - f->micro_version = 9; + f->micro_version = 10; } else av_assert0(0); @@ -480,6 +480,8 @@ av_cold int ff_ffv1_write_extradata(AVCodecContext *avctx) put_symbol(&c, state, f->chroma_h_shift, 0); put_symbol(&c, state, f->chroma_v_shift, 0); put_rac(&c, state, f->transparency); + if (f->colorspace == 2) + put_symbol(&c, state, f->bayer_order, 0); /* 0 = RGGB */ put_symbol(&c, state, f->num_h_slices - 1, 0); put_symbol(&c, state, f->num_v_slices - 1, 0); @@ -566,9 +568,9 @@ static int sort_stt(FFV1Context *s, uint8_t stt[256]) int ff_ffv1_encode_determine_slices(AVCodecContext *avctx) { FFV1Context *s = avctx->priv_data; - int plane_count = 1 + 2*s->chroma_planes + s->transparency; - int max_h_slices = AV_CEIL_RSHIFT(avctx->width , s->chroma_h_shift); - int max_v_slices = AV_CEIL_RSHIFT(avctx->height, s->chroma_v_shift); + int plane_count = 1 + 2*s->chroma_planes + s->bayer + s->transparency; + int max_h_slices = AV_CEIL_RSHIFT(avctx->width , s->bayer ? 1 : s->chroma_h_shift); + int max_v_slices = AV_CEIL_RSHIFT(avctx->height, s->bayer ? 1 : s->chroma_v_shift); s->num_v_slices = (avctx->width > 352 || avctx->height > 288 || !avctx->slices) ? 2 : 1; s->num_v_slices = FFMIN(s->num_v_slices, max_v_slices); for (; s->num_v_slices <= 32; s->num_v_slices++) { @@ -694,6 +696,8 @@ av_cold int ff_ffv1_encode_init(AVCodecContext *avctx) s->plane_count = 2; if (!s->chroma_planes && s->version > 3) s->plane_count--; + if (s->bayer) + s->plane_count = 3; s->picture_number = 0; @@ -804,6 +808,7 @@ av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx, FFV1Context *s = avctx->priv_data; const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt); + s->bayer = 0; s->plane_count = 3; switch(pix_fmt) { case AV_PIX_FMT_GRAY9: @@ -911,6 +916,14 @@ av_cold int ff_ffv1_encode_setup_plane_info(AVCodecContext *avctx, s->use32bit = 1; s->version = FFMAX(s->version, 1); break; + case AV_PIX_FMT_BAYER_RGGB16: + s->colorspace = 2; + s->chroma_planes = 1; + s->bits_per_raw_sample = 16; + s->use32bit = 1; + s->version = FFMAX(s->version, 4); + s->bayer = 1; + break; case AV_PIX_FMT_GBRP: case AV_PIX_FMT_0RGB32: s->colorspace = 1; @@ -1106,7 +1119,7 @@ static void encode_slice_header(FFV1Context *f, FFV1SliceContext *sc) if (sc->slice_coding_mode == 1) ff_ffv1_clear_slice_state(f, sc); put_symbol(c, state, sc->slice_coding_mode, 0); - if (sc->slice_coding_mode != 1 && f->colorspace == 1) { + if (sc->slice_coding_mode != 1 && f->colorspace != 0) { put_symbol(c, state, sc->slice_rct_by_coef, 0); put_symbol(c, state, sc->slice_rct_ry_coef, 0); } @@ -1569,6 +1582,86 @@ static int encode_float32_rgb_frame(FFV1Context *f, FFV1SliceContext *sc, return 0; } +static int encode_bayer_frame(FFV1Context *f, FFV1SliceContext *sc, + const uint8_t *src[4], + int w, int h, const int stride[4], int ac) +{ + const int pass1 = !!(f->avctx->flags & AV_CODEC_FLAG_PASS1); + const int ring_size = f->context_model ? 3 : 2; + TYPE *sample[4][3]; + + int bits[4], offset; + ff_ffv1_compute_bits_per_plane(f, sc, bits, &offset, NULL, f->bits_per_raw_sample); + + w >>= 1; + + sc->run_index = 0; + + for (int p = 0; p < MAX_PLANES; ++p) + sample[p][2] = RENAME(sc->sample_buffer); + + memset(RENAME(sc->sample_buffer), 0, ring_size * MAX_PLANES * + (w + 6) * sizeof(*RENAME(sc->sample_buffer))); + + for (int y = 0; y < h; y += 2) { + for (int i = 0; i < ring_size; i++) + for (int p = 0; p < MAX_PLANES; p++) + sample[p][i] = RENAME(sc->sample_buffer) + p*ring_size*(w+6) + + ((h+i-y/2) % ring_size)*(w+6) + 3; + + for (int x = 0; x < w; x++) { + const uint16_t *l1 = ((const uint16_t*)(src[0] + stride[0]*(y + 0) + x*2*2)); + const uint16_t *l2 = ((const uint16_t*)(src[0] + stride[0]*(y + 1) + x*2*2)); + + int r, gr, gb, b; + r = l1[0]; + gr = l1[1]; + gb = l2[0]; + b = l2[1]; + + if (sc->slice_coding_mode != 1) { + /** + * Bayer 2x2 RCT, based on: + * "Reversible color transform for Bayer color filter array images", S. Poomrittigul et al, + * APSIPA Transactions on Signal and Information Processing (2013) 2 (1): 1-10, + * doi:10.1017/ATSIP.2013.6 */ + int gd = gr - gb; + int gm = gb + (gd >> 1); + + b -= gm; + r -= gm; + gm += (b * sc->slice_rct_by_coef + r * sc->slice_rct_ry_coef) >> 2; + b += offset; + r += offset; + gd += offset; + + gr = gm; + gb = gd; + } + + sample[0][0][x] = gr; + sample[1][0][x] = gb; + sample[2][0][x] = b; + sample[3][0][x] = r; + } + + for (int p = 0; p < 4; p++) { + int ret; + sample[p][0][-1] = sample[p][1][0 ]; + sample[p][1][ w] = sample[p][1][w-1]; + /* Plane contexts: gm=0 (luma), b-gm/r-gm=1 (chroma diff from + * green), gd=2 (own context - green-green diff has different + * statistics from both luma and chroma). */ + ret = RENAME(encode_line)(f, sc, f->avctx, w, sample[p], + p == 1 ? 2 : (p > 1), + bits[p], ac, pass1); + if (ret < 0) + return ret; + } + } + + return 0; +} static int encode_slice(AVCodecContext *c, void *arg) { @@ -1664,6 +1757,8 @@ retry: ret |= encode_plane(f, sc, p->data[0] + (ps>>1) + ps*x + y*p->linesize[0], width, height, p->linesize[0], 1, 1, 2, ac); } else if (f->bits_per_raw_sample == 32) { ret = encode_float32_rgb_frame(f, sc, planes, width, height, p->linesize, ac); + } else if (f->bayer) { + ret = encode_bayer_frame(f, sc, planes, width, height, p->linesize, ac); } else if (f->use32bit) { ret = encode_rgb_frame32(f, sc, planes, width, height, p->linesize, ac); } else { @@ -1706,7 +1801,7 @@ size_t ff_ffv1_encode_buffer_size(AVCodecContext *avctx) if (f->version > 3) { maxsize *= f->bits_per_raw_sample + 1; if (f->remap_mode) - maxsize += f->slice_count * 70000 * (1 + 2*f->chroma_planes + f->transparency); + maxsize += f->slice_count * 70000 * (1 + 2*f->chroma_planes + f->bayer + f->transparency); } else { maxsize += f->slice_count * 2 * (avctx->width + avctx->height); //for bug with slices that code some pixels more than once maxsize *= 8*(2*f->bits_per_raw_sample + 5); @@ -1957,7 +2052,8 @@ const FFCodec ff_ffv1_encoder = { AV_PIX_FMT_YUV440P10, AV_PIX_FMT_YUV440P12, AV_PIX_FMT_YAF16, AV_PIX_FMT_GRAYF16, - AV_PIX_FMT_GBRPF16, AV_PIX_FMT_GBRPF32), + AV_PIX_FMT_GBRPF16, AV_PIX_FMT_GBRPF32, + AV_PIX_FMT_BAYER_RGGB16), .color_ranges = AVCOL_RANGE_MPEG, .p.priv_class = &ffv1_class, .caps_internal = FF_CODEC_CAP_INIT_CLEANUP | FF_CODEC_CAP_EOF_FLUSH, _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
