录制RTSP流时如何正确设置fps_mode为cfr参数?
问题:JavaCV实现RTSP转HLS并固定恒定帧率(CFR)
已通过FFmpeg命令实现可变帧率RTSP流转恒定帧率HLS,命令如下:
ffmpeg -use_wallclock_as_timestamps 1 -rtsp_transport tcp -i <rtsp-url> -fps_mode cfr -vf "fps=8.0" -max_delay 0 -f hls -fflags nobuffer -fflags flush_packets -vcodec libx264 -hls_flags program_date_time+split_by_time+append_list -hls_list_size 0 -hls_time 5 <output-file>
现尝试用JavaCV(版本:javacv 1.5.9、javacpp 1.5.9、ffmpeg 6.0-1.5.9)实现相同功能,但在FrameGrabber和FrameRecorder中设置fps_mode=cfr均未生效,求正确配置方法。
原JavaCV代码片段:
// FrameGrabber creation FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(streamURL); frameGrabber.setOption("timeout", timeout); frameGrabber.setOption("rtsp_transport", rtspTransportProtocol); frameGrabber.setOption("loglevel", "debug"); frameGrabber.setOption("fflags", "nobuffer"); frameGrabber.setOption("use_wallclock_as_timestamps", "1"); frameGrabber.setOption("fps_mode", "cfr"); // frameGrabber.setOption("vsync", "1"); frameGrabber.setFormat("rtsp"); frameGrabber.setTimeout(3 * 1000000); frameGrabber.start(); //FrameRecorder creation FFmpegFrameRecorder hlsRecorder = new FFmpegFrameRecorder(outputFile, frameWidth, frameHeight, audioChannel); hlsRecorder.setInterleaved(true); hlsRecorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); hlsRecorder.setFrameRate(frameGrabber.getFrameRate()); hlsRecorder.setFormat("hls"); hlsRecorder.setGopSize(gopSize); hlsRecorder.setOption("hls_flags", "program_date_time+split_by_time+append_list"); hlsRecorder.setOption("hls_list_size", "0"); // This option sets the playlist to an infinite size hlsRecorder.setOption("hls_time", "5"); // This option sets the duration of each segment // hlsRecorder.setVideoOption("fps_mode", "cfr"); // hlsRecorder.setVideoOption("vsync", "1"); hlsRecorder.start();
解决方案
核心配置要点
fps_mode=cfr是视频编码器专属选项,需通过setVideoOption而非全局setOption配置在FrameRecorder上- 必须添加
fps滤镜实现帧率转换,对应FFmpeg命令的-vf "fps=8.0" - 明确设置目标帧率,而非复用原流的可变帧率
- 补充原命令中缺失的
max_delay、flush_packets等选项
修正后的完整代码
// FrameGrabber creation FFmpegFrameGrabber frameGrabber = new FFmpegFrameGrabber(streamURL); frameGrabber.setOption("timeout", timeout); frameGrabber.setOption("rtsp_transport", rtspTransportProtocol); frameGrabber.setOption("loglevel", "debug"); frameGrabber.setOption("fflags", "nobuffer"); frameGrabber.setOption("use_wallclock_as_timestamps", "1"); frameGrabber.setOption("max_delay", "0"); // 对应FFmpeg的-max_delay 0 frameGrabber.setFormat("rtsp"); frameGrabber.setTimeout(3 * 1000000); frameGrabber.start(); //FrameRecorder creation FFmpegFrameRecorder hlsRecorder = new FFmpegFrameRecorder(outputFile, frameWidth, frameHeight, audioChannel); hlsRecorder.setInterleaved(true); hlsRecorder.setVideoCodec(avcodec.AV_CODEC_ID_H264); hlsRecorder.setFrameRate(8.0); // 直接设置目标恒定帧率 hlsRecorder.setFormat("hls"); hlsRecorder.setGopSize(gopSize); // 添加帧率转换滤镜,等价于FFmpeg的-vf "fps=8.0" hlsRecorder.setVideoFilter("fps=8.0"); // 配置CFR模式相关的编码器选项 hlsRecorder.setVideoOption("fps_mode", "cfr"); hlsRecorder.setVideoOption("vsync", "1"); // HLS相关配置 hlsRecorder.setOption("hls_flags", "program_date_time+split_by_time+append_list"); hlsRecorder.setOption("hls_list_size", "0"); hlsRecorder.setOption("hls_time", "5"); hlsRecorder.setOption("fflags", "flush_packets"); // 对应FFmpeg的-fflags flush_packets hlsRecorder.start();
关键说明
setVideoFilter("fps=8.0"):强制将可变帧率流转换为固定8fps,是实现恒定帧率的核心步骤setVideoOption("fps_mode", "cfr"):告诉编码器以恒定帧率模式输出,配合vsync=1确保帧同步逻辑正确setFrameRate(8.0):明确告知编码器输出的目标帧率,避免复用原流的可变帧率参数
内容的提问来源于stack exchange,提问作者Deepak
相关产品推荐
相关产品推荐

