[视频] 使用 JavaCV 来显示和保存来自摄像头的视频

JavaCV

javacv开发包是用于支持java多媒体开发的一套开发包,可以适用于本地多媒体(音视频)调用以及音视频,图片等文件后期操作(图片修改,音视频解码剪辑等等功能)。
https://github.com/bytedeco/javacv

本文默认音视频处理使用ffmpeg,图像处理使用opencv,摄像头抓取使用opencv

Maven依赖

  <dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv-platform</artifactId>
    <version>1.5.4</version>
  </dependency>

上面的是全平台的,国内经常有下载不完整的问题,可以用下面这个

  <dependency>
    <groupId>org.bytedeco</groupId>
    <artifactId>javacv</artifactId>
    <version>1.5.4</version>
  </dependency>

Gradle依赖

  dependencies {
    implementation group: 'org.bytedeco', name: 'javacv-platform', version: '1.5.4'
  }

从javacv0.8开始,已经不需要本地安装opencv,直接通过引用opencv对应的系统平台的引用包即可。

预览本机摄像头视频图像的简单实现

    public static void main(String[] args) throws Exception {
        SpringApplication.run(VideoApplication.class, args);
        //新建opencv抓取器,一般的电脑和移动端设备中摄像头默认序号是0,不排除其他情况
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);
        grabber.start();//开始获取摄像头数据

        //新建一个预览窗口
        CanvasFrame canvas = new CanvasFrame("摄像头预览");
        canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //窗口是否关闭
        while(canvas.isDisplayable()){
            /*获取摄像头图像并在窗口中显示,这里Frame frame=grabber.grab()得到是解码后的视频图像*/
            canvas.showImage(grabber.grab());
        }
        grabber.close();//停止抓取
    }

需要如图配置

预览的同时,保存为FLV文件

    public static void main(String[] args) {
        SpringApplication.run(VideoApplication.class, args);
        recordCamera("C:\\FFOutput\\output.flv",25);
    }

    public static void recordCamera(String outputFile, double frameRate) {
        FrameGrabber grabber = FrameGrabber.createDefault(0);//本机摄像头默认0
        grabber.start();//开启抓取器

        OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();//转换器
        // 抓取一帧视频并将其转换为图像,至于用这个图像用来做什么?加水印,人脸识别等等自行添加
        IplImage grabbedImage = converter.convert(grabber.grab());
        int width = grabbedImage.width();
        int height = grabbedImage.height();

        FrameRecorder recorder = FrameRecorder.createDefault(outputFile, width, height);
        recorder.setVideoCodec(AV_CODEC_ID_H264); // avcodec.AV_CODEC_ID_H264,编码
        recorder.setFormat("flv");//封装格式,如果是推送到rtmp就必须是flv封装格式
        recorder.setFrameRate(frameRate);

        recorder.start();//开启录制器
        long startTime=0;
        long videoTS=0;

        CanvasFrame frame = new CanvasFrame("camera", CanvasFrame.getDefaultGamma() / grabber.getGamma());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setAlwaysOnTop(true);
        Frame rotatedFrame=converter.convert(grabbedImage);//不知道为什么这里不做转换就不能推到rtmp
        while (frame.isVisible() && (grabbedImage = converter.convert(grabber.grab())) != null) {

            rotatedFrame = converter.convert(grabbedImage);
            frame.showImage(rotatedFrame);
            if (startTime == 0) {
                startTime = System.currentTimeMillis();
            }
            videoTS = 1000 * (System.currentTimeMillis() - startTime);
            recorder.setTimestamp(videoTS);
            recorder.record(rotatedFrame);
            Thread.sleep(40);
        }
        frame.dispose();//关闭窗口
        recorder.close();//关闭推流录制器,close包含release和stop操作
        grabber.close();//关闭抓取器
    }
posted @ 2021-01-21 14:50  哆啦梦乐园  阅读(1140)  评论(0编辑  收藏  举报