summaryrefslogtreecommitdiff
path: root/libavcodec/proresenc.c
diff options
context:
space:
mode:
Diffstat (limited to 'libavcodec/proresenc.c')
-rw-r--r--libavcodec/proresenc.c72
1 files changed, 62 insertions, 10 deletions
diff --git a/libavcodec/proresenc.c b/libavcodec/proresenc.c
index 73f7f7d167..7e3e066875 100644
--- a/libavcodec/proresenc.c
+++ b/libavcodec/proresenc.c
@@ -139,11 +139,14 @@ struct TrellisNode {
int score;
};
+#define MAX_STORED_Q 16
+
typedef struct ProresContext {
AVClass *class;
DECLARE_ALIGNED(16, DCTELEM, blocks)[MAX_PLANES][64 * 4 * MAX_MBS_PER_SLICE];
DECLARE_ALIGNED(16, uint16_t, emu_buf)[16*16];
- int16_t quants[16][64];
+ int16_t quants[MAX_STORED_Q][64];
+ int16_t custom_q[64];
ProresDSPContext dsp;
ScanTable scantable;
@@ -156,6 +159,8 @@ typedef struct ProresContext {
int num_planes;
int bits_per_mb;
+ int frame_size;
+
int profile;
const struct prores_profile *profile_info;
@@ -348,6 +353,15 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
int slice_width_factor = av_log2(mbs_per_slice);
int num_cblocks, pwidth;
int plane_factor, is_chroma;
+ uint16_t *qmat;
+
+ if (quant < MAX_STORED_Q) {
+ qmat = ctx->quants[quant];
+ } else {
+ qmat = ctx->custom_q;
+ for (i = 0; i < 64; i++)
+ qmat[i] = ctx->profile_info->quant[i] * quant;
+ }
for (i = 0; i < ctx->num_planes; i++) {
is_chroma = (i == 1 || i == 2);
@@ -373,7 +387,7 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
sizes[i] = encode_slice_plane(ctx, pb, src, pic->linesize[i],
mbs_per_slice, ctx->blocks[0],
num_cblocks, plane_factor,
- ctx->quants[quant]);
+ qmat);
total_size += sizes[i];
}
return total_size;
@@ -500,6 +514,8 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
int error, bits, bits_limit;
int mbs, prev, cur, new_score;
int slice_bits[TRELLIS_WIDTH], slice_score[TRELLIS_WIDTH];
+ int overquant;
+ uint16_t *qmat;
mbs = x + mbs_per_slice;
@@ -526,7 +542,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
mbs_per_slice, num_cblocks[i]);
}
- for (q = min_quant; q <= max_quant; q++) {
+ for (q = min_quant; q < max_quant + 2; q++) {
ctx->nodes[trellis_node + q].prev_node = -1;
ctx->nodes[trellis_node + q].quant = q;
}
@@ -549,12 +565,43 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
slice_bits[q] = bits;
slice_score[q] = error;
}
+ if (slice_bits[max_quant] <= ctx->bits_per_mb * mbs_per_slice) {
+ slice_bits[max_quant + 1] = slice_bits[max_quant];
+ slice_score[max_quant + 1] = slice_score[max_quant] + 1;
+ overquant = max_quant;
+ } else {
+ for (q = max_quant + 1; q < 128; q++) {
+ bits = 0;
+ error = 0;
+ if (q < MAX_STORED_Q) {
+ qmat = ctx->quants[q];
+ } else {
+ qmat = ctx->custom_q;
+ for (i = 0; i < 64; i++)
+ qmat[i] = ctx->profile_info->quant[i] * q;
+ }
+ for (i = 0; i < ctx->num_planes; i++) {
+ bits += estimate_slice_plane(ctx, &error, i,
+ src, pic->linesize[i],
+ mbs_per_slice,
+ num_cblocks[i], plane_factor[i],
+ qmat);
+ }
+ if (bits <= ctx->bits_per_mb * mbs_per_slice)
+ break;
+ }
+
+ slice_bits[max_quant + 1] = bits;
+ slice_score[max_quant + 1] = error;
+ overquant = q;
+ }
+ ctx->nodes[trellis_node + max_quant + 1].quant = overquant;
bits_limit = mbs * ctx->bits_per_mb;
- for (pq = min_quant; pq <= max_quant; pq++) {
+ for (pq = min_quant; pq < max_quant + 2; pq++) {
prev = trellis_node - TRELLIS_WIDTH + pq;
- for (q = min_quant; q <= max_quant; q++) {
+ for (q = min_quant; q < max_quant + 2; q++) {
cur = trellis_node + q;
bits = ctx->nodes[prev].bits + slice_bits[q];
@@ -578,7 +625,7 @@ static int find_slice_quant(AVCodecContext *avctx, const AVFrame *pic,
error = ctx->nodes[trellis_node + min_quant].score;
pq = trellis_node + min_quant;
- for (q = min_quant + 1; q <= max_quant; q++) {
+ for (q = min_quant + 1; q < max_quant + 2; q++) {
if (ctx->nodes[trellis_node + q].score <= error) {
error = ctx->nodes[trellis_node + q].score;
pq = trellis_node + q;
@@ -606,8 +653,7 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
avctx->coded_frame->pict_type = AV_PICTURE_TYPE_I;
avctx->coded_frame->key_frame = 1;
- pkt_size = ctx->mb_width * ctx->mb_height * 64 * 3 * 12
- + ctx->num_slices * 2 + 200 + FF_MIN_BUFFER_SIZE;
+ pkt_size = ctx->frame_size + FF_MIN_BUFFER_SIZE;
if ((ret = ff_alloc_packet(pkt, pkt_size)) < 0) {
av_log(avctx, AV_LOG_ERROR, "Error getting output packet.\n");
@@ -762,9 +808,13 @@ static av_cold int encode_init(AVCodecContext *avctx)
break;
ctx->bits_per_mb = ctx->profile_info->br_tab[i];
+ ctx->frame_size = ctx->num_slices * (2 + 2 * ctx->num_planes
+ + (2 * mps * ctx->bits_per_mb) / 8)
+ + 200;
+
min_quant = ctx->profile_info->min_quant;
max_quant = ctx->profile_info->max_quant;
- for (i = min_quant; i <= max_quant; i++) {
+ 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;
}
@@ -773,6 +823,8 @@ static av_cold int encode_init(AVCodecContext *avctx)
av_log(avctx, AV_LOG_DEBUG, "profile %d, %d slices, %d bits per MB\n",
ctx->profile, ctx->num_slices, ctx->bits_per_mb);
+ av_log(avctx, AV_LOG_DEBUG, "estimated frame size %d\n",
+ ctx->frame_size);
ctx->nodes = av_malloc((ctx->slices_width + 1) * TRELLIS_WIDTH
* sizeof(*ctx->nodes));
@@ -780,7 +832,7 @@ static av_cold int encode_init(AVCodecContext *avctx)
encode_close(avctx);
return AVERROR(ENOMEM);
}
- for (i = min_quant; i <= max_quant; i++) {
+ for (i = min_quant; i < max_quant + 2; i++) {
ctx->nodes[i].prev_node = -1;
ctx->nodes[i].bits = 0;
ctx->nodes[i].score = 0;