android recorder通过rtp发送h264视频数据给vlc播放
android player通过rtp协议接收h264视频数据播放
Android recorder通过rtp发送aac数据给vlc播放
Android player实现播放来自rtp连接的aac数据的player
目录
截图
采集camera数据
数据采集部分使用的是Camera2,CameraHolder是对camera2的简单封装。
Camera2有个显著的优势,他可以同时添加多个surface用于接收camer数据。
下面是通过CameraHolder启动camera的流程:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......
cameraHolder = CameraHolder(this)
}
override fun onStart() {
super.onStart()
cameraHolder.startPreview().invalidate()
}
override fun onStop() {
super.onStop()
cameraHolder.stopPreview().invalidate()
}
override fun onDestroy() {
super.onDestroy()
cameraHolder.release().invalidate()
recorder.stopVideoEncoder()
}
在启动camera和预览的时候可以不用考虑camera的当前状态,这是CameraHolder的优势。有的朋友会问启动预览肯定要依赖surface,这里启动预览时怎么保证surface已经设置?
在封装Camera2的时候就想到了这种依赖问题,这种依赖导致我们每次接口调用都要判断依赖对象是否创建,代码写起来繁琐也难看。看下CameraHolder是如何解决的这个问题:
fun invalidate() = runInCameraThread {
if (cameraPermissionInProcess) {
Log.d(TAG, "invalidate cameraPermissionInProcess $cameraPermissionInProcess")
return@runInCameraThread
}
if (cameraCaptureSession != null && (!requestPreview || requestRestartPreview || !requestOpen || requestRestartOpen)) {
cameraCaptureSession?.close()
cameraCaptureSession = null
requestRestartPreview = false
Log.d(TAG, "invalidate cameraCaptureSession?.close()")
}
if (cameraDevice != null && (!requestOpen || requestRestartOpen)) {
cameraDevice?.close()
cameraDevice = null
requestRestartOpen = false
Log.d(TAG, "invalidate cameraDevice?.close()")
}
if (cameraDevice == null && requestOpen) {
Log.d(TAG, "invalidate openCamera()")
openCameraInternal()
}
if (cameraDevice != null && cameraCaptureSession == null && requestPreview) {
Log.d(TAG, "invalidate startPreview()")
startPreviewInternal()
}
if (requestRelease) {
Log.d(TAG, "invalidate release()")
handler = null
handlerThread.quitSafely()
}
}
我只贴出了CameraHodler的一个invalidate方法,这个方法应该算是CameraHodler最重要的部分。invalidate方法定义了camera启动、预览、停止预览和关闭camera的流程模