Ffmpeg 将数据包多路复用到mp4文件中-重新访问

Ffmpeg 将数据包多路复用到mp4文件中-重新访问,ffmpeg,libav,Ffmpeg,Libav,我在这里指的是这个帖子: 那边的问题基本上和我的一样,第一个答案看起来很有希望。 用户pogorskiy提供的源代码(某种伪代码)似乎正是我所需要的: AVOutputFormat * outFmt = av_guess_format("mp4", NULL, NULL); AVFormatContext *outFmtCtx = NULL; avformat_alloc_output_context2(&outFmtCtx, outFmt, NULL, NULL); AVStream

我在这里指的是这个帖子:

那边的问题基本上和我的一样,第一个答案看起来很有希望。 用户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数据,我从第三方API从我的connectec摄像头接收。没有要打开的文件,也没有要从中读取输入数据的文件,也没有要从相机接收的RTSP流。这只是一个API调用,它给我一个指向H264编码帧的指针,该帧正是AVP数据包的原始数据

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

Could not find tag for codec none in stream #0, codec not currently supported in container
因此,我开始向编解码器添加更多信息,正如波戈斯基所建议的:

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文件将数据包写入吗?

好的,我已经开始工作了。至少我可以打开一个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);
charoutputfilename[]=“camera.mp4”;
av_日志_设置_级别(av_日志_调试);
AVOutputFormat*OUTPMT=av_guess_格式(“mp4”,空,空);
AVFormatContext*outpmtctx=NULL;
avformat_alloc_output_context2(&outpmtctx,outpmt,NULL,NULL);
AVStream*outStrm=avformat\u new\u stream(outpmtctx,NULL);
outsrm->id=0;
outsrm->time_base={1,30};
平均帧速率={1,30};
AVCodec*codec=NULL;
avcodec\u get\u context\u defaults3(outsrm->codec,codec);
outpmtctx->video\u codec\u id=AV\u codec\u id\u H264;
///....
///设置一些必需的值,例如
///EXTRM->编解码器->标志
///EXTRM->编解码器->采样/纵横比
///超出->处置
///outStrm->codec->codec\u标签
///输出->编解码器->每个原始样本的比特数
///输出->编解码器->色度采样位置
outStrm->codepar->codec_id=AV_codec_id_H264;
outStrm->codepar->codec\u type=AVMEDIA\u type\u视频;
///EXTRM->编解码器->时基
///EXTRARM->编解码器->外部数据
///EXTRARM->编解码器->外部数据大小
///外扩->编解码器->pix\U fmt
超出长度->编解码器->宽度=1920;
outStrm->codepar->高度=1080;
///EXTRM->编解码器->采样/纵横比
///有关详细信息,请参见ffmpeg.c
avio_打开(&OUTPMTCTX->pb、outputFileName、avio_标志_写入);
avformat_write_头(OUTPMTCTX,NULL);
***通过GenICam API的摄像头访问循环从这里开始***
n++;
av_初始_数据包(&av数据包);
avPacket.data=static_cast(pPtr);//来自带有H264编码帧的摄像机的原始数据
avPacket.size=datasize;//从GenICam API接收的数据大小以及pPtr(原始数据)
avPacket.pts=(1/30)*n;//愚蠢的尝试以某种方式设置pts和dts。。。正在做这个。。。
avPacket.dts=(1/30)*(n-1);
avPacket.pos=n;
avPacket.stream_index=outsrm->index;
av写入帧(OUTPMTCTX和avPacket);
****摄像头接入环路到此结束****
av_写入_拖车(OUTPMTCTX);
avio_关闭(OUTPMTCTX->pb);
avformat_free_context(outpmtctx);
正如我所说,生成的mp4文件在一瞬间显示第一帧,然后停止播放。 我认为会显示第一帧,因为我确保这是一个包含完整图像的I帧

我不知道我是否必须向muxer提供一些额外的数据才能获得一个工作的mp4文件。我还在做这个

欢迎提出任何意见和想法

谢谢,
Maik

哦,顺便说一句,我不得不根据我在这里找到的信息修改上述代码:意思是
AVStream*outStrm=av_new_stream(outpmtctx,0)现在是
AVStream*outStrm=avformat\u new\u流(outpmtctx,NULL);outsrm->id=0似乎我问的ffmpeg/libav问题非常不具体,因为我没有得到任何答复(最后两个问题也没有得到太多的答复)。我必须承认,libav lib是一头野兽,因此我很难为我想实现的目标提出正确的问题。也许有人能指出我的问题中有什么是很难理解的,这样我就可以改进我的提问方式。然而,我(又一次)自己做到了。至少有一件事专门回答了我的问题,那就是如何用上述方法打开mp4文件并将我的视频包写入其中(见下面的答案)。
avPacket.pts=(1/30)*n
-->pts/dts是有符号整数。所有计算出的值都将被转换到地板(值)。因为你的时基是1/30。只需将其设置为
n
。显然,您所说的是正确的。我在那里犯了一个多么愚蠢的错误。但是,它仍然不会在MediaInfo中显示任何dts时间。mp4文件包含了我所有的数据包数据,但由于似乎存在时间问题,它在头文件中说,该文件的长度为40ms。通过在VLC中打开它,它仍然只显示第一帧,然后停止。