* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include "libavutil/mem_internal.h"
#include "libavutil/opt.h"
#include "libavutil/pixdesc.h"
#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,
}
}
-static int encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
+static void encode_slice_plane(ProresContext *ctx, PutBitContext *pb,
const uint16_t *src, ptrdiff_t linesize,
int mbs_per_slice, int16_t *blocks,
int blocks_per_mb, int plane_size_factor,
const int16_t *qmat)
{
- int blocks_per_slice, saved_pos;
-
- saved_pos = put_bits_count(pb);
- blocks_per_slice = mbs_per_slice * blocks_per_mb;
+ int blocks_per_slice = mbs_per_slice * blocks_per_mb;
encode_dcs(pb, blocks, blocks_per_slice, qmat[0]);
encode_acs(pb, blocks, blocks_per_slice, plane_size_factor,
ctx->scantable, qmat);
- flush_put_bits(pb);
-
- return (put_bits_count(pb) - saved_pos) >> 3;
}
static void put_alpha_diff(PutBitContext *pb, int cur, int prev, int abits)
}
// todo alpha quantisation for high quants
-static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
+static void encode_alpha_plane(ProresContext *ctx, PutBitContext *pb,
int mbs_per_slice, uint16_t *blocks,
int quant)
{
const int abits = ctx->alpha_bits;
const int mask = (1 << abits) - 1;
const int num_coeffs = mbs_per_slice * 256;
- int saved_pos = put_bits_count(pb);
int prev = mask, cur;
int idx = 0;
int run = 0;
} while (idx < num_coeffs);
if (run)
put_alpha_run(pb, run);
- flush_put_bits(pb);
- return (put_bits_count(pb) - saved_pos) >> 3;
}
static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
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 */
+ encode_slice_plane(ctx, pb, src, linesize,
+ mbs_per_slice, ctx->blocks[0],
+ num_cblocks, plane_factor, qmat);
+ } else { /* chroma plane */
+ 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,
ctx->blocks[0], mbs_per_slice, ctx->alpha_bits);
- sizes[i] = encode_alpha_plane(ctx, pb, mbs_per_slice,
- ctx->blocks[0], quant);
- }
- total_size += sizes[i];
- if (put_bits_left(pb) < 0) {
- av_log(avctx, AV_LOG_ERROR,
- "Underestimated required buffer size.\n");
- return AVERROR_BUG;
+ encode_alpha_plane(ctx, pb, mbs_per_slice, ctx->blocks[0], quant);
}
+ flush_put_bits(pb);
+ sizes[i] = put_bytes_output(pb) - total_size;
+ total_size = put_bytes_output(pb);
}
return total_size;
}
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;
for (q = min_quant; q <= max_quant; q++) {
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 (bits > 65000 * 8)
error = SCORE_LIMIT;
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 (bits <= ctx->bits_per_mb * mbs_per_slice)
break;
int interlaced = !!(avctx->flags & AV_CODEC_FLAG_INTERLACED_DCT);
avctx->bits_per_raw_sample = 10;
-#if FF_API_CODED_FRAME
-FF_DISABLE_DEPRECATION_WARNINGS
- avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
- avctx->coded_frame->key_frame = 1;
-FF_ENABLE_DEPRECATION_WARNINGS
-#endif
ctx->fdct = prores_fdct;
ctx->scantable = interlaced ? ff_prores_interlaced_scan
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 *
{ "4444xq", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = PRORES_PROFILE_4444XQ },
0, 0, VE, "profile" },
{ "vendor", "vendor ID", OFFSET(vendor),
- AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
+ AV_OPT_TYPE_STRING, { .str = "Lavc" }, 0, 0, VE },
{ "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 8192, VE },
{ "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
.init = encode_init,
.close = encode_close,
.encode2 = encode_frame,
- .capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS | AV_CODEC_CAP_INTRA_ONLY,
+ .capabilities = AV_CODEC_CAP_SLICE_THREADS | AV_CODEC_CAP_FRAME_THREADS,
.pix_fmts = (const enum AVPixelFormat[]) {
AV_PIX_FMT_YUV422P10, AV_PIX_FMT_YUV444P10,
AV_PIX_FMT_YUVA444P10, AV_PIX_FMT_NONE
},
.priv_class = &proresenc_class,
+ .profiles = NULL_IF_CONFIG_SMALL(ff_prores_profiles),
};