我正在使用FFMPEG解码H264(或H265)RTSP流。
我的系统有2个软件:服务器和客户端
Server: Read frames from RTSP stream --> Forward frames to Client
Client: Receive frames from Server --> Decode --> Render
我已经实现了并且工作正常,但是有一种情况使我的系统无法正常工作。即从服务器-客户端的Internet速度较慢时,帧无法实时传输到客户端。
目前,我通过在达到队列数限制时跳过一些帧(不发送给客户端)来解决此问题。以下是我的摘要代码
//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 ***
的行中,此算法连续跳过帧,因此它可能会使Client上的解码器意外发生错误或崩溃?
然后像这样跳过帧时,使客户端渲染帧不正常吗?
有人打电话给我,说明在我的情况下跳过帧的正确算法?
非常感谢您!
答案 0 :(得分:2)
我对AVPacket
的文档进行了简短的阅读,内容为:
对于视频,通常应包含一个压缩帧。
理论上,您不能跳过压缩视频流的帧,因为大多数帧不包含有关该帧图像的完整信息,而仅包含与某些先前帧相比的更改。因此,如果您跳过一个帧,则很多尾随解码帧可能不会包含正确的结果(直到下一个关键帧刷新整个图像)。
答案 1 :(得分:1)
“”我的问题是代码
SkipThisFrame ***
的这一行重点 连续跳过帧,因此可能会使客户端上的解码器出现 意外的错误或崩溃?”
我发现一件事是错误的...
您的While(true)
语句也需要break;
才能停止,否则它们将永远运行,从而阻塞了其他功能并导致系统崩溃。想一想,您说“虽然循环确实是XYZ指令,但确实如此” ,但您从不说何时停止( eg: break
做下一个指示)。计算机卡住了,只能执行第一个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;
}
希望有帮助。让我知道结果/错误。