Android MediaCodec с MediaProjection

#android-mediacodec

#android-mediacodec

Вопрос:

я хотел бы записать экран с помощью 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)
}
 

Ответ №1:

Выходной буфер, который вы получили от onOutputBufferAvailable кодировщика, находится в формате h264 и не является буфером NV21, поэтому вы не могли не сохранить его в bitmap как есть. Что вам нужно сделать, так это MediaMuxer сохранить его в виде воспроизводимого видеоформата, такого как файлы mp4.