From: IndecisiveTurtle <[email protected]>
---
libavcodec/Makefile | 2 +-
libavcodec/proresenc_kostya.c | 414 +--------------------------
libavcodec/proresenc_kostya_common.c | 364 +++++++++++++++++++++++
libavcodec/proresenc_kostya_common.h | 131 +++++++++
4 files changed, 511 insertions(+), 400 deletions(-)
create mode 100644 libavcodec/proresenc_kostya_common.c
create mode 100644 libavcodec/proresenc_kostya_common.h
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 3d036de4b6..d8e1ac5a54 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -638,7 +638,7 @@ OBJS-$(CONFIG_PPM_ENCODER) += pnmenc.o
OBJS-$(CONFIG_PRORES_DECODER) += proresdec.o proresdsp.o proresdata.o
OBJS-$(CONFIG_PRORES_ENCODER) += proresenc_anatoliy.o proresdata.o
OBJS-$(CONFIG_PRORES_AW_ENCODER) += proresenc_anatoliy.o proresdata.o
-OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o
+OBJS-$(CONFIG_PRORES_KS_ENCODER) += proresenc_kostya.o proresdata.o
proresenc_kostya_common.o
OBJS-$(CONFIG_PRORES_RAW_DECODER) += prores_raw.o proresdsp.o proresdata.o
OBJS-$(CONFIG_PRORES_VIDEOTOOLBOX_ENCODER) += videotoolboxenc.o
OBJS-$(CONFIG_PROSUMER_DECODER) += prosumer.o
diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c
index b98bc5c195..31d22a14ac 100644
--- a/libavcodec/proresenc_kostya.c
+++ b/libavcodec/proresenc_kostya.c
@@ -33,179 +33,7 @@
#include "profiles.h"
#include "bytestream.h"
#include "proresdata.h"
-
-#define CFACTOR_Y422 2
-#define CFACTOR_Y444 3
-
-#define MAX_MBS_PER_SLICE 8
-
-#define MAX_PLANES 4
-
-enum {
- PRORES_PROFILE_AUTO = -1,
- PRORES_PROFILE_PROXY = 0,
- PRORES_PROFILE_LT,
- PRORES_PROFILE_STANDARD,
- PRORES_PROFILE_HQ,
- PRORES_PROFILE_4444,
- PRORES_PROFILE_4444XQ,
-};
-
-enum {
- QUANT_MAT_PROXY = 0,
- QUANT_MAT_PROXY_CHROMA,
- QUANT_MAT_LT,
- QUANT_MAT_STANDARD,
- QUANT_MAT_HQ,
- QUANT_MAT_XQ_LUMA,
- QUANT_MAT_DEFAULT,
-};
-
-static const uint8_t prores_quant_matrices[][64] = {
- { // proxy
- 4, 7, 9, 11, 13, 14, 15, 63,
- 7, 7, 11, 12, 14, 15, 63, 63,
- 9, 11, 13, 14, 15, 63, 63, 63,
- 11, 11, 13, 14, 63, 63, 63, 63,
- 11, 13, 14, 63, 63, 63, 63, 63,
- 13, 14, 63, 63, 63, 63, 63, 63,
- 13, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63,
- },
- { // proxy chromas
- 4, 7, 9, 11, 13, 14, 63, 63,
- 7, 7, 11, 12, 14, 63, 63, 63,
- 9, 11, 13, 14, 63, 63, 63, 63,
- 11, 11, 13, 14, 63, 63, 63, 63,
- 11, 13, 14, 63, 63, 63, 63, 63,
- 13, 14, 63, 63, 63, 63, 63, 63,
- 13, 63, 63, 63, 63, 63, 63, 63,
- 63, 63, 63, 63, 63, 63, 63, 63
- },
- { // LT
- 4, 5, 6, 7, 9, 11, 13, 15,
- 5, 5, 7, 8, 11, 13, 15, 17,
- 6, 7, 9, 11, 13, 15, 15, 17,
- 7, 7, 9, 11, 13, 15, 17, 19,
- 7, 9, 11, 13, 14, 16, 19, 23,
- 9, 11, 13, 14, 16, 19, 23, 29,
- 9, 11, 13, 15, 17, 21, 28, 35,
- 11, 13, 16, 17, 21, 28, 35, 41,
- },
- { // standard
- 4, 4, 5, 5, 6, 7, 7, 9,
- 4, 4, 5, 6, 7, 7, 9, 9,
- 5, 5, 6, 7, 7, 9, 9, 10,
- 5, 5, 6, 7, 7, 9, 9, 10,
- 5, 6, 7, 7, 8, 9, 10, 12,
- 6, 7, 7, 8, 9, 10, 12, 15,
- 6, 7, 7, 9, 10, 11, 14, 17,
- 7, 7, 9, 10, 11, 14, 17, 21,
- },
- { // high quality
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 5,
- 4, 4, 4, 4, 4, 4, 5, 5,
- 4, 4, 4, 4, 4, 5, 5, 6,
- 4, 4, 4, 4, 5, 5, 6, 7,
- 4, 4, 4, 4, 5, 6, 7, 7,
- },
- { // XQ luma
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 2,
- 2, 2, 2, 2, 2, 2, 2, 3,
- 2, 2, 2, 2, 2, 2, 3, 3,
- 2, 2, 2, 2, 2, 3, 3, 3,
- 2, 2, 2, 2, 3, 3, 3, 4,
- 2, 2, 2, 2, 3, 3, 4, 4,
- },
- { // codec default
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- 4, 4, 4, 4, 4, 4, 4, 4,
- },
-};
-
-#define NUM_MB_LIMITS 4
-static const int prores_mb_limits[NUM_MB_LIMITS] = {
- 1620, // up to 720x576
- 2700, // up to 960x720
- 6075, // up to 1440x1080
- 9216, // up to 2048x1152
-};
-
-static const struct prores_profile {
- const char *full_name;
- uint32_t tag;
- int min_quant;
- int max_quant;
- int br_tab[NUM_MB_LIMITS];
- int quant;
- int quant_chroma;
-} prores_profile_info[6] = {
- {
- .full_name = "proxy",
- .tag = MKTAG('a', 'p', 'c', 'o'),
- .min_quant = 4,
- .max_quant = 8,
- .br_tab = { 300, 242, 220, 194 },
- .quant = QUANT_MAT_PROXY,
- .quant_chroma = QUANT_MAT_PROXY_CHROMA,
- },
- {
- .full_name = "LT",
- .tag = MKTAG('a', 'p', 'c', 's'),
- .min_quant = 1,
- .max_quant = 9,
- .br_tab = { 720, 560, 490, 440 },
- .quant = QUANT_MAT_LT,
- .quant_chroma = QUANT_MAT_LT,
- },
- {
- .full_name = "standard",
- .tag = MKTAG('a', 'p', 'c', 'n'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 1050, 808, 710, 632 },
- .quant = QUANT_MAT_STANDARD,
- .quant_chroma = QUANT_MAT_STANDARD,
- },
- {
- .full_name = "high quality",
- .tag = MKTAG('a', 'p', 'c', 'h'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 1566, 1216, 1070, 950 },
- .quant = QUANT_MAT_HQ,
- .quant_chroma = QUANT_MAT_HQ,
- },
- {
- .full_name = "4444",
- .tag = MKTAG('a', 'p', '4', 'h'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 2350, 1828, 1600, 1425 },
- .quant = QUANT_MAT_HQ,
- .quant_chroma = QUANT_MAT_HQ,
- },
- {
- .full_name = "4444XQ",
- .tag = MKTAG('a', 'p', '4', 'x'),
- .min_quant = 1,
- .max_quant = 6,
- .br_tab = { 3525, 2742, 2400, 2137 },
- .quant = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */
- .quant_chroma = QUANT_MAT_HQ,
- }
-};
+#include "proresenc_kostya_common.h"
#define TRELLIS_WIDTH 16
#define SCORE_LIMIT INT_MAX / 2
@@ -217,8 +45,6 @@ struct TrellisNode {
int score;
};
-#define MAX_STORED_Q 16
-
typedef struct ProresThreadData {
DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 *
MAX_MBS_PER_SLICE];
DECLARE_ALIGNED(16, uint16_t, emu_buf)[16 * 16];
@@ -227,49 +53,6 @@ typedef struct ProresThreadData {
struct TrellisNode *nodes;
} ProresThreadData;
-typedef struct ProresContext {
- AVClass *class;
- DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 *
MAX_MBS_PER_SLICE];
- DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
- int16_t quants[MAX_STORED_Q][64];
- int16_t quants_chroma[MAX_STORED_Q][64];
- int16_t custom_q[64];
- int16_t custom_chroma_q[64];
- const uint8_t *quant_mat;
- const uint8_t *quant_chroma_mat;
- const uint8_t *scantable;
-
- void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src,
- ptrdiff_t linesize, int16_t *block);
- FDCTDSPContext fdsp;
-
- const AVFrame *pic;
- int mb_width, mb_height;
- int mbs_per_slice;
- int num_chroma_blocks, chroma_factor;
- int slices_width;
- int slices_per_picture;
- int pictures_per_frame; // 1 for progressive, 2 for interlaced
- int cur_picture_idx;
- int num_planes;
- int bits_per_mb;
- int force_quant;
- int alpha_bits;
- int warn;
-
- char *vendor;
- int quant_sel;
-
- int frame_size_upper_bound;
-
- int profile;
- const struct prores_profile *profile_info;
-
- int *slice_q;
-
- ProresThreadData *tdata;
-} ProresContext;
-
static void get_slice_data(ProresContext *ctx, const uint16_t *src,
ptrdiff_t linesize, int x, int y, int w, int h,
int16_t *blocks, uint16_t *emu_buf,
@@ -369,6 +152,8 @@ static void get_alpha_data(ProresContext *ctx, const
uint16_t *src,
}
}
+int slice = 0;
+
/**
* Write an unsigned rice/exp golomb codeword.
*/
@@ -437,7 +222,6 @@ static void encode_acs(PutBitContext *pb, int16_t *blocks,
int prev_level = 2;
int run = 0, level;
int max_coeffs, abs_level;
-
max_coeffs = blocks_per_slice << 6;
for (i = 1; i < 64; i++) {
@@ -685,7 +469,6 @@ static int estimate_acs(int *error, int16_t *blocks, int
blocks_per_slice,
bits += estimate_vlc(ff_prores_run_to_cb[prev_run], run);
bits += estimate_vlc(ff_prores_level_to_cb[prev_level],
abs_level - 1) + 1;
-
prev_run = FFMIN(run, 15);
prev_level = FFMIN(abs_level, 9);
run = 0;
@@ -905,7 +688,6 @@ static int find_slice_quant(AVCodecContext *avctx,
for (q = min_quant; q < max_quant + 2; q++) {
cur = trellis_node + q;
-
bits = td->nodes[prev].bits + slice_bits[q];
error = slice_score[q];
if (bits > bits_limit)
@@ -965,67 +747,33 @@ static int encode_frame(AVCodecContext *avctx, AVPacket
*pkt,
const AVFrame *pic, int *got_packet)
{
ProresContext *ctx = avctx->priv_data;
- uint8_t *orig_buf, *buf, *slice_hdr, *slice_sizes, *tmp;
+ uint8_t *orig_buf, *buf, *slice_hdr, *slice_sizes;
uint8_t *picture_size_pos;
PutBitContext pb;
int x, y, i, mb, q = 0;
int sizes[4] = { 0 };
- int slice_hdr_size = 2 + 2 * (ctx->num_planes - 1);
+ int slice_hdr_size = 2 * ctx->num_planes;
int frame_size, picture_size, slice_size;
int pkt_size, ret;
int max_slice_size = (ctx->frame_size_upper_bound - 200) /
(ctx->pictures_per_frame * ctx->slices_per_picture + 1);
- uint8_t frame_flags;
+ pkt_size = ctx->frame_size_upper_bound;
ctx->pic = pic;
- pkt_size = ctx->frame_size_upper_bound;
if ((ret = ff_alloc_packet(avctx, pkt, pkt_size +
FF_INPUT_BUFFER_MIN_SIZE)) < 0)
return ret;
orig_buf = pkt->data;
-
- // frame atom
- orig_buf += 4; // frame size
- bytestream_put_be32 (&orig_buf, FRAME_ID); // frame container ID
- buf = orig_buf;
-
- // frame header
- tmp = buf;
- buf += 2; // frame header size will be
stored here
- bytestream_put_be16 (&buf, ctx->chroma_factor != CFACTOR_Y422 ||
ctx->alpha_bits ? 1 : 0);
- bytestream_put_buffer(&buf, ctx->vendor, 4);
- bytestream_put_be16 (&buf, avctx->width);
- bytestream_put_be16 (&buf, avctx->height);
-
- frame_flags = ctx->chroma_factor << 6;
- if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT)
- frame_flags |= (pic->flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 0x04 :
0x08;
- bytestream_put_byte (&buf, frame_flags);
-
- bytestream_put_byte (&buf, 0); // reserved
- bytestream_put_byte (&buf, pic->color_primaries);
- bytestream_put_byte (&buf, pic->color_trc);
- bytestream_put_byte (&buf, pic->colorspace);
- bytestream_put_byte (&buf, ctx->alpha_bits >> 3);
- bytestream_put_byte (&buf, 0); // reserved
- if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
- bytestream_put_byte (&buf, 0x03); // matrix flags - both
matrices are present
- bytestream_put_buffer(&buf, ctx->quant_mat, 64); // luma
quantisation matrix
- bytestream_put_buffer(&buf, ctx->quant_chroma_mat, 64); // chroma
quantisation matrix
- } else {
- bytestream_put_byte (&buf, 0x00); // matrix flags - default
matrices are used
- }
- bytestream_put_be16 (&tmp, buf - orig_buf); // write back frame header
size
+ buf = ff_prores_kostya_write_frame_header(avctx, ctx, &orig_buf,
pic->flags,
+ pic->color_primaries, pic->color_trc,
+ pic->colorspace);
for (ctx->cur_picture_idx = 0;
ctx->cur_picture_idx < ctx->pictures_per_frame;
ctx->cur_picture_idx++) {
// picture header
picture_size_pos = buf + 1;
- bytestream_put_byte (&buf, 0x40); // picture header size (in
bits)
- buf += 4; // picture data size will
be stored here
- bytestream_put_be16 (&buf, ctx->slices_per_picture);
- bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); //
slice width and height in MBs
+ buf = ff_prores_kostya_write_picture_header(ctx, buf);
// seek table - will be filled during slice encoding
slice_sizes = buf;
@@ -1048,7 +796,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket
*pkt,
while (ctx->mb_width - x < mbs_per_slice)
mbs_per_slice >>= 1;
- bytestream_put_byte(&buf, slice_hdr_size << 3);
+ bytestream_put_byte(&buf, slice_hdr_size * 8);
slice_hdr = buf;
buf += slice_hdr_size - 1;
if (pkt_size <= buf - orig_buf + 2 * max_slice_size) {
@@ -1076,13 +824,11 @@ static int encode_frame(AVCodecContext *avctx, AVPacket
*pkt,
return ret;
pkt_size += delta;
- // restore pointers
orig_buf = pkt->data + (orig_buf - start);
buf = pkt->data + (buf - start);
picture_size_pos = pkt->data + (picture_size_pos - start);
slice_sizes = pkt->data + (slice_sizes - start);
slice_hdr = pkt->data + (slice_hdr - start);
- tmp = pkt->data + (tmp - start);
}
init_put_bits(&pb, buf, (pkt_size - (buf - orig_buf)));
ret = encode_slice(avctx, pic, &pb, sizes, x, y, q,
@@ -1149,105 +895,18 @@ static void prores_fdct(FDCTDSPContext *fdsp, const
uint16_t *src,
static av_cold int encode_init(AVCodecContext *avctx)
{
ProresContext *ctx = avctx->priv_data;
- int mps;
- int i, j;
- int min_quant, max_quant;
- int interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT);
+ int err = 0, i, j, min_quant, max_quant;
- avctx->bits_per_raw_sample = 10;
+ err = ff_prores_kostya_encode_init(avctx, ctx, avctx->pix_fmt);
+ if (err < 0)
+ return err;
ctx->fdct = prores_fdct;
- ctx->scantable = interlaced ? ff_prores_interlaced_scan
- : ff_prores_progressive_scan;
ff_fdctdsp_init(&ctx->fdsp, avctx);
- mps = ctx->mbs_per_slice;
- if (mps & (mps - 1)) {
- av_log(avctx, AV_LOG_ERROR,
- "there should be an integer power of two MBs per slice\n");
- return AVERROR(EINVAL);
- }
- if (ctx->profile == PRORES_PROFILE_AUTO) {
- const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(avctx->pix_fmt);
- ctx->profile = (desc->flags & AV_PIX_FMT_FLAG_ALPHA ||
- !(desc->log2_chroma_w + desc->log2_chroma_h))
- ? PRORES_PROFILE_4444 : PRORES_PROFILE_HQ;
- av_log(avctx, AV_LOG_INFO, "Autoselected %s. It can be overridden "
- "through -profile option.\n", ctx->profile ==
PRORES_PROFILE_4444
- ? "4:4:4:4 profile because of the used input colorspace"
- : "HQ profile to keep best quality");
- }
- if (av_pix_fmt_desc_get(avctx->pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
- if (ctx->profile != PRORES_PROFILE_4444 &&
- ctx->profile != PRORES_PROFILE_4444XQ) {
- // force alpha and warn
- av_log(avctx, AV_LOG_WARNING, "Profile selected will not "
- "encode alpha. Override with -profile if needed.\n");
- ctx->alpha_bits = 0;
- }
- if (ctx->alpha_bits & 7) {
- av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
- return AVERROR(EINVAL);
- }
- avctx->bits_per_coded_sample = 32;
- } else {
- ctx->alpha_bits = 0;
- }
-
- ctx->chroma_factor = avctx->pix_fmt == AV_PIX_FMT_YUV422P10
- ? CFACTOR_Y422
- : CFACTOR_Y444;
- ctx->profile_info = prores_profile_info + ctx->profile;
- ctx->num_planes = 3 + !!ctx->alpha_bits;
-
- ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
-
- if (interlaced)
- ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
- else
- ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
-
- ctx->slices_width = ctx->mb_width / mps;
- ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
- ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
- ctx->pictures_per_frame = 1 + interlaced;
-
- if (ctx->quant_sel == -1) {
- ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
- ctx->quant_chroma_mat =
prores_quant_matrices[ctx->profile_info->quant_chroma];
- } else {
- ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
- ctx->quant_chroma_mat = prores_quant_matrices[ctx->quant_sel];
- }
-
- if (strlen(ctx->vendor) != 4) {
- av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
- return AVERROR_INVALIDDATA;
- }
-
- ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
if (!ctx->force_quant) {
- if (!ctx->bits_per_mb) {
- for (i = 0; i < NUM_MB_LIMITS - 1; i++)
- if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
- ctx->pictures_per_frame)
- break;
- ctx->bits_per_mb = ctx->profile_info->br_tab[i];
- if (ctx->alpha_bits)
- ctx->bits_per_mb *= 20;
- } else if (ctx->bits_per_mb < 128) {
- av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at
least 128\n");
- return AVERROR_INVALIDDATA;
- }
-
min_quant = ctx->profile_info->min_quant;
max_quant = ctx->profile_info->max_quant;
- for (i = min_quant; i < MAX_STORED_Q; i++) {
- for (j = 0; j < 64; j++) {
- ctx->quants[i][j] = ctx->quant_mat[j] * i;
- ctx->quants_chroma[i][j] = ctx->quant_chroma_mat[j] * i;
- }
- }
ctx->slice_q = av_malloc_array(ctx->slices_per_picture,
sizeof(*ctx->slice_q));
if (!ctx->slice_q)
@@ -1269,51 +928,8 @@ static av_cold int encode_init(AVCodecContext *avctx)
ctx->tdata[j].nodes[i].score = 0;
}
}
- } else {
- int ls = 0;
- int ls_chroma = 0;
-
- if (ctx->force_quant > 64) {
- av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is
64\n");
- return AVERROR_INVALIDDATA;
- }
-
- for (j = 0; j < 64; j++) {
- ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
- ctx->quants_chroma[0][j] = ctx->quant_chroma_mat[j] *
ctx->force_quant;
- ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1;
- ls_chroma += av_log2((1 << 11) / ctx->quants_chroma[0][j]) * 2 +
1;
- }
-
- ctx->bits_per_mb = ls * 4 + ls_chroma * 4;
- if (ctx->chroma_factor == CFACTOR_Y444)
- ctx->bits_per_mb += ls_chroma * 4;
}
- ctx->frame_size_upper_bound = (ctx->pictures_per_frame *
- ctx->slices_per_picture + 1) *
- (2 + 2 * ctx->num_planes +
- (mps * ctx->bits_per_mb) / 8)
- + 200;
-
- if (ctx->alpha_bits) {
- // The alpha plane is run-coded and might exceed the bit budget.
- ctx->frame_size_upper_bound += (ctx->pictures_per_frame *
- ctx->slices_per_picture + 1) *
- /* num pixels per slice */ (ctx->mbs_per_slice * 256 *
- /* bits per pixel */ (1 + ctx->alpha_bits + 1) + 7 >> 3);
- }
-
- avctx->codec_tag = ctx->profile_info->tag;
- avctx->profile = ctx->profile;
-
- av_log(avctx, AV_LOG_DEBUG,
- "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
- ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
- interlaced ? "yes" : "no", ctx->bits_per_mb);
- av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
- ctx->frame_size_upper_bound);
-
return 0;
}
diff --git a/libavcodec/proresenc_kostya_common.c
b/libavcodec/proresenc_kostya_common.c
new file mode 100644
index 0000000000..d432d10369
--- /dev/null
+++ b/libavcodec/proresenc_kostya_common.c
@@ -0,0 +1,364 @@
+/*
+ * Apple ProRes encoder
+ *
+ * Copyright (c) 2011 Anatoliy Wasserman
+ * Copyright (c) 2012 Konstantin Shishkov
+ *
+ * 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 "avcodec.h"
+#include "bytestream.h"
+#include "proresdata.h"
+#include <sys/types.h>
+#include "proresenc_kostya_common.h"
+
+static const uint8_t prores_quant_matrices[][64] = {
+ { // proxy
+ 4, 7, 9, 11, 13, 14, 15, 63,
+ 7, 7, 11, 12, 14, 15, 63, 63,
+ 9, 11, 13, 14, 15, 63, 63, 63,
+ 11, 11, 13, 14, 63, 63, 63, 63,
+ 11, 13, 14, 63, 63, 63, 63, 63,
+ 13, 14, 63, 63, 63, 63, 63, 63,
+ 13, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63,
+ },
+ { // proxy chromas
+ 4, 7, 9, 11, 13, 14, 63, 63,
+ 7, 7, 11, 12, 14, 63, 63, 63,
+ 9, 11, 13, 14, 63, 63, 63, 63,
+ 11, 11, 13, 14, 63, 63, 63, 63,
+ 11, 13, 14, 63, 63, 63, 63, 63,
+ 13, 14, 63, 63, 63, 63, 63, 63,
+ 13, 63, 63, 63, 63, 63, 63, 63,
+ 63, 63, 63, 63, 63, 63, 63, 63
+ },
+ { // LT
+ 4, 5, 6, 7, 9, 11, 13, 15,
+ 5, 5, 7, 8, 11, 13, 15, 17,
+ 6, 7, 9, 11, 13, 15, 15, 17,
+ 7, 7, 9, 11, 13, 15, 17, 19,
+ 7, 9, 11, 13, 14, 16, 19, 23,
+ 9, 11, 13, 14, 16, 19, 23, 29,
+ 9, 11, 13, 15, 17, 21, 28, 35,
+ 11, 13, 16, 17, 21, 28, 35, 41,
+ },
+ { // standard
+ 4, 4, 5, 5, 6, 7, 7, 9,
+ 4, 4, 5, 6, 7, 7, 9, 9,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 5, 6, 7, 7, 9, 9, 10,
+ 5, 6, 7, 7, 8, 9, 10, 12,
+ 6, 7, 7, 8, 9, 10, 12, 15,
+ 6, 7, 7, 9, 10, 11, 14, 17,
+ 7, 7, 9, 10, 11, 14, 17, 21,
+ },
+ { // high quality
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 5,
+ 4, 4, 4, 4, 4, 4, 5, 5,
+ 4, 4, 4, 4, 4, 5, 5, 6,
+ 4, 4, 4, 4, 5, 5, 6, 7,
+ 4, 4, 4, 4, 5, 6, 7, 7,
+ },
+ { // XQ luma
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 3,
+ 2, 2, 2, 2, 2, 2, 3, 3,
+ 2, 2, 2, 2, 2, 3, 3, 3,
+ 2, 2, 2, 2, 3, 3, 3, 4,
+ 2, 2, 2, 2, 3, 3, 4, 4,
+ },
+ { // codec default
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ },
+};
+
+static const int prores_mb_limits[NUM_MB_LIMITS] = {
+ 1620, // up to 720x576
+ 2700, // up to 960x720
+ 6075, // up to 1440x1080
+ 9216, // up to 2048x1152
+};
+
+static const prores_profile prores_profile_info[6] = {
+ {
+ .full_name = "proxy",
+ .tag = MKTAG('a', 'p', 'c', 'o'),
+ .min_quant = 4,
+ .max_quant = 8,
+ .br_tab = { 300, 242, 220, 194 },
+ .quant = QUANT_MAT_PROXY,
+ .quant_chroma = QUANT_MAT_PROXY_CHROMA,
+ },
+ {
+ .full_name = "LT",
+ .tag = MKTAG('a', 'p', 'c', 's'),
+ .min_quant = 1,
+ .max_quant = 9,
+ .br_tab = { 720, 560, 490, 440 },
+ .quant = QUANT_MAT_LT,
+ .quant_chroma = QUANT_MAT_LT,
+ },
+ {
+ .full_name = "standard",
+ .tag = MKTAG('a', 'p', 'c', 'n'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 1050, 808, 710, 632 },
+ .quant = QUANT_MAT_STANDARD,
+ .quant_chroma = QUANT_MAT_STANDARD,
+ },
+ {
+ .full_name = "high quality",
+ .tag = MKTAG('a', 'p', 'c', 'h'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 1566, 1216, 1070, 950 },
+ .quant = QUANT_MAT_HQ,
+ .quant_chroma = QUANT_MAT_HQ,
+ },
+ {
+ .full_name = "4444",
+ .tag = MKTAG('a', 'p', '4', 'h'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 2350, 1828, 1600, 1425 },
+ .quant = QUANT_MAT_HQ,
+ .quant_chroma = QUANT_MAT_HQ,
+ },
+ {
+ .full_name = "4444XQ",
+ .tag = MKTAG('a', 'p', '4', 'x'),
+ .min_quant = 1,
+ .max_quant = 6,
+ .br_tab = { 3525, 2742, 2400, 2137 },
+ .quant = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */
+ .quant_chroma = QUANT_MAT_HQ,
+ }
+};
+
+av_cold int ff_prores_kostya_encode_init(AVCodecContext *avctx, ProresContext
*ctx,
+ enum AVPixelFormat pix_fmt)
+{
+ int mps, i, j, min_quant;
+ int interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT);
+
+ avctx->bits_per_raw_sample = 10;
+
+ ctx->scantable = interlaced ? ff_prores_interlaced_scan
+ : ff_prores_progressive_scan;
+
+ mps = ctx->mbs_per_slice;
+ if (mps & (mps - 1)) {
+ av_log(avctx, AV_LOG_ERROR,
+ "there should be an integer power of two MBs per slice\n");
+ return AVERROR(EINVAL);
+ }
+ if (ctx->profile == PRORES_PROFILE_AUTO) {
+ const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(pix_fmt);
+ ctx->profile = (desc->flags & AV_PIX_FMT_FLAG_ALPHA ||
+ !(desc->log2_chroma_w + desc->log2_chroma_h))
+ ? PRORES_PROFILE_4444 : PRORES_PROFILE_HQ;
+ av_log(avctx, AV_LOG_INFO, "Autoselected %s. It can be overridden "
+ "through -profile option.\n", ctx->profile ==
PRORES_PROFILE_4444
+ ? "4:4:4:4 profile because of the used input colorspace"
+ : "HQ profile to keep best quality");
+ }
+ if (av_pix_fmt_desc_get(pix_fmt)->flags & AV_PIX_FMT_FLAG_ALPHA) {
+ if (ctx->profile != PRORES_PROFILE_4444 &&
+ ctx->profile != PRORES_PROFILE_4444XQ) {
+ // force alpha and warn
+ av_log(avctx, AV_LOG_WARNING, "Profile selected will not "
+ "encode alpha. Override with -profile if needed.\n");
+ ctx->alpha_bits = 0;
+ }
+ if (ctx->alpha_bits & 7) {
+ av_log(avctx, AV_LOG_ERROR, "alpha bits should be 0, 8 or 16\n");
+ return AVERROR(EINVAL);
+ }
+ avctx->bits_per_coded_sample = 32;
+ } else {
+ ctx->alpha_bits = 0;
+ }
+
+ ctx->chroma_factor = pix_fmt == AV_PIX_FMT_YUV422P10
+ ? CFACTOR_Y422
+ : CFACTOR_Y444;
+ ctx->profile_info = prores_profile_info + ctx->profile;
+ ctx->num_planes = 3 + !!ctx->alpha_bits;
+
+ ctx->mb_width = FFALIGN(avctx->width, 16) >> 4;
+
+ if (interlaced)
+ ctx->mb_height = FFALIGN(avctx->height, 32) >> 5;
+ else
+ ctx->mb_height = FFALIGN(avctx->height, 16) >> 4;
+
+ ctx->slices_width = ctx->mb_width / mps;
+ ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
+ ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
+ ctx->pictures_per_frame = 1 + interlaced;
+
+ if (ctx->quant_sel == -1) {
+ ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
+ ctx->quant_chroma_mat =
prores_quant_matrices[ctx->profile_info->quant_chroma];
+ } else {
+ ctx->quant_mat = prores_quant_matrices[ctx->quant_sel];
+ ctx->quant_chroma_mat = prores_quant_matrices[ctx->quant_sel];
+ }
+
+ if (strlen(ctx->vendor) != 4) {
+ av_log(avctx, AV_LOG_ERROR, "vendor ID should be 4 bytes\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ ctx->force_quant = avctx->global_quality / FF_QP2LAMBDA;
+ if (!ctx->force_quant) {
+ if (!ctx->bits_per_mb) {
+ for (i = 0; i < NUM_MB_LIMITS - 1; i++)
+ if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height *
+ ctx->pictures_per_frame)
+ break;
+ ctx->bits_per_mb = ctx->profile_info->br_tab[i];
+ if (ctx->alpha_bits)
+ ctx->bits_per_mb *= 20;
+ } else if (ctx->bits_per_mb < 128) {
+ av_log(avctx, AV_LOG_ERROR, "too few bits per MB, please set at
least 128\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ min_quant = ctx->profile_info->min_quant;
+ for (i = min_quant; i < MAX_STORED_Q; i++) {
+ for (j = 0; j < 64; j++) {
+ ctx->quants[i][j] = ctx->quant_mat[j] * i;
+ ctx->quants_chroma[i][j] = ctx->quant_chroma_mat[j] * i;
+ }
+ }
+ } else {
+ int ls = 0;
+ int ls_chroma = 0;
+
+ if (ctx->force_quant > 64) {
+ av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is
64\n");
+ return AVERROR_INVALIDDATA;
+ }
+
+ for (j = 0; j < 64; j++) {
+ ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
+ ctx->quants_chroma[0][j] = ctx->quant_chroma_mat[j] *
ctx->force_quant;
+ ls += av_log2((1 << 11) / ctx->quants[0][j]) * 2 + 1;
+ ls_chroma += av_log2((1 << 11) / ctx->quants_chroma[0][j]) * 2 +
1;
+ }
+
+ ctx->bits_per_mb = ls * 4 + ls_chroma * 4;
+ if (ctx->chroma_factor == CFACTOR_Y444)
+ ctx->bits_per_mb += ls_chroma * 4;
+ }
+
+ ctx->frame_size_upper_bound = (ctx->pictures_per_frame *
+ ctx->slices_per_picture + 1) *
+ (2 + 2 * ctx->num_planes +
+ (mps * ctx->bits_per_mb) / 8)
+ + 200;
+
+ if (ctx->alpha_bits) {
+ // The alpha plane is run-coded and might exceed the bit budget.
+ ctx->frame_size_upper_bound += (ctx->pictures_per_frame *
+ ctx->slices_per_picture + 1) *
+ /* num pixels per slice */ (ctx->mbs_per_slice * 256 *
+ /* bits per pixel */ (1 + ctx->alpha_bits + 1) + 7 >> 3);
+ }
+
+ avctx->codec_tag = ctx->profile_info->tag;
+ avctx->profile = ctx->profile;
+
+ av_log(avctx, AV_LOG_DEBUG,
+ "profile %d, %d slices, interlacing: %s, %d bits per MB\n",
+ ctx->profile, ctx->slices_per_picture * ctx->pictures_per_frame,
+ interlaced ? "yes" : "no", ctx->bits_per_mb);
+ av_log(avctx, AV_LOG_DEBUG, "frame size upper bound: %d\n",
+ ctx->frame_size_upper_bound);
+
+ return 0;
+}
+
+uint8_t* ff_prores_kostya_write_frame_header(AVCodecContext *avctx,
ProresContext *ctx,
+ uint8_t **orig_buf, int flags,
+ enum AVColorPrimaries
color_primaries,
+ enum
AVColorTransferCharacteristic color_trc,
+ enum AVColorSpace colorspace)
+{
+ uint8_t *buf, *tmp;
+ uint8_t frame_flags;
+
+ // frame atom
+ *orig_buf += 4; // frame size
+ bytestream_put_be32 (orig_buf, FRAME_ID); // frame container ID
+ buf = *orig_buf;
+
+ // frame header
+ tmp = buf;
+ buf += 2; // frame header size will be
stored here
+ bytestream_put_be16 (&buf, ctx->chroma_factor != CFACTOR_Y422 ||
ctx->alpha_bits ? 1 : 0);
+ bytestream_put_buffer(&buf, (uint8_t*)ctx->vendor, 4);
+ bytestream_put_be16 (&buf, avctx->width);
+ bytestream_put_be16 (&buf, avctx->height);
+
+ frame_flags = ctx->chroma_factor << 6;
+ if (avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT)
+ frame_flags |= (flags & AV_FRAME_FLAG_TOP_FIELD_FIRST) ? 0x04 : 0x08;
+ bytestream_put_byte (&buf, frame_flags);
+
+ bytestream_put_byte (&buf, 0); // reserved
+ bytestream_put_byte (&buf, color_primaries);
+ bytestream_put_byte (&buf, color_trc);
+ bytestream_put_byte (&buf, colorspace);
+ bytestream_put_byte (&buf, ctx->alpha_bits >> 3);
+ bytestream_put_byte (&buf, 0); // reserved
+ if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
+ bytestream_put_byte (&buf, 0x03); // matrix flags - both
matrices are present
+ bytestream_put_buffer(&buf, ctx->quant_mat, 64); // luma
quantisation matrix
+ bytestream_put_buffer(&buf, ctx->quant_chroma_mat, 64); // chroma
quantisation matrix
+ } else {
+ bytestream_put_byte (&buf, 0x00); // matrix flags - default
matrices are used
+ }
+ bytestream_put_be16 (&tmp, buf - *orig_buf); // write back frame header
size
+ return buf;
+}
+
+uint8_t* ff_prores_kostya_write_picture_header(ProresContext *ctx, uint8_t
*buf)
+{
+ bytestream_put_byte (&buf, 0x40); // picture header size (in bits)
+ buf += 4; // picture data size will be
stored here
+ bytestream_put_be16 (&buf, ctx->slices_per_picture);
+ bytestream_put_byte (&buf, av_log2(ctx->mbs_per_slice) << 4); // slice
width and height in MBs
+ return buf;
+}
\ No newline at end of file
diff --git a/libavcodec/proresenc_kostya_common.h
b/libavcodec/proresenc_kostya_common.h
new file mode 100644
index 0000000000..f18adc36af
--- /dev/null
+++ b/libavcodec/proresenc_kostya_common.h
@@ -0,0 +1,131 @@
+/*
+ * Apple ProRes encoder
+ *
+ * Copyright (c) 2011 Anatoliy Wasserman
+ * Copyright (c) 2012 Konstantin Shishkov
+ *
+ * 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_PRORESENC_KOSTYA_H
+#define AVCODEC_PRORESENC_KOSTYA_H
+
+#include "libavutil/attributes_internal.h"
+#include "libavutil/mem_internal.h"
+#include "libavutil/pixfmt.h"
+#include "fdctdsp.h"
+
+FF_VISIBILITY_PUSH_HIDDEN
+
+#define CFACTOR_Y422 2
+#define CFACTOR_Y444 3
+
+#define MAX_MBS_PER_SLICE 8
+
+#define MAX_PLANES 4
+
+#define NUM_MB_LIMITS 4
+
+#define MAX_STORED_Q 16
+
+enum {
+ PRORES_PROFILE_AUTO = -1,
+ PRORES_PROFILE_PROXY = 0,
+ PRORES_PROFILE_LT,
+ PRORES_PROFILE_STANDARD,
+ PRORES_PROFILE_HQ,
+ PRORES_PROFILE_4444,
+ PRORES_PROFILE_4444XQ,
+};
+
+enum {
+ QUANT_MAT_PROXY = 0,
+ QUANT_MAT_PROXY_CHROMA,
+ QUANT_MAT_LT,
+ QUANT_MAT_STANDARD,
+ QUANT_MAT_HQ,
+ QUANT_MAT_XQ_LUMA,
+ QUANT_MAT_DEFAULT,
+};
+
+typedef struct prores_profile {
+ const char *full_name;
+ uint32_t tag;
+ int min_quant;
+ int max_quant;
+ int br_tab[NUM_MB_LIMITS];
+ int quant;
+ int quant_chroma;
+} prores_profile;
+
+typedef struct ProresContext {
+ AVClass *class;
+ DECLARE_ALIGNED(16, int16_t, blocks)[MAX_PLANES][64 * 4 *
MAX_MBS_PER_SLICE];
+ DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
+ int16_t quants[MAX_STORED_Q][64];
+ int16_t quants_chroma[MAX_STORED_Q][64];
+ int16_t custom_q[64];
+ int16_t custom_chroma_q[64];
+ const uint8_t *quant_mat;
+ const uint8_t *quant_chroma_mat;
+ const uint8_t *scantable;
+
+ void (*fdct)(FDCTDSPContext *fdsp, const uint16_t *src,
+ ptrdiff_t linesize, int16_t *block);
+ FDCTDSPContext fdsp;
+
+ const AVFrame *pic;
+ int mb_width, mb_height;
+ int mbs_per_slice;
+ int num_chroma_blocks, chroma_factor;
+ int slices_width;
+ int slices_per_picture;
+ int pictures_per_frame; // 1 for progressive, 2 for interlaced
+ int cur_picture_idx;
+ int num_planes;
+ int bits_per_mb;
+ int force_quant;
+ int alpha_bits;
+ int warn;
+
+ char *vendor;
+ int quant_sel;
+
+ int frame_size_upper_bound;
+
+ int profile;
+ const struct prores_profile *profile_info;
+
+ int *slice_q;
+
+ struct ProresThreadData *tdata;
+} ProresContext;
+
+av_cold int ff_prores_kostya_encode_init(AVCodecContext *avctx, ProresContext
*ctx,
+ enum AVPixelFormat pixfmt);
+
+uint8_t* ff_prores_kostya_write_frame_header(AVCodecContext *avctx,
ProresContext *ctx,
+ uint8_t **orig_buf, int flags,
+ enum AVColorPrimaries
color_primaries,
+ enum
AVColorTransferCharacteristic color_trc,
+ enum AVColorSpace colorspace);
+
+uint8_t* ff_prores_kostya_write_picture_header(ProresContext *ctx, uint8_t
*buf);
+
+FF_VISIBILITY_POP_HIDDEN
+
+#endif
\ No newline at end of file
--
2.50.1
_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]