`

javacv demo

阅读更多
==============================================
启动nginx rtmp服务
端口1935
配置live1
地址rtmp://localhost:1935/live1/room1

使用vlc可以访问地址rtmp://localhost:1935/live1/room1

注意延迟
==============================================
pom.xml
==============================================
<!--javacv-->
        <dependency>
            <groupId>org.bytedeco</groupId>
            <artifactId>javacv-platform</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>org.bytedeco.javacpp-presets</groupId>
            <artifactId>opencv</artifactId>
            <version>3.1.0-1.3</version>
        </dependency>
==============================================
TestRecordSoundAndPicture.java
==============================================
public class TestRecordSoundAndPicture {

    public static void main(String[] args) {
        try {
            recordWebcamAndMicrophone(0,4,"rtmp://localhost:1935/live1/room1",200,600,50);
        } catch (FrameGrabber.Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 推送/录制本机的音/视频(Webcam/Microphone)到流媒体服务器(Stream media server)
     *
     * @param WEBCAM_DEVICE_INDEX
     *            - 视频设备,本机默认是0
     * @param AUDIO_DEVICE_INDEX
     *            - 音频设备,本机默认是4
     * @param outputFile
     *            - 输出文件/地址(可以是本地文件,也可以是流媒体服务器地址)
     * @param captureWidth
     *            - 摄像头宽
     * @param captureHeight
     *            - 摄像头高
     * @param FRAME_RATE
     *            - 视频帧率:最低 25(即每秒25张图片,低于25就会出现闪屏)
     * @throws FrameGrabber.Exception
     */
    public static void recordWebcamAndMicrophone(int WEBCAM_DEVICE_INDEX, final int AUDIO_DEVICE_INDEX, String outputFile,
                                                 int captureWidth, int captureHeight, final int FRAME_RATE) throws FrameGrabber.Exception {
        long startTime = 0;
        long videoTS = 0;
        /**
         * FrameGrabber 类包含:OpenCVFrameGrabber
         * (opencv_videoio),C1394FrameGrabber, FlyCaptureFrameGrabber,
         * OpenKinectFrameGrabber,PS3EyeFrameGrabber,VideoInputFrameGrabber, 和
         * FFmpegFrameGrabber.
         */
        OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(WEBCAM_DEVICE_INDEX);
        grabber.setImageWidth(captureWidth);
        grabber.setImageHeight(captureHeight);
        System.out.println("开始抓取摄像头...");
        int isTrue = 0;// 摄像头开启状态
        try {
            grabber.start();
            isTrue += 1;
        } catch (FrameGrabber.Exception e2) {
            if (grabber != null) {
                try {
                    grabber.restart();
                    isTrue += 1;
                } catch (FrameGrabber.Exception e) {
                    isTrue -= 1;
                    try {
                        grabber.stop();
                    } catch (FrameGrabber.Exception e1) {
                        isTrue -= 1;
                    }
                }
            }
        }
        if (isTrue < 0) {
            System.err.println("摄像头首次开启失败,尝试重启也失败!");
            return;
        } else if (isTrue < 1) {
            System.err.println("摄像头开启失败!");
            return;
        } else if (isTrue == 1) {
            System.err.println("摄像头开启成功!");
        } else if (isTrue == 1) {
            System.err.println("摄像头首次开启失败,重新启动成功!");
        }

        /**
         * FFmpegFrameRecorder(String filename, int imageWidth, int imageHeight,
         * int audioChannels) fileName可以是本地文件(会自动创建),也可以是RTMP路径(发布到流媒体服务器)
         * imageWidth = width (为捕获器设置宽) imageHeight = height (为捕获器设置高)
         * audioChannels = 2(立体声);1(单声道);0(无音频)
         */
        final FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, captureWidth, captureHeight, 2);
        recorder.setInterleaved(true);

        /**
         * 该参数用于降低延迟 参考FFMPEG官方文档:https://trac.ffmpeg.org/wiki/StreamingGuide
         * 官方原文参考:ffmpeg -f dshow -i video="Virtual-Camera" -vcodec libx264
         * -tune zerolatency -b 900k -f mpegts udp://10.1.0.102:1234
         */

        recorder.setVideoOption("tune", "zerolatency");
        /**
         * 权衡quality(视频质量)和encode speed(编码速度) values(值):
         * ultrafast(终极快),superfast(超级快), veryfast(非常快), faster(很快), fast(快),
         * medium(中等), slow(慢), slower(很慢), veryslow(非常慢)
         * ultrafast(终极快)提供最少的压缩(低编码器CPU)和最大的视频流大小;而veryslow(非常慢)提供最佳的压缩(高编码器CPU)的同时降低视频流的大小
         * 参考:https://trac.ffmpeg.org/wiki/Encode/H.264 官方原文参考:-preset ultrafast
         * as the name implies provides for the fastest possible encoding. If
         * some tradeoff between quality and encode speed, go for the speed.
         * This might be needed if you are going to be transcoding multiple
         * streams on one machine.
         */
        recorder.setVideoOption("preset", "ultrafast");
        /**
         * 参考转流命令: ffmpeg
         * -i'udp://localhost:5000?fifo_size=1000000&overrun_nonfatal=1' -crf 30
         * -preset ultrafast -acodec aac -strict experimental -ar 44100 -ac
         * 2-b:a 96k -vcodec libx264 -r 25 -b:v 500k -f flv 'rtmp://<wowza
         * serverIP>/live/cam0' -crf 30
         * -设置内容速率因子,这是一个x264的动态比特率参数,它能够在复杂场景下(使用不同比特率,即可变比特率)保持视频质量;
         * 可以设置更低的质量(quality)和比特率(bit rate),参考Encode/H.264 -preset ultrafast
         * -参考上面preset参数,与视频压缩率(视频大小)和速度有关,需要根据情况平衡两大点:压缩率(视频大小),编/解码速度 -acodec
         * aac -设置音频编/解码器 (内部AAC编码) -strict experimental
         * -允许使用一些实验的编解码器(比如上面的内部AAC属于实验编解码器) -ar 44100 设置音频采样率(audio sample
         * rate) -ac 2 指定双通道音频(即立体声) -b:a 96k 设置音频比特率(bit rate) -vcodec libx264
         * 设置视频编解码器(codec) -r 25 -设置帧率(frame rate) -b:v 500k -设置视频比特率(bit
         * rate),比特率越高视频越清晰,视频体积也会变大,需要根据实际选择合理范围 -f flv
         * -提供输出流封装格式(rtmp协议只支持flv封装格式) 'rtmp://<FMS server
         * IP>/live/cam0'-流媒体服务器地址
         */
        recorder.setVideoOption("crf", "25");
        // 2000 kb/s, 720P视频的合理比特率范围
        recorder.setVideoBitrate(2000000);
        // h264编/解码器
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
        // 封装格式flv
        recorder.setFormat("flv");
        // 视频帧率(保证视频质量的情况下最低25,低于25会出现闪屏)
        recorder.setFrameRate(FRAME_RATE);
        // 关键帧间隔,一般与帧率相同或者是视频帧率的两倍
        recorder.setGopSize(FRAME_RATE * 2);
        // 不可变(固定)音频比特率
        recorder.setAudioOption("crf", "0");
        // 最高质量
        recorder.setAudioQuality(0);
        // 音频比特率
        recorder.setAudioBitrate(192000);
        // 音频采样率
        recorder.setSampleRate(44100);
        // 双通道(立体声)
        recorder.setAudioChannels(2);
        // 音频编/解码器
        recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
        System.out.println("开始录制...");

        try {
            recorder.start();
        } catch (FrameRecorder.Exception e2) {
            if (recorder != null) {
                System.out.println("关闭失败,尝试重启");
                try {
                    recorder.stop();
                    recorder.start();
                } catch (FrameRecorder.Exception e) {
                    try {
                        System.out.println("开启失败,关闭录制");
                        recorder.stop();
                        return;
                    } catch (FrameRecorder.Exception e1) {
                        return;
                    }
                }
            }

        }
        // 音频捕获
        new Thread(new Runnable() {
            public void run() {
                /**
                 * 设置音频编码器 最好是系统支持的格式,否则getLine() 会发生错误
                 * 采样率:44.1k;采样率位数:16位;立体声(stereo);是否签名;true:
                 * big-endian字节顺序,false:little-endian字节顺序(详见:ByteOrder类)
                 */
                AudioFormat audioFormat = new AudioFormat(44100.0F, 16, 2, true, false);

                // 通过AudioSystem获取本地音频混合器信息
                Mixer.Info[] minfoSet = AudioSystem.getMixerInfo();
                // 通过AudioSystem获取本地音频混合器
                Mixer mixer = AudioSystem.getMixer(minfoSet[AUDIO_DEVICE_INDEX]);
                // 通过设置好的音频编解码器获取数据线信息
                DataLine.Info dataLineInfo = new DataLine.Info(TargetDataLine.class, audioFormat);
                try {
                    // 打开并开始捕获音频
                    // 通过line可以获得更多控制权
                    // 获取设备:TargetDataLine line
                    // =(TargetDataLine)mixer.getLine(dataLineInfo);
                    final TargetDataLine line = (TargetDataLine) AudioSystem.getLine(dataLineInfo);
                    line.open(audioFormat);
                    line.start();
                    // 获得当前音频采样率
                    final int sampleRate = (int) audioFormat.getSampleRate();
                    // 获取当前音频通道数量
                    final int numChannels = audioFormat.getChannels();
                    // 初始化音频缓冲区(size是音频采样率*通道数)
                    int audioBufferSize = sampleRate * numChannels;
                    final byte[] audioBytes = new byte[audioBufferSize];

                    ScheduledThreadPoolExecutor exec = new ScheduledThreadPoolExecutor(1);
                    exec.scheduleAtFixedRate(new Runnable() {
                        public void run() {
                            try {
                                // 非阻塞方式读取
                                int nBytesRead = line.read(audioBytes, 0, line.available());
                                // 因为我们设置的是16位音频格式,所以需要将byte[]转成short[]
                                int nSamplesRead = nBytesRead / 2;
                                short[] samples = new short[nSamplesRead];
                                /**
                                 * ByteBuffer.wrap(audioBytes)-将byte[]数组包装到缓冲区
                                 * ByteBuffer.order(ByteOrder)-按little-endian修改字节顺序,解码器定义的
                                 * ByteBuffer.asShortBuffer()-创建一个新的short[]缓冲区
                                 * ShortBuffer.get(samples)-将缓冲区里short数据传输到short[]
                                 */
                                ByteBuffer.wrap(audioBytes).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);
                                // 将short[]包装到ShortBuffer
                                ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamplesRead);
                                // 按通道录制shortBuffer
                                recorder.recordSamples(sampleRate, numChannels, sBuff);
                            } catch (FrameRecorder.Exception e) {
                                e.printStackTrace();
                            }
                        }
                    }, 0, (long) 1000 / FRAME_RATE, TimeUnit.MILLISECONDS);
                } catch (LineUnavailableException e1) {
                    e1.printStackTrace();
                }
            }
        }).start();

        // javaCV提供了优化非常好的硬件加速组件来帮助显示我们抓取的摄像头视频
        CanvasFrame cFrame = new CanvasFrame("Capture Preview", CanvasFrame.getDefaultGamma() / grabber.getGamma());
        Frame capturedFrame = null;
        // 执行抓取(capture)过程
        while ((capturedFrame = grabber.grab()) != null) {
            if (cFrame.isVisible()) {
                //本机预览要发送的帧
                cFrame.showImage(capturedFrame);
            }
            //定义我们的开始时间,当开始时需要先初始化时间戳
            if (startTime == 0)
                startTime = System.currentTimeMillis();

            // 创建一个 timestamp用来写入帧中
            videoTS = 1000 * (System.currentTimeMillis() - startTime);
            //检查偏移量
            if (videoTS > recorder.getTimestamp()) {
                System.out.println("Lip-flap correction: " + videoTS + " : " + recorder.getTimestamp() + " -> "
                        + (videoTS - recorder.getTimestamp()));
                //告诉录制器写入这个timestamp
                recorder.setTimestamp(videoTS);
            }
            // 发送帧
            try {
                recorder.record(capturedFrame);
            } catch (FrameRecorder.Exception e) {
                System.out.println("录制帧发生异常,什么都不做");
            }
        }

        cFrame.dispose();
        try {
            if (recorder != null) {
                recorder.stop();
            }
        } catch (FrameRecorder.Exception e) {
            System.out.println("关闭录制器失败");
            try {
                if (recorder != null) {
                    grabber.stop();
                }
            } catch (FrameGrabber.Exception e1) {
                System.out.println("关闭摄像头失败");
                return;
            }
        }
        try {
            if (recorder != null) {
                grabber.stop();
            }
        } catch (FrameGrabber.Exception e) {
            System.out.println("关闭摄像头失败");
        }
    }
}
分享到:
评论

相关推荐

    【免费】JavaCV Demo Android

    这个“JavaCV Demo Android”是一个专门针对Android平台的应用示例,展示了如何在Android设备上使用JavaCV进行人脸识别。 OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉库,它包含了大量的...

    Javacv Demo - Face Detection

    Javacv编写的人脸检测demo,实测可运行,所需jar包可配置maven: &lt;groupId&gt;org.bytedeco &lt;artifactId&gt;javacv-platform &lt;version&gt;1.4.4 &lt;/dependency&gt;

    javacv的demo

    在这个“javacv的demo”中,我们可能找到一个展示JavaCV功能的示例应用。这个示例可能包括了如何使用JavaCV进行视频捕获、处理、推流等操作。在实际应用中,这些功能可以用于创建监控系统、视频分析软件,甚至复杂的...

    javacv-platform-1.5.1-source_javacv-platform_javacv1.5download_图

    8. **Demo.java** - 这通常是演示各种功能的综合代码,可能包含了JavaCV库中的多个基本操作。 9. **ImageSegmentation.java** - 图像分割是将图像分成具有不同特征的区域,这个文件可能展示了如何使用JavaCV实现...

    javaCV_demo.zip

    在这个`javaCV_demo.zip`压缩包中,我们看到的是一些示例代码和依赖,用于演示如何利用JavaCV进行摄像头录制、麦克风录音、音视频转码以及通过RTSP(Real Time Streaming Protocol)和RTMP(Real-Time Messaging ...

    基于javacv的人脸检测Demo

    在这个“基于javacv的人脸检测Demo”中,我们将深入探讨如何使用JavaCV进行人脸检测。 首先,人脸检测是计算机视觉领域的一个经典任务,其目的是在图像或视频流中识别和定位人脸。OpenCV库包含了多种人脸检测算法,...

    Android高级应用源码-android 使用javacv进行录像[模仿vine].rar

    源码参考,欢迎下载

    使用JavaCV提供的支持, 使用OpenGL实时处理+显示摄像头采集的图像, 并使用FFMPEG实时录制音视频_Java

    在本文中,我们将深入探讨如何使用JavaCV库在Android平台上实现OpenGL实时图像处理,同时结合FFmpeg进行音视频录制。JavaCV是一个强大的工具包,它为Java和Android开发者提供了多种计算机视觉库的接口,包括OpenCV、...

    基于javaCv实现的PCA人脸识别Demo

    在这个"基于javaCv实现的PCA人脸识别Demo"项目中,开发者使用JavaCv来构建一个简单的人脸识别应用。 PCA(主成分分析,Principal Component Analysis)是机器学习和统计学中的一个常用方法,用于数据降维。在人脸...

    Android直播实现(一)Android端推流、播放

    使用javacv来实现,最终也是用过ffmpeg来进行编码和推流,javacv实现到可以直接接收摄像头的帧数据 需要自己实现的代码只是打开摄像头,写一个SurfaceView进行预览,然后实现PreviewCallback将摄像头每一帧的数据...

    javacv视频播放源码.zip

    javacv视频播放源码: /** * 视频播放器Demo */ public class Demo extends MouseAdapter implements ActionListener,dropFileListener, ChangeListener, videoStateChangeListener { public Demo(){ //初始化...

    javacv调用摄像头拍照

    javacv 的开发jar,及简单demo,0.8版本免安装,支持windows-32位,及64位。其实和jdk安装版本有关,64位系统装32位jdk,或者32位系统可直接用opencv-2.4.9-0.8-windows-x86.jar 的dll;如64位系统装了64位jdk可直接...

    javacv-platform-1.3.3-src

    JavaCV 1.3.3 binary archive javacv-platform-1.3.3-bin.zip (212 MB) JavaCV 1.3.3 source archive javacv-platform-1.3.3-src.zip (456 KB) The binary archive contains builds for Android, Linux, Mac OS X, ...

    java1.4.1截取视频图片

    `javacv1.4.1从视频截取图片Demo多平台通用` 这个文件名可能暗示着提供了一个可以在不同平台上运行的示例代码。通常,JavaCV 通过自动检测和加载对应平台的动态库(如 `.dll`、`.so` 或 `.dylib`),确保跨平台兼容...

    javacv-examples:在Java虚拟机上使用JavaCV OpenCV库的示例

    JavaCV-示例该项目包含使用和来自项目的其他库包装器的。 -在罗伯特Laganière的书“OpenCV计算机视觉应用编程食谱”介绍的例子JavaCV版本。 Cookbook中的原始示例是C ++,在此将它们转换为使用JavaCV API。 使用库...

    基于javaCv实现的PCA人脸识别Demo.zip

    1.版本:matlab2014/2019a/2021a,内含运行结果,不会运行可私信 2.领域:智能优化算法、神经网络预测、信号处理、元胞自动机、图像处理、路径规划、无人机等多种领域的Matlab仿真,更多内容可点击博主头像 ...

    启动电脑摄像头demo

    在这个"启动电脑摄像头demo"项目中,开发者很可能使用了JavaCV来实现摄像头的开启和数据捕获。 JavaCV的使用通常涉及以下几个步骤: 1. **导入依赖**:在项目中添加JavaCV的相关库,这可以通过Maven或Gradle等构建...

    RTSP_Demo.zip

    【RTSP_Demo.zip】是一个包含使用JavaCV在Android Studio中实现RTSP流截图的示例项目。这个项目主要是为了帮助开发者了解如何在Android平台上处理实时传输协议(RTSP)视频流,并从中提取图像。JavaCV是一个开源的...

    Android-ffmpeg-CameraRecord:使用JavaCV提供的支持,使用OpenGL实时处理+显示摄像头采集的图像,并使用FFMPEG实时录制音视频

    安卓下实现的实时相机滤镜显示+拍照+处理结果视频音频录制演示(需要javacv,已配置好) 截屏 开发中,功能不全 目前仅是demo,预期参考,本repo的代码请随意使用,我无所谓 :face_savoring_food: ,当然对你有帮助...

    Java控制摄像头

    在项目中,`Demo.java`很可能是展示如何使用JavaCV来控制摄像头的示例代码。这个DEMO通常会包含初始化摄像头、捕获视频流、处理帧数据以及显示图像等内容。下面是一个简单的JavaCV控制摄像头的步骤: 1. **引入依赖...

Global site tag (gtag.js) - Google Analytics