[FFmpeg-devel] [PATCH v4 1/4] libavcodec/vc2enc: Split out common functions between software and hardware encoders

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Mon May 19 18:56:55 EEST 2025


IndecisiveTurtle:
> From: IndecisiveTurtle <geoster3d at gmail.com>
> 
> ---
>  libavcodec/Makefile        |   2 +-
>  libavcodec/vc2enc.c        | 679 ++-----------------------------------
>  libavcodec/vc2enc_common.c | 571 +++++++++++++++++++++++++++++++
>  libavcodec/vc2enc_common.h | 178 ++++++++++
>  4 files changed, 772 insertions(+), 658 deletions(-)
>  create mode 100644 libavcodec/vc2enc_common.c
>  create mode 100644 libavcodec/vc2enc_common.h
> 
> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> index 77734dff24..bdf0d6742e 100644
> --- a/libavcodec/Makefile
> +++ b/libavcodec/Makefile
> @@ -771,7 +771,7 @@ OBJS-$(CONFIG_VC1_CUVID_DECODER)       += cuviddec.o
>  OBJS-$(CONFIG_VC1_MMAL_DECODER)        += mmaldec.o
>  OBJS-$(CONFIG_VC1_QSV_DECODER)         += qsvdec.o
>  OBJS-$(CONFIG_VC1_V4L2M2M_DECODER)     += v4l2_m2m_dec.o
> -OBJS-$(CONFIG_VC2_ENCODER)             += vc2enc.o vc2enc_dwt.o diractab.o
> +OBJS-$(CONFIG_VC2_ENCODER)             += vc2enc.o vc2enc_dwt.o vc2enc_common.o diractab.o

Seems like this should be split into two lines

