1
0
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:
Kostya Shishkov 2012-03-03 19:14:35 +01:00
parent 1ba08c94f5
commit 4db4b53dc8

View File

@ -42,6 +42,67 @@ enum {
PRORES_PROFILE_HQ, 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 #define NUM_MB_LIMITS 4
static const int prores_mb_limits[NUM_MB_LIMITS] = { static const int prores_mb_limits[NUM_MB_LIMITS] = {
1620, // up to 720x576 1620, // up to 720x576
@ -56,7 +117,7 @@ static const struct prores_profile {
int min_quant; int min_quant;
int max_quant; int max_quant;
int br_tab[NUM_MB_LIMITS]; int br_tab[NUM_MB_LIMITS];
uint8_t quant[64]; int quant;
} prores_profile_info[4] = { } prores_profile_info[4] = {
{ {
.full_name = "proxy", .full_name = "proxy",
@ -64,16 +125,7 @@ static const struct prores_profile {
.min_quant = 4, .min_quant = 4,
.max_quant = 8, .max_quant = 8,
.br_tab = { 300, 242, 220, 194 }, .br_tab = { 300, 242, 220, 194 },
.quant = { .quant = QUANT_MAT_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,
},
}, },
{ {
.full_name = "LT", .full_name = "LT",
@ -81,16 +133,7 @@ static const struct prores_profile {
.min_quant = 1, .min_quant = 1,
.max_quant = 9, .max_quant = 9,
.br_tab = { 720, 560, 490, 440 }, .br_tab = { 720, 560, 490, 440 },
.quant = { .quant = QUANT_MAT_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,
},
}, },
{ {
.full_name = "standard", .full_name = "standard",
@ -98,16 +141,7 @@ static const struct prores_profile {
.min_quant = 1, .min_quant = 1,
.max_quant = 6, .max_quant = 6,
.br_tab = { 1050, 808, 710, 632 }, .br_tab = { 1050, 808, 710, 632 },
.quant = { .quant = QUANT_MAT_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,
},
}, },
{ {
.full_name = "high quality", .full_name = "high quality",
@ -115,16 +149,7 @@ static const struct prores_profile {
.min_quant = 1, .min_quant = 1,
.max_quant = 6, .max_quant = 6,
.br_tab = { 1566, 1216, 1070, 950 }, .br_tab = { 1566, 1216, 1070, 950 },
.quant = { .quant = QUANT_MAT_HQ,
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,
},
} }
// for 4444 profile bitrate numbers are { 2350, 1828, 1600, 1425 } // 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]; DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
int16_t quants[MAX_STORED_Q][64]; int16_t quants[MAX_STORED_Q][64];
int16_t custom_q[64]; int16_t custom_q[64];
const uint8_t *quant_mat;
ProresDSPContext dsp; ProresDSPContext dsp;
ScanTable scantable; ScanTable scantable;
@ -159,6 +185,9 @@ typedef struct ProresContext {
int num_planes; int num_planes;
int bits_per_mb; int bits_per_mb;
char *vendor;
int quant_sel;
int frame_size; int frame_size;
int profile; int profile;
@ -373,7 +402,7 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
} else { } else {
qmat = ctx->custom_q; qmat = ctx->custom_q;
for (i = 0; i < 64; i++) 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++) { for (i = 0; i < ctx->num_planes; i++) {
@ -591,7 +620,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
} else { } else {
qmat = ctx->custom_q; qmat = ctx->custom_q;
for (i = 0; i < 64; i++) 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++) { for (i = 0; i < ctx->num_planes; i++) {
bits += estimate_slice_plane(ctx, &error, i, bits += estimate_slice_plane(ctx, &error, i,
@ -684,7 +713,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
tmp = buf; tmp = buf;
buf += 2; // frame header size will be stored here buf += 2; // frame header size will be stored here
bytestream_put_be16 (&buf, 0); // version 1 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->width);
bytestream_put_be16 (&buf, avctx->height); bytestream_put_be16 (&buf, avctx->height);
bytestream_put_byte (&buf, ctx->chroma_factor << 6); // frame flags 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, avctx->colorspace);
bytestream_put_byte (&buf, 0x40); // source format and alpha information bytestream_put_byte (&buf, 0x40); // source format and alpha information
bytestream_put_byte (&buf, 0); // reserved bytestream_put_byte (&buf, 0); // reserved
bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present if (ctx->quant_sel != QUANT_MAT_DEFAULT) {
// luma quantisation matrix bytestream_put_byte (&buf, 0x03); // matrix flags - both matrices are present
for (i = 0; i < 64; i++) // luma quantisation matrix
bytestream_put_byte(&buf, ctx->profile_info->quant[i]); for (i = 0; i < 64; i++)
// chroma quantisation matrix bytestream_put_byte(&buf, ctx->quant_mat[i]);
for (i = 0; i < 64; i++) // chroma quantisation matrix
bytestream_put_byte(&buf, ctx->profile_info->quant[i]); for (i = 0; i < 64; 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 bytestream_put_be16 (&tmp, buf - orig_buf); // write back frame header size
// picture header // 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->slices_width += av_popcount(ctx->mb_width - ctx->slices_width * mps);
ctx->num_slices = ctx->mb_height * ctx->slices_width; ctx->num_slices = ctx->mb_height * ctx->slices_width;
for (i = 0; i < NUM_MB_LIMITS - 1; i++) if (ctx->quant_sel == -1)
if (prores_mb_limits[i] >= ctx->mb_width * ctx->mb_height) ctx->quant_mat = prores_quant_matrices[ctx->profile_info->quant];
break; else
ctx->bits_per_mb = ctx->profile_info->br_tab[i]; 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 ctx->frame_size = ctx->num_slices * (2 + 2 * ctx->num_planes
+ (2 * mps * ctx->bits_per_mb) / 8) + (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; max_quant = ctx->profile_info->max_quant;
for (i = min_quant; i < MAX_STORED_Q; i++) { 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->profile_info->quant[j] * i; ctx->quants[i][j] = ctx->quant_mat[j] * i;
} }
avctx->codec_tag = ctx->profile_info->tag; avctx->codec_tag = ctx->profile_info->tag;
@ -877,6 +925,24 @@ static const AVOption options[] = {
0, 0, VE, "profile" }, 0, 0, VE, "profile" },
{ "hq", NULL, 0, AV_OPT_TYPE_CONST, { PRORES_PROFILE_HQ }, { "hq", NULL, 0, AV_OPT_TYPE_CONST, { PRORES_PROFILE_HQ },
0, 0, VE, "profile" }, 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 } { NULL }
}; };