Android Camera2 管道:如何使用来自输入表面的 MediaCodec 对 h.264 单元进行编码?
Android Camera2 pipeline: How do I encode h.264 units using MediaCodec from an input Surface?
我有一个使用 Camera2 API 的 Android 应用程序。最终目标是让 h264 单元写入流。到目前为止我有
- 已成功创建捕获会话并可以通过以下方式写入预览、本地录制和流媒体表面:
session.device.createCaptureRequest(CameraDevice.TEMPLATE_RECORD).run {
addTarget(previewSurface)
addTarget(recorder.surface)
addTarget(streamer.surface)
set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(args.fps, args.fps))
build()
}
- 设置一个 MediaCodec 来编码来自上面
streamer.suface
参数的数据,其中表面是从如下创建的 MediaCodec 对 mediaCodec.createInputSurface
的调用派生的
internal fun streamingCodec(args: CameraFragmentArgs): MediaCodec {
val mediaFormat = MediaFormat.createVideoFormat("video/avc", args.width, args.height).apply {
setInteger(MediaFormat.KEY_BIT_RATE, 2000 * 1024)
setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2)
setInteger(MediaFormat.KEY_FRAME_RATE, args.fps)
setInteger(
MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
)
}
val encoderName = MediaCodecList(MediaCodecList.REGULAR_CODECS).findEncoderForFormat(mediaFormat)
return MediaCodec.createByCodecName(encoderName).apply {
configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
}
}
- 当上面的
surface
在ByteBuffer
中有信息时使用异步回调
private class StreamingCallBack) : MediaCodec.Callback() {
override fun onInputBufferAvailable(codec: MediaCodec, index: Int) = Unit
override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: BufferInfo) {
val byteBuffer = codec.getOutputBuffer(index)
// Is the data in the buffer properly encoded as h.264 here? Did I need to use MediaExtractor?
}
override fun onOutputFormatChanged(codec: MediaCodec, format: MediaFormat) = Unit
override fun onError(codec: MediaCodec, e: MediaCodec.CodecException) {
Log.i("TEST", "onError in codec")
}
}
我的困惑是,在这一点上,ByteBuffer
中的值是否编码正确?在将 MediaCodec
传递给编码之前,我是否需要使用 MediaExtractor
清理来自输入 Surface
的数据?管道足够干净,但我不太确定什么是必要的。这个 document 是最大的指南,它提到 MediaCodec
对原始数据进行操作,这让我觉得我需要 MediaExtractor
,但这不需要 Surface
作为输入,使管道中项目的正确顺序更加混乱。
您不需要 MediaExtractor - 它用于处理完整的容器文件并拆分出各种流和其他组件。
MediaCodec 直接从相机接收原始图像缓冲区,并将输出编码缓冲区。如果要保存标准视频文件,则需要将那些编码的 ByteBuffers 提供给 MediaMuxer 实例。如果您只是将编码缓冲区发送到其他地方进行解码(例如视频聊天应用程序),您可以将 ByteBuffers 提供给目的地的 MediaCodec。
我不能说你给 MediaCodec 的所有参数是否都正确,但我没有看到任何明显的错误。
我有一个使用 Camera2 API 的 Android 应用程序。最终目标是让 h264 单元写入流。到目前为止我有
- 已成功创建捕获会话并可以通过以下方式写入预览、本地录制和流媒体表面:
session.device.createCaptureRequest(CameraDevice.TEMPLATE_RECORD).run {
addTarget(previewSurface)
addTarget(recorder.surface)
addTarget(streamer.surface)
set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, Range(args.fps, args.fps))
build()
}
- 设置一个 MediaCodec 来编码来自上面
streamer.suface
参数的数据,其中表面是从如下创建的 MediaCodec 对mediaCodec.createInputSurface
的调用派生的
internal fun streamingCodec(args: CameraFragmentArgs): MediaCodec {
val mediaFormat = MediaFormat.createVideoFormat("video/avc", args.width, args.height).apply {
setInteger(MediaFormat.KEY_BIT_RATE, 2000 * 1024)
setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 2)
setInteger(MediaFormat.KEY_FRAME_RATE, args.fps)
setInteger(
MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
)
}
val encoderName = MediaCodecList(MediaCodecList.REGULAR_CODECS).findEncoderForFormat(mediaFormat)
return MediaCodec.createByCodecName(encoderName).apply {
configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
}
}
- 当上面的
surface
在ByteBuffer
中有信息时使用异步回调
private class StreamingCallBack) : MediaCodec.Callback() {
override fun onInputBufferAvailable(codec: MediaCodec, index: Int) = Unit
override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: BufferInfo) {
val byteBuffer = codec.getOutputBuffer(index)
// Is the data in the buffer properly encoded as h.264 here? Did I need to use MediaExtractor?
}
override fun onOutputFormatChanged(codec: MediaCodec, format: MediaFormat) = Unit
override fun onError(codec: MediaCodec, e: MediaCodec.CodecException) {
Log.i("TEST", "onError in codec")
}
}
我的困惑是,在这一点上,ByteBuffer
中的值是否编码正确?在将 MediaCodec
传递给编码之前,我是否需要使用 MediaExtractor
清理来自输入 Surface
的数据?管道足够干净,但我不太确定什么是必要的。这个 document 是最大的指南,它提到 MediaCodec
对原始数据进行操作,这让我觉得我需要 MediaExtractor
,但这不需要 Surface
作为输入,使管道中项目的正确顺序更加混乱。
您不需要 MediaExtractor - 它用于处理完整的容器文件并拆分出各种流和其他组件。
MediaCodec 直接从相机接收原始图像缓冲区,并将输出编码缓冲区。如果要保存标准视频文件,则需要将那些编码的 ByteBuffers 提供给 MediaMuxer 实例。如果您只是将编码缓冲区发送到其他地方进行解码(例如视频聊天应用程序),您可以将 ByteBuffers 提供给目的地的 MediaCodec。
我不能说你给 MediaCodec 的所有参数是否都正确,但我没有看到任何明显的错误。