解码H264流时如何跳过帧?



我正在使用FFMPEG解码H264(或H265(RTSP流。

我的系统有 2 个软件:服务器和客户端

Server: Read frames from RTSP stream --> Forward frames to Client    
Client: Receive frames from Server --> Decode --> Render

我已经实现了并且工作正常,但是有一种情况使我的系统工作不好。也就是说,当服务器 - 客户端的互联网速度很慢时,帧无法实时传输到客户端。

目前,我通过在队列达到计数限制时跳过一些帧(不发送到客户端(来处理此问题。以下是我的摘要代码

//At Server Software (include 2 threads A and B)
//Thread A: Read AVPacket and forward to Client
while(true)
{
AVPacket packet;
av_init_packet(&packet);
packet.size = 0;
packet.data = NULL;
int ret = AVERROR(EAGAIN);
while (AVERROR(EAGAIN) == ret)
ret = av_read_frame(pFormatCtx, &packet);
if(packet.size > 0)
{
if(mySendQueue.count < 120) //limit 120 packet in queue
mySendQueue.Enqueue(packet); ////Thread B will read from this queue, to send packets to Client via TCP socket
else
;//SkipThisFrame ***: No send
}
}
//Thread B: Send To Client via TCP Socket
While(true)
{
AVPacket packet;
if(mySendQueue.Dequeue(packet))
{
SendPacketToClient(packet);
}
}
//At Server Software : Receive AVPacket from Server --> Decode --> Render
While(true)
{
AVPacket packet;
AVFrame frame;
ReadPacketFromServer(packet);
if (av_decode_asyn(pCodecCtx, &frame, &frameFinished, &packet) == RS_OK)
{
if (frameFinished)
{
RenderFrame(frame);
}
}           
}
UINT32 __clrcall av_decode_asyn(AVCodecContext *pCodecCtx, AVFrame *frame, int *frameFinished, AVPacket *packet)
{
int ret = -1;
*frameFinished = 0;
if (packet) 
{
ret = avcodec_send_packet(pCodecCtx, packet);
// In particular, we don't expect AVERROR(EAGAIN), because we read all
// decoded frames with avcodec_receive_frame() until done.
if (ret < 0 && ret != AVERROR_EOF)
return RS_NOT_OK;
}
ret = avcodec_receive_frame(pCodecCtx, frame);
if (ret < 0 && ret != AVERROR(EAGAIN))
{
return RS_NOT_OK;
}
if (ret >= 0)
*frameFinished = 1;
return RS_OK;
}

我的问题是专注于代码行SkipThisFrame ***,这种算法连续跳帧,所以它可能会使客户端上的解码器发生意外错误或崩溃?

而当像这样跳过帧时,使客户端渲染帧不正常吗?

有人打电话给我,在我的情况下跳过帧的正确算法?

谢谢!

我对AVPacket的文档有一个简短的阅读,它说:

对于视频,它通常应包含一个压缩帧。

从理论上讲,您不能跳过压缩视频流的帧,因为大多数帧不包含有关该帧图像的完整信息,而仅包含与以前的某些帧相比的更改。因此,如果您跳过一个帧,则许多尾随解码帧可能不会包含正确的结果(直到下一个关键帧刷新整个图像(。

"我的问题是专注于代码行SkipThisFrame ***,这个算法连续跳过帧,因此可能会使客户端上的解码器发生 意外错误或崩溃?

我注意到的一件事是错误的...
您的While(true)语句也需要一个break;才能停止,否则它们将永远运行,阻塞其他函数并导致系统崩溃。想想看,你说"虽然循环是真的,但你从不说什么时候停止(例如:break离开这个 While 循环来做下一个指令(。计算机只做第一个循环While并且还重复到无穷大......

尝试像这样设置:

//At Server Software (include 2 threads A and B)
//Thread A: Read AVPacket and forward to Client
while(true)
{
AVPacket packet;
av_init_packet(&packet);
packet.size = 0;
packet.data = NULL;
int ret = AVERROR(EAGAIN);
while (AVERROR(EAGAIN) == ret) { ret = av_read_frame(pFormatCtx, &packet); }
if(packet.size > 0)
{
if(mySendQueue.count < 120) //limit 120 packet in queue
{
mySendQueue.Enqueue(packet); ////Thread B will read from this queue, to send packets to Client via TCP socket
}
//else {  } //no need for ELSE if doing nothing... //SkipThisFrame ***: No send
}
break; //stop this part and move to "Thead B"
}
//Thread B: Send To Client via TCP Socket
While(true)
{
AVPacket packet;
if( mySendQueue.Dequeue(packet) )
{ SendPacketToClient(packet); break; }
}
//At Server Software : Receive AVPacket from Server --> Decode --> Render
While(true)
{
AVPacket packet; AVFrame frame;
ReadPacketFromServer(packet);
if (av_decode_asyn(pCodecCtx, &frame, &frameFinished, &packet) == RS_OK)
{ 
if (frameFinished) { RenderFrame(frame);  break; }
}           
}
UINT32 __clrcall av_decode_asyn(AVCodecContext *pCodecCtx, AVFrame *frame, int *frameFinished, AVPacket *packet)
{
int ret = -1;
*frameFinished = 0;
if (packet) 
{
ret = avcodec_send_packet(pCodecCtx, packet);
// In particular, we don't expect AVERROR(EAGAIN), because we read all
// decoded frames with avcodec_receive_frame() until done.
if (ret < 0 && ret != AVERROR_EOF)
return RS_NOT_OK;
}
ret = avcodec_receive_frame(pCodecCtx, frame);
if (ret < 0 && ret != AVERROR(EAGAIN))
{
return RS_NOT_OK;
}
if (ret >= 0)
*frameFinished = 1;
return RS_OK;
}

希望对您有所帮助。让我知道结果/错误。

最新更新