Search code examples
c++visual-studioffmpegh.264vcpkg

FFmpeg c api create encoder for AV_CODEC_ID_H264 crash on Windows


I'm using ffmpeg (version 5.1.2) to clip a mp4 video per frame so I need to decode and encode it. However, when I'm creating the encoder for its video stream, the program always crashes at the call to avio_open2(), after H264 gives this error message:

[h264_mf @ 0000025C1EBC1900] could not set output type (80004005)

enter image description here

The configuration (time_base, pix_fmt, width, height) of the codec context of the encoder is copied from the decoder, and I checked if the pixel format is supported by finding if it's in codec->pix_fmts.

I find that the problem does not involve all my other pieces of code, because this minimal program can duplicate the same problem:

extern "C"
{
#include <libavcodec/avcodec.h>
}

int main()
{
    auto codec = avcodec_find_encoder(AV_CODEC_ID_H264);
    auto codec_ctx = avcodec_alloc_context3(codec);

    codec_ctx->pix_fmt = AV_PIX_FMT_YUV420P;
    codec_ctx->width = 2560;
    codec_ctx->height = 1440;
    codec_ctx->time_base.num = 1; codec_ctx->time_base.den = 180000;

    avcodec_open2(codec_ctx, codec, NULL);

    return 0;
}

Then I suspect if it's a bug of ffmpeg. My environment is Windows 11 64-bit, Visual Studio 2022. The ffmpeg library is obtained from vcpkg, as shown in the following image:

enter image description here


Solution

  • I found that the problem is triggered by a time base that is too small.

    More specifically, I tested that, assuming the numerator is 1, when the denominator <= 172, the encoder can be created with no problem. When denominator > 172, however, the problem will always occur. enter image description here enter image description here

    I find it very strange, as the time base is directly copied from the decoder, where it's directly copied from the stream settings. That is, at least H264 could use this time base to encode a video. I don't understand why this specific encoder found by ffmpeg doesn't support it but at least I can continue my work.

    Edit: I found in the comment of AVCodecContext::time_base that for decoding it's deprecated and I am supposed to use the framerate for this purpose (i.e. copy the stream's r_frame_rate to codec_ctx->framerate). This value is 30/1 and its reciprocal is bigger than the limit 1/172. However, for encoding it's a must set and this is (kind of) the cause of my confusion. Still, a strange thing is that the input stream's time base is 1/90000 < 1/127.