IndecisiveTurtle: > From: IndecisiveTurtle <geoste...@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 <atomnu...@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 <atomnu...@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 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".