Использование 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
Я считаю, что вам нужно установить c-> флаги | = AV_CODEC_FLAG_QSCALE ;, в противном случае он будет считать, VBR. Я признаю, что на самом деле я его не тестировал, но это то, что делает ffmpeg_opt.c при разборе «-q: v». –
Спасибо. Я попробую. Я также заметил, что FF_QP2LAMBDA определяется как 118. Я не знаю, почему я думал, что это 2 или 1. –