将AVPackets合并为mp4文件-重新访问

时间:2019-05-09 07:54:52

标签: ffmpeg libav

我在这里指的是这个线程: Muxing AVPackets into mp4 file

那里的问题基本上与我相同,第一个答案看起来非常有希望。 用户 pogorskiy 提供的源代码(伪类)似乎完全符合我的要求:

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

pkt 数据,我是从connectec摄像机的第三方API收到的。没有可打开的文件可从中读取输入数据,也没有可从相机接收的RTSP流。这只是一个API调用,它为我提供了指向H264编码帧的指针,该帧正是AVPacket的原始数据。

无论如何,我尝试将这段代码用作应用程序的基础,但是出现的第一个问题是,我遇到运行时错误:

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

因此,我开始按照 pogorskiy 的建议向编解码器添加更多信息:

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

现在,我希望提供一个codec_id,运行时消息至少会有所不同,但是仍然相同:

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

关于如何设置结构以便打开mp4文件以将数据包写入的任何想法吗?

1 个答案:

答案 0 :(得分:1)

好的,我知道了。至少我可以打开一个mp4文件,并将H264编码的数据包写入其中。该文件甚至在VLC中打开并显示第一帧。仅此而已,只是一个开始。

所以我将代码放在她身上,以显示此最小解决方案。如果有人提出他/她的意见,我仍然感到非常高兴,因为它仍然无法完美运行...

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

正如我所说,生成的mp4文件在瞬间显示了第一帧,此后停止播放。 我认为会显示第一帧,因为我确保这是一个包含完整图像的I帧。

我不知道是否必须向muxer提供一些其他数据才能获得可用的mp4文件。我还在努力。

任何评论和想法都非常欢迎!

谢谢, 迈克