Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/228.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何在MediaCodec编码器和CameraX之间共享曲面_Android_Android Mediacodec_Kotlin Android Extensions_Android Camerax - Fatal编程技术网

Android 如何在MediaCodec编码器和CameraX之间共享曲面

Android 如何在MediaCodec编码器和CameraX之间共享曲面,android,android-mediacodec,kotlin-android-extensions,android-camerax,Android,Android Mediacodec,Kotlin Android Extensions,Android Camerax,我想从CameraX(预览用例)中获取图像,并使用MediaCodec将其编码为h.264视频。我怎样才能做到这一点? 我尝试的是使用Preview.Builder()中的MediaCodec.createInputSurface()返回的Surface,方法是使用Preview.setSurfaceProvider()。我从Preview.SurfaceProvider继承一个类,然后在该设置中配置编码器并覆盖onSurfaceRequested()以从createInputSurface()

我想从
CameraX
(预览用例)中获取图像,并使用
MediaCodec
将其编码为h.264视频。我怎样才能做到这一点? 我尝试的是使用
Preview.Builder()
中的
MediaCodec.createInputSurface()
返回的
Surface
,方法是使用
Preview.setSurfaceProvider()
。我从
Preview.SurfaceProvider
继承一个类,然后在该设置中配置编码器并覆盖
onSurfaceRequested()
以从
createInputSurface()返回
Surface
。这会起作用吗?我真的可以共享这样的曲面,并期望CameraX写入该曲面并填充编码器的输入吗

有没有一种更有效的方法来编码实时CameraX提要


注意:我正在使用KOTLIN,我最终通过CameraX OpenGL测试解决了这个问题。这是CameraX的beta 7版本

像往常一样设置camerax,但使用2个预览:

val preview: Preview = Preview.Builder().apply {
    setTargetResolution(targetSize)
    setTargetRotation(rotation)
}.build()

val encoderPreview: Preview = Preview.Builder().apply {
    setTargetResolution(targetSize)
    setTargetRotation(rotation)
}.build()

cameraProvider.unbindAll()

camera = cameraProvider.bindToLifecycle(
        lifecycleOwner,
        cameraSelector,
        preview,
        encoderPreview
)

preview.setSurfaceProvider(viewFinder.createSurfaceProvider())
然后初始化编码器:

val format = MediaFormat.createVideoFormat(
        "video/avc", resolution.width, resolution.height
)

format.setInteger(
        MediaFormat.KEY_COLOR_FORMAT,
        MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface
)

format.setInteger(MediaFormat.KEY_BIT_RATE, 500 * 1024)
format.setInteger(MediaFormat.KEY_FRAME_RATE, 25)
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 3)

encoder = MediaCodec.createEncoderByType("video/avc")

encoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
并将两者连接起来:

private val glRenderer = OpenGLRenderer()

surface = encoder.createInputSurface()

glRenderer.attachInputPreview(encoderPreview)

glRenderer.setFrameUpdateListener(executor, Consumer<Long> {
    // when frame is written to output surface
    publishFrame()
})

encoder.start()

glRenderer.attachOutputSurface(surface, resolution, 0)
请注意,编码器中的
FRAME\u RATE
参数不受重视,您将根据发布到输出表面的帧数(称为
publishFrame
的次数)获得帧速率。要控制帧速率更改,
OpenGLRenderer
中的
private void renderLatest()
函数(删除帧,不要调用
renderTexture


编辑:更新的解决方案,它是camerax google group对话的一部分

谢谢你。连接两者时,在何处使用encoderPreview?我看到您在
glRenderer.attachInputPreview(preview)
中使用了
preview
。如果你有一个样本,我一直在努力让它与我的编码器一起工作,屏幕只是黑色的。嗨!我犯了一个错误。在glRenderer.attachInputPreview中,应为encoderPreview。已经修复了上面的问题。我不再使用上面的解决方案了。这是可行的,但我在预览转换方面遇到了问题,因为流(编码)与UI上的不同,UI上的流可以动态更改。现在只需一次预览即可实现所有内容,并且在OpenGLRender中具有额外的上下文。在cpp中也有必要重新编写一些代码。太复杂了,无法在这里发布:)啊,谢谢。我希望有一种更简单的方法告诉相机预览面使用mediacodec输入面。我将详细介绍如何使用OpenGLRenderer。我正在做的部分编码是在cpp中进行的,但我希望将其与摄像机分开,我想这有待确定。无论如何谢谢你@nymeria,检查我在上次编辑中添加的链接,查看新的解决方案。
private fun publishFrame() {
    val index: Int = try {
        encoder.dequeueOutputBuffer(info, 10 * 1000)
    } catch (e: Exception) {
        -1
    }

    if (!isRunning.get()) {
        return
    }

    if (index >= 0) {
        val outputBuffer = encoder.getOutputBuffer(index)
        if (outputBuffer == null) {
            return
        }

        if (info.size > 0) {
            outputBuffer.position(info.offset)
            outputBuffer.limit(info.offset + info.size)
            info.presentationTimeUs = System.nanoTime() / 1000

            // do something with frame
        }

        encoder.releaseOutputBuffer(index, false)

        if (info.flags.hasFlag(MediaCodec.BUFFER_FLAG_END_OF_STREAM)) {
            return
        }
    }
}