Android Camera2 管道:如何使用 MediaCodec 从输入 Surface 对 h.264 单元进行编



我有一个使用 Camera2 API 的 Android 应用程序。最终目标是让 h264 单元写入流。到目前为止,我有

  1. 已成功创建捕获会话,并可通过以下方式写入预览、本地录制和流式处理图面:
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()
}
    设置一个媒体编解码器,
  1. 以对来自上述streamer.suface参数的数据进行编码,其中表面派生自从媒体编解码器中调用mediaCodec.createInputSurface
  2. 如下所示
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)
}
}
  1. 当上面的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中的值是否正确编码?在将输入Surface传递给要编码的MediaCodec之前,是否需要使用MediaExtractor来清理来自输入的数据?管道足够干净,但我不太确定什么是必要的。本文档一直是最大的指南,它提到了对原始数据进行操作的MediaCodec,这让我认为我需要MediaExtractor,但这并没有将Surface作为输入,使管道中项目的正确顺序更加混乱。

你不需要MediaExtractor - 用于处理一个完整的容器文件并拆分出它的各种流和其他组件。

媒体编解码器直接从相机接收原始图像缓冲区,并将输出编码缓冲区。 如果要保存标准视频文件,则需要将这些编码的字节缓冲区馈送到MediaMuxer实例中。 如果您只是将编码的缓冲区发送到其他地方进行解码(例如用于视频聊天应用程序(,则只需将 ByteBuffer 馈送到目的地的媒体编解码器即可。

我无法说明您对MediaCodec的所有参数是否正确,但我没有看到任何明显的错误。

最新更新