mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2026-08-09 17:39:08 +00:00
ffv1enc: implement Bayer pixel format encoding
Sponsored-by: Sovereign Tech Fund
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user