#include "avcodec.h"
#include "fdctdsp.h"
#include "put_bits.h"
+#include "profiles.h"
#include "bytestream.h"
#include "internal.h"
#include "proresdata.h"
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,
};
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,
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,
int max_quant;
int br_tab[NUM_MB_LIMITS];
int quant;
+ int quant_chroma;
} prores_profile_info[6] = {
{
.full_name = "proxy",
.max_quant = 8,
.br_tab = { 300, 242, 220, 194 },
.quant = QUANT_MAT_PROXY,
+ .quant_chroma = QUANT_MAT_PROXY_CHROMA,
},
{
.full_name = "LT",
.max_quant = 9,
.br_tab = { 720, 560, 490, 440 },
.quant = QUANT_MAT_LT,
+ .quant_chroma = QUANT_MAT_LT,
},
{
.full_name = "standard",
.max_quant = 6,
.br_tab = { 1050, 808, 710, 632 },
.quant = QUANT_MAT_STANDARD,
+ .quant_chroma = QUANT_MAT_STANDARD,
},
{
.full_name = "high quality",
.max_quant = 6,
.br_tab = { 1566, 1216, 1070, 950 },
.quant = QUANT_MAT_HQ,
+ .quant_chroma = QUANT_MAT_HQ,
},
{
.full_name = "4444",
.max_quant = 6,
.br_tab = { 2350, 1828, 1600, 1425 },
.quant = QUANT_MAT_HQ,
+ .quant_chroma = QUANT_MAT_HQ,
},
{
.full_name = "4444XQ",
.min_quant = 1,
.max_quant = 6,
.br_tab = { 3525, 2742, 2400, 2137 },
- .quant = QUANT_MAT_HQ,
+ .quant = QUANT_MAT_HQ, /* Fix me : use QUANT_MAT_XQ_LUMA */
+ .quant_chroma = QUANT_MAT_HQ,
}
};
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 custom_q[64];
+ int16_t custom_chroma_q[64];
struct TrellisNode *nodes;
} ProresThreadData;
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;
int plane_factor, is_chroma;
uint16_t *qmat;
+ uint16_t *qmat_chroma;
if (ctx->pictures_per_frame == 1)
line_add = 0;
if (ctx->force_quant) {
qmat = ctx->quants[0];
+ qmat_chroma = ctx->quants_chroma[0];
} else if (quant < MAX_STORED_Q) {
qmat = ctx->quants[quant];
+ qmat_chroma = ctx->quants_chroma[quant];
} else {
qmat = ctx->custom_q;
- for (i = 0; i < 64; i++)
+ qmat_chroma = ctx->custom_chroma_q;
+ for (i = 0; i < 64; i++) {
qmat[i] = ctx->quant_mat[i] * quant;
+ qmat_chroma[i] = ctx->quant_chroma_mat[i] * quant;
+ }
}
for (i = 0; i < ctx->num_planes; i++) {
pwidth, avctx->height / ctx->pictures_per_frame,
ctx->blocks[0], ctx->emu_buf,
mbs_per_slice, num_cblocks, is_chroma);
- sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
- mbs_per_slice, ctx->blocks[0],
- num_cblocks, plane_factor,
- qmat);
+ if (!is_chroma) {/* luma quant */
+ sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
+ mbs_per_slice, ctx->blocks[0],
+ num_cblocks, plane_factor,
+ qmat);
+ } else { /* chroma plane */
+ sizes[i] = encode_slice_plane(ctx, pb, src, linesize,
+ mbs_per_slice, ctx->blocks[0],
+ num_cblocks, plane_factor,
+ qmat_chroma);
+ }
} else {
get_alpha_data(ctx, src, linesize, xp, yp,
pwidth, avctx->height / ctx->pictures_per_frame,
return dbits + 1;
}
-static int estimate_alpha_plane(ProresContext *ctx, int *error,
+static int estimate_alpha_plane(ProresContext *ctx,
const uint16_t *src, ptrdiff_t linesize,
- int mbs_per_slice, int quant,
- int16_t *blocks)
+ int mbs_per_slice, int16_t *blocks)
{
const int abits = ctx->alpha_bits;
const int mask = (1 << abits) - 1;
int run = 0;
int bits;
- *error = 0;
cur = blocks[idx++];
bits = est_alpha_diff(cur, prev, abits);
prev = cur;
int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
int overquant;
uint16_t *qmat;
+ uint16_t *qmat_chroma;
int linesize[4], line_add;
+ int alpha_bits = 0;
if (ctx->pictures_per_frame == 1)
line_add = 0;
td->nodes[trellis_node + q].quant = q;
}
+ if (ctx->alpha_bits)
+ alpha_bits = estimate_alpha_plane(ctx, src, linesize[3],
+ mbs_per_slice, td->blocks[3]);
// todo: maybe perform coarser quantising to fit into frame size when needed
for (q = min_quant; q <= max_quant; q++) {
- bits = 0;
+ bits = alpha_bits;
error = 0;
- for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+ bits += estimate_slice_plane(ctx, &error, 0,
+ src, linesize[0],
+ mbs_per_slice,
+ num_cblocks[0], plane_factor[0],
+ ctx->quants[q], td); /* estimate luma plane */
+ for (i = 1; i < ctx->num_planes - !!ctx->alpha_bits; i++) { /* estimate chroma plane */
bits += estimate_slice_plane(ctx, &error, i,
src, linesize[i],
mbs_per_slice,
num_cblocks[i], plane_factor[i],
- ctx->quants[q], td);
+ ctx->quants_chroma[q], td);
}
- if (ctx->alpha_bits)
- bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
- mbs_per_slice, q, td->blocks[3]);
if (bits > 65000 * 8)
error = SCORE_LIMIT;
overquant = max_quant;
} else {
for (q = max_quant + 1; q < 128; q++) {
- bits = 0;
+ bits = alpha_bits;
error = 0;
if (q < MAX_STORED_Q) {
qmat = ctx->quants[q];
+ qmat_chroma = ctx->quants_chroma[q];
} else {
qmat = td->custom_q;
- for (i = 0; i < 64; i++)
+ qmat_chroma = td->custom_chroma_q;
+ for (i = 0; i < 64; i++) {
qmat[i] = ctx->quant_mat[i] * q;
+ qmat_chroma[i] = ctx->quant_chroma_mat[i] * q;
+ }
}
- for (i = 0; i < ctx->num_planes - !!ctx->alpha_bits; i++) {
+ bits += estimate_slice_plane(ctx, &error, 0,
+ src, linesize[0],
+ mbs_per_slice,
+ num_cblocks[0], plane_factor[0],
+ qmat, td);/* estimate luma plane */
+ for (i = 1; i < ctx->num_planes - !!ctx->alpha_bits; i++) { /* estimate chroma plane */
bits += estimate_slice_plane(ctx, &error, i,
src, linesize[i],
mbs_per_slice,
num_cblocks[i], plane_factor[i],
- qmat, td);
+ qmat_chroma, td);
}
- if (ctx->alpha_bits)
- bits += estimate_alpha_plane(ctx, &error, src, linesize[3],
- mbs_per_slice, q, td->blocks[3]);
if (bits <= ctx->bits_per_mb * mbs_per_slice)
break;
}
ctx->slices_per_picture = ctx->mb_height * ctx->slices_width;
ctx->pictures_per_frame = 1 + interlaced;
- if (ctx->quant_sel == -1)
+ if (ctx->quant_sel == -1) {
ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
- else
+ 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");
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++)
+ 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(ctx->slices_per_picture * sizeof(*ctx->slice_q));
}
} 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");
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 * 8;
+ ctx->bits_per_mb = ls * 4 + ls_chroma * 4;
if (ctx->chroma_factor == CFACTOR_Y444)
- ctx->bits_per_mb += ls * 4;
+ ctx->bits_per_mb += ls_chroma * 4;
}
ctx->frame_size_upper_bound = (ctx->pictures_per_frame *
AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
},
.priv_class = &proresenc_class,
+ .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles),
};