FFMPEG: Decode video in h264rgb/libx264rgb error - c++

I did a small program to encode raw images in h264rgb codec with ffmpeg.
I use this codec because I needed to encode lossless rgb images (not possible with the classic h264 codec).
But now, I have a problem. I'm not able to decode the video generated with ffmpeg. I did a second small program for that, but I get a segfault when I reach the avcodec_decode_video2() function.
I did all the initialisation correctly. I didn't forget the avcodec_register_all() and av_init_packet() functions.
Here is the code for initialisation:
_c = NULL;
_frame_nb = 0;
// Register all formats and codecs
#pragma omp critical
{
avcodec_register_all();
}
_pkt = new AVPacket;
av_init_packet(_pkt); // a defaut de pouvoir ecrire : pkt = av_packet_alloc();
if(!_pkt)
exit(1);
_codec = avcodec_find_encoder_by_name("libx264rgb");
if (!_codec) {
fprintf(stderr, "codec not found\n");
exit(1);
}
_c = avcodec_alloc_context3(_codec);
if (!_c) {
fprintf(stderr, "Could not allocate video codec context\n");
exit(1);
}
_c->debug = true;
_c->pix_fmt = (AVPixelFormat)AV_PIX_FMT_RGB24;
_c->width = this->_headerCam[this->_currentCam]->iNbCol;
_c->height = this->_headerCam[this->_currentCam]->iNbLine;
_picture = av_frame_alloc();
if (!_picture) {
fprintf(stderr, "Could not allocate video _picture\n");
exit(1);
}
_tmp_picture = av_frame_alloc();
if (!_tmp_picture) {
fprintf(stderr, "Could not allocate video _tmp_picture\n");
exit(1);
}
_tmp_picture->format = (AVPixelFormat)AV_PIX_FMT_RGB24;
_tmp_picture->width = this->_headerCam[this->_currentCam]->iNbCol;
_tmp_picture->height = this->_headerCam[this->_currentCam]->iNbLine;
_tmp_picture->linesize[0] = this->_headerCam[this->_currentCam]->iNbCol;
/* open it */
if (avcodec_open2(_c, _codec, NULL) < 0) {
fprintf(stderr, "could not open codec\n");
exit(1);
}
And the decode function:
_pkt->data = NULL; // packet data will be allocated by the encoder
_pkt->size = 0;
unsigned char * inbuf;
inbuf = (uint8_t*)av_malloc(w*h*3);
//! read img size
int size_img;
fread(&size_img, sizeof(int), 1, this->_pFile);
_pkt->size = fread(inbuf, 1, size_img, this->_pFile);
_pkt->data = (unsigned char*)inbuf;
if(_pkt->size)
{
len = avcodec_decode_video2(_c, _tmp_picture, &got_picture, _pkt);
...
}
Any idea?

+What the comment says, instead of inbuf = (uint8_t*)av_malloc(w*h*3); you should use this:
int buffer_size = av_image_get_buffer_size((AVPixelFormat)AV_PIX_FMT_RGB24, w, h, 1);
inbuf = (uint8_t*)av_malloc(buffer_size);
Because of portability for alignment and such issues.
And also fix this line _tmp_picture->linesize[0] = ...
with this:
_tmp_picture->linesize[0] = av_image_get_linesize((AVPixelFormat)AV_PIX_FMT_RGB24, w, 0);
Hope that helps.

Well, I finally found a beginning of answer:
I used avcodec_find_encoder_by_name() instead of the avcodec_find_decoder_by_name()... It's certainly better if I want to decode data...
But now, I have the problem that _codec = avcodec_find_decoder_by_name("libx264rgb"); doesn't find the codec. But it works for _codec = avcodec_find_encoder_by_name("libx264rgb"); when I encoded my video.
EDIT : With _codec = avcodec_find_decoder(AV_CODEC_ID_H264); instead of _codec = avcodec_find_decoder_by_name("libx264rgb");, it is able to decode my video. It's weird but ok. Now, I hope I get lossless images.
EDIT2: Now, everything works! I got lossless decoded images with the AV_CODEC_ID_H264 decoder. To summarize, if you want to decode a video encoded with libx264rgb, you can use the classic AV_CODEC_ID_H264 codec.

