我正在使用ffmpeg 4.1,并且正在显示多个摄像机(h264和h265)的实时流。
我的程序收集相同帧的数据包,然后调用encodeVideo函数。实际上,它会一次发送一帧的所有数据包。
如果没有丢失的数据包,程序运行良好。当我删除随机I帧中的数据包时,h264和h265流均按预期工作(会跳过几秒钟,但仍继续流传输)。
当我从h265流中删除随机P帧中的数据包时,avcodec_send_packet函数将给出AVERROR_INVALIDDATA,并且流将继续。
但是,当我从h264流中删除随机P帧中的数据包时,avcodec_send_packet函数将给出0。然后,avcodec_receive_frame函数将连续给出AVERROR(EAGAIN)并且流冻结。
void decodeVideo(array<uint8_t>^ data, int length, AvFrame^ finishedFrame)
{
AVPacket* videoPacket = new AVPacket();
av_init_packet(videoPacket);
pin_ptr<unsigned char> dataPtr = &data[0];
videoPacket->data = dataPtr;
videoPacket->size = length;
int retVal = avcodec_send_packet((AVCodecContext*)context, videoPacket);
if(retVal < 0)
{
if (retVal == AVERROR_EOF)
Utility::Log->ErrorFormat("avcodec_send_packet() return value is AVERROR_EOF.");
else if( retVal == AVERROR_INVALIDDATA)
Utility::Log->ErrorFormat("avcodec_send_packet() INVALID DATA!");
else
Utility::Log->ErrorFormat("avcodec_send_packet() return value is negative:{0}",retVal);
}
else
{
int receive_frame = avcodec_receive_frame((AVCodecContext*)context, (AVFrame*)finishedFrame);
if (receive_frame == AVERROR(EAGAIN))
Utility::Log->ErrorFormat("avcodec_receive_frame() returns AVERROR(EAGAIN)");
else if(receive_frame == AVERROR_EOF)
Utility::Log->ErrorFormat("avcodec_receive_frame() returns AVERROR(AVERROR_EOF)");
else
Utility::Log->ErrorFormat("avcodec_receive_frame() return value is negative:{0}",receive_frame);
}
av_packet_unref(videoPacket);
delete videoPacket;
}
当我如图所示添加avcodec_flush_buffers
时,我的问题得到了暂时解决。但是一段时间后它再次冻结。
if(receive_frame == AVERROR(EAGAIN))
{
Utility::Log->ErrorFormat("avcodec_receive_frame() returns AVERROR(EAGAIN)");
avcodec_flush_buffers((AVCodecContext*)context);
}
使用ffmpeg版本4.1.1测试了相同的结果。
查找ffmpeg版本,例如2.5解码功能是不同的,但是当我删除数据包时没有问题。但是我也正在使用h265流。
EDIT2
AVCodecID id = AVCodecID::AV_CODEC_ID_H264;
AVCodec* dec = avcodec_find_decoder(id);
AVCodecContext* decContext = avcodec_alloc_context3(dec);
在这些行之后,我的代码包括以下行。 当我删除它们时,现在没有问题。
if(dec->capabilities & AV_CODEC_CAP_TRUNCATED)
decContext->flags |= AV_CODEC_FLAG_TRUNCATED;
decContext->flags2 |= AV_CODEC_FLAG2_CHUNKS;