mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2024-12-23 12:43:46 +02:00
proresenc: give user a possibility to alter some encoding parameters
This allows user to select quantisation matrix from different profile, stamp frames with custom vendor string and change target bitrate.
This commit is contained in:
parent
1ba08c94f5
commit
4db4b53dc8
@ -42,6 +42,67 @@ enum {
|
||||
PRORES_PROFILE_HQ,
|
||||
};
|
||||
|
||||
enum {
|
||||
QUANT_MAT_PROXY = 0,
|
||||
QUANT_MAT_LT,
|
||||
QUANT_MAT_STANDARD,
|
||||
QUANT_MAT_HQ,
|
||||
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,
|
||||
},
|
||||
{ // 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,
|
||||
},
|
||||
{ // 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
|
||||
@ -56,7 +117,7 @@ static const struct prores_profile {
|
||||
int min_quant;
|
||||
int max_quant;
|
||||
int br_tab[NUM_MB_LIMITS];
|
||||
uint8_t quant[64];
|
||||
int quant;
|
||||
} prores_profile_info[4] = {
|
||||
{
|
||||
.full_name = "proxy",
|
||||
@ -64,16 +125,7 @@ static const struct prores_profile {
|
||||
.min_quant = 4,
|
||||
.max_quant = 8,
|
||||
.br_tab = { 300, 242, 220, 194 },
|
||||
.quant = {
|
||||
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,
|
||||
},
|
||||
.quant = QUANT_MAT_PROXY,
|
||||
},
|
||||
{
|
||||
.full_name = "LT",
|
||||
@ -81,16 +133,7 @@ static const struct prores_profile {
|
||||
.min_quant = 1,
|
||||
.max_quant = 9,
|
||||
.br_tab = { 720, 560, 490, 440 },
|
||||
.quant = {
|
||||
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,
|
||||
},
|
||||
.quant = QUANT_MAT_LT,
|
||||
},
|
||||
{
|
||||
.full_name = "standard",
|
||||
@ -98,16 +141,7 @@ static const struct prores_profile {
|
||||
.min_quant = 1,
|
||||
.max_quant = 6,
|
||||
.br_tab = { 1050, 808, 710, 632 },
|
||||
.quant = {
|
||||
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,
|
||||
},
|
||||
.quant = QUANT_MAT_STANDARD,
|
||||
},
|
||||
{
|
||||
.full_name = "high quality",
|
||||
@ -115,16 +149,7 @@ static const struct prores_profile {
|
||||
.min_quant = 1,
|
||||
.max_quant = 6,
|
||||
.br_tab = { 1566, 1216, 1070, 950 },
|
||||
.quant = {
|
||||
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,
|
||||
},
|
||||
.quant = QUANT_MAT_HQ,
|
||||
}
|
||||
// for 4444 profile bitrate numbers are { 2350, 1828, 1600, 1425 }
|
||||
};
|
||||
@ -147,6 +172,7 @@ typedef struct ProresContext {
|
||||
DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
|
||||
int16_t quants[MAX_STORED_Q][64];
|
||||
int16_t custom_q[64];
|
||||
const uint8_t *quant_mat;
|
||||
|
||||
ProresDSPContext dsp;
|
||||
ScanTable scantable;
|
||||
@ -159,6 +185,9 @@ typedef struct ProresContext {
|
||||
int num_planes;
|
||||
int bits_per_mb;
|
||||
|
||||
char *vendor;
|
||||
int quant_sel;
|
||||
|
||||
int frame_size;
|
||||
|
||||
int profile;
|
||||
@ -373,7 +402,7 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
|
||||
} else {
|
||||
qmat = ctx->custom_q;
|
||||
for (i = 0; i < 64; i++)
|
||||
qmat[i] = ctx->profile_info->quant[i] * quant;
|
||||
qmat[i] = ctx->quant_mat[i] * quant;
|
||||
}
|
||||
|
||||
for (i = 0; i < ctx->num_planes; i++) {
|
||||
@ -591,7 +620,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
|
||||
} else {
|
||||
qmat = ctx->custom_q;
|
||||
for (i = 0; i < 64; i++)
|
||||
qmat[i] = ctx->profile_info->quant[i] * q;
|
||||
qmat[i] = ctx->quant_mat[i] * q;
|
||||
}
|
||||
for (i = 0; i < ctx->num_planes; i++) {
|
||||
bits += estimate_slice_plane(ctx, &error, i,
|
||||
@ -684,7 +713,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
|
||||
tmp = buf;
|
||||
buf += 2; // frame header size will be stored here
|
||||
bytestream_put_be16 (&buf, 0); // version 1
|
||||
bytestream_put_buffer(&buf, "Lavc", 4); // creator
|
||||
bytestream_put_buffer(&buf, ctx->vendor, 4);
|
||||
bytestream_put_be16 (&buf, avctx->width);
|
||||
bytestream_put_be16 (&buf, avctx->height);
|
||||
bytestream_put_byte (&buf, ctx->chroma_factor << 6); // frame flags
|
||||
@ -694,13 +723,17 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
|
||||
bytestream_put_byte (&buf, avctx->colorspace);
|
||||
bytestream_put_byte (&buf, 0x40); // source format and alpha information
|
||||
bytestream_put_byte (&buf, 0); // reserved
|
||||
if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
|
||||
bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present
|
||||
// luma quantisation matrix
|
||||
for (i = 0; i < 64; i++)
|
||||
bytestream_put_byte(&buf, ctx->profile_info->quant[i]);
|
||||
bytestream_put_byte(&buf, ctx->quant_mat[i]);
|
||||
// chroma quantisation matrix
|
||||
for (i = 0; i < 64; i++)
|
||||
bytestream_put_byte(&buf, ctx->profile_info->quant[i]);
|
||||
bytestream_put_byte(&buf, ctx->quant_mat[i]);
|
||||
} else {
|
||||
bytestream_put_byte (&buf, 0x00); // matrix flags - default matrices are used
|
||||
}
|
||||
bytestream_put_be16 (&tmp, buf - orig_buf); // write back frame header size
|
||||
|
||||
// picture header
|
||||
@ -816,10 +849,25 @@ static av_cold int encode_init(AVCodecContext *avctx)
|
||||
ctx->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
|
||||
ctx->num_slices = ctx->mb_height * ctx->slices_width;
|
||||
|
||||
if (ctx->quant_sel == -1)
|
||||
ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
|
||||
else
|
||||
ctx->quant_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;
|
||||
}
|
||||
|
||||
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)
|
||||
break;
|
||||
ctx->bits_per_mb = ctx->profile_info->br_tab[i];
|
||||
} 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;
|
||||
}
|
||||
|
||||
ctx->frame_size = ctx->num_slices * (2 + 2 * ctx->num_planes
|
||||
+ (2 * mps * ctx->bits_per_mb) / 8)
|
||||
@ -829,7 +877,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
|
||||
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->profile_info->quant[j] * i;
|
||||
ctx->quants[i][j] = ctx->quant_mat[j] * i;
|
||||
}
|
||||
|
||||
avctx->codec_tag = ctx->profile_info->tag;
|
||||
@ -877,6 +925,24 @@ static const AVOption options[] = {
|
||||
0, 0, VE, "profile" },
|
||||
{ "hq", NULL, 0, AV_OPT_TYPE_CONST, { PRORES_PROFILE_HQ },
|
||||
0, 0, VE, "profile" },
|
||||
{ "vendor", "vendor ID", OFFSET(vendor),
|
||||
AV_OPT_TYPE_STRING, { .str = "Lavc" }, CHAR_MIN, CHAR_MAX, VE },
|
||||
{ "bits_per_mb", "desired bits per macroblock", OFFSET(bits_per_mb),
|
||||
AV_OPT_TYPE_INT, { 0 }, 0, 8192, VE },
|
||||
{ "quant_mat", "quantiser matrix", OFFSET(quant_sel), AV_OPT_TYPE_INT,
|
||||
{ -1 }, -1, QUANT_MAT_DEFAULT, VE, "quant_mat" },
|
||||
{ "auto", NULL, 0, AV_OPT_TYPE_CONST, { -1 },
|
||||
0, 0, VE, "quant_mat" },
|
||||
{ "proxy", NULL, 0, AV_OPT_TYPE_CONST, { QUANT_MAT_PROXY },
|
||||
0, 0, VE, "quant_mat" },
|
||||
{ "lt", NULL, 0, AV_OPT_TYPE_CONST, { QUANT_MAT_LT },
|
||||
0, 0, VE, "quant_mat" },
|
||||
{ "standard", NULL, 0, AV_OPT_TYPE_CONST, { QUANT_MAT_STANDARD },
|
||||
0, 0, VE, "quant_mat" },
|
||||
{ "hq", NULL, 0, AV_OPT_TYPE_CONST, { QUANT_MAT_HQ },
|
||||
0, 0, VE, "quant_mat" },
|
||||
{ "default", NULL, 0, AV_OPT_TYPE_CONST, { QUANT_MAT_DEFAULT },
|
||||
0, 0, VE, "quant_mat" },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user