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]

Reply via email to