X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavcodec%2Fproresenc_kostya.c;h=d140ef053ab5475a59bc3db1188a7b8d00013773;hb=e5af9203098a889f36b759652615046254d45102;hp=149dc81b3c79937bd7e737f29fd69150e46a1375;hpb=b1ab02895b121b92dc3483c79e45eb5ea686f3aa;p=ffmpeg diff --git a/libavcodec/proresenc_kostya.c b/libavcodec/proresenc_kostya.c index 149dc81b3c7..d140ef053ab 100644 --- a/libavcodec/proresenc_kostya.c +++ b/libavcodec/proresenc_kostya.c @@ -23,11 +23,13 @@ * 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" @@ -51,9 +53,11 @@ enum { 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, }; @@ -68,6 +72,16 @@ static const uint8_t prores_quant_matrices[][64] = { 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, @@ -98,6 +112,16 @@ static const uint8_t prores_quant_matrices[][64] = { 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, @@ -125,6 +149,7 @@ static const struct prores_profile { int max_quant; int br_tab[NUM_MB_LIMITS]; int quant; + int quant_chroma; } prores_profile_info[6] = { { .full_name = "proxy", @@ -133,6 +158,7 @@ static const struct prores_profile { .max_quant = 8, .br_tab = { 300, 242, 220, 194 }, .quant = QUANT_MAT_PROXY, + .quant_chroma = QUANT_MAT_PROXY_CHROMA, }, { .full_name = "LT", @@ -141,6 +167,7 @@ static const struct prores_profile { .max_quant = 9, .br_tab = { 720, 560, 490, 440 }, .quant = QUANT_MAT_LT, + .quant_chroma = QUANT_MAT_LT, }, { .full_name = "standard", @@ -149,6 +176,7 @@ static const struct prores_profile { .max_quant = 6, .br_tab = { 1050, 808, 710, 632 }, .quant = QUANT_MAT_STANDARD, + .quant_chroma = QUANT_MAT_STANDARD, }, { .full_name = "high quality", @@ -157,6 +185,7 @@ static const struct prores_profile { .max_quant = 6, .br_tab = { 1566, 1216, 1070, 950 }, .quant = QUANT_MAT_HQ, + .quant_chroma = QUANT_MAT_HQ, }, { .full_name = "4444", @@ -165,6 +194,7 @@ static const struct prores_profile { .max_quant = 6, .br_tab = { 2350, 1828, 1600, 1425 }, .quant = QUANT_MAT_HQ, + .quant_chroma = QUANT_MAT_HQ, }, { .full_name = "4444XQ", @@ -172,7 +202,8 @@ static const struct prores_profile { .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, } }; @@ -192,6 +223,7 @@ typedef struct 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 custom_q[64]; + int16_t custom_chroma_q[64]; struct TrellisNode *nodes; } ProresThreadData; @@ -200,8 +232,11 @@ typedef struct ProresContext { 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, @@ -429,23 +464,17 @@ static void encode_acs(PutBitContext *pb, int16_t *blocks, } } -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) @@ -481,14 +510,13 @@ static void put_alpha_run(PutBitContext *pb, int run) } // 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; @@ -509,8 +537,6 @@ static int encode_alpha_plane(ProresContext *ctx, PutBitContext *pb, } 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, @@ -527,6 +553,7 @@ 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; @@ -535,12 +562,17 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, 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++) { @@ -569,23 +601,24 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic, 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; } @@ -712,10 +745,9 @@ static int est_alpha_diff(int cur, int prev, int abits) return dbits + 1; } -static int estimate_alpha_plane(ProresContext *ctx, int *error, +static int estimate_alpha_plane(ProresContext *ctx, const uint16_t *src, ptrdiff_t linesize, - int mbs_per_slice, int quant, - int16_t *blocks) + int mbs_per_slice, int16_t *blocks) { const int abits = ctx->alpha_bits; const int mask = (1 << abits) - 1; @@ -725,7 +757,6 @@ static int estimate_alpha_plane(ProresContext *ctx, int *error, int run = 0; int bits; - *error = 0; cur = blocks[idx++]; bits = est_alpha_diff(cur, prev, abits); prev = cur; @@ -773,7 +804,9 @@ static int find_slice_quant(AVCodecContext *avctx, 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; if (ctx->pictures_per_frame == 1) line_add = 0; @@ -819,20 +852,25 @@ static int find_slice_quant(AVCodecContext *avctx, td->nodes[trellis_node + q].quant = q; } + if (ctx->alpha_bits) + alpha_bits = estimate_alpha_plane(ctx, src, linesize[3], + mbs_per_slice, td->blocks[3]); // todo: maybe perform coarser quantising to fit into frame size when needed for (q = min_quant; q <= max_quant; q++) { - bits = 0; + 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 (ctx->alpha_bits) - bits += estimate_alpha_plane(ctx, &error, src, linesize[3], - mbs_per_slice, q, td->blocks[3]); if (bits > 65000 * 8) error = SCORE_LIMIT; @@ -845,25 +883,31 @@ static int find_slice_quant(AVCodecContext *avctx, overquant = max_quant; } else { for (q = max_quant + 1; q < 128; q++) { - bits = 0; + bits = alpha_bits; 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 (ctx->alpha_bits) - bits += estimate_alpha_plane(ctx, &error, src, linesize[3], - mbs_per_slice, q, td->blocks[3]); if (bits <= ctx->bits_per_mb * mbs_per_slice) break; } @@ -1135,12 +1179,6 @@ static av_cold int encode_init(AVCodecContext *avctx) 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 @@ -1198,10 +1236,13 @@ FF_ENABLE_DEPRECATION_WARNINGS 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"); @@ -1226,8 +1267,10 @@ FF_ENABLE_DEPRECATION_WARNINGS 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)); @@ -1258,6 +1301,7 @@ FF_ENABLE_DEPRECATION_WARNINGS } } 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"); @@ -1266,12 +1310,14 @@ FF_ENABLE_DEPRECATION_WARNINGS 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 * @@ -1324,7 +1370,7 @@ static const AVOption options[] = { { "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, @@ -1353,7 +1399,7 @@ static const AVClass proresenc_class = { .version = LIBAVUTIL_VERSION_INT, }; -AVCodec ff_prores_ks_encoder = { +const AVCodec ff_prores_ks_encoder = { .name = "prores_ks", .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)"), .type = AVMEDIA_TYPE_VIDEO, @@ -1362,10 +1408,11 @@ AVCodec ff_prores_ks_encoder = { .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), };