2017-02-03 6 views
1

Использование ffmpeg в качестве библиотеки. Я ищу, чтобы создать слайдер глобального качества с очень противоречивыми результатами. AvCodecContext::global_quality кажется хорошим местом для начала. Не все кодеки с потерями ссылаются на этого участника, но, похоже, они работают для ProRes.Невозможно реплицировать настройку качества FROMpeg Proores

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. Я много разбираюсь в коде, чтобы дать подсказку о том, к чему я звоню.

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

Edit:

Выходы 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 
+2

Я считаю, что вам нужно установить c-> флаги | = AV_CODEC_FLAG_QSCALE ;, в противном случае он будет считать, VBR. Я признаю, что на самом деле я его не тестировал, но это то, что делает ffmpeg_opt.c при разборе «-q: v». –

+0

Спасибо. Я попробую. Я также заметил, что FF_QP2LAMBDA определяется как 118. Я не знаю, почему я думал, что это 2 или 1. –

ответ

0

Существует некоторый взлом, поддерживающий старые кодеки. Таким образом, входное значение умножается внутри. Нужно делать то же самое, как ffmpeg.exe

#define FF_QP2LAMBDA 118 

//from ffmpeg_opt.c 

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