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() : 釋放串流