Related

ffmpeg api alternate transcoding and remuxing for same file

Context
Hello !
I'm currently working on the development of a small library allowing to cut an h.264 video on any frame, but without re-encoding (transcoding) the whole video. The idea is to re-encode only the GOP on which we want to cut, and to rewrite (remux) directly the others GOP.
The avcut project (https://github.com/anyc/avcut) allows to do that, but requires a systematic decoding of each package, and seems to not work with the recent versions of ffmpeg from the tests I could do and from the recent feedbacks in the github issues.
As a beginner, I started from the code examples provided in the ffmpeg documentation, in particular: transcoding.c and remuxing.c.
Problem encountered
The problem I'm having is that I can't get both transcoding and remuxing to work properly at the same time. In particular, depending on the method I use to initialize the AVCodecParameters of the output video stream, transcoding works, or remuxing works:
avcodec_parameters_copy works well for remuxing
avcodec_parameters_from_context works well for transcoding
In case I choose avcodec_parameters_from_context, the transcoded GOP are correctly read by my video player (parole), but the remuxed packets are not read, and ffprobe does not show/detect them.
In case I choose avcodec_parameters_from_context, the remuxing GOP are correctly read by my video player, but the transcoding key_frame are bugged (I have the impression that the b-frame and p-frame are ok), and ffprobe -i return an error about the NAL of the key-frames:
[h264 # 0x55ec8a079300] sps_id 32 out of range
[h264 # 0x55ec8a079300] Invalid NAL unit size (1677727148 > 735).
[h264 # 0x55ec8a079300] missing picture in access unit with size 744
I suspect that the problem is related to the extradata of the packets. Through some experiments on the different attributes of the output AVCodecParameters, it seems that it is the extradata and extradata_size attributes that are responsible for the functioning of one method or the other.
Version
ffmpeg development branch retrieved on 2022-05-17 from https://github.com/FFmpeg/FFmpeg.
Compiled with --enable-libx264 --enable-gpl --enable-decoder=png --enable-encoder=png
Code
My code is written in c++ and is based on two classes: a class defining the parameters and methods on the input file (InputContexts) and a class defining them for the output file (OutputContexts). The code of these two classes is defined in the following files:
contexts.h
contexts.cpp
The code normally involved in the problem is the following:
stream initialization
int OutputContexts::init(const char* out_filename, InputContexts* input_contexts){
int ret;
int stream_index = 0;
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
return ret;
}
av_dump_format(ofmt_ctx, 0, out_filename, 1);
encoders.resize(input_contexts->ifmt_ctx->nb_streams, nullptr);
codecs.resize(input_contexts->ifmt_ctx->nb_streams, nullptr);
// stream mapping
for (int i = 0; i < input_contexts->ifmt_ctx->nb_streams; i++) {
AVStream *out_stream;
AVStream *in_stream = input_contexts->ifmt_ctx->streams[i];
AVCodecContext* decoder_ctx = input_contexts->decoders[i];
// add new stream to output context
out_stream = avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
return ret;
}
// from avcut blog
av_dict_copy(&out_stream->metadata, in_stream->metadata, 0);
out_stream->time_base = in_stream->time_base;
// encoder
if (decoder_ctx->codec_type == AVMEDIA_TYPE_VIDEO){
ret = prepare_encoder_video(i, input_contexts);
if (ret < 0){
fprintf(stderr, "Error while preparing encoder for stream #%u\n", i);
return ret;
}
// from avcut
out_stream->sample_aspect_ratio = in_stream->sample_aspect_ratio;
// works well for remuxing
ret = avcodec_parameters_copy(out_stream->codecpar, in_stream->codecpar);
if (ret < 0) {
fprintf(stderr, "Failed to copy codec parameters\n");
return ret;
}
// works well for transcoding
// ret = avcodec_parameters_from_context(out_stream->codecpar, encoders[i]);
// if (ret < 0) {
// av_log(NULL, AV_LOG_ERROR, "Failed to copy encoder parameters to output stream #%u\n", i);
// return ret;
// }
} else if (decoder_ctx->codec_type == AVMEDIA_TYPE_AUDIO) {
...
} else {
...
}
// TODO useful ???
// set current stream position to 0
// out_stream->codecpar->codec_tag = 0;
}
// opening output file in write mode with the ouput context
if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", out_filename);
return ret;
}
}
// write headers from output context in output file
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
return ret;
}
return ret;
}
AVCodecContext initialization for encoder
int OutputContexts::prepare_encoder_video(int stream_index, InputContexts* input_contexts){
int ret;
const AVCodec* encoder;
AVCodecContext* decoder_ctx = input_contexts->decoders[stream_index];
AVCodecContext* encoder_ctx;
if (video_index >= 0){
fprintf(stderr, "Impossible to mark stream #%u as video, stream #%u is already registered as video stream.\n",
stream_index, video_index);
return -1; //TODO change this value for correct error code
}
video_index = stream_index;
if(decoder_ctx->codec_id == AV_CODEC_ID_H264){
encoder = avcodec_find_encoder_by_name("libx264");
if (!encoder) {
av_log(NULL, AV_LOG_FATAL, "Encoder libx264 not found\n");
return AVERROR_INVALIDDATA;
}
fmt::print("Encoder libx264 will be used for stream {}.\n", stream_index);
} else {
std::string s = fmt::format("No video encoder found for the given codec_id: {}\n", avcodec_get_name(decoder_ctx->codec_id));
av_log(NULL, AV_LOG_FATAL, s.c_str());
return AVERROR_INVALIDDATA;
}
encoder_ctx = avcodec_alloc_context3(encoder);
if (!encoder_ctx) {
av_log(NULL, AV_LOG_FATAL, "Failed to allocate the encoder context\n");
return AVERROR(ENOMEM);
}
// from avcut
encoder_ctx->time_base = decoder_ctx->time_base;
encoder_ctx->ticks_per_frame = decoder_ctx->ticks_per_frame;
encoder_ctx->delay = decoder_ctx->delay;
encoder_ctx->width = decoder_ctx->width;
encoder_ctx->height = decoder_ctx->height;
encoder_ctx->pix_fmt = decoder_ctx->pix_fmt;
encoder_ctx->sample_aspect_ratio = decoder_ctx->sample_aspect_ratio;
encoder_ctx->color_primaries = decoder_ctx->color_primaries;
encoder_ctx->color_trc = decoder_ctx->color_trc;
encoder_ctx->colorspace = decoder_ctx->colorspace;
encoder_ctx->color_range = decoder_ctx->color_range;
encoder_ctx->chroma_sample_location = decoder_ctx->chroma_sample_location;
encoder_ctx->profile = decoder_ctx->profile;
encoder_ctx->level = decoder_ctx->level;
encoder_ctx->thread_count = 1; // spawning more threads causes avcodec_close to free threads multiple times
encoder_ctx->codec_tag = 0;
// correct values ???
encoder_ctx->qmin = 16;
encoder_ctx->qmax = 26;
encoder_ctx->max_qdiff = 4;
// end from avcut
// according to avcut, should not be set
// if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER){
// encoder_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
// }
ret = avcodec_open2(encoder_ctx, encoder, NULL);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", stream_index);
return ret;
}
codecs[stream_index] = encoder;
encoders[stream_index] = encoder_ctx;
return ret;
}
Example
To illustrate my problem, I provide here a test code using the two classes that alternates between transcoding and remuxing at each key-frame encountered in the file using my classes.
trans_remux.cpp
To compile the code:
g++ -o trans_remux trans_remux.cpp contexts.cpp -D__STDC_CONSTANT_MACROS `pkg-config --libs libavfilter` -lfmt -g
Currently the code is using avcodec_parameters_copy (contexts.cpp:333), so it works well for remuxing. If you want to test the version with avcodec_parameters_from_context, pls comment from line 333 to 337 in contexts.cpp and uncomment from line 340 to 344 and recompile.

