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
}
}
}