>  OBJS-$(CONFIG_VCR1_DECODER)            += vcr1.o
>  OBJS-$(CONFIG_VMDAUDIO_DECODER)        += vmdaudio.o
>  OBJS-$(CONFIG_VMDVIDEO_DECODER)        += vmdvideo.o
> diff --git a/libavcodec/vc2enc.c b/libavcodec/vc2enc.c
> index 99ca95c40a..939bafa195 100644
> --- a/libavcodec/vc2enc.c
> +++ b/libavcodec/vc2enc.c
> @@ -30,505 +30,11 @@
>  #include "put_bits.h"
>  #include "version.h"
>  
> -#include "vc2enc_dwt.h"
> -#include "diractab.h"
> -
> -/* The limited size resolution of each slice forces us to do this */
> -#define SSIZE_ROUND(b) (FFALIGN((b), s->size_scaler) + 4 + s->prefix_bytes)
> +#include "vc2enc_common.h"
>  
>  /* Decides the cutoff point in # of slices to distribute the leftover bytes */
>  #define SLICE_REDIST_TOTAL 150
>  
> -typedef struct VC2BaseVideoFormat {
> -    enum AVPixelFormat pix_fmt;
> -    AVRational time_base;
> -    int width, height;
> -    uint8_t interlaced, level;
> -    char name[13];
> -} VC2BaseVideoFormat;
> -
> -static const VC2BaseVideoFormat base_video_fmts[] = {
> -    { 0 }, /* Custom format, here just to make indexing equal to base_vf */
> -    { AV_PIX_FMT_YUV420P,   { 1001, 15000 },  176,  120, 0, 1,     "QSIF525" },
> -    { AV_PIX_FMT_YUV420P,   {    2,    25 },  176,  144, 0, 1,     "QCIF"    },
> -    { AV_PIX_FMT_YUV420P,   { 1001, 15000 },  352,  240, 0, 1,     "SIF525"  },
> -    { AV_PIX_FMT_YUV420P,   {    2,    25 },  352,  288, 0, 1,     "CIF"     },
> -    { AV_PIX_FMT_YUV420P,   { 1001, 15000 },  704,  480, 0, 1,     "4SIF525" },
> -    { AV_PIX_FMT_YUV420P,   {    2,    25 },  704,  576, 0, 1,     "4CIF"    },
> -
> -    { AV_PIX_FMT_YUV422P10, { 1001, 30000 },  720,  480, 1, 2,   "SD480I-60" },
> -    { AV_PIX_FMT_YUV422P10, {    1,    25 },  720,  576, 1, 2,   "SD576I-50" },
> -
> -    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 1280,  720, 0, 3,  "HD720P-60"  },
> -    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 1280,  720, 0, 3,  "HD720P-50"  },
> -    { AV_PIX_FMT_YUV422P10, { 1001, 30000 }, 1920, 1080, 1, 3,  "HD1080I-60" },
> -    { AV_PIX_FMT_YUV422P10, {    1,    25 }, 1920, 1080, 1, 3,  "HD1080I-50" },
> -    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 1920, 1080, 0, 3,  "HD1080P-60" },
> -    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 1920, 1080, 0, 3,  "HD1080P-50" },
> -
> -    { AV_PIX_FMT_YUV444P12, {    1,    24 }, 2048, 1080, 0, 4,        "DC2K" },
> -    { AV_PIX_FMT_YUV444P12, {    1,    24 }, 4096, 2160, 0, 5,        "DC4K" },
> -
> -    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 3840, 2160, 0, 6, "UHDTV 4K-60" },
> -    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 3840, 2160, 0, 6, "UHDTV 4K-50" },
> -
> -    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 7680, 4320, 0, 7, "UHDTV 8K-60" },
> -    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 7680, 4320, 0, 7, "UHDTV 8K-50" },
> -
> -    { AV_PIX_FMT_YUV422P10, { 1001, 24000 }, 1920, 1080, 0, 3,  "HD1080P-24" },
> -    { AV_PIX_FMT_YUV422P10, { 1001, 30000 },  720,  486, 1, 2,  "SD Pro486"  },
> -};
> -static const int base_video_fmts_len = FF_ARRAY_ELEMS(base_video_fmts);
> -
> -enum VC2_QM {
> -    VC2_QM_DEF = 0,
> -    VC2_QM_COL,
> -    VC2_QM_FLAT,
> -
> -    VC2_QM_NB
> -};
> -
> -typedef struct SubBand {
> -    dwtcoef *buf;
> -    ptrdiff_t stride;
> -    int width;
> -    int height;
> -} SubBand;
> -
> -typedef struct Plane {
> -    SubBand band[MAX_DWT_LEVELS][4];
> -    dwtcoef *coef_buf;
> -    int width;
> -    int height;
> -    int dwt_width;
> -    int dwt_height;
> -    ptrdiff_t coef_stride;
> -} Plane;
> -
> -typedef struct SliceArgs {
> -    const struct VC2EncContext *ctx;
> -    union {
> -        int cache[DIRAC_MAX_QUANT_INDEX];
> -        uint8_t *buf;
> -    };
> -    int x;
> -    int y;
> -    int quant_idx;
> -    int bits_ceil;
> -    int bits_floor;
> -    int bytes;
> -} SliceArgs;
> -
> -typedef struct TransformArgs {
> -    const struct VC2EncContext *ctx;
> -    Plane *plane;
> -    const void *idata;
> -    ptrdiff_t istride;
> -    int field;
> -    VC2TransformContext t;
> -} TransformArgs;
> -
> -typedef struct VC2EncContext {
> -    AVClass *av_class;
> -    PutBitContext pb;
> -    Plane plane[3];
> -    AVCodecContext *avctx;
> -    DiracVersionInfo ver;
> -
> -    SliceArgs *slice_args;
> -    TransformArgs transform_args[3];
> -
> -    /* For conversion from unsigned pixel values to signed */
> -    int diff_offset;
> -    int bpp;
> -    int bpp_idx;
> -
> -    /* Picture number */
> -    uint32_t picture_number;
> -
> -    /* Base video format */
> -    int base_vf;
> -    int level;
> -    int profile;
> -
> -    /* Quantization matrix */
> -    uint8_t quant[MAX_DWT_LEVELS][4];
> -    int custom_quant_matrix;
> -
> -    /* Division LUT */
> -    uint32_t qmagic_lut[116][2];
> -
> -    int num_x; /* #slices horizontally */
> -    int num_y; /* #slices vertically */
> -    int prefix_bytes;
> -    int size_scaler;
> -    int chroma_x_shift;
> -    int chroma_y_shift;
> -
> -    /* Rate control stuff */
> -    int frame_max_bytes;
> -    int slice_max_bytes;
> -    int slice_min_bytes;
> -    int q_ceil;
> -    int q_avg;
> -
> -    /* Options */
> -    double tolerance;
> -    int wavelet_idx;
> -    int wavelet_depth;
> -    int strict_compliance;
> -    int slice_height;
> -    int slice_width;
> -    int interlaced;
> -    enum VC2_QM quant_matrix;
> -
> -    /* Parse code state */
> -    uint32_t next_parse_offset;
> -    enum DiracParseCodes last_parse_code;
> -} VC2EncContext;
> -
> -/// x_k x_{k-1} ... x_0 -> 0 x_k 0 x_{k - 1} ... 0 x_0
> -static uint16_t interleaved_ue_golomb_tab[256];
> -/// 1 x_{k-1} ... x_0 -> 0 0 0 x_{k - 1} ... 0 x_0
> -static uint16_t top_interleaved_ue_golomb_tab[256];
> -/// 1 x_{k-1} ... x_0 -> 2 * k
> -static uint8_t golomb_len_tab[256];
> -
> -static av_cold void vc2_init_static_data(void)
> -{
> -    interleaved_ue_golomb_tab[1] = 1;
> -    for (unsigned i = 2; i < 256; ++i) {
> -        golomb_len_tab[i] = golomb_len_tab[i >> 1] + 2;
> -        interleaved_ue_golomb_tab[i] = (interleaved_ue_golomb_tab[i >> 1] << 2) | (i & 1);
> -        top_interleaved_ue_golomb_tab[i] = interleaved_ue_golomb_tab[i] ^ (1 << golomb_len_tab[i]);
> -    }
> -}
> -
> -static av_always_inline void put_vc2_ue_uint_inline(PutBitContext *pb, uint32_t val)
> -{
> -    uint64_t pbits = 1;
> -    int bits = 1;
> -
> -    ++val;
> -
> -    while (val >> 8) {
> -        pbits |= (uint64_t)interleaved_ue_golomb_tab[val & 0xff] << bits;
> -        val  >>= 8;
> -        bits  += 16;
> -    }
> -    pbits |= (uint64_t)top_interleaved_ue_golomb_tab[val] << bits;
> -    bits  += golomb_len_tab[val];
> -
> -    put_bits63(pb, bits, pbits);
> -}
> -
> -static av_noinline void put_vc2_ue_uint(PutBitContext *pb, uint32_t val)
> -{
> -    put_vc2_ue_uint_inline(pb, val);
> -}
> -
> -static av_always_inline int count_vc2_ue_uint(uint32_t val)
> -{
> -    return 2 * av_log2(val + 1) + 1;
> -}
> -
> -/* VC-2 10.4 - parse_info() */
> -static void encode_parse_info(VC2EncContext *s, enum DiracParseCodes pcode)
> -{
> -    uint32_t cur_pos, dist;
> -
> -    align_put_bits(&s->pb);
> -
> -    cur_pos = put_bytes_count(&s->pb, 0);
> -
> -    /* Magic string */
> -    ff_put_string(&s->pb, "BBCD", 0);
> -
> -    /* Parse code */
> -    put_bits(&s->pb, 8, pcode);
> -
> -    /* Next parse offset */
> -    dist = cur_pos - s->next_parse_offset;
> -    AV_WB32(s->pb.buf + s->next_parse_offset + 5, dist);
> -    s->next_parse_offset = cur_pos;
> -    put_bits32(&s->pb, pcode == DIRAC_PCODE_END_SEQ ? 13 : 0);
> -
> -    /* Last parse offset */
> -    put_bits32(&s->pb, s->last_parse_code == DIRAC_PCODE_END_SEQ ? 13 : dist);
> -
> -    s->last_parse_code = pcode;
> -}
> -
> -/* VC-2 11.1 - parse_parameters()
> - * The level dictates what the decoder should expect in terms of resolution
> - * and allows it to quickly reject whatever it can't support. Remember,
> - * this codec kinda targets cheapo FPGAs without much memory. Unfortunately
> - * it also limits us greatly in our choice of formats, hence the flag to disable
> - * strict_compliance */
> -static void encode_parse_params(VC2EncContext *s)
> -{
> -    put_vc2_ue_uint(&s->pb, s->ver.major); /* VC-2 demands this to be 2 */
> -    put_vc2_ue_uint(&s->pb, s->ver.minor); /* ^^ and this to be 0       */
> -    put_vc2_ue_uint(&s->pb, s->profile);   /* 3 to signal HQ profile    */
> -    put_vc2_ue_uint(&s->pb, s->level);     /* 3 - 1080/720, 6 - 4K      */
> -}
> -
> -/* VC-2 11.3 - frame_size() */
> -static void encode_frame_size(VC2EncContext *s)
> -{
> -    put_bits(&s->pb, 1, !s->strict_compliance);
> -    if (!s->strict_compliance) {
> -        AVCodecContext *avctx = s->avctx;
> -        put_vc2_ue_uint(&s->pb, avctx->width);
> -        put_vc2_ue_uint(&s->pb, avctx->height);
> -    }
> -}
> -
> -/* VC-2 11.3.3 - color_diff_sampling_format() */
> -static void encode_sample_fmt(VC2EncContext *s)
> -{
> -    put_bits(&s->pb, 1, !s->strict_compliance);
> -    if (!s->strict_compliance) {
> -        int idx;
> -        if (s->chroma_x_shift == 1 && s->chroma_y_shift == 0)
> -            idx = 1; /* 422 */
> -        else if (s->chroma_x_shift == 1 && s->chroma_y_shift == 1)
> -            idx = 2; /* 420 */
> -        else
> -            idx = 0; /* 444 */
> -        put_vc2_ue_uint(&s->pb, idx);
> -    }
> -}
> -
> -/* VC-2 11.3.4 - scan_format() */
> -static void encode_scan_format(VC2EncContext *s)
> -{
> -    put_bits(&s->pb, 1, !s->strict_compliance);
> -    if (!s->strict_compliance)
> -        put_vc2_ue_uint(&s->pb, s->interlaced);
> -}
> -
> -/* VC-2 11.3.5 - frame_rate() */
> -static void encode_frame_rate(VC2EncContext *s)
> -{
> -    put_bits(&s->pb, 1, !s->strict_compliance);
> -    if (!s->strict_compliance) {
> -        AVCodecContext *avctx = s->avctx;
> -        put_vc2_ue_uint(&s->pb, 0);
> -        put_vc2_ue_uint(&s->pb, avctx->time_base.den);
> -        put_vc2_ue_uint(&s->pb, avctx->time_base.num);
> -    }
> -}
> -
> -/* VC-2 11.3.6 - aspect_ratio() */
> -static void encode_aspect_ratio(VC2EncContext *s)
> -{
> -    put_bits(&s->pb, 1, !s->strict_compliance);
> -    if (!s->strict_compliance) {
> -        AVCodecContext *avctx = s->avctx;
> -        put_vc2_ue_uint(&s->pb, 0);
> -        put_vc2_ue_uint(&s->pb, avctx->sample_aspect_ratio.num);
> -        put_vc2_ue_uint(&s->pb, avctx->sample_aspect_ratio.den);
> -    }
> -}
> -
> -/* VC-2 11.3.7 - clean_area() */
> -static void encode_clean_area(VC2EncContext *s)
> -{
> -    put_bits(&s->pb, 1, 0);
> -}
> -
> -/* VC-2 11.3.8 - signal_range() */
> -static void encode_signal_range(VC2EncContext *s)
> -{
> -    put_bits(&s->pb, 1, !s->strict_compliance);
> -    if (!s->strict_compliance)
> -        put_vc2_ue_uint(&s->pb, s->bpp_idx);
> -}
> -
> -/* VC-2 11.3.9 - color_spec() */
> -static void encode_color_spec(VC2EncContext *s)
> -{
> -    AVCodecContext *avctx = s->avctx;
> -    put_bits(&s->pb, 1, !s->strict_compliance);
> -    if (!s->strict_compliance) {
> -        int val;
> -        put_vc2_ue_uint(&s->pb, 0);
> -
> -        /* primaries */
> -        put_bits(&s->pb, 1, 1);
> -        if (avctx->color_primaries == AVCOL_PRI_BT470BG)
> -            val = 2;
> -        else if (avctx->color_primaries == AVCOL_PRI_SMPTE170M)
> -            val = 1;
> -        else if (avctx->color_primaries == AVCOL_PRI_SMPTE240M)
> -            val = 1;
> -        else
> -            val = 0;
> -        put_vc2_ue_uint(&s->pb, val);
> -
> -        /* color matrix */
> -        put_bits(&s->pb, 1, 1);
> -        if (avctx->colorspace == AVCOL_SPC_RGB)
> -            val = 3;
> -        else if (avctx->colorspace == AVCOL_SPC_YCOCG)
> -            val = 2;
> -        else if (avctx->colorspace == AVCOL_SPC_BT470BG)
> -            val = 1;
> -        else
> -            val = 0;
> -        put_vc2_ue_uint(&s->pb, val);
> -
> -        /* transfer function */
> -        put_bits(&s->pb, 1, 1);
> -        if (avctx->color_trc == AVCOL_TRC_LINEAR)
> -            val = 2;
> -        else if (avctx->color_trc == AVCOL_TRC_BT1361_ECG)
> -            val = 1;
> -        else
> -            val = 0;
> -        put_vc2_ue_uint(&s->pb, val);
> -    }
> -}
> -
> -/* VC-2 11.3 - source_parameters() */
> -static void encode_source_params(VC2EncContext *s)
> -{
> -    encode_frame_size(s);
> -    encode_sample_fmt(s);
> -    encode_scan_format(s);
> -    encode_frame_rate(s);
> -    encode_aspect_ratio(s);
> -    encode_clean_area(s);
> -    encode_signal_range(s);
> -    encode_color_spec(s);
> -}
> -
> -/* VC-2 11 - sequence_header() */
> -static void encode_seq_header(VC2EncContext *s)
> -{
> -    align_put_bits(&s->pb);
> -    encode_parse_params(s);
> -    put_vc2_ue_uint(&s->pb, s->base_vf);
> -    encode_source_params(s);
> -    put_vc2_ue_uint(&s->pb, s->interlaced); /* Frames or fields coding */
> -}
> -
> -/* VC-2 12.1 - picture_header() */
> -static void encode_picture_header(VC2EncContext *s)
> -{
> -    align_put_bits(&s->pb);
> -    put_bits32(&s->pb, s->picture_number++);
> -}
> -
> -/* VC-2 12.3.4.1 - slice_parameters() */
> -static void encode_slice_params(VC2EncContext *s)
> -{
> -    put_vc2_ue_uint(&s->pb, s->num_x);
> -    put_vc2_ue_uint(&s->pb, s->num_y);
> -    put_vc2_ue_uint(&s->pb, s->prefix_bytes);
> -    put_vc2_ue_uint(&s->pb, s->size_scaler);
> -}
> -
> -/* 1st idx = LL, second - vertical, third - horizontal, fourth - total */
> -static const uint8_t vc2_qm_col_tab[][4] = {
> -    {20,  9, 15,  4},
> -    { 0,  6,  6,  4},
> -    { 0,  3,  3,  5},
> -    { 0,  3,  5,  1},
> -    { 0, 11, 10, 11}
> -};
> -
> -static const uint8_t vc2_qm_flat_tab[][4] = {
> -    { 0,  0,  0,  0},
> -    { 0,  0,  0,  0},
> -    { 0,  0,  0,  0},
> -    { 0,  0,  0,  0},
> -    { 0,  0,  0,  0}
> -};
> -
> -static void init_quant_matrix(VC2EncContext *s)
> -{
> -    int level, orientation;
> -
> -    if (s->wavelet_depth <= 4 && s->quant_matrix == VC2_QM_DEF) {
> -        s->custom_quant_matrix = 0;
> -        for (level = 0; level < s->wavelet_depth; level++) {
> -            s->quant[level][0] = ff_dirac_default_qmat[s->wavelet_idx][level][0];
> -            s->quant[level][1] = ff_dirac_default_qmat[s->wavelet_idx][level][1];
> -            s->quant[level][2] = ff_dirac_default_qmat[s->wavelet_idx][level][2];
> -            s->quant[level][3] = ff_dirac_default_qmat[s->wavelet_idx][level][3];
> -        }
> -        return;
> -    }
> -
> -    s->custom_quant_matrix = 1;
> -
> -    if (s->quant_matrix == VC2_QM_DEF) {
> -        for (level = 0; level < s->wavelet_depth; level++) {
> -            for (orientation = 0; orientation < 4; orientation++) {
> -                if (level <= 3)
> -                    s->quant[level][orientation] = ff_dirac_default_qmat[s->wavelet_idx][level][orientation];
> -                else
> -                    s->quant[level][orientation] = vc2_qm_col_tab[level][orientation];
> -            }
> -        }
> -    } else if (s->quant_matrix == VC2_QM_COL) {
> -        for (level = 0; level < s->wavelet_depth; level++) {
> -            for (orientation = 0; orientation < 4; orientation++) {
> -                s->quant[level][orientation] = vc2_qm_col_tab[level][orientation];
> -            }
> -        }
> -    } else {
> -        for (level = 0; level < s->wavelet_depth; level++) {
> -            for (orientation = 0; orientation < 4; orientation++) {
> -                s->quant[level][orientation] = vc2_qm_flat_tab[level][orientation];
> -            }
> -        }
> -    }
> -}
> -
> -/* VC-2 12.3.4.2 - quant_matrix() */
> -static void encode_quant_matrix(VC2EncContext *s)
> -{
> -    int level;
> -    put_bits(&s->pb, 1, s->custom_quant_matrix);
> -    if (s->custom_quant_matrix) {
> -        put_vc2_ue_uint(&s->pb, s->quant[0][0]);
> -        for (level = 0; level < s->wavelet_depth; level++) {
> -            put_vc2_ue_uint(&s->pb, s->quant[level][1]);
> -            put_vc2_ue_uint(&s->pb, s->quant[level][2]);
> -            put_vc2_ue_uint(&s->pb, s->quant[level][3]);
> -        }
> -    }
> -}
> -
> -/* VC-2 12.3 - transform_parameters() */
> -static void encode_transform_params(VC2EncContext *s)
> -{
> -    put_vc2_ue_uint(&s->pb, s->wavelet_idx);
> -    put_vc2_ue_uint(&s->pb, s->wavelet_depth);
> -
> -    encode_slice_params(s);
> -    encode_quant_matrix(s);
> -}
> -
> -/* VC-2 12.2 - wavelet_transform() */
> -static void encode_wavelet_transform(VC2EncContext *s)
> -{
> -    encode_transform_params(s);
> -    align_put_bits(&s->pb);
> -}
> -
> -/* VC-2 12 - picture_parse() */
> -static void encode_picture_start(VC2EncContext *s)
> -{
> -    align_put_bits(&s->pb);
> -    encode_picture_header(s);
> -    align_put_bits(&s->pb);
> -    encode_wavelet_transform(s);
> -}
> -
>  #define QUANT(c, mul, add, shift) (((mul) * (c) + (add)) >> (shift))
>  
>  /* VC-2 13.5.5.2 - slice_band() */
> @@ -558,6 +64,11 @@ static void encode_subband(const VC2EncContext *s, PutBitContext *pb,
>      }
>  }
>  
> +static inline int count_vc2_ue_uint(uint32_t val)
> +{
> +    return 2 * av_log2(val + 1) + 1;
> +}
> +
>  static int count_hq_slice(SliceArgs *slice, int quant_idx)
>  {
>      int x, y;
> @@ -657,7 +168,7 @@ static int calc_slice_sizes(VC2EncContext *s)
>      SliceArgs *enc_args = s->slice_args;
>      SliceArgs *top_loc[SLICE_REDIST_TOTAL] = {NULL};
>  
> -    init_quant_matrix(s);
> +    ff_vc2_init_quant_matrix(s, s->quant);
>  
>      for (slice_y = 0; slice_y < s->num_y; slice_y++) {
>          for (slice_x = 0; slice_x < s->num_x; slice_x++) {
> @@ -782,7 +293,7 @@ static int encode_hq_slice(AVCodecContext *avctx, void *arg)
>  }
>  
>  /* VC-2 13.5.1 - low_delay_transform_data() */
> -static int encode_slices(VC2EncContext *s)
> +static void encode_slices(VC2EncContext *s)
>  {
>      uint8_t *buf;
>      int slice_x, slice_y, skip = 0;
> @@ -803,8 +314,6 @@ static int encode_slices(VC2EncContext *s)
>                        sizeof(SliceArgs));
>  
>      skip_put_bytes(&s->pb, skip);
> -
> -    return 0;
>  }
>  
>  /*
> @@ -902,7 +411,7 @@ static int dwt_plane(AVCodecContext *avctx, void *arg)
>  }
>  
>  static int encode_frame(VC2EncContext *s, AVPacket *avpkt, const AVFrame *frame,
> -                        const char *aux_data, const int header_size, int field)
> +                        const int header_size, int field)
>  {
>      int i, ret;
>      int64_t max_frame_bytes;
> @@ -929,25 +438,8 @@ static int encode_frame(VC2EncContext *s, AVPacket *avpkt, const AVFrame *frame,
>          init_put_bits(&s->pb, avpkt->data, avpkt->size);
>      }
>  
> -    /* Sequence header */
> -    encode_parse_info(s, DIRAC_PCODE_SEQ_HEADER);
> -    encode_seq_header(s);
> -
> -    /* Encoder version */
> -    if (aux_data) {
> -        encode_parse_info(s, DIRAC_PCODE_AUX);
> -        ff_put_string(&s->pb, aux_data, 1);
> -    }
> -
> -    /* Picture header */
> -    encode_parse_info(s, DIRAC_PCODE_PICTURE_HQ);
> -    encode_picture_start(s);
> -
> -    /* Encode slices */
> -    encode_slices(s);
> -
> -    /* End sequence */
> -    encode_parse_info(s, DIRAC_PCODE_END_SEQ);
> +    /* Encode frame */
> +    ff_vc2_encode_frame(s, encode_slices);
>  
>      return 0;
>  }
> @@ -956,45 +448,20 @@ static av_cold int vc2_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
>                                        const AVFrame *frame, int *got_packet)
>  {
>      int ret = 0;
> -    int slice_ceil, sig_size = 256;
>      VC2EncContext *s = avctx->priv_data;
>      const int bitexact = avctx->flags & AV_CODEC_FLAG_BITEXACT;
> -    const char *aux_data = bitexact ? "Lavc" : LIBAVCODEC_IDENT;
>      const int aux_data_size = bitexact ? sizeof("Lavc") : sizeof(LIBAVCODEC_IDENT);
>      const int header_size = 100 + aux_data_size;
> -    int64_t r_bitrate = avctx->bit_rate >> (s->interlaced);
> -
> -    s->avctx = avctx;
> -    s->size_scaler = 2;
> -    s->prefix_bytes = 0;
> -    s->last_parse_code = 0;
> -    s->next_parse_offset = 0;
> -
> -    /* Rate control */
> -    s->frame_max_bytes = (av_rescale(r_bitrate, s->avctx->time_base.num,
> -                                     s->avctx->time_base.den) >> 3) - header_size;
> -    s->slice_max_bytes = slice_ceil = av_rescale(s->frame_max_bytes, 1, s->num_x*s->num_y);
> -
> -    /* Find an appropriate size scaler */
> -    while (sig_size > 255) {
> -        int r_size = SSIZE_ROUND(s->slice_max_bytes);
> -        if (r_size > slice_ceil) {
> -            s->slice_max_bytes -= r_size - slice_ceil;
> -            r_size = SSIZE_ROUND(s->slice_max_bytes);
> -        }
> -        sig_size = r_size/s->size_scaler; /* Signalled slize size */
> -        s->size_scaler <<= 1;
> -    }
>  
> -    s->slice_min_bytes = s->slice_max_bytes - s->slice_max_bytes*(s->tolerance/100.0f);
> -    if (s->slice_min_bytes < 0 || s->slice_max_bytes > INT_MAX >> 3)
> -        return AVERROR(EINVAL);
> +    ret = ff_vc2_frame_init_properties(avctx, s);
> +    if (ret)
> +        return ret;
>  
> -    ret = encode_frame(s, avpkt, frame, aux_data, header_size, s->interlaced);
> +    ret = encode_frame(s, avpkt, frame, header_size, s->interlaced);
>      if (ret)
>          return ret;
>      if (s->interlaced) {
> -        ret = encode_frame(s, avpkt, frame, aux_data, header_size, 2);
> +        ret = encode_frame(s, avpkt, frame, header_size, 2);
>          if (ret)
>              return ret;
>      }
> @@ -1026,83 +493,13 @@ static av_cold int vc2_encode_end(AVCodecContext *avctx)
>  
>  static av_cold int vc2_encode_init(AVCodecContext *avctx)
>  {
> -    static AVOnce init_static_once = AV_ONCE_INIT;
>      Plane *p;
>      SubBand *b;
> -    int i, level, o, shift;
> +    int ret, i, level, o, shift;
>      const AVPixFmtDescriptor *pixdesc;
>      int depth;
>      VC2EncContext *s = avctx->priv_data;
>  
> -    s->picture_number = 0;
> -
> -    /* Total allowed quantization range */
> -    s->q_ceil    = DIRAC_MAX_QUANT_INDEX;
> -
> -    s->ver.major = 2;
> -    s->ver.minor = 0;
> -    s->profile   = 3;
> -    s->level     = 3;
> -
> -    s->base_vf   = -1;
> -    s->strict_compliance = 1;
> -
> -    s->q_avg = 0;
> -    s->slice_max_bytes = 0;
> -    s->slice_min_bytes = 0;
> -
> -    /* Mark unknown as progressive */
> -    s->interlaced = !((avctx->field_order == AV_FIELD_UNKNOWN) ||
> -                      (avctx->field_order == AV_FIELD_PROGRESSIVE));
> -
> -    for (i = 0; i < base_video_fmts_len; i++) {
> -        const VC2BaseVideoFormat *fmt = &base_video_fmts[i];
> -        if (avctx->pix_fmt != fmt->pix_fmt)
> -            continue;
> -        if (avctx->time_base.num != fmt->time_base.num)
> -            continue;
> -        if (avctx->time_base.den != fmt->time_base.den)
> -            continue;
> -        if (avctx->width != fmt->width)
> -            continue;
> -        if (avctx->height != fmt->height)
> -            continue;
> -        if (s->interlaced != fmt->interlaced)
> -            continue;
> -        s->base_vf = i;
> -        s->level   = base_video_fmts[i].level;
> -        break;
> -    }
> -
> -    if (s->interlaced)
> -        av_log(avctx, AV_LOG_WARNING, "Interlacing enabled!\n");
> -
> -    if ((s->slice_width  & (s->slice_width  - 1)) ||
> -        (s->slice_height & (s->slice_height - 1))) {
> -        av_log(avctx, AV_LOG_ERROR, "Slice size is not a power of two!\n");
> -        return AVERROR(EINVAL);
> -    }
> -
> -    if ((s->slice_width > avctx->width) ||
> -        (s->slice_height > avctx->height)) {
> -        av_log(avctx, AV_LOG_ERROR, "Slice size is bigger than the image!\n");
> -        return AVERROR(EINVAL);
> -    }
> -
> -    if (s->base_vf <= 0) {
> -        if (avctx->strict_std_compliance < FF_COMPLIANCE_STRICT) {
> -            s->strict_compliance = s->base_vf = 0;
> -            av_log(avctx, AV_LOG_WARNING, "Format does not strictly comply with VC2 specs\n");
> -        } else {
> -            av_log(avctx, AV_LOG_WARNING, "Given format does not strictly comply with "
> -                   "the specifications, decrease strictness to use it.\n");
> -            return AVERROR(EINVAL);
> -        }
> -    } else {
> -        av_log(avctx, AV_LOG_INFO, "Selected base video format = %i (%s)\n",
> -               s->base_vf, base_video_fmts[s->base_vf].name);
> -    }
> -
>      pixdesc = av_pix_fmt_desc_get(avctx->pix_fmt);
>      /* Chroma subsampling */
>      s->chroma_x_shift = pixdesc->log2_chroma_w;
> @@ -1110,47 +507,21 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx)
>  
>      /* Bit depth and color range index */
>      depth = pixdesc->comp[0].depth;
> -    if (depth == 8 && avctx->color_range == AVCOL_RANGE_JPEG) {
> -        s->bpp = 1;
> -        s->bpp_idx = 1;
> -        s->diff_offset = 128;
> -    } else if (depth == 8 && (avctx->color_range == AVCOL_RANGE_MPEG ||
> -               avctx->color_range == AVCOL_RANGE_UNSPECIFIED)) {
> -        s->bpp = 1;
> -        s->bpp_idx = 2;
> -        s->diff_offset = 128;
> -    } else if (depth == 10) {
> -        s->bpp = 2;
> -        s->bpp_idx = 3;
> -        s->diff_offset = 512;
> -    } else {
> -        s->bpp = 2;
> -        s->bpp_idx = 4;
> -        s->diff_offset = 2048;
> -    }
> +
> +    /* Context initialization */
> +    ret = ff_vc2_encode_init(avctx, depth);
> +    if (ret < 0)
> +        return ret;
>  
>      /* Planes initialization */
>      for (i = 0; i < 3; i++) {
> -        int w, h;
>          p = &s->plane[i];
> -        p->width      = avctx->width  >> (i ? s->chroma_x_shift : 0);
> -        p->height     = avctx->height >> (i ? s->chroma_y_shift : 0);
> -        if (s->interlaced)
> -            p->height >>= 1;
> -        p->dwt_width  = w = FFALIGN(p->width,  (1 << s->wavelet_depth));
> -        p->dwt_height = h = FFALIGN(p->height, (1 << s->wavelet_depth));
> -        p->coef_stride = FFALIGN(p->dwt_width, 32);
>          p->coef_buf = av_mallocz(p->coef_stride*p->dwt_height*sizeof(dwtcoef));
>          if (!p->coef_buf)
>              return AVERROR(ENOMEM);
>          for (level = s->wavelet_depth-1; level >= 0; level--) {
> -            w = w >> 1;
> -            h = h >> 1;
>              for (o = 0; o < 4; o++) {
>                  b = &p->band[level][o];
> -                b->width  = w;
> -                b->height = h;
> -                b->stride = p->coef_stride;
>                  shift = (o > 1)*b->height*b->stride + (o & 1)*b->width;
>                  b->buf = p->coef_buf + shift;
>              }
> @@ -1164,10 +535,6 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx)
>              return AVERROR(ENOMEM);
>      }
>  
> -    /* Slices */
> -    s->num_x = s->plane[0].dwt_width/s->slice_width;
> -    s->num_y = s->plane[0].dwt_height/s->slice_height;
> -
>      s->slice_args = av_calloc(s->num_x*s->num_y, sizeof(SliceArgs));
>      if (!s->slice_args)
>          return AVERROR(ENOMEM);
> @@ -1189,8 +556,6 @@ static av_cold int vc2_encode_init(AVCodecContext *avctx)
>          }
>      }
>  
> -    ff_thread_once(&init_static_once, vc2_init_static_data);
> -
>      return 0;
>  }
>  
> diff --git a/libavcodec/vc2enc_common.c b/libavcodec/vc2enc_common.c
> new file mode 100644
> index 0000000000..bd27fd3c40
> --- /dev/null
> +++ b/libavcodec/vc2enc_common.c
> @@ -0,0 +1,571 @@
> +/*
> +* Copyright (C) 2016 Open Broadcast Systems Ltd.
> +* Author        2016 Rostislav Pehlivanov <atomnuker at gmail.com>
> +*
> +* This file is part of FFmpeg.
> +*
> +* FFmpeg is free software; you can redistribute it and/or
> +* modify it under the terms of the GNU Lesser General Public
> +* License as published by the Free Software Foundation; either
> +* version 2.1 of the License, or (at your option) any later version.
> +*
> +* FFmpeg is distributed in the hope that it will be useful,
> +* but WITHOUT ANY WARRANTY; without even the implied warranty of
> +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +* Lesser General Public License for more details.
> +*
> +* You should have received a copy of the GNU Lesser General Public
> +* License along with FFmpeg; if not, write to the Free Software
> +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +*/
> +
> +#include "libavutil/pixdesc.h"
> +#include "libavutil/thread.h"
> +#include "vc2enc_common.h"
> +#include "version.h"
> +
> +typedef struct VC2BaseVideoFormat {
> +    enum AVPixelFormat pix_fmt;
> +    AVRational time_base;
> +    int width, height;
> +    uint8_t interlaced, level;
> +    char name[13];
> +} VC2BaseVideoFormat;
> +
> +static const VC2BaseVideoFormat base_video_fmts[] = {
> +    { 0 }, /* Custom format, here just to make indexing equal to base_vf */
> +    { AV_PIX_FMT_YUV420P,   { 1001, 15000 },  176,  120, 0, 1,     "QSIF525" },
> +    { AV_PIX_FMT_YUV420P,   {    2,    25 },  176,  144, 0, 1,     "QCIF"    },
> +    { AV_PIX_FMT_YUV420P,   { 1001, 15000 },  352,  240, 0, 1,     "SIF525"  },
> +    { AV_PIX_FMT_YUV420P,   {    2,    25 },  352,  288, 0, 1,     "CIF"     },
> +    { AV_PIX_FMT_YUV420P,   { 1001, 15000 },  704,  480, 0, 1,     "4SIF525" },
> +    { AV_PIX_FMT_YUV420P,   {    2,    25 },  704,  576, 0, 1,     "4CIF"    },
> +
> +    { AV_PIX_FMT_YUV422P10, { 1001, 30000 },  720,  480, 1, 2,   "SD480I-60" },
> +    { AV_PIX_FMT_YUV422P10, {    1,    25 },  720,  576, 1, 2,   "SD576I-50" },
> +
> +    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 1280,  720, 0, 3,  "HD720P-60"  },
> +    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 1280,  720, 0, 3,  "HD720P-50"  },
> +    { AV_PIX_FMT_YUV422P10, { 1001, 30000 }, 1920, 1080, 1, 3,  "HD1080I-60" },
> +    { AV_PIX_FMT_YUV422P10, {    1,    25 }, 1920, 1080, 1, 3,  "HD1080I-50" },
> +    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 1920, 1080, 0, 3,  "HD1080P-60" },
> +    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 1920, 1080, 0, 3,  "HD1080P-50" },
> +
> +    { AV_PIX_FMT_YUV444P12, {    1,    24 }, 2048, 1080, 0, 4,        "DC2K" },
> +    { AV_PIX_FMT_YUV444P12, {    1,    24 }, 4096, 2160, 0, 5,        "DC4K" },
> +
> +    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 3840, 2160, 0, 6, "UHDTV 4K-60" },
> +    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 3840, 2160, 0, 6, "UHDTV 4K-50" },
> +
> +    { AV_PIX_FMT_YUV422P10, { 1001, 60000 }, 7680, 4320, 0, 7, "UHDTV 8K-60" },
> +    { AV_PIX_FMT_YUV422P10, {    1,    50 }, 7680, 4320, 0, 7, "UHDTV 8K-50" },
> +
> +    { AV_PIX_FMT_YUV422P10, { 1001, 24000 }, 1920, 1080, 0, 3,  "HD1080P-24" },
> +    { AV_PIX_FMT_YUV422P10, { 1001, 30000 },  720,  486, 1, 2,  "SD Pro486"  },
> +};
> +static const int base_video_fmts_len = FF_ARRAY_ELEMS(base_video_fmts);
> +
> +/// x_k x_{k-1} ... x_0 -> 0 x_k 0 x_{k - 1} ... 0 x_0
> +uint16_t interleaved_ue_golomb_tab[256];
> +/// 1 x_{k-1} ... x_0 -> 0 0 0 x_{k - 1} ... 0 x_0
> +uint16_t top_interleaved_ue_golomb_tab[256];
> +/// 1 x_{k-1} ... x_0 -> 2 * k
> +uint8_t golomb_len_tab[256];
> +
> +static av_cold void vc2_init_static_data(void)
> +{
> +    interleaved_ue_golomb_tab[1] = 1;
> +    for (unsigned i = 2; i < 256; ++i) {
> +        golomb_len_tab[i] = golomb_len_tab[i >> 1] + 2;
> +        interleaved_ue_golomb_tab[i] = (interleaved_ue_golomb_tab[i >> 1] << 2) | (i & 1);
> +        top_interleaved_ue_golomb_tab[i] = interleaved_ue_golomb_tab[i] ^ (1 << golomb_len_tab[i]);
> +    }
> +}
> +
> +static void put_vc2_ue_uint(PutBitContext *pb, uint32_t val)
> +{
> +    put_vc2_ue_uint_inline(pb, val);
> +}
> +
> +/* VC-2 10.4 - parse_info() */
> +static void encode_parse_info(VC2EncContext *s, enum DiracParseCodes pcode)
> +{
> +    uint32_t cur_pos, dist;
> +
> +    align_put_bits(&s->pb);
> +
> +    cur_pos = put_bytes_count(&s->pb, 0);
> +
> +    /* Magic string */
> +    ff_put_string(&s->pb, "BBCD", 0);
> +
> +    /* Parse code */
> +    put_bits(&s->pb, 8, pcode);
> +
> +    /* Next parse offset */
> +    dist = cur_pos - s->next_parse_offset;
> +    AV_WB32(s->pb.buf + s->next_parse_offset + 5, dist);
> +    s->next_parse_offset = cur_pos;
> +    put_bits32(&s->pb, pcode == DIRAC_PCODE_END_SEQ ? 13 : 0);
> +
> +    cur_pos = put_bytes_count(&s->pb, 0);
> +
> +    /* Last parse offset */
> +    put_bits32(&s->pb, s->last_parse_code == DIRAC_PCODE_END_SEQ ? 13 : dist);
> +
> +    s->last_parse_code = pcode;
> +}
> +
> +/* VC-2 11.1 - parse_parameters()
> +* The level dictates what the decoder should expect in terms of resolution
> +* and allows it to quickly reject whatever it can't support. Remember,
> +* this codec kinda targets cheapo FPGAs without much memory. Unfortunately
> +* it also limits us greatly in our choice of formats, hence the flag to disable
> +* strict_compliance */
> +static void encode_parse_params(VC2EncContext *s)
> +{
> +    put_vc2_ue_uint(&s->pb, s->ver.major); /* VC-2 demands this to be 2 */
> +    put_vc2_ue_uint(&s->pb, s->ver.minor); /* ^^ and this to be 0       */
> +    put_vc2_ue_uint(&s->pb, s->profile);   /* 3 to signal HQ profile    */
> +    put_vc2_ue_uint(&s->pb, s->level);     /* 3 - 1080/720, 6 - 4K      */
> +}
> +
> +/* VC-2 11.3 - frame_size() */
> +static void encode_frame_size(VC2EncContext *s)
> +{
> +    put_bits(&s->pb, 1, !s->strict_compliance);
> +    if (!s->strict_compliance) {
> +        AVCodecContext *avctx = s->avctx;
> +        put_vc2_ue_uint(&s->pb, avctx->width);
> +        put_vc2_ue_uint(&s->pb, avctx->height);
> +    }
> +}
> +
> +/* VC-2 11.3.3 - color_diff_sampling_format() */
> +static void encode_sample_fmt(VC2EncContext *s)
> +{
> +    put_bits(&s->pb, 1, !s->strict_compliance);
> +    if (!s->strict_compliance) {
> +        int idx;
> +        if (s->chroma_x_shift == 1 && s->chroma_y_shift == 0)
> +            idx = 1; /* 422 */
> +        else if (s->chroma_x_shift == 1 && s->chroma_y_shift == 1)
> +            idx = 2; /* 420 */
> +        else
> +            idx = 0; /* 444 */
> +        put_vc2_ue_uint(&s->pb, idx);
> +    }
> +}
> +
> +/* VC-2 11.3.4 - scan_format() */
> +static void encode_scan_format(VC2EncContext *s)
> +{
> +    put_bits(&s->pb, 1, !s->strict_compliance);
> +    if (!s->strict_compliance)
> +        put_vc2_ue_uint(&s->pb, s->interlaced);
> +}
> +
> +/* VC-2 11.3.5 - frame_rate() */
> +static void encode_frame_rate(VC2EncContext *s)
> +{
> +    put_bits(&s->pb, 1, !s->strict_compliance);
> +    if (!s->strict_compliance) {
> +        AVCodecContext *avctx = s->avctx;
> +        put_vc2_ue_uint(&s->pb, 0);
> +        put_vc2_ue_uint(&s->pb, avctx->time_base.den);
> +        put_vc2_ue_uint(&s->pb, avctx->time_base.num);
> +    }
> +}
> +
> +/* VC-2 11.3.6 - aspect_ratio() */
> +static void encode_aspect_ratio(VC2EncContext *s)
> +{
> +    put_bits(&s->pb, 1, !s->strict_compliance);
> +    if (!s->strict_compliance) {
> +        AVCodecContext *avctx = s->avctx;
> +        put_vc2_ue_uint(&s->pb, 0);
> +        put_vc2_ue_uint(&s->pb, avctx->sample_aspect_ratio.num);
> +        put_vc2_ue_uint(&s->pb, avctx->sample_aspect_ratio.den);
> +    }
> +}
> +
> +/* VC-2 11.3.7 - clean_area() */
> +static void encode_clean_area(VC2EncContext *s)
> +{
> +    put_bits(&s->pb, 1, 0);
> +}
> +
> +/* VC-2 11.3.8 - signal_range() */
> +static void encode_signal_range(VC2EncContext *s)
> +{
> +    put_bits(&s->pb, 1, !s->strict_compliance);
> +    if (!s->strict_compliance)
> +        put_vc2_ue_uint(&s->pb, s->bpp_idx);
> +}
> +
> +/* VC-2 11.3.9 - color_spec() */
> +static void encode_color_spec(VC2EncContext *s)
> +{
> +    AVCodecContext *avctx = s->avctx;
> +    put_bits(&s->pb, 1, !s->strict_compliance);
> +    if (!s->strict_compliance) {
> +        int val;
> +        put_vc2_ue_uint(&s->pb, 0);
> +
> +        /* primaries */
> +        put_bits(&s->pb, 1, 1);
> +        if (avctx->color_primaries == AVCOL_PRI_BT470BG)
> +            val = 2;
> +        else if (avctx->color_primaries == AVCOL_PRI_SMPTE170M)
> +            val = 1;
> +        else if (avctx->color_primaries == AVCOL_PRI_SMPTE240M)
> +            val = 1;
> +        else
> +            val = 0;
> +        put_vc2_ue_uint(&s->pb, val);
> +
> +        /* color matrix */
> +        put_bits(&s->pb, 1, 1);
> +        if (avctx->colorspace == AVCOL_SPC_RGB)
> +            val = 3;
> +        else if (avctx->colorspace == AVCOL_SPC_YCOCG)
> +            val = 2;
> +        else if (avctx->colorspace == AVCOL_SPC_BT470BG)
> +            val = 1;
> +        else
> +            val = 0;
> +        put_vc2_ue_uint(&s->pb, val);
> +
> +        /* transfer function */
> +        put_bits(&s->pb, 1, 1);
> +        if (avctx->color_trc == AVCOL_TRC_LINEAR)
> +            val = 2;
> +        else if (avctx->color_trc == AVCOL_TRC_BT1361_ECG)
> +            val = 1;
> +        else
> +            val = 0;
> +        put_vc2_ue_uint(&s->pb, val);
> +    }
> +}
> +
> +/* VC-2 11.3 - source_parameters() */
> +static void encode_source_params(VC2EncContext *s)
> +{
> +    encode_frame_size(s);
> +    encode_sample_fmt(s);
> +    encode_scan_format(s);
> +    encode_frame_rate(s);
> +    encode_aspect_ratio(s);
> +    encode_clean_area(s);
> +    encode_signal_range(s);
> +    encode_color_spec(s);
> +}
> +
> +/* VC-2 11 - sequence_header() */
> +static void encode_seq_header(VC2EncContext *s)
> +{
> +    align_put_bits(&s->pb);
> +    encode_parse_params(s);
> +    put_vc2_ue_uint(&s->pb, s->base_vf);
> +    encode_source_params(s);
> +    put_vc2_ue_uint(&s->pb, s->interlaced); /* Frames or fields coding */
> +}
> +
> +/* VC-2 12.1 - picture_header() */
> +static void encode_picture_header(VC2EncContext *s)
> +{
> +    align_put_bits(&s->pb);
> +    put_bits32(&s->pb, s->picture_number++);
> +}
> +
> +/* VC-2 12.3.4.1 - slice_parameters() */
> +static void encode_slice_params(VC2EncContext *s)
> +{
> +    put_vc2_ue_uint(&s->pb, s->num_x);
> +    put_vc2_ue_uint(&s->pb, s->num_y);
> +    put_vc2_ue_uint(&s->pb, s->prefix_bytes);
> +    put_vc2_ue_uint(&s->pb, s->size_scaler);
> +}
> +
> +/* 1st idx = LL, second - vertical, third - horizontal, fourth - total */
> +static const uint8_t vc2_qm_col_tab[][4] = {
> +    {20,  9, 15,  4},
> +    { 0,  6,  6,  4},
> +    { 0,  3,  3,  5},
> +    { 0,  3,  5,  1},
> +    { 0, 11, 10, 11}
> +};
> +
> +static const uint8_t vc2_qm_flat_tab[][4] = {
> +    { 0,  0,  0,  0},
> +    { 0,  0,  0,  0},
> +    { 0,  0,  0,  0},
> +    { 0,  0,  0,  0},
> +    { 0,  0,  0,  0}
> +};
> +
> +void ff_vc2_init_quant_matrix(VC2EncContext *s, uint8_t quant[MAX_DWT_LEVELS][4])
> +{
> +    int level, orientation;
> +
> +    if (s->wavelet_depth <= 4 && s->quant_matrix == VC2_QM_DEF) {
> +        s->custom_quant_matrix = 0;
> +        for (level = 0; level < s->wavelet_depth; level++) {
> +            quant[level][0] = ff_dirac_default_qmat[s->wavelet_idx][level][0];
> +            quant[level][1] = ff_dirac_default_qmat[s->wavelet_idx][level][1];
> +            quant[level][2] = ff_dirac_default_qmat[s->wavelet_idx][level][2];
> +            quant[level][3] = ff_dirac_default_qmat[s->wavelet_idx][level][3];
> +        }
> +        return;
> +    }
> +
> +    s->custom_quant_matrix = 1;
> +
> +    if (s->quant_matrix == VC2_QM_DEF) {
> +        for (level = 0; level < s->wavelet_depth; level++) {
> +            for (orientation = 0; orientation < 4; orientation++) {
> +                if (level <= 3)
> +                    quant[level][orientation] = ff_dirac_default_qmat[s->wavelet_idx][level][orientation];
> +                else
> +                    quant[level][orientation] = vc2_qm_col_tab[level][orientation];
> +            }
> +        }
> +    } else if (s->quant_matrix == VC2_QM_COL) {
> +        for (level = 0; level < s->wavelet_depth; level++) {
> +            for (orientation = 0; orientation < 4; orientation++) {
> +                quant[level][orientation] = vc2_qm_col_tab[level][orientation];
> +            }
> +        }
> +    } else {
> +        for (level = 0; level < s->wavelet_depth; level++) {
> +            for (orientation = 0; orientation < 4; orientation++) {
> +                quant[level][orientation] = vc2_qm_flat_tab[level][orientation];
> +            }
> +        }
> +    }
> +}
> +
> +/* VC-2 12.3.4.2 - quant_matrix() */
> +static void encode_quant_matrix(VC2EncContext *s)
> +{
> +    int level;
> +    put_bits(&s->pb, 1, s->custom_quant_matrix);
> +    if (s->custom_quant_matrix) {
> +        put_vc2_ue_uint(&s->pb, s->quant[0][0]);
> +        for (level = 0; level < s->wavelet_depth; level++) {
> +            put_vc2_ue_uint(&s->pb, s->quant[level][1]);
> +            put_vc2_ue_uint(&s->pb, s->quant[level][2]);
> +            put_vc2_ue_uint(&s->pb, s->quant[level][3]);
> +        }
> +    }
> +}
> +
> +/* VC-2 12.3 - transform_parameters() */
> +static void encode_transform_params(VC2EncContext *s)
> +{
> +    put_vc2_ue_uint(&s->pb, s->wavelet_idx);
> +    put_vc2_ue_uint(&s->pb, s->wavelet_depth);
> +
> +    encode_slice_params(s);
> +    encode_quant_matrix(s);
> +}
> +
> +/* VC-2 12.2 - wavelet_transform() */
> +static void encode_wavelet_transform(VC2EncContext *s)
> +{
> +    encode_transform_params(s);
> +    align_put_bits(&s->pb);
> +}
> +
> +/* VC-2 12 - picture_parse() */
> +static void encode_picture_start(VC2EncContext *s)
> +{
> +    align_put_bits(&s->pb);
> +    encode_picture_header(s);
> +    align_put_bits(&s->pb);
> +    encode_wavelet_transform(s);
> +}
> +
> +int ff_vc2_encode_init(AVCodecContext *avctx, int depth)
> +{
> +    static AVOnce init_static_once = AV_ONCE_INIT;
> +    int i, level, o;
> +    SubBand *b;
> +    Plane *p;
> +    VC2EncContext *s = avctx->priv_data;
> +
> +    s->picture_number = 0;
> +
> +    /* Total allowed quantization range */
> +    s->q_ceil    = DIRAC_MAX_QUANT_INDEX;
> +
> +    s->ver.major = 2;
> +    s->ver.minor = 0;
> +    s->profile   = 3;
> +    s->level     = 3;
> +
> +    s->base_vf   = -1;
> +    s->strict_compliance = 1;
> +
> +    s->q_avg = 0;
> +    s->slice_max_bytes = 0;
> +    s->slice_min_bytes = 0;
> +
> +    /* Mark unknown as progressive */
> +    s->interlaced = !((avctx->field_order == AV_FIELD_UNKNOWN) ||
> +                    (avctx->field_order == AV_FIELD_PROGRESSIVE));
> +
> +    for (i = 0; i < base_video_fmts_len; i++) {
> +        const VC2BaseVideoFormat *fmt = &base_video_fmts[i];
> +        if (avctx->pix_fmt != fmt->pix_fmt || avctx->time_base.num != fmt->time_base.num ||
> +            avctx->time_base.den != fmt->time_base.den || avctx->width != fmt->width ||
> +            avctx->height != fmt->height || s->interlaced != fmt->interlaced)
> +            continue;
> +        s->base_vf = i;
> +        s->level   = base_video_fmts[i].level;
> +        break;
> +    }
> +
> +    if (s->interlaced)
> +        av_log(avctx, AV_LOG_WARNING, "Interlacing enabled!\n");
> +
> +    if ((s->slice_width  & (s->slice_width  - 1)) ||
> +        (s->slice_height & (s->slice_height - 1))) {
> +        av_log(avctx, AV_LOG_ERROR, "Slice size is not a power of two!\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    if ((s->slice_width > avctx->width) ||
> +        (s->slice_height > avctx->height)) {
> +        av_log(avctx, AV_LOG_ERROR, "Slice size is bigger than the image!\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    if (s->base_vf <= 0) {
> +        if (avctx->strict_std_compliance < FF_COMPLIANCE_STRICT) {
> +            s->strict_compliance = s->base_vf = 0;
> +            av_log(avctx, AV_LOG_WARNING, "Format does not strictly comply with VC2 specs\n");
> +        } else {
> +            av_log(avctx, AV_LOG_WARNING, "Given format does not strictly comply with "
> +                "the specifications, decrease strictness to use it.\n");
> +            return AVERROR(EINVAL);
> +        }
> +    } else {
> +        av_log(avctx, AV_LOG_INFO, "Selected base video format = %i (%s)\n",
> +            s->base_vf, base_video_fmts[s->base_vf].name);
> +    }
> +
> +    /* Bit depth and color range index */
> +    if (depth == 8 && avctx->color_range == AVCOL_RANGE_JPEG) {
> +        s->bpp = 1;
> +        s->bpp_idx = 1;
> +        s->diff_offset = 128;
> +    } else if (depth == 8 && (avctx->color_range == AVCOL_RANGE_MPEG ||
> +            avctx->color_range == AVCOL_RANGE_UNSPECIFIED)) {
> +        s->bpp = 1;
> +        s->bpp_idx = 2;
> +        s->diff_offset = 128;
> +    } else if (depth == 10) {
> +        s->bpp = 2;
> +        s->bpp_idx = 3;
> +        s->diff_offset = 512;
> +    } else {
> +        s->bpp = 2;
> +        s->bpp_idx = 4;
> +        s->diff_offset = 2048;
> +    }
> +
> +    /* Planes initialization */
> +    for (i = 0; i < 3; i++) {
> +        int w, h;
> +        p = &s->plane[i];
> +        p->width      = avctx->width  >> (i ? s->chroma_x_shift : 0);
> +        p->height     = avctx->height >> (i ? s->chroma_y_shift : 0);
> +        if (s->interlaced)
> +            p->height >>= 1;
> +        p->dwt_width  = w = FFALIGN(p->width,  (1 << s->wavelet_depth));
> +        p->dwt_height = h = FFALIGN(p->height, (1 << s->wavelet_depth));
> +        p->coef_stride = FFALIGN(p->dwt_width, 32);
> +        for (level = s->wavelet_depth-1; level >= 0; level--) {
> +            w = w >> 1;
> +            h = h >> 1;
> +            for (o = 0; o < 4; o++) {
> +                b = &p->band[level][o];
> +                b->width  = w;
> +                b->height = h;
> +                b->stride = p->coef_stride;
> +            }
> +        }
> +    }
> +
> +    /* Slices */
> +    s->num_x = s->plane[0].dwt_width/s->slice_width;
> +    s->num_y = s->plane[0].dwt_height/s->slice_height;
> +
> +    ff_thread_once(&init_static_once, vc2_init_static_data);
> +
> +    return 0;
> +}
> +
> +int ff_vc2_frame_init_properties(AVCodecContext *avctx, VC2EncContext *s)
> +{
> +    int slice_ceil, sig_size = 256;
> +    const int bitexact = avctx->flags & AV_CODEC_FLAG_BITEXACT;
> +    const int aux_data_size = bitexact ? sizeof("Lavc") : sizeof(LIBAVCODEC_IDENT);
> +    const int header_size = 100 + aux_data_size;
> +    int64_t r_bitrate = avctx->bit_rate >> (s->interlaced);
> +
> +    s->avctx = avctx;
> +    s->size_scaler = 2;
> +    s->prefix_bytes = 0;
> +    s->last_parse_code = 0;
> +    s->next_parse_offset = 0;
> +
> +    /* Rate control */
> +    s->frame_max_bytes = (av_rescale(r_bitrate, s->avctx->time_base.num,
> +                                     s->avctx->time_base.den) >> 3) - header_size;
> +    s->slice_max_bytes = slice_ceil = av_rescale(s->frame_max_bytes, 1, s->num_x * s->num_y);
> +
> +    /* Find an appropriate size scaler */
> +    while (sig_size > 255) {
> +        int r_size = SSIZE_ROUND(s->slice_max_bytes);
> +        if (r_size > slice_ceil) {
> +            s->slice_max_bytes -= r_size - slice_ceil;
> +            r_size = SSIZE_ROUND(s->slice_max_bytes);
> +        }
> +        sig_size = r_size/s->size_scaler; /* Signalled slize size */
> +        s->size_scaler <<= 1;
> +    }
> +
> +    s->slice_min_bytes = s->slice_max_bytes - s->slice_max_bytes*(s->tolerance/100.0f);
> +    if (s->slice_min_bytes < 0 || s->slice_max_bytes > INT_MAX >> 3)
> +        return AVERROR(EINVAL);
> +
> +    return 0;
> +}
> +
> +void ff_vc2_encode_frame(VC2EncContext *s, void(*encode_slices)(VC2EncContext*))
> +{
> +    const int bitexact = s->avctx->flags & AV_CODEC_FLAG_BITEXACT;
> +    const char *aux_data = bitexact ? "Lavc" : LIBAVCODEC_IDENT;
> +
> +    /* Sequence header */
> +    encode_parse_info(s, DIRAC_PCODE_SEQ_HEADER);
> +    encode_seq_header(s);
> +
> +    /* Encoder version */
> +    if (aux_data) {
> +        encode_parse_info(s, DIRAC_PCODE_AUX);
> +        ff_put_string(&s->pb, aux_data, 1);
> +    }
> +
> +    /* Picture header */
> +    encode_parse_info(s, DIRAC_PCODE_PICTURE_HQ);
> +    encode_picture_start(s);
> +
> +    /* Encode slices */
> +    encode_slices(s);

I know that I told you to factor out writing the actual frame, but I was
not aware at the time that encode_slices() will differ between the
encoders. Better add two functions: ff_vc2_write_frame_header(), doing
everything before encode_slices() here and one
ff_vc2_write_sequence_end() for the end-of-sequence below.

> +
> +    /* End sequence */
> +    encode_parse_info(s, DIRAC_PCODE_END_SEQ);
> +}
> \ No newline at end of file
> diff --git a/libavcodec/vc2enc_common.h b/libavcodec/vc2enc_common.h
> new file mode 100644
> index 0000000000..0466869943
> --- /dev/null
> +++ b/libavcodec/vc2enc_common.h
> @@ -0,0 +1,178 @@
> +/*
> +* Copyright (C) 2016 Open Broadcast Systems Ltd.
> +* Author        2016 Rostislav Pehlivanov <atomnuker at gmail.com>
> +*
> +* This file is part of FFmpeg.
> +*
> +* FFmpeg is free software; you can redistribute it and/or
> +* modify it under the terms of the GNU Lesser General Public
> +* License as published by the Free Software Foundation; either
> +* version 2.1 of the License, or (at your option) any later version.
> +*
> +* FFmpeg is distributed in the hope that it will be useful,
> +* but WITHOUT ANY WARRANTY; without even the implied warranty of
> +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +* Lesser General Public License for more details.
> +*
> +* You should have received a copy of the GNU Lesser General Public
> +* License along with FFmpeg; if not, write to the Free Software
> +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> +*/
> +
> +#ifndef AVCODEC_VC2ENC_COMMON_H
> +#define AVCODEC_VC2ENC_COMMON_H
> +
> +#include "avcodec.h"
> +#include "dirac.h"
> +#include "put_bits.h"
> +#include "libavutil/attributes_internal.h"
> +
> +#include "vc2enc_dwt.h"
> +#include "diractab.h"
> +
> +/* The limited size resolution of each slice forces us to do this */
> +#define SSIZE_ROUND(b) (FFALIGN((b), s->size_scaler) + 4 + s->prefix_bytes)
> +
> +FF_VISIBILITY_PUSH_HIDDEN
> +
> +enum VC2_QM {
> +    VC2_QM_DEF = 0,
> +    VC2_QM_COL,
> +    VC2_QM_FLAT,
> +
> +    VC2_QM_NB
> +};
> +
> +typedef struct SubBand {
> +    dwtcoef *buf;
> +    ptrdiff_t stride;
> +    int width;
> +    int height;
> +    int shift;
> +} SubBand;
> +
> +typedef struct Plane {
> +    SubBand band[MAX_DWT_LEVELS][4];
> +    dwtcoef *coef_buf;
> +    int width;
> +    int height;
> +    int dwt_width;
> +    int dwt_height;
> +    ptrdiff_t coef_stride;
> +} Plane;
> +
> +typedef struct SliceArgs {
> +    const struct VC2EncContext *ctx;
> +    union {
> +        int cache[DIRAC_MAX_QUANT_INDEX];
> +        uint8_t *buf;
> +    };
> +    int x;
> +    int y;
> +    int quant_idx;
> +    int bits_ceil;
> +    int bits_floor;
> +    int bytes;
> +} SliceArgs;

This structure is only used by the software encoder; use a "struct
SliceArgs *" below and keep this structure in vc2enc.c. This will allow
to avoid the diractab inclusion (if I am not mistaken).

> +
> +typedef struct TransformArgs {
> +    const struct VC2EncContext *ctx;
> +    Plane *plane;
> +    const void *idata;
> +    ptrdiff_t istride;
> +    int field;
> +    VC2TransformContext t;
> +} TransformArgs;
> +
> +typedef struct VC2EncContext {
> +    AVClass *av_class;
> +    PutBitContext pb;
> +    Plane plane[3];
> +    AVCodecContext *avctx;
> +    DiracVersionInfo ver;
> +
> +    SliceArgs *slice_args;
> +    TransformArgs transform_args[3];
> +
> +    /* For conversion from unsigned pixel values to signed */
> +    int diff_offset;
> +    int bpp;
> +    int bpp_idx;
> +
> +    /* Picture number */
> +    uint32_t picture_number;
> +
> +    /* Base video format */
> +    int base_vf;
> +    int level;
> +    int profile;
> +
> +    /* Quantization matrix */
> +    uint8_t quant[MAX_DWT_LEVELS][4];
> +    int custom_quant_matrix;
> +
> +    /* Division LUT */
> +    uint32_t qmagic_lut[116][2];
> +
> +    int num_x; /* #slices horizontally */
> +    int num_y; /* #slices vertically */
> +    int prefix_bytes;
> +    int size_scaler;
> +    int chroma_x_shift;
> +    int chroma_y_shift;
> +
> +    /* Rate control stuff */
> +    int frame_max_bytes;
> +    int slice_max_bytes;
> +    int slice_min_bytes;
> +    int q_ceil;
> +    int q_avg;
> +
> +    /* Options */
> +    double tolerance;
> +    int wavelet_idx;
> +    int wavelet_depth;
> +    int strict_compliance;
> +    int slice_height;
> +    int slice_width;
> +    int interlaced;
> +    enum VC2_QM quant_matrix;
> +
> +    /* Parse code state */
> +    uint32_t next_parse_offset;
> +    enum DiracParseCodes last_parse_code;
> +} VC2EncContext;
> +
> +extern uint16_t interleaved_ue_golomb_tab[256];
> +extern uint16_t top_interleaved_ue_golomb_tab[256];
> +extern uint8_t golomb_len_tab[256];

Missing ff_ prefix.

> +
> +static inline void put_vc2_ue_uint_inline(PutBitContext *pb, uint32_t val)
> +{
> +    uint64_t pbits = 1;
> +    int bits = 1;
> +
> +    ++val;
> +
> +    while (val >> 8) {
> +        pbits |= (uint64_t)interleaved_ue_golomb_tab[val & 0xff] << bits;
> +        val  >>= 8;
> +        bits  += 16;
> +    }
> +    pbits |= (uint64_t)top_interleaved_ue_golomb_tab[val] << bits;
> +    bits  += golomb_len_tab[val];
> +
> +    put_bits63(pb, bits, pbits);
> +}
> +
> +int ff_vc2_encode_init(AVCodecContext *avctx, int depth);
> +
> +int ff_vc2_frame_init_properties(AVCodecContext *avctx, VC2EncContext *s);
> +
> +void ff_vc2_init_quant_matrix(VC2EncContext *s, uint8_t quant[MAX_DWT_LEVELS][4]);
> +
> +void ff_vc2_encode_frame(VC2EncContext *s, void(*encode_slices)(VC2EncContext*));
> +
> +FF_VISIBILITY_POP_HIDDEN
> +
> +#endif



More information about the ffmpeg-devel mailing list