|
|
|
@@ -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; |
|
|
|
|