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


歡迎訪問我的GitHub

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

本篇概覽

  • 本文是《JavaCV的攝像頭實戰》的第五篇,一起來考慮個問題:本地攝像頭的內容,如何讓網絡上的其他人看見?

  • 這就涉及到了推流,如下圖,基於JavaCV的應用將攝像頭的視頻幀推送到媒體服務器,觀看者用播放器軟件遠程連接媒體服務器,就能觀看攝像頭的內容了:

在這里插入圖片描述

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

編碼

  • 《JavaCV的攝像頭實戰之一:基礎》一文創建的simple-grab-push工程中已寫好父類AbstractCameraApplication,本篇繼續使用該工程,創建子類實現那些抽象方法即可

  • 編碼前先回顧父類的基礎結構,如下圖,粗體是父類定義的各個方法,紅色塊都是需要子類來實現抽象方法,所以接下來,咱們以本地窗口預覽為目標實現這三個紅色方法即可:

在這里插入圖片描述

  • 新建文件RecordCamera.java,這是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方法,注意參數600表示抓取和錄制的操作執行600秒:
    public static void main(String[] args) {
        new RecordCamera().action(600);
    }
  • 運行main方法,等到控制台輸出下圖紅框的內容時,表示已經開始推流:

在這里插入圖片描述

  • 用本機或局域網內另一台電腦,用VLC軟件打開剛才推流的地址rtmp://192.168.50.43:21935/hls/camera,稍等幾秒鍾后開始正常播放:

在這里插入圖片描述

  • 還可用VLC的工具查看編碼信息:

在這里插入圖片描述

  • 至此,咱們已完成了推流功能,驗證遠程播放也正常,得益於JavaCV的強大,整個過程是如此的輕松愉快,接下來請繼續關注欣宸原創,《JavaCV的攝像頭實戰》系列還會呈現更多豐富的應用;

  • 此刻聰明的您一定發現了問題:只推視頻嗎?連聲音都沒有,就這?沒錯,接下來的實戰,咱們該挑戰音頻處理了

源碼下載

名稱 鏈接 備注
項目主頁 https://github.com/zq2599/blog_demos 該項目在GitHub上的主頁
git倉庫地址(https) https://github.com/zq2599/blog_demos.git 該項目源碼的倉庫地址,https協議
git倉庫地址(ssh) git@github.com:zq2599/blog_demos.git 該項目源碼的倉庫地址,ssh協議
  • 這個git項目中有多個文件夾,本篇的源碼在javacv-tutorials文件夾下,如下圖紅框所示:

在這里插入圖片描述

  • javacv-tutorials里面有多個子工程,《JavaCV的攝像頭實戰》系列的代碼在simple-grab-push工程下:

在這里插入圖片描述

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

https://github.com/zq2599/blog_demos


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM