音频采集:AudioRecord
视频采集:Camera预览回调YUV数据
编码:MediaCodec
合成封包MP4:MediaMuxer
首先确定几条线程处理任务
1.audioThread 音频采集和编码
2.videoThread 视频编码
3.muxerThread 合成
示例代码:Kotlin
所有详细代码已上传github,后面会给出地址,示例Activity是Camera1PreviewActivity
代码中少了一些验证,比如设备支持预览的格式,这在之前的文章提到过,要注意自己的设备是否支持该设置。
在最后,会写出容易出现的问题,代码运行不正确的时候,可以对照下,是否
犯了这些错误
1.初始化和打开相机
预览界面用的SurfaceView,通过前面的学习应该知道相机预览,就不多说
private fun initView() {
surfaceView = findViewById(com.example.mediastudyproject.R.id.surface_view)
surfaceView.holder.addCallback(object : SurfaceHolder.Callback2 {
override fun surfaceRedrawNeeded(holder: SurfaceHolder?) {
}
override fun surfaceChanged(
holder: SurfaceHolder?,
format: Int,
width: Int,
height: Int
) {
isSurfaceAvailiable = true
this@Camera1PreviewActivity.holder = holder
}
override fun surfaceDestroyed(holder: SurfaceHolder?) {
isSurfaceAvailiable = false
mCamera?.stopPreview()
//这里要把之前设置的预览回调取消,不然关闭app,camera释放了,但是还在回调,会报异常
mCamera?.setPreviewCallback(null)
mCamera?.release()
mCamera = null
}
override fun surfaceCreated(holder: SurfaceHolder?) {
isSurfaceAvailiable = true
this@Camera1PreviewActivity.holder = holder
thread {
//打开相机
openCamera(Camera.CameraInfo.CAMERA_FACING_BACK)
}
}
})
}
相机参数设置
/**
* 初始化并打开相机,我这里默认打开的后置摄像头
*/
private fun openCamera(cameraId: Int) {
mCamera = Camera.open(cameraId)
mCamera?.run {
setPreviewDisplay(holder)
setDisplayOrientation(WindowDegree.getDegree(this@Camera1PreviewActivity))
var cameraInfo = Camera.CameraInfo()
Camera.getCameraInfo(cameraId, cameraInfo)
Log.i("camera1", "相机方向 ${cameraInfo.orientation}")
val parameters = parameters
parameters?.run {
//自动曝光结果给我爆一团黑,不能忍 自己设置
exposureCompensation = maxExposureCompensation
//自动白平衡
autoWhiteBalanceLock = isAutoWhiteBalanceLockSupported
//设置预览大小
appropriatePreviewSizes = getAppropriatePreviewSizes(parameters)
setPreviewSize(appropriatePreviewSizes?.width!!, appropriatePreviewSizes?.height!!)
//设置对焦模式
val supportedFocusModes = supportedFocusModes
if (supportedFocusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {
//设置自动对焦,启动自动对焦是通过Camera的autoFocus方法实现
//如果要连续对焦,这个方法要多次调用,这里就没有调用autoFocus
//想要连续对焦的可以自己实现,通过Handler连续发送消息就行
focusMode = Camera.Parameters.FOCUS_MODE_AUTO
}
previewFormat = ImageFormat.NV21
}
//相机资源回收的时候,注意setPreviewCallBack(null),将回调移除
setPreviewCallback { data, camera ->
//isRecording是一个开启录制的标志,回调帧数据存放在集合中等待编码器编码
if (isRecording) {
if (data != null) {
Log.i("camera1", "获