我用 CameraX 的 OpenGL 测试中的
OpenGLRenderer 终于解决了这个问题。这适用于 CameraX 的 beta 7 版本。
像往常一样设置 CameraX,但使用两个预览。
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> {
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
}
encoder.releaseOutputBuffer(index, false)
if (info.flags.hasFlag(MediaCodec.BUFFER_FLAG_END_OF_STREAM)) {
return
}
}
}
请注意,编码器中的
FRAME_RATE
参数不受尊重,您将根据发布到输出表面的帧数(调用
publishFrame
的次数)获得帧速率。要控制帧速率,请更改
OpenGLRenderer
中的
private void renderLatest()
函数(丢弃帧,不要调用
renderTexture
)。
编辑:关于Camerax谷歌小组的对话中提出的更新解决方案
可以在此处找到。
glRenderer.attachInputPreview(preview)
中使用了preview
。如果您有示例,我一直很难让它与我的编码器配合工作,屏幕只是黑色的。 - nymeria