Live555 truncates encoded data of FFMpeg

I am trying to stream H264 based data using Live555 over RTSP.
I am capturing data using V4L2, and then encodes it using FFMPEG and then passing data to Live555's DeviceSource file, in that I using H264VideoStreamFramer class,
Below is my codec settings to configure AVCodecContext of encoder,
codec = avcodec_find_encoder_by_name(CODEC_NAME);
if (!codec) {
cerr << "Codec " << codec_name << " not found\n";
exit(1);
}
c = avcodec_alloc_context3(codec);
if (!c) {
cerr << "Could not allocate video codec context\n";
exit(1);
}
pkt = av_packet_alloc();
if (!pkt)
exit(1);
/* put sample parameters */
c->bit_rate = 400000;
/* resolution must be a multiple of two */
c->width = PIC_HEIGHT;
c->height = PIC_WIDTH;
/* frames per second */
c->time_base = (AVRational){1, FPS};
c->framerate = (AVRational){FPS, 1};
c->gop_size = 10;
c->max_b_frames = 1;
c->pix_fmt = AV_PIX_FMT_YUV420P;
c->rtp_payload_size = 30000;
if (codec->id == AV_CODEC_ID_H264)
av_opt_set(c->priv_data, "preset", "fast", 0);
av_opt_set_int(c->priv_data, "slice-max-size", 30000, 0);
/* open it */
ret = avcodec_open2(c, codec, NULL);
if (ret < 0) {
cerr << "Could not open codec\n";
exit(1);
}
And I am getting encoded data using avcodec_receive_packet() function. which will return AVPacket.
And I am passing AVPacket's data into DeviceSource file below is code snippet of my Live555 code:
void DeviceSource::deliverFrame() {
if (!isCurrentlyAwaitingData()) return; // we're not ready for the data yet
u_int8_t* newFrameDataStart = (u_int8_t*) pkt->data;
unsigned newFrameSize = pkt->size; //%%% TO BE WRITTEN %%%
// Deliver the data here:
if (newFrameSize > fMaxSize) { // Condition becomes true many times
fFrameSize = fMaxSize;
fNumTruncatedBytes = newFrameSize - fMaxSize;
} else {
fFrameSize = newFrameSize;
}
gettimeofday(&fPresentationTime, NULL); // If you have a more accurate time - e.g., from an encoder - then use that instead.
// If the device is *not* a 'live source' (e.g., it comes instead from a file or buffer), then set "fDurationInMicroseconds" here.
memmove(fTo, newFrameDataStart, fFrameSize);
}
But here, sometimes my packet's size is getting more than fMaxSize value and as per LIVE555 logic it will truncate frame data, so that sometimes I am getting bad frames on my VLC,
From Live555 forum, I get to know that encoder should not send packet whose size is more than fMaxSize value, so my question is:
How to restrict encoder to limit size of packet?
Thanks in Advance,
Harshil
You can increase the maximum allowed sample size by changing "maxSize" in the OutPacketBuffer class in MediaSink.cpp. This worked for me. There are cases we may require high-quality video to be streamed, I don't think we will always be able to restrict the encoder to not to produce samples of size more than a particular value which would result in video quality issues. In fact, the samples are fragmented by the UDP sink live555 to match the default MTU (1500), so increasing the max sample size limit has no side effects.

