zoukankan      html  css  js  c++  java
  • JavaCV 采集摄像头和麦克风数据推流直播

    越来越觉得放弃JavaCV FFmpeg native API,直接使用JavaCV二次封装的API开发是很明智的选择,使用JavaCV二次封装的API开发避免了各种内存操作不当引起的crash。

    上一次介绍了 JavaCV 采集摄像头及桌面视频数据,这次介绍一下如何采集摄像头和麦克风数据推送到流媒体服务器。

    其他关于JavaCV的文章,可以通过下面的链接查看:
    JavaCV-开发系列文章汇总篇(https://www.cnblogs.com/itqn/p/14696221.html)

    引入依赖

    跟上一次一样,这里使用的还是最新的JavaCV库(1.5.5).

    <properties>
      <javacpp.version>1.5.5</javacpp.version>
    </properties>
    <dependencies>
      <dependency>
        <groupId>org.bytedeco</groupId>
        <artifactId>javacv</artifactId>
        <version>${javacpp.version}</version>
      </dependency>
      <dependency>
        <groupId>org.bytedeco</groupId>
        <artifactId>javacv-platform</artifactId>
        <version>${javacpp.version}</version>
      </dependency>
    </dependencies>
    

    视频采集录制

    JavaCV 采集摄像头及桌面视频数据 介绍了两种采集摄像头数据的方法,这里采用第一种,即使用 OpencvFrameGrabber 采集摄像头数据。

    public class VideoRecorder implements Runnable {
    
      private static final int VIDEO_DEVICE_INDEX = 0;
      private FFmpegFrameRecorder recorder;
      private int width, height;
      public VideoRecorder(FFmpegFrameRecorder recorder, int width, int height) {
        this.recorder = recorder;
        this.width = width;
        this.height = height;
      }
    
      @Override
      public void run() {
        try {
          OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(VIDEO_DEVICE_INDEX);
          grabber.setImageWidth(width);
          grabber.setImageHeight(height);
          grabber.start();
    
          long startTS = 0, videoTS = 0;
          Frame frame = null;
          while (!Thread.interrupted() && (frame = grabber.grab()) != null) {
            if (startTS == 0) {
              startTS = System.currentTimeMillis();
            }
            videoTS = 1000 * (System.currentTimeMillis() - startTS);
            if (videoTS > recorder.getTimestamp()) {
              recorder.setTimestamp(videoTS);
            }
            recorder.record(frame);
          }
    
          grabber.close();
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
    

    音频采集录制

    音频采集直接使用JDK的API即可,直接读麦克风的数据塞给录制器,采样率为44100,16bit,小端模式。

    public class AudioRecoder implements Runnable {
    
      private FFmpegFrameRecorder recorder;
      private int channels;
      private int sampleRate;
      public AudioRecoder(FFmpegFrameRecorder recorder, int sampleRate, int channels) {
        this.recorder = recorder;
        this.sampleRate = sampleRate;
        this.channels = channels;
      }
    
      @Override
      public void run() {
        try {
          AudioFormat format = new AudioFormat(Float.valueOf(sampleRate), 16, channels, true, false);
          TargetDataLine line = (TargetDataLine) AudioSystem.getLine(new DataLine.Info(TargetDataLine.class, format));
          line.open(format);
          line.start();
    
          int sampleRate = (int) format.getSampleRate();
          int numChannels = format.getChannels();
          byte[] buffer = new byte[sampleRate * numChannels];
    
          while (!Thread.interrupted()) {
            int nBytesRead = 0;
            while (nBytesRead == 0) {
              nBytesRead = line.read(buffer, 0, line.available());
            }
            int nSamplesRead = nBytesRead / 2;
            short[] samples = new short[nSamplesRead];
            ByteBuffer.wrap(buffer).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(samples);
            ShortBuffer sBuff = ShortBuffer.wrap(samples, 0, nSamplesRead);
            recorder.recordSamples(sampleRate, numChannels, sBuff);
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    
    }
    

    录制推流

    这里的录制推流涉及音频和视频,音频和视频分开线程采集并录制,这样可以降低延迟,在录制推流方面还可以通过设置录制参数降低延迟:

    recorder.setVideoOption("tune", "zerolatency");
    recorder.setVideoOption("preset", "ultrafast");
    

    启动录制推流器,视频采集录制线程和音频采集录制线程,开始推流:

    recorder.start();
    Thread vt = new Thread(new VideoRecorder(recorder, width, height));
    Thread at = new Thread(new AudioRecoder(recorder, sampleRate, channels));
    		
    vt.start();
    at.start();
    		
    vt.join();
    at.join();
    

    效果展示

    可以使用VLC拉取程序的推流查看效果:

    拉流的音视频流信息:

    录制推流完整源码可以在公众号上获取

    =========================================================
    关注公众号 “HiIT青年” 发送 “javacv-recoder” 获取。(如果没有收到回复,可能是你之前取消过关注。)

    HiIT青年
    关注公众号,阅读更多文章。

  • 相关阅读:
    Java RunTime Environment (JRE) or Java Development Kit (JDK) must be available in order to run Eclipse. ......
    UVA 1597 Searching the Web
    UVA 1596 Bug Hunt
    UVA 230 Borrowers
    UVA 221 Urban Elevations
    UVA 814 The Letter Carrier's Rounds
    UVA 207 PGA Tour Prize Money
    UVA 1592 Database
    UVA 540 Team Queue
    UVA 12096 The SetStack Computer
  • 原文地址:https://www.cnblogs.com/itqn/p/14640484.html
Copyright © 2011-2022 走看看