我终于解决了这个问题OpenGL渲染器 https://android.googlesource.com/platform/frameworks/support/+/de44ffe38b6d7d2e78db7191dd679eb64b15b962/camera/integration-tests/coretestapp/src/main/java/androidx/camera/integration/core/OpenGLRenderer.java来自 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)
发布框架功能:
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
)。控制帧速率变化private void renderLatest()
函数于OpenGLRenderer
(丢帧,不调用renderTexture
).
编辑:较新的解决方案作为camerax谷歌组对话的一部分出现可以在这里找到 https://groups.google.com/a/android.com/g/camerax-developers/c/pxUHvlDta54