Using libavformat to mux H.264 frames into RTP

I have an encoder that produces a series of H.264 I-frames and P-frames. I'm trying to use libavformat to mux and transmit these frames over RTP, but I'm stuck.
My program sends RTP data, but the RTP timestamp increments by 1 each successive frame, instead of 90000/fps. It also doesn't look like it's doing the proper framing for H.264 NAL, since I can't decode the stream as H.264 in Wireshark.
I suspect that I'm not setting up the codec information properly, but it appears in many places in the output format context, so it's unclear what exactly needs to be setup. The examples seem to all copy codec context info from encoders, which isn't my use case.
This is what I'm trying:
int main() {
AVFormatContext context = avformat_alloc_context();
if (!context) {
printf("avformat_alloc_context failed\n");
return;
}
AVOutputFormat *format = av_guess_format("rtp", NULL, NULL);
if (!format) {
printf("av_guess_format failed\n");
return;
}
context->oformat = format;
snprintf(context->filename, sizeof(context->filename), "rtp://%s:%d", "192.168.2.16", 10000);
if (avio_open(&(context->pb), context->filename, AVIO_FLAG_READ_WRITE) < 0) {
printf("avio_open failed\n");
return;
}
stream = avformat_new_stream(context, NULL);
if (!stream) {
printf("avformat_new_stream failed\n");
return;
}
stream->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
stream->codecpar->codec_id = AV_CODEC_ID_H264;
stream->codecpar->width = 1920;
stream->codecpar->height = 1080;
avformat_write_header(context, NULL);
...
write packets
...
}
Example write packet:
int write_packet(uint8_t *data, int size) {
AVPacket p;
av_init_packet(&p);
p.data = buffer;
p.size = size;
p.stream_index = stream->index;
av_interleaved_write_frame(context, &p);
}
I've even went so far to build in libx264, find the encoder, and copy the codec context info from there into the stream codecpar, with the same result. My goal is to build without libx264, and any other libs that aren't required, but it isn't clear whether libx264 is required for defaults such as time base.
How can the libavformat RTP muxer be initialized to properly send H.264 frames over RTCP+RTP?

