prores: allow user to set fixed quantiser
This commit is contained in:
		@@ -184,6 +184,7 @@ typedef struct ProresContext {
 | 
			
		||||
    int num_slices;
 | 
			
		||||
    int num_planes;
 | 
			
		||||
    int bits_per_mb;
 | 
			
		||||
    int force_quant;
 | 
			
		||||
 | 
			
		||||
    char *vendor;
 | 
			
		||||
    int quant_sel;
 | 
			
		||||
@@ -397,7 +398,9 @@ static int encode_slice(AVCodecContext *avctx, const AVFrame *pic,
 | 
			
		||||
    int plane_factor, is_chroma;
 | 
			
		||||
    uint16_t *qmat;
 | 
			
		||||
 | 
			
		||||
    if (quant < MAX_STORED_Q) {
 | 
			
		||||
    if (ctx->force_quant) {
 | 
			
		||||
        qmat = ctx->quants[0];
 | 
			
		||||
    } else if (quant < MAX_STORED_Q) {
 | 
			
		||||
        qmat = ctx->quants[quant];
 | 
			
		||||
    } else {
 | 
			
		||||
        qmat = ctx->custom_q;
 | 
			
		||||
@@ -750,21 +753,23 @@ static int encode_frame(AVCodecContext *avctx, AVPacket *pkt,
 | 
			
		||||
    // slices
 | 
			
		||||
    for (y = 0; y < ctx->mb_height; y++) {
 | 
			
		||||
        mbs_per_slice = ctx->mbs_per_slice;
 | 
			
		||||
        for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
 | 
			
		||||
            while (ctx->mb_width - x < mbs_per_slice)
 | 
			
		||||
                mbs_per_slice >>= 1;
 | 
			
		||||
            q = find_slice_quant(avctx, pic, (mb + 1) * TRELLIS_WIDTH, x, y,
 | 
			
		||||
                                 mbs_per_slice);
 | 
			
		||||
        }
 | 
			
		||||
        if (!ctx->force_quant) {
 | 
			
		||||
            for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
 | 
			
		||||
                while (ctx->mb_width - x < mbs_per_slice)
 | 
			
		||||
                    mbs_per_slice >>= 1;
 | 
			
		||||
                q = find_slice_quant(avctx, pic, (mb + 1) * TRELLIS_WIDTH, x, y,
 | 
			
		||||
                                     mbs_per_slice);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        for (x = ctx->slices_width - 1; x >= 0; x--) {
 | 
			
		||||
            ctx->slice_q[x] = ctx->nodes[q].quant;
 | 
			
		||||
            q = ctx->nodes[q].prev_node;
 | 
			
		||||
            for (x = ctx->slices_width - 1; x >= 0; x--) {
 | 
			
		||||
                ctx->slice_q[x] = ctx->nodes[q].quant;
 | 
			
		||||
                q = ctx->nodes[q].prev_node;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        mbs_per_slice = ctx->mbs_per_slice;
 | 
			
		||||
        for (x = mb = 0; x < ctx->mb_width; x += mbs_per_slice, mb++) {
 | 
			
		||||
            q = ctx->slice_q[mb];
 | 
			
		||||
            q = ctx->force_quant ? ctx->force_quant : ctx->slice_q[mb];
 | 
			
		||||
 | 
			
		||||
            while (ctx->mb_width - x < mbs_per_slice)
 | 
			
		||||
                mbs_per_slice >>= 1;
 | 
			
		||||
@@ -859,27 +864,66 @@ static av_cold int encode_init(AVCodecContext *avctx)
 | 
			
		||||
        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->force_quant = avctx->global_quality / FF_QP2LAMBDA;
 | 
			
		||||
    if (!ctx->force_quant) {
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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++)
 | 
			
		||||
                ctx->quants[i][j] = ctx->quant_mat[j] * i;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ctx->nodes = av_malloc((ctx->slices_width + 1) * TRELLIS_WIDTH
 | 
			
		||||
                               * sizeof(*ctx->nodes));
 | 
			
		||||
        if (!ctx->nodes) {
 | 
			
		||||
            encode_close(avctx);
 | 
			
		||||
            return AVERROR(ENOMEM);
 | 
			
		||||
        }
 | 
			
		||||
        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;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ctx->slice_q = av_malloc(ctx->slices_width * sizeof(*ctx->slice_q));
 | 
			
		||||
        if (!ctx->slice_q) {
 | 
			
		||||
            encode_close(avctx);
 | 
			
		||||
            return AVERROR(ENOMEM);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        int ls = 0;
 | 
			
		||||
 | 
			
		||||
        if (ctx->force_quant > 64) {
 | 
			
		||||
            av_log(avctx, AV_LOG_ERROR, "too large quantiser, maximum is 64\n");
 | 
			
		||||
            return AVERROR_INVALIDDATA;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (j = 0; j < 64; j++) {
 | 
			
		||||
            ctx->quants[0][j] = ctx->quant_mat[j] * ctx->force_quant;
 | 
			
		||||
            ls += av_log2((1 << 11)  / ctx->quants[0][j]) * 2 + 1;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        ctx->bits_per_mb = ls * 8;
 | 
			
		||||
        if (ctx->chroma_factor == CFACTOR_Y444)
 | 
			
		||||
            ctx->bits_per_mb += ls * 4;
 | 
			
		||||
        if (ctx->num_planes == 4)
 | 
			
		||||
            ctx->bits_per_mb += ls * 4;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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_STORED_Q; i++) {
 | 
			
		||||
        for (j = 0; j < 64; j++)
 | 
			
		||||
            ctx->quants[i][j] = ctx->quant_mat[j] * i;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    avctx->codec_tag   = ctx->profile_info->tag;
 | 
			
		||||
 | 
			
		||||
    av_log(avctx, AV_LOG_DEBUG, "profile %d, %d slices, %d bits per MB\n",
 | 
			
		||||
@@ -887,24 +931,6 @@ static av_cold int encode_init(AVCodecContext *avctx)
 | 
			
		||||
    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));
 | 
			
		||||
    if (!ctx->nodes) {
 | 
			
		||||
        encode_close(avctx);
 | 
			
		||||
        return AVERROR(ENOMEM);
 | 
			
		||||
    }
 | 
			
		||||
    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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ctx->slice_q = av_malloc(ctx->slices_width * sizeof(*ctx->slice_q));
 | 
			
		||||
    if (!ctx->slice_q) {
 | 
			
		||||
        encode_close(avctx);
 | 
			
		||||
        return AVERROR(ENOMEM);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user