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 文件。