无法复制FFMpeg Prores的质量设置

时间:2017-02-03 19:55:30

标签: c ffmpeg

使用ffmpeg作为库。我正在寻找创建一个具有非常不一致结果的全局质量滑块。 AvCodecContext::global_quality似乎是个好地方。并非所有有损编解码器都引用此成员,但它似乎适用于ProRes。

c:\>ffmpeg.exe -i test.mov -c:v prores_ks -q:v 28 out.mov     # output 10mb file

c:\>ffmpeg.exe -i test.mov -c:v prores_ks -q:v 2 out.mov     # output 28mb file

大。现在让我们在代码中完成它。基于Muxing.c。为了暗示我正在调用哪个api,我正在提炼出很多代码。

AVStream* AddStream(AVFormatContext* formatContext, int quality)
{
    AVCodec* codec = AVFindEncoder("prores_ks");

    AVStream* newStream = avformat_new_stream(formatContext, codec);

    newStream->id = formatContext->nb_streams - 1;

    AVCodecContext c = avcodec_alloc_context3(codec);

    c->codec_id = AV_CODEC_ID_PRORES;
    c->codec_type = AVMEDIA_TYPE_VIDEO;
    c->width = 1920;
    c->height = 1080;

    newStream->time_base = av_inv_q(frameRate);
    c->time_base = av_inv_q(frameRate);

    c->pix_fmt = AV_PIX_FMT_YUVA444P10;

    c->global_quality = quality;

    return newStream;
}
......
//excerpt from WriteFrame()

AVPacket pkt;
av_init_packet(&pkt);
pkt.data= pVideoBuffer;
pkt.size= iVideoBufferSize;
int gotpkt = 0;
int ret = avcodec_encode_video2(pCodecContext, &pkt, pPicture, &gotpkt);
if (ret == 0)
{
    av_packet_rescale_ts(&pkt, pCodecContext->time_base, pVideoStream->time_base);

    if (gotpkt) {
        ret = av_interleaved_write_frame(pFormatContext, &pkt);
    }
}

我无法获得影响输出大小的质量。有什么想法吗?

这是proresenc_kostya.c的摘录

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 *
                                       ctx->pictures_per_frame)
                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->slice_q = av_malloc(ctx->slices_per_picture * sizeof(*ctx->slice_q));
    if (!ctx->slice_q) {
        encode_close(avctx);
        return AVERROR(ENOMEM);
    }

    ctx->tdata = av_mallocz(avctx->thread_count * sizeof(*ctx->tdata));
    if (!ctx->tdata) {
        encode_close(avctx);
        return AVERROR(ENOMEM);
    }

    for (j = 0; j < avctx->thread_count; j++) {
        ctx->tdata[j].nodes = av_malloc((ctx->slices_width + 1)
                                        * TRELLIS_WIDTH
                                        * sizeof(*ctx->tdata->nodes));
        if (!ctx->tdata[j].nodes) {
            encode_close(avctx);
            return AVERROR(ENOMEM);
        }
        for (i = min_quant; i < max_quant + 2; i++) {
            ctx->tdata[j].nodes[i].prev_node = -1;
            ctx->tdata[j].nodes[i].bits      = 0;
            ctx->tdata[j].nodes[i].score     = 0;
        }
    }
} 

编辑:

来自ffmpeg.exe的输出:

profile 4, 1020 slices, interlacing: no, 6576 bits per MB
frame size upper bound: 11429274

我的应用上的ffmpeg avlog输出:

profile 4, 1020 slices, interlacing: no, 1425 bits per MB
frame size upper bound: 6170103

1 个答案:

答案 0 :(得分:0)

有一些黑客支持旧的编解码器。因此输入值在内部相乘。一个需要与ffmpeg.exe

相同
#define FF_QP2LAMBDA 118

//from ffmpeg_opt.c

ost->enc_ctx->global_quality = FF_QP2LAMBDA * qscale;