JavaCV的攝像頭實戰之五:推流

程式設計師欣宸發表於2022-02-09

歡迎訪問我的GitHub

這裡分類和彙總了欣宸的全部原創(含配套原始碼):https://github.com/zq2599/blog_demos

本篇概覽

  • 本文是《JavaCV的攝像頭實戰》的第五篇,一起來考慮個問題:本地攝像頭的內容,如何讓網路上的其他人看見?
  • 這就涉及到了推流,如下圖,基於JavaCV的應用將攝像頭的視訊幀推送到媒體伺服器,觀看者用播放器軟體遠端連線媒體伺服器,就能觀看攝像頭的內容了:

在這裡插入圖片描述

  • 今天的主要工作就是開發上圖的JavaCV應用,然後驗證功能是否正常;

編碼

  • 《JavaCV的攝像頭實戰之一:基礎》一文建立的<font color="red">simple-grab-push</font>工程中已寫好父類<font color="blue">AbstractCameraApplication</font>,本篇繼續使用該工程,建立子類實現那些抽象方法即可
  • 編碼前先回顧父類的基礎結構,如下圖,粗體是父類定義的各個方法,紅色塊都是需要子類來實現抽象方法,所以接下來,我們們以本地視窗預覽為目標實現這三個紅色方法即可:

在這裡插入圖片描述

  • 新建檔案<font color="blue">RecordCamera.java</font>,這是AbstractCameraApplication的子類,其程式碼很簡單,接下來按上圖順序依次說明
  • 《JavaCV的攝像頭實戰之一:基礎》中已部署好了媒體伺服器,這裡定義一個成員變數儲存媒體伺服器的推流地址,請您按自己的情況調整:
private static final String RECORD_ADDRESS = "rtmp://192.168.50.43:21935/hls/camera";
  • 還要準備一個成員變數,推流的時候在幀上新增時間戳:
protected long startRecordTime = 0L;
  • 將視訊幀推送到媒體伺服器的功能來自FrameRecorder,這是個抽象類,本篇用到的是其子類FFmpegFrameRecorder,所以定義FrameRecorder型別的成員變數:
    // 幀錄製器
    protected FrameRecorder recorder;
  • 然後是初始化操作,請注意各項引數設定(1280*720解析度攝像頭的情況):
    @Override
    protected void initOutput() throws Exception {
        // 例項化FFmpegFrameRecorder,將SRS的推送地址傳入
        recorder = FrameRecorder.createDefault(RECORD_ADDRESS, getCameraImageWidth(), getCameraImageHeight());

        // 降低啟動時的延時,參考
        // https://trac.ffmpeg.org/wiki/StreamingGuide)
        recorder.setVideoOption("tune", "zerolatency");
        // 在視訊質量和編碼速度之間選擇適合自己的方案,包括這些選項:
        // ultrafast,superfast, veryfast, faster, fast, medium, slow, slower, veryslow
        // ultrafast offers us the least amount of compression (lower encoder
        // CPU) at the cost of a larger stream size
        // at the other end, veryslow provides the best compression (high
        // encoder CPU) while lowering the stream size
        // (see: https://trac.ffmpeg.org/wiki/Encode/H.264)
        // ultrafast對CPU消耗最低
        recorder.setVideoOption("preset", "ultrafast");
        // Constant Rate Factor (see: https://trac.ffmpeg.org/wiki/Encode/H.264)
        recorder.setVideoOption("crf", "28");
        // 2000 kb/s, reasonable "sane" area for 720
        recorder.setVideoBitrate(2000000);

        // 設定編碼格式
        recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);

        // 設定封裝格式
        recorder.setFormat("flv");

        // FPS (frames per second)
        // 一秒內的幀數
        recorder.setFrameRate(getFrameRate());
        // Key frame interval, in our case every 2 seconds -> 30 (fps) * 2 = 60
        // 關鍵幀間隔
        recorder.setGopSize((int)getFrameRate()*2);

        // 幀錄製器開始初始化
        recorder.start();
    }
  • 接下來是output方法,關鍵是recorder.record,另外要注意時間戳的計算和設定:
    @Override
    protected void output(Frame frame) throws Exception {
        if (0L==startRecordTime) {
            startRecordTime = System.currentTimeMillis();
        }

        // 時間戳
        recorder.setTimestamp(1000 * (System.currentTimeMillis()-startRecordTime));

        // 存檔
        recorder.record(frame);
    }
  • 最後是處理視訊的迴圈結束後,程式退出前要做的事情,即關閉幀抓取器:
    @Override
    protected void releaseOutputResource() throws Exception {
        recorder.close();
    }
  • 另外還要注意兩幀之間的延時,由於推流涉及到網路,因此不能像本地預覽那樣根據幀率嚴格計算,實際間隔要更小一些:
    @Override
    protected int getInterval() {
        // 相比本地預覽,推流時兩幀間隔時間更短
        return super.getInterval()/4;
    }
  • 至此,推流功能已開發完成,再寫上main方法,注意引數<font color="blue">600</font>表示抓取和錄製的操作執行600秒:
    public static void main(String[] args) {
        new RecordCamera().action(600);
    }
  • 執行main方法,等到控制檯輸出下圖紅框的內容時,表示已經開始推流:

在這裡插入圖片描述

  • 用本機或區域網內另一臺電腦,用VLC軟體開啟剛才推流的地址<font color="blue">rtmp://192.168.50.43:21935/hls/camera</font>,稍等幾秒鐘後開始正常播放:

在這裡插入圖片描述

  • 還可用VLC的工具檢視編碼資訊:

在這裡插入圖片描述

  • 至此,我們們已完成了推流功能,驗證遠端播放也正常,得益於JavaCV的強大,整個過程是如此的輕鬆愉快,接下來請繼續關注欣宸原創,《JavaCV的攝像頭實戰》系列還會呈現更多豐富的應用;
  • 此刻聰明的您一定發現了問題:只推視訊嗎?連聲音都沒有,就這?沒錯,接下來的實戰,我們們該挑戰音訊處理了

原始碼下載

名稱連結備註
專案主頁https://github.com/zq2599/blo...該專案在GitHub上的主頁
git倉庫地址(https)https://github.com/zq2599/blo...該專案原始碼的倉庫地址,https協議
git倉庫地址(ssh)git@github.com:zq2599/blog_demos.git該專案原始碼的倉庫地址,ssh協議
  • 這個git專案中有多個資料夾,本篇的原始碼在<font color="blue">javacv-tutorials</font>資料夾下,如下圖紅框所示:

在這裡插入圖片描述

  • <font color="blue">javacv-tutorials</font>裡面有多個子工程,《JavaCV的攝像頭實戰》系列的程式碼在<font color="red">simple-grab-push</font>工程下:

在這裡插入圖片描述

你不孤單,欣宸原創一路相伴

https://github.com/zq2599/blog_demos

相關文章