Muxing AVPackets into mp4 file - revisited

2019-07-28 21:31发布

I'm refering to this thread here: Muxing AVPackets into mp4 file

The question over there is mainly the same that I have and the first answer looks very promising. The source (somkind of pseudo) code that the user pogorskiy provides seems to do exactly what I need:

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);

The pkt data, I receive from a third party API from my connectec camera. There is no file to open, to read the input data from and there is no RTSP stream to be received from the camera. It is just an API call, that gives me the pointer to a H264 encoded frame which is exactly the raw data for an AVPacket.

Anyway, I try to use this code as base for my applicatio, but the first problem that occurs is, that I get a runtime error:

Could not find tag for codec none in stream #0, codec not currently supported in container

So I started adding some more information to the codec, as pogorskiy suggested:

outStrm->codec->codec_id = AV_CODEC_ID_H264;
outStrm->codec->width = 1920;
outStrm->codec->height = 1080;

Now that I provided a codec_id, I was hoping, that the runtime message changes to at least something different, but it still ist the same:

Could not find tag for codec none in stream #0, codec not currently supported in container

Any idea on how I can set up the structures, so that I can open an mp4 file for writing my packets to?

标签: ffmpeg libav
1条回答
爱情/是我丢掉的垃圾
2楼-- · 2019-07-28 22:00

Okay, I got it working. At least I can open an mp4 file and write my H264 encoded packets to it. The file even opens in VLC and shows the very first frame... Nothing more, but it is a start.

So I place the code her, in order to show this minimal solution. I still am very happy if somebody would give his/hers opinion on it, because it still does not work perfectly...

char outputFileName[] = "camera.mp4";

av_log_set_level(AV_LOG_DEBUG);

AVOutputFormat * outFmt = av_guess_format("mp4", NULL, NULL);
AVFormatContext *outFmtCtx = NULL;
avformat_alloc_output_context2(&outFmtCtx, outFmt, NULL, NULL);
AVStream * outStrm = avformat_new_stream(outFmtCtx, NULL);
outStrm->id = 0;
outStrm->time_base = {1, 30};
outStrm->avg_frame_rate = {1, 30};

AVCodec * codec = NULL;
avcodec_get_context_defaults3(outStrm->codec, codec);

outFmtCtx->video_codec_id = AV_CODEC_ID_H264;

///....
/// 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->codecpar->codec_id = AV_CODEC_ID_H264;
outStrm->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
/// outStrm->codec->time_base
/// outStrm->codec->extradata 
/// outStrm->codec->extradata_size
/// outStrm->codec->pix_fmt
outStrm->codecpar->width = 1920;
outStrm->codecpar->height = 1080;
/// outStrm->codec->sample_aspect_ratio
/// see ffmpeg.c for details  

avio_open(&outFmtCtx->pb, outputFileName, AVIO_FLAG_WRITE);

avformat_write_header(outFmtCtx, NULL); 

*** Camera access loop via GenICam API starts here ***
n++;
av_init_packet(&avPacket);
avPacket.data = static_cast<uint8_t*>(pPtr); // raw data from the Camera with H264 encoded frame
avPacket.size = datasize; // datasize received from the GenICam API along with pPtr (the raw data)
avPacket.pts = (1/30) * n; // stupid try to set pts and dts somehow... Working on this...
avPacket.dts = (1/30) * (n-1);
avPacket.pos = n;
avPacket.stream_index = outStrm->index;

av_write_frame(outFmtCtx, &avPacket);

**** Camera access loop ends here ****

av_write_trailer(outFmtCtx);
avio_close(outFmtCtx->pb);
avformat_free_context(outFmtCtx);

As I said, the resulting mp4 file shows the very first frame for a split second and after that it stops playing. I think the first frame is displayed, because I make sure that this is an I-frame, containing the complete image.

I don't know if I have to provide some additional data to the muxer in order to get a working mp4 file. I'm still working on this.

Any comments and ideas are highly welcome!

Thanks, Maik

查看更多
登录 后发表回答