我想从 CameraX
(预览用例)获取图像并使用 MediaCodec
将它们编码为 h.264 视频。我怎样才能做到这一点?
我正在尝试的是,通过使用 在
。我从 Preview.Builder()
中使用从 MediaCodec.createInputSurface()
返回的 Surface
预览.setSurfaceProvider()Preview.SurfaceProvider
继承了一个类,然后在该设置中配置我的编码器并覆盖 onSurfaceRequested()
以从 createInputSurface 返回
。预计这会起作用吗?我真的可以像这样共享一个 Surface 并期望 CameraX 写入这个 Surface 并为我的编码器填充 Input 吗? Surface
()
是否有更有效的方法来编码实时 CameraX 提要?
注意:我正在使用 KOTLIN
最佳答案
我终于用 OpenGLRenderer 解决了这个问题来自 CameraX OpenGL 测试。这是针对 Beta 7 版的 CameraX。
像往常一样设置 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)
发布框架函数:
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
}
}
}
请注意,编码器中的 FRAME_RATE
参数不受重视,您将根据发布到输出表面的帧数(调用 publishFrame
的次数)获得帧速率.在 OpenGLRenderer
中控制帧率变化 private void renderLatest()
函数(丢帧,不要调用 renderTexture
)。
编辑:作为 camerax 谷歌群组对话的一部分出现的较新解决方案 can be found here
关于android - 如何在 MediaCodec 编码器和 CameraX 之间共享 Surface,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61934659/