最近咱们项目有一个需求就是解决客户端播放RTSP视频流花屏的问题,通常来讲丢包就会引发花屏,致使客户端花屏的因素又有不少,好比说:服务器
其中服务器到客户端的丢包问题咱们已经解决了,那么相机到服务器的丢包问题怎么解决呢?这个问题解决不了的,能够解决的问题就是即便相机到服务器丢包后,也让客户端知道,而后不解码丢包的那一帧数据直到下一个关键帧的到来,这样客户端播放视频就不会
花屏了,可是这样作就会让视频播放卡顿一下(以50帧一个关键帧来算的话会卡顿2秒),可是卡顿总比花屏强吧,由于花屏后咱们的AI服务器就采集不到人脸了,可是FFMpeg并无对外提供接口标志该AVPacket不完整,内部也不会将AVPacket丢弃,这样服务端调用av_read_frame读取的AVPacket时并不知道该包是否完整,一小段调用例子以下:函数
while (1) { AVPacket pkt; // 不知道pkt是否完整 ret = av_read_frame(f->ctx, &pkt); if (ret == AVERROR(EAGAIN)) { av_usleep(10000); continue; } if (ret < 0) { av_thread_message_queue_set_err_recv(f->in_thread_queue, ret); break; } }
FFMpeg不提供接口,那么就只有修改FFMpeg源码,浏览FFMpeg源码一天后,对外的接口只须要在AVPacket结构体里面增长一个判断包完整性的标志变量,修改源码后的接口调用以下:3d
while (1) { AVPacket pkt; ret = av_read_frame(f->ctx, &pkt); if (pkt.nLostPackets) { // Do something. } else { // Do something } }
下面将介绍修改FFMpeg源码的细节。code
1、avformat.h里面增长int av_read_frame_aozhen(AVFormatContext s, AVPacket pkt)函数:
而且在对应实现文件utils.c里面对其实现:
orm
2、avcodec.h里面的AVPacket结构体增长成员变量int nIsLostPackets:
而且在avpacket.c里面的av_init_packets函数里面对其初始化:
视频
3、utils.c里面read_frame_internal函数增长临时变量int nIsLostPackets = 0,read_frame_internal函数调用ff_read_packet的后一句增长nIsLostPackets = cur_pkt.nIsLostPackets:
而且在函数末尾将nIsLostPackets赋值给pkt->nIsLostPackets:
blog
4、在rtpdec.c的rtp_parse_queued_packet函数里面增长丢包判断的代码:
接口