Android MediaCodec 与 MediaProjection
Android MediaCodec with MediaProjection
我想用 MediaCodec 和 MediaProjection 录制屏幕。 MediaCodec 启动后,我希望看到显示图像。但是我在 onOutputBufferAvailable 中得到了错误的显示图像。我也在使用 Galaxy S20 进行测试。我的代码有什么问题?
private fun startRecording(){
val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val defaultDisplay: Display = displayManager.getDisplay(Display.DEFAULT_DISPLAY)
val metrics = resources.displayMetrics
prepareMediaCodec(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi)
}
private fun prepareMediaCodec(screenWidth: Int, screenHeight: Int, screenDensity : Int) {
val mediaFormat =
MediaFormat.createVideoFormat("video/avc", screenWidth, screenHeight).apply {
setInteger(MediaFormat.KEY_BIT_RATE, 6000000)
setInteger(MediaFormat.KEY_FRAME_RATE, 30)
setInteger(MediaFormat.KEY_CAPTURE_RATE, 30)
setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / 30)
setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1)
setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
}
mediaCodec = MediaCodec.createEncoderByType("video/avc")
mediaCodec.setCallback(object : MediaCodec.Callback() {
override fun onOutputBufferAvailable( p0: MediaCodec,outputBufferId: Int, info: MediaCodec.BufferInfo) {
val encodedData: ByteBuffer = mediaCodec.getOutputBuffer(outputBufferId)
encodedData.position(info.offset)
encodedData.limit(info.offset + info.size)
val data = ByteArray(encodedData.remaining())
encodedData.get(data)
val baos =ByteArrayOutputStream()
val yuvImage = YuvImage(data, ImageFormat.NV21, screenWidth, screenHeight, null)
yuvImage.compressToJpeg(Rect(0, 0, screenWidth, screenHeight), 80, baos)
val response = baos.toByteArray()
val bitmap: Bitmap? = BitmapFactory.decodeByteArray(response, 0, response.size)
Log.e(TAG, bitmap.toString()) // check bitmap
mediaCodec.releaseOutputBuffer(outputBufferId, false)
}
...
})
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
mediaCodec.start()
mediaProjection.createVirtualDisplay(
"Record", screenWidth, screenHeight, screenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mediaCodec.createInputSurface(), null)
}
您从编码器 onOutputBufferAvailable
收到的输出缓冲区是 h264 格式,而不是 NV21 缓冲区,因此您不能不将其原样保存为位图。
您需要做的是使用 MediaMuxer
将其保存为可播放的视频格式,例如 mp4 文件。
我想用 MediaCodec 和 MediaProjection 录制屏幕。 MediaCodec 启动后,我希望看到显示图像。但是我在 onOutputBufferAvailable 中得到了错误的显示图像。我也在使用 Galaxy S20 进行测试。我的代码有什么问题?
private fun startRecording(){
val displayManager = getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
val defaultDisplay: Display = displayManager.getDisplay(Display.DEFAULT_DISPLAY)
val metrics = resources.displayMetrics
prepareMediaCodec(metrics.widthPixels, metrics.heightPixels, metrics.densityDpi)
}
private fun prepareMediaCodec(screenWidth: Int, screenHeight: Int, screenDensity : Int) {
val mediaFormat =
MediaFormat.createVideoFormat("video/avc", screenWidth, screenHeight).apply {
setInteger(MediaFormat.KEY_BIT_RATE, 6000000)
setInteger(MediaFormat.KEY_FRAME_RATE, 30)
setInteger(MediaFormat.KEY_CAPTURE_RATE, 30)
setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / 30)
setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1)
setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1)
setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
}
mediaCodec = MediaCodec.createEncoderByType("video/avc")
mediaCodec.setCallback(object : MediaCodec.Callback() {
override fun onOutputBufferAvailable( p0: MediaCodec,outputBufferId: Int, info: MediaCodec.BufferInfo) {
val encodedData: ByteBuffer = mediaCodec.getOutputBuffer(outputBufferId)
encodedData.position(info.offset)
encodedData.limit(info.offset + info.size)
val data = ByteArray(encodedData.remaining())
encodedData.get(data)
val baos =ByteArrayOutputStream()
val yuvImage = YuvImage(data, ImageFormat.NV21, screenWidth, screenHeight, null)
yuvImage.compressToJpeg(Rect(0, 0, screenWidth, screenHeight), 80, baos)
val response = baos.toByteArray()
val bitmap: Bitmap? = BitmapFactory.decodeByteArray(response, 0, response.size)
Log.e(TAG, bitmap.toString()) // check bitmap
mediaCodec.releaseOutputBuffer(outputBufferId, false)
}
...
})
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
mediaCodec.start()
mediaProjection.createVirtualDisplay(
"Record", screenWidth, screenHeight, screenDensity,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mediaCodec.createInputSurface(), null)
}
您从编码器 onOutputBufferAvailable
收到的输出缓冲区是 h264 格式,而不是 NV21 缓冲区,因此您不能不将其原样保存为位图。
您需要做的是使用 MediaMuxer
将其保存为可播放的视频格式,例如 mp4 文件。