相機預覽 RE

      在〈相機預覽 RE〉中尚無留言

RootEncoder 使用 Android 系統預設的 SurfaceView 進行預覽,SurfaceView 採用 OpenGL 硬体加速渲染畫面,顯示速度非常快速。

SurfaceHolder.Callback

SurfaceView 啟動需要一段時間,啟動完後會調用 SurfaceHolder.Callback,所以在 MainActivity 繼承 SurfaceHolder.Callback 介面,然後實作相關方法。

class MainActivity : AppCompatActivity(), SurfaceHolder.Callback{
    fun init() {
        ui.surfaceView.holder.addCallback(this)
    }
    override fun surfaceCreated(holder: SurfaceHolder) {
    }
    override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
    }
    override fun surfaceDestroyed(holder: SurfaceHolder) {
    }
}

surfaceCreated 是 SurfaceView 啟動完後第一個會執行的方法,所以開始預覽相機的時機就是在此方法中。

ConnectChecker

ConnectChecker 用來監控 GenericsStream 的狀態,比如開始連線、連線失敗、連線成功、斷線等,所以繼承此介面,並實作如下的方法。

class MainActivity : AppCompatActivity(), ConnectChecker, SurfaceHolder.Callback{
    override fun onAuthError() {}
    override fun onAuthSuccess() {}
    override fun onConnectionFailed(reason: String) {}
    override fun onConnectionStarted(url: String) {}
    override fun onConnectionSuccess() {}
    override fun onDisconnect() {}
}

GenericStream

GenericStream 最上層的類別,此類別可以初始化相機,設定視頻來源,音頻來源,並且由此進行錄影,儲存,拍照等功能。

底下產生 genericStream 物件並指定 ConnectChecker,產生物件時預設使用 Camera2Source 為視頻來源,MicrophoneSource 為音頻來源。

請注意,vBitrate (影像位元率)要改成 4500K,若依官網的 1200K,傳送到 SRS 伺服器的 rtmp 畫質會非常不好。

另外音頻的 sampleRate 一定要改成 44100 或 48000,因為某些手機的音頻編碼器只支援這二種 sampleRate,若依官網說明的 32000,則傳送到 SRS 伺服器的 rtmp 影片會卡頓。

class MainActivity : AppCompatActivity(), ConnectChecker, SurfaceHolder.Callback{
    lateinit var surfaceView:SurfaceView
    var genericStream:GenericStream
    private val width = 1920
    private val height = 1080

    //4500k 影像可清析,官網是設定 1200k
    private val vBitrate = 4500 * 1000
    private var rotation = 0

    //sampleRate 44100 影像才會順,官網預設的 32000 影像會卡頓
    //可能有的手機不支援聲音 32000 編碼
    private val sampleRate = 44100
    private val isStereo = true
    private val aBitrate = 128 * 1000
    fun init() {
        surfaceView=SurfaceView(this)
        ui.container.addView(surfaceView)
        surfaceView.holder.addCallback(this)
        genericStream = GenericStream(this, this).apply {
            getGlInterface().autoHandleOrientation = true
            getStreamClient().setBitrateExponentialFactor(0.5f)
            getStreamClient().setLogs(false)
            getStreamClient().setReTries(10)
        }
        try {
            genericStream.prepareVideo(width, height, vBitrate, rotation = rotation) &&
                    genericStream.prepareAudio(sampleRate, isStereo, aBitrate)
        }
        catch (e: IllegalArgumentException) {
            Toast.makeText(this, "Audio or Video configuration failed", Toast.LENGTH_SHORT).show()
            finish()
        }
    }
    override fun onAuthError() {}
    override fun onAuthSuccess() {}
    override fun onConnectionFailed(reason: String) {}
    override fun onConnectionStarted(url: String) {}
    override fun onConnectionSuccess() {}
    override fun onDisconnect() {}
    override fun onBackPressed(){
        super.onBackPressed()
        if (genericStream.isOnPreview)genericStream.stopPreview()
        genericStream.release()
        finish()
    }
}

執在上面的程式碼即可看到相機預覽畫面

CameraXSource

GenericStream 支援 Camera1Source、Camera2Source、CameraXSource 三種視頻來源,預設使用  Camera2Source,可以使用如下方法變更來源。

genericStream.changeVideoSource(CameraXSource(this))

但是 CameraXSource 目前還有問題,比如無法切換到前相機,且 Encoder 也不支援 CameraXSource,所以不建議更換此來源。

prepareVideo

genericStream.prepareVideo 設定畫面的寬高,bitrate,旋轉角度。bitRate 官網預設是1200k,因為畫質會非常差,所以請改用 4500k。

prepareAudio

genericStream.prepareAudio 設定音頻取樣率,雙聲道,bitrate

切換相機

切換前後相機需先取得 VideoSource,再將 videoSource 轉成相對的 CameraSource,再用 switchCamera 切換,底下代碼可以切到前相機。

        when(val source = genericStream.videoSource){
            is Camera1Source -> source.switchCamera()
            is Camera2Source -> source.switchCamera()
            is CameraXSource -> source.switchCamera()//有 bug,無法切換
        }

startPreview

開始預覽的時機在 surfaceCreated 中,只要執行如下方法即可預覽

 genericStream.startPreview(ui.surfaceView)

stopPreview

退出程式時執行 genericStream.stopPreview() 停止預覽,最後還要執行 genericStream.release(),一般網站都說明把退出預覽時機寫在 onDestroy() 方法中,但這個方法有時是無法被觸發,所以請寫在 onBackPressed() 方法中。

    override fun onBackPressed(){
        super.onBackPressed()
        if (genericStream.isOnPreview)genericStream.stopPreview()
        genericStream.release()
        finish()
    }

GenericStream常用方法

GenericStream 常用的方法列示如下

prepareVideo(....) : 指定視頻格式 
prepareAudio(...) : 指定音頻格式
startPreview(surfaceView) : 開始預覽,預覽顯示在 SurfaceView 物件上
startStream("rtmp://ip/live/video1") : 開始串流
startRecord("path") : 開始錄影
stopRecord() : 停止錄影
stopStream() : 停止串流
stopPreview() : 停止預覽
release() : 釋放串流

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *