I am developing a tool which receives a h.264 live stream from the network (the sender is a hardware encoder), buffers the last x-minutes and creates a video file of the last x-minutes if triggered.
My tool is able to receive the live stream and also to buffer AVPackets the with boost::serialization. Furthermore I am able to load the buffered AVPackets.
But when I try to create/mux a video file (mp4) with the loaded AVPackets there occurs an error in the mp4-file or mp4-header. I am able to create a mp4-file and also to write Packets to the file with av_interleaved_write_frame(). The mp4-file has also a plausible size. So it seams that the AVPackets were written to the file.
But when I try to open the mp4-file with a player like vlc, the video doesn't play. The player provides an error like: the header isn't correct and doesn't play any frame. But I write the header with the writeHeader() function to the AVFormatContext.
I guess that the reason is that the AVFormatContext isn't correctly initialized but with the example of ffmpeg/libav (muxing-examples) I can't solve the problem.
Has any one a solution (example code) or an other example how to correctly initialize the AVFormatContext?
Thanks for your help. Olgen
avcodec_init();
avcodec_register_all();
av_register_all();
av_log_set_level(AV_LOG_DEBUG);
char *outputFilename = "/tmp/output.mp4";
// define AVOutputFormat
AVOutputFormat *outputFormat = NULL;
outputFormat = av_guess_format("mp4", NULL, NULL);
if (!outputFormat) {
fprintf(stderr, "Could not find suitable output format\n");
return 1;
}
// define AVFormatContext
AVFormatContext *formatContext = NULL;
// lallocate the output media context
std::cout << "alloc" << std::endl;
formatContext = avformat_alloc_context();
// avformat_alloc_output_context(&formatContext, outputFormat, NULL, NULL);
if (!formatContext) {
fprintf(stderr, "Memory error\n");
return 1;
}
std::cout << "stream" << std::endl;
AVStream * video_st = av_new_stream(formatContext, 0);
AVCodec * codec = NULL;
avcodec_get_context_defaults3(video_st->codec, codec);
video_st->codec->coder_type = AVMEDIA_TYPE_VIDEO;
video_st->codec->flags = fc->streams[0]->codec->flags;
video_st->codec->sample_aspect_ratio = fc->streams[0]->codec->sample_aspect_ratio;
video_st->disposition = fc->streams[0]->disposition;
video_st->codec->codec_tag = fc->streams[0]->codec->codec_tag;
video_st->codec->bits_per_raw_sample = fc->streams[0]->codec->bits_per_raw_sample;
video_st->codec->chroma_sample_location = fc->streams[0]->codec->chroma_sample_location;
video_st->codec->codec_id = fc->streams[0]->codec->codec_id;
video_st->codec->codec_tag = fc->streams[0]->codec->codec_tag;
video_st->codec->time_base = fc->streams[0]->codec->time_base;
video_st->codec->extradata = fc->streams[0]->codec->extradata;
video_st->codec->extradata_size = fc->streams[0]->codec->extradata_size;
video_st->codec->pix_fmt = fc->streams[0]->codec->pix_fmt;
video_st->codec->width = fc->streams[0]->codec->width;
video_st->codec->height = fc->streams[0]->codec->height;
video_st->codec->sample_aspect_ratio = fc->streams[0]->codec->sample_aspect_ratio;
std::cout << "file" << std::endl;
avio_open(&formatContext->pb, outputFilename, AVIO_FLAG_WRITE);
std::cout << "header" << std::endl;
avformat_write_header(formatContext, NULL);
// av_write_header(formatContext);
// loop to write AVPackets with av_write_frame
The programm crashes after the avformat_write_header(formatContext, NULL) with a memory error. I also tried avformat_alloc_output_context() instead of avformat_alloc_output_context2() but both functions don't work. So I used avformat_alloc_context() (see above)
I think there is an alloction problem but why I can't use avformat_alloc_output_context2 or avformat_alloc_output_context. Could somebody figure out my problem here?
This is a general scheme shows how to mux video file from an existing packets
AVOutputFormat * outFmt = av_guess_format("mp4", NULL, NULL);
AVFormatContext *outFmtCtx = NULL;
avformat_alloc_output_context2(&outFmtCtx, outFmt, NULL, NULL);
AVStream * outStrm = av_new_stream(outFmtCtx, 0);
AVCodec * codec = NULL;
avcodec_get_context_defaults3(outStrm->codec, codec);
outStrm->codec->coder_type = AVMEDIA_TYPE_VIDEO;
///....
/// set some required value, such as
/// outStrm->codec->flags
/// outStrm->codec->sample_aspect_ratio
/// outStrm->disposition
/// outStrm->codec->codec_tag
/// outStrm->codec->bits_per_raw_sample
/// outStrm->codec->chroma_sample_location
/// outStrm->codec->codec_id
/// outStrm->codec->codec_tag
/// outStrm->codec->time_base
/// outStrm->codec->extradata
/// outStrm->codec->extradata_size
/// outStrm->codec->pix_fmt
/// outStrm->codec->width
/// outStrm->codec->height
/// outStrm->codec->sample_aspect_ratio
/// see ffmpeg.c for details
avio_open(&outFmtCtx->pb, outputFileName, AVIO_FLAG_WRITE);
avformat_write_header(outFmtCtx, NULL);
for (...)
{
av_write_frame(outFmtCtx, &pkt);
}
av_write_trailer(outFmtCtx);
avio_close(outFmtCtx->pb);
avformat_free_context(outFmtCtx);
For troubleshooting, it is useful to set detailed logging: av_log_set_level(AV_LOG_DEBUG);