in app/src/main/java/com/amazonaws/services/chime/sdkdemo/utils/CpuVideoProcessor.kt [86:138]
override fun onVideoFrameReceived(frame: VideoFrame) {
frame.retain()
handler.post {
// Note: This processor assumes that the incoming call will be on a valid EGL context
textureFrameBuffer.setSize(frame.getRotatedWidth(), frame.getRotatedHeight())
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, textureFrameBuffer.frameBufferId)
val matrix = Matrix()
// Shift before flipping
matrix.preTranslate(0.5f, 0.5f)
// RGBA frames are upside down relative to texture coordinates
matrix.preScale(1f, -1f)
// Unshift following flip
matrix.preTranslate(-0.5f, -0.5f)
// Note the draw call will account for any rotation, so we need to account for that in viewport width/height
rectDrawer.drawFrame(
frame,
0,
0,
frame.getRotatedWidth(),
frame.getRotatedHeight(),
matrix
)
// Read RGBA data to native byte buffer
val rgbaData = JniUtil.nativeAllocateByteBuffer(frame.width * frame.height * 4)
GLES20.glReadPixels(
0,
0,
frame.getRotatedWidth(),
frame.getRotatedHeight(),
GLES20.GL_RGBA,
GLES20.GL_UNSIGNED_BYTE,
rgbaData
)
GlUtil.checkGlError("glReadPixels")
val rgbaBuffer =
VideoFrameRGBABuffer(
frame.getRotatedWidth(),
frame.getRotatedHeight(),
rgbaData, frame.getRotatedWidth() * 4,
Runnable { JniUtil.nativeFreeByteBuffer(rgbaData) })
convertToBlackAndWhite(rgbaBuffer)
val processedFrame = VideoFrame(frame.timestampNs, rgbaBuffer)
frame.release()
sinks.forEach { it.onVideoFrameReceived(processedFrame) }
processedFrame.release()
}
}