How to set ffmpeg qscale in C/C++ for image encoding

Viewed 1245

I have a working image encoder in C++ using ffmpeg as the backend. I am taking videos in and saving frames out as jpeg, but I am having difficulty adjusting the quality of the output jpegs.
Things I have tried:
Setting AVCodecContext's global_quality and compression_level fields.
I have also tried setting qscale with an AVDictionary of options, but have been unsuccessful there too.

I know its possible because with the command line I can
ffmpeg -i INPUT -q:v 2 output_frame_%02d.jpg and get higher quality images.

3 Answers

The command line -q option effects two things

    enc_ctx->flags |= AV_CODEC_FLAG_QSCALE;
    enc_ctx->global_quality = FF_QP2LAMBDA * qscale;

where enc_ctx is the AVCodecContext for the output stream and FF_QP2LAMBDA is 118

When you use interface function such as

avcodec_decode_video2
avcodec_encode_video2
avcodec_send_frame
avcodec_receive_packet

The flagsand global_quality do not work. You should modified line 3814 at static int encode_picture(MpegEncContext *s, int picture_number) in ./libavcodec/mpegvideo_enc.c:

    ...
    if (estimate_qp(s, 0) < 0)
        return -1;
    s->qscale = 5; //modify qscale here
    if (s->qscale < 3 && s->max_qcoeff <= 128 &&
        s->pict_type == AV_PICTURE_TYPE_I &&
        !(s->avctx->flags & AV_CODEC_FLAG_QSCALE))
        s->qscale= 3; //reduce clipping problems
    ...

In my case, setting the global_quality didn't work.

I changed qmin instead of global_quality and it worked.

jpegContext->flags |= AV_CODEC_FLAG_QSCALE;
jpegContext->qmin = 3;

or change the quality of pFrame

jpegContext->flags |= AV_CODEC_FLAG_QSCALE;
pFrame->quality = FF_QP2LAMBDA * qscale;

Refer to this project for practical example

Related