Camera2、MediaCodec录制mp4
躬行之
共 4273字,需浏览 9分钟
·
2021-01-18 16:25
PS:做想做的事,每天至少做一点,不求做多少,慢慢改变。
Camera2的使用
MediaCodec输入方式
MediaCodec编码Camera2数据
录制流程
录制效果
Camera2的使用
MediaCodec的输入方式
Surface:使用 Surface 作为编码器 MediaCodec 的输入,即将 MediaCodec 创建的 Surface 作为其输入,这个 Surface 由 MediaCodec 的 createInputSurface 方法创建,当相机将会将有效数据渲染到该 Surface 中,MediaCodec 就可以直接输出编码后的数据了。
InputBuffer:使用输入缓冲区作为编码器 MediaCodec 的输入,这里需要填充的数据就是原始帧数据,对应 Camera2 来说可直接通过 ImageReader 来进行帧数据的获取,获取到的 Image 包含了宽度、高度、格式、时间戳及 YUV 数据分量等信息,可控程度更高。
MediaCodec编码Camera2数据
1// 返回已成功编码的输出缓冲区的索引
2var outputBufferId: Int = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0)
3if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
4 // 添加视频轨道
5 mTrackIndex = mMediaMuxer.addTrack(mMediaCodec.outputFormat)
6 mMediaMuxer.start()
7 mStartMuxer = true
8} else {
9 while (outputBufferId >= 0) {
10 if (!mStartMuxer) {
11 Log.i(TAG, "MediaMuxer not start")
12 continue
13 }
14 // 获取有效数据
15 val outputBuffer = mMediaCodec.getOutputBuffer(outputBufferId) ?: continue
16 outputBuffer.position(bufferInfo.offset)
17 outputBuffer.limit(bufferInfo.offset + bufferInfo.size)
18 if (pts == 0L) {
19 pts = bufferInfo.presentationTimeUs
20 }
21 bufferInfo.presentationTimeUs = bufferInfo.presentationTimeUs - pts
22 // 将数据写入复用器以生成文件
23 mMediaMuxer.writeSampleData(mTrackIndex, outputBuffer, bufferInfo)
24 Log.d(
25 TAG,
26 "pts = ${bufferInfo.presentationTimeUs / 1000000.0f} s ,${pts / 1000} ms"
27 )
28 mMediaCodec.releaseOutputBuffer(outputBufferId, false)
29 outputBufferId = mMediaCodec.dequeueOutputBuffer(bufferInfo, 0)
30 }
31}
录制流程
1// 配置状态
2mMediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
3// 创建Surface作为MediaCodec的输入,createInputSurface只能在configure与start之间调用创建Surface
4mSurface = mMediaCodec.createInputSurface()
5// start ...
1// 创建CaptureSession
2@RequiresApi(Build.VERSION_CODES.P)
3private suspend fun createCaptureSession(): CameraCaptureSession = suspendCoroutine { cont ->
4 val outputs = mutableListOf()
5 // 预览Surface
6 outputs.add(OutputConfiguration(mSurface))
7 // 添加MediaCodec用作输入的Surface
8 outputs.add(OutputConfiguration(EncodeManager.getSurface()))
9 val sessionConfiguration = SessionConfiguration(
10 SessionConfiguration.SESSION_REGULAR,
11 outputs, mExecutor, ...)
12 mCameraDevice.createCaptureSession(sessionConfiguration)
13}
1// 添加预览的Surface和生成Image的Surface
2mCaptureRequestBuild = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
3val sur = EncodeManager.getSurface()
4mCaptureRequestBuild.addTarget(sur)
5mCaptureRequestBuild.addTarget(mSurface)
6
7// 设置各种参数
8mCaptureRequestBuild.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE, 1) // 视频稳定功能是否激活
9// 发送CaptureRequest
10mCameraCaptureSession.setRepeatingRequest(
11 mCaptureRequestBuild.build(),
12 null,
13 mCameraHandler
14)
15// 开始编码
16EncodeManager.startEncode()
录制效果
评论