Android Camera2 管道 : How do I encode h. 264 个单元使用来自输入 Surface 的 MediaCodec?

标签 android android-camera android-camera2 video-encoding android-mediacodec

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

  1. 已成功创建捕获 session ,并可以通过以下方式写入预览、本地录制和流式传输表面:
    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.createInputSurface 派生的从 MediaCodec 创建如下
  •     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 中的值编码正确吗?我需要使用 MediaExtractor清理来自输入 Surface 的数据在我传递它之前 MediaCodec编码?管道足够干净,但我不太确定什么是必要的或不需要的。这个document是最大的指南,它提到了 MediaCodec对原始数据进行操作,这让我觉得我需要 MediaExtractor ,但这并不需要 Surface作为输入,使得管道中项目的正确顺序变得更加困惑。

    最佳答案

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

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

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

    关于Android Camera2 管道 : How do I encode h. 264 个单元使用来自输入 Surface 的 MediaCodec?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61922147/

    相关文章:

    java - 为什么我会收到 Json Malformed Exception

    android - 如何在Android应用程序中实现兼容性

    jquery - 在 Android 应用程序中包装 HTML

    android - 适用于 Android 的 Facebook SDK - 以编程方式设置应用程序 ID

    Android捕捉慢动作视频

    java.lang.RuntimeException : takePicture failed

    android - TextureView 的 "Consumer Side"何时关闭?

    android camera2 createCaptureSession 已弃用

    camera - 在Android中使用Camera2进行实时处理时应采用哪种图像格式?

    android - 在抽屉导航中的项目列表上方添加图像