PTS and DTS calculation for video and audio frames

I am receiving video H264 encoded data and audio G.711 PCM encoded data from two different threads to mux / write into mov multimedia container.
The writer function signatures are like:
bool WriteAudio(const unsigned char *pEncodedData, size_t iLength);
bool WriteVideo(const unsigned char *pEncodedData, size_t iLength, bool const bIFrame);
And the function for adding audio and video streams looks like:
AVStream* AudioVideoRecorder::AddMediaStream(enum AVCodecID codecID) {
Log("Adding stream: %s.", avcodec_get_name(codecID));
AVCodecContext* pCodecCtx;
AVStream* pStream;
/* find the encoder */
AVCodec* codec = avcodec_find_encoder(codecID);
if (!codec) {
LogErr("Could not find encoder for %s", avcodec_get_name(codecID));
return NULL;
}
pStream = avformat_new_stream(m_pFormatCtx, codec);
if (!pStream) {
LogErr("Could not allocate stream.");
return NULL;
}
pStream->id = m_pFormatCtx->nb_streams - 1;
pStream->time_base = (AVRational){1, VIDEO_FRAME_RATE};
pCodecCtx = pStream->codec;
switch(codec->type) {
case AVMEDIA_TYPE_VIDEO:
pCodecCtx->codec_id = codecID;
pCodecCtx->bit_rate = VIDEO_BIT_RATE;
pCodecCtx->width = PICTURE_WIDTH;
pCodecCtx->height = PICTURE_HEIGHT;
pCodecCtx->gop_size = VIDEO_FRAME_RATE;
pCodecCtx->pix_fmt = PIX_FMT_YUV420P;
m_pVideoStream = pStream;
break;
case AVMEDIA_TYPE_AUDIO:
pCodecCtx->codec_id = codecID;
pCodecCtx->sample_fmt = AV_SAMPLE_FMT_S16;
pCodecCtx->bit_rate = 64000;
pCodecCtx->sample_rate = 8000;
pCodecCtx->channels = 1;
m_pAudioStream = pStream;
break;
default:
break;
}
/* Some formats want stream headers to be separate. */
if (m_pOutputFmt->flags & AVFMT_GLOBALHEADER)
m_pFormatCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
return pStream;
}
Inside WriteAudio(..) and WriteVideo(..) functions, I am creating AVPakcet using av_init_packet(...) and set pEncodedData and iLength as packet.data and packet.size. I printed packet.pts and packet.dts and its equivalent to AV_NOPTS_VALUE.
Now, how do I calculate the PTS, DTS, and packet duration (packet.dts, packet.pts and packet.duration) correctly for both audio and video data so that I can sync audio & video and play it properly? I saw many examples on the internet, but none of them are making sense to me. I am new with ffmpeg, and my conception may not be correct in some context. I want to do it in the appropriate way.
Thanks in advance!
EDIT: In my video streams, there is no B frame. So, I think PTS and DTS can be kept the same here.
PTS/DTS are timestamps, they should be set to the timestamps of the input data. I don't know where your date comes from, but any input has some form of timestamps associated with it. Typically, the timestamps of the input media file or a system clock-derived metric if you're recording from your soundcard+webcam, and so on. You should convert these numbers into the form expected, and then assign them to AVPacket.pts/dts.

Muxing AVPackets into mp4 file

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);
This might not be the case, but avformat_write_header function should be used for writing header instead of function pointer in AVOutputFormat.write_header