JavaCV 拉流存储到本地示例解析
作者:JinYx
这篇文章主要介绍了JavaCV 拉流存储到本地示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
拉流整体代码
import org.bytedeco.ffmpeg.global.avcodec; import org.bytedeco.javacv.*; public class LivePuller { public void pull(String rtmp, String outputVideoPath) { FFmpegFrameGrabber grabber = null; FFmpegFrameRecorder recorder = null; try { FFmpegLogCallback.set(); boolean hasStream = false; grabber = new FFmpegFrameGrabber(rtmp); grabber.setOption("nobuffer", "1"); // 采集流超时时间,停止推流后,grab() 大致会在 20 秒左右超时停止;值也不宜太小,否则可能有些音视频帧采集不到影响推流 grabber.setOption("rw_timeout", "1000000"); grabber.setVideoCodec(avcodec.AV_CODEC_ID_MPEG4); // setPixelFormat,可能会导致图片帧保存的是黑白照 // grabber.setPixelFormat(avutil.AV_PIX_FMT_YUV420P); grabber.setFormat("flv"); grabber.setAudioCodec(avcodec.AV_CODEC_ID_AAC); // 先执行代码后有直播流的情况下,grabber.start() 会抛出异常;因此循环start(),直到有流数据时成功 while (!hasStream) { try { grabber.start(); hasStream = true; } catch (Exception ignored) { } finally { try { Thread.sleep(100); } catch (Exception e) { e.printStackTrace(); } } } // 重置分辨率 int imageWidth = grabber.getImageWidth(); int imageHeight = grabber.getImageHeight(); if (imageWidth > 1920 || imageHeight > 1080) { double wScale = imageWidth * 1.0 / 1920; double hScale = imageHeight * 1.0 / 1080; double scale = Math.max(wScale, hScale); grabber.setImageWidth((int) (imageWidth / scale)); grabber.setImageHeight((int) (imageHeight / scale)); } recorder = new FFmpegFrameRecorder(outputVideoPath, grabber.getImageWidth(), grabber.getImageHeight()); recorder.setOption("nobuffer", "1"); recorder.setAudioChannels(grabber.getAudioChannels()); recorder.setFrameRate(grabber.getFrameRate()); // 保持和采集一样的帧率,避免音画不同步; recorder.setVideoQuality(0); // 视频质量(清晰度) recorder.setAudioQuality(0); // 音频质量 // --------------------------- 非必须 ------------------------------ // 当设置了下方的录制器的视频编码,需要再加上 setVideoBitrate 保证视频质量 recorder.setVideoBitrate(grabber.getVideoBitrate()); recorder.setVideoCodec(grabber.getVideoCodec()); // 指定为 mp4 录制时需要 avcodec.AV_CODEC_ID_MPEG4 // // 当上面 grabber 没有设置 setPixelFormat,recorder.setPixelFormat 最好不要使用 grabber.getPixelFormat();可能异常 // recorder.setPixelFormat(grabber.getPixelFormat()); // recorder.setFormat(grabber.getFormat()); // recorder.setAudioCodec(grabber.getAudioCodec()); // recorder.setSampleRate(grabber.getSampleRate()); recorder.start(); Frame frame; while ((frame = grabber.grab()) != null) { // 此处不能判断 frame.streamIndex 为 avutil.AVMEDIA_TYPE_VIDEO 或 avutil.AVMEDIA_TYPE_DATA;遇到过采集流时两个类型是反着的 if (frame.image != null || frame.samples != null) { // frame.image 是图像数据,frame.samples 是声音数据 recorder.record(frame); } } } catch (Exception e) { e.printStackTrace(); } finally { if (grabber != null) { try { grabber.close(); } catch (FrameGrabber.Exception e) { e.printStackTrace(); } } if (recorder != null) { try { recorder.close(); } catch (FrameRecorder.Exception e) { e.printStackTrace(); } } } } }
拉流整体代码如上,基本该有的地方都有注释;同 JavaCV 推流 也是改变分辨率等参数保证拉流速率,以及设置帧率保证音画同步;
示例解析
另外上面提到 grabber.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
不要设置,避免后续的 JavaCV 保存视频帧图片 时保存的图片是黑白的;另外上面的代码经过测试是可以将拉取的音视频流保存成 mp4 格式,通过浏览器直接播放的
注意测试 mp4 文件保存的时候,尽量每次写入一个新的文件;避免在调试过程中,出现因浏览器缓存等问题导致之前有问题的 mp4 的文件,在参数调整好后依然不能正常播放等情况
以上就是JavaCV 拉流存储到本地示例解析的详细内容,更多关于JavaCV 拉流存储到本地的资料请关注脚本之家其它相关文章!