项目码云(Gitee)地址:https://gitee.com/banmajio/RTSPtoRTMP
项目github地址:https://github.com/banmajio/RTSPtoRTMP
个人博客:banmajio’s blog
javacv使用ffmpeg将rtsp转rtmp直播流播放的问题解决与优化系列文章:
FFmpeg转封装rtsp到rtmp(无需转码,低资源消耗)
JavaCV中FFmpegFrameGrabber调用start()方法时出现阻塞的解决办法
JavaCV异常汇总 JavaCV异常汇总
问题分析
根据网上查阅的资料应该是:正常情况下,每一帧或者每一包过来的数据,dts和pts是累增的,也就是说,当前的帧或者pkt的dts和pts要比上一帧或者pkt的dts和pts要大的,当获取到的当前pkt的dts小于上一pkt的pts时,回报av_write_frame() error -22的错误。
解决方法
在推pkt之前加一个dts和pts的判断,如果是异常的pkt就丢掉,如果是正常的pkt则继续推。
AVPacket pkt = null;
//用来记录dts和pts
long dts = 0;
long pts = 0;
for (int no_frame_index = 0; no_frame_index < 5 || err_index < 5;) {
if (interrupt) {
break;
}
pkt = grabber.grabPacket();
if (pkt == null || pkt.size() <= 0 || pkt.data() == null) {
// 空包记录次数跳过
no_frame_index++;
err_index++;
continue;
}
// 获取到的pkt的dts,pts异常,将此包丢弃掉。
if (pkt.dts() == avutil.AV_NOPTS_VALUE && pkt.pts() == avutil.AV_NOPTS_VALUE || pkt.pts() < dts) {
logger.debug("异常pkt 当前pts: " + pkt.pts() + " dts: " + pkt.dts() + " 上一包的pts: " + pts + " dts: "
+ dts);
err_index++;
av_packet_unref(pkt);
continue;
}
// 更新上一pkt的dts,pts
dts = pkt.dts();
pts = pkt.pts();
// 推数据包
err_index += (recorder.recordPacket(pkt) ? 0 : 1);
// 将缓存空间的引用计数-1,并将Packet中的其他字段设为初始值。如果引用计数为0,自动的释放缓存空间。
av_packet_unref(pkt);
}