Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing an output file for muxing mkv with FFmpeg

I'm a first time user of ffmpeg and I'm having trouble with initializing an output file for mkv muxing. I followed the description on the middle of this page but it doesn't work.

When I call the avformat_write_header() function it returns the error code -1094995529, which means: Invalid data found when processing input.

When I allocate the output context to mp4 format (I use in both cases the avformat_alloc_output_context2) I don't get this error, and it sucessfully writes the header. I tried to analyze the code of this example but I couldn't figure out what the problem is (I also tried different functions with no result).

Here is my code:

const char *filename = "c:\\Users\\MPM\\Desktop\\test.mkv";
AVFormatContext *mkvVideo = NULL;

int ret = 0;
ret = avformat_alloc_output_context2(&mkvVideo, av_guess_format("matroska", "c:\\Users\\MPM\\Desktop\\test.mkv", NULL), "mkv", filename);

std::cout << "\n avformat_alloc_output_context2: " << ret<<"\n";

AVStream* video_stream = avformat_new_stream(mkvVideo, NULL);

video_stream->time_base.den = 25;
video_stream->time_base.num = 1;
video_stream->id = mkvVideo->nb_streams - 1;

video_stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
video_stream->codecpar->codec_id = AV_CODEC_ID_H264;
video_stream->codecpar->bit_rate = 40000;
video_stream->codecpar->width = 1920;
video_stream->codecpar->height = 1080;
video_stream->codecpar->format = 0;

// AVCodec *video_codec = avcodec_find_encoder(AV_CODEC_ID_H264);
// AVCodecContext *codecCTx = NULL;

// codecCTx = avcodec_alloc_context3(video_codec);
// avcodec_get_context_defaults3(codecCTx, video_codec);

// ret = avcodec_parameters_to_context(codecCTx, video_stream->codecpar);
// std::cout << "\n avcodec_parameters_to_context: " << ret;

// codecCTx->framerate = { 25, 1 };
// codecCTx->gop_size = 12; 
// codecCTx->pix_fmt = AV_PIX_FMT_YUV420;
// codecCTx->max_b_frames = 1;
// codecCTx->codec_tag = 1;
// codecCTx->codec_type = AVMEDIA_TYPE_VIDEO;

std::cout << std::endl;
av_dump_format(mkvVideo, 0, filename, 1);

ret = avio_open(&mkvVideo->pb, "c:\\Users\\MPM\\Desktop\\test.mp4", AVIO_FLAG_READ_WRITE);
std::cout << "\n avio open: " << ret;

ret = avformat_write_header(mkvVideo, NULL);
std::cout << "\n ret: " << ret;

if (ret < 0)
    {
        char buffer[50];
        size_t bufsize = 50;
        av_strerror(ret, buffer, bufsize);
        std::cout << "\n error message: ";
        for (int i = 0; i < bufsize; i++) std::cout << buffer[i];
        exit(1);
    }

The printed output data about the output format (by the av_dump_format) is the following:

Output #0, matroska, to 'c:\Users\\MPM\\Desktop\\test.mkv':
Stream #0:0: Video: h264, yuv420p, 1920x1080, q=2-31, 40 kb/s, 25 tbn

I think there can be two reasons why it's not working:

  1. There are some missing parameters for the AVStream

  2. An mkv output format needs to be initialized differently

So can anyone tell me what I am doing wrong?

like image 457
MPM Avatar asked Oct 15 '22 14:10

MPM


1 Answers

So it turned out that the problem was indeed with the H264 codec initialization. The videostream->codecpar->extradata field has to be allocated and filled with NAL units which are streaming parameters. Doing this is an other complicated problem.

As I did not need streaming for my my project I simply allocated some space with avmalloc() to the extradata field and then I was able to initialize the output file.

like image 192
MPM Avatar answered Oct 19 '22 11:10

MPM