Feature: add MediaProjectionController

pull/209/head
xufuji456 3 years ago
parent f24bd1f809
commit e288658223
  1. 23
      AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaMuxController.kt
  2. 100
      AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaProjectionController.kt
  3. 10
      AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaRecordController.kt

@ -21,6 +21,7 @@ open class MediaMuxController {
return false return false
} }
var happenError = false var happenError = false
// 1、create MediaMuxer
val mediaMuxer = MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) val mediaMuxer = MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4)
val mediaExtractor = MediaExtractor() val mediaExtractor = MediaExtractor()
try { try {
@ -28,7 +29,11 @@ open class MediaMuxController {
var audioIndex = 0 var audioIndex = 0
var audioFormat: MediaFormat? = null var audioFormat: MediaFormat? = null
var videoFormat: MediaFormat? = null var videoFormat: MediaFormat? = null
var finished = false
val bufferInfo = MediaCodec.BufferInfo()
val inputBuffer = ByteBuffer.allocate(2 * 1024 * 1024)
mediaExtractor.setDataSource(inputPath) mediaExtractor.setDataSource(inputPath)
// select track with mimetype
for (i in 0 until mediaExtractor.trackCount) { for (i in 0 until mediaExtractor.trackCount) {
val mediaFormat = mediaExtractor.getTrackFormat(i) val mediaFormat = mediaExtractor.getTrackFormat(i)
val mimeType = mediaFormat.getString(MediaFormat.KEY_MIME) val mimeType = mediaFormat.getString(MediaFormat.KEY_MIME)
@ -42,25 +47,24 @@ open class MediaMuxController {
mediaExtractor.selectTrack(i) mediaExtractor.selectTrack(i)
} }
} }
// 2、add MediaFormat into track
if (videoFormat != null) { if (videoFormat != null) {
mediaMuxer.addTrack(videoFormat) mediaMuxer.addTrack(videoFormat)
} }
if (audioFormat != null) { if (audioFormat != null) {
mediaMuxer.addTrack(audioFormat) mediaMuxer.addTrack(audioFormat)
} }
// 3、start the muxer
var finished = false
val bufferInfo = MediaCodec.BufferInfo()
val inputBuffer = ByteBuffer.allocate(2 * 1024 * 1024)
mediaMuxer.start() mediaMuxer.start()
while (!finished) { while (!finished) {
// demux media stream
val sampleSize = mediaExtractor.readSampleData(inputBuffer, 0) val sampleSize = mediaExtractor.readSampleData(inputBuffer, 0)
if (sampleSize > 0) { if (sampleSize > 0) {
bufferInfo.size = sampleSize bufferInfo.size = sampleSize
bufferInfo.flags = mediaExtractor.sampleFlags bufferInfo.flags = mediaExtractor.sampleFlags
bufferInfo.presentationTimeUs = mediaExtractor.sampleTime bufferInfo.presentationTimeUs = mediaExtractor.sampleTime
// 4、call MediaMuxer to mux media stream
if (mediaExtractor.sampleTrackIndex == videoIndex) { if (mediaExtractor.sampleTrackIndex == videoIndex) {
mediaMuxer.writeSampleData(videoIndex, inputBuffer, bufferInfo) mediaMuxer.writeSampleData(videoIndex, inputBuffer, bufferInfo)
} else if (mediaExtractor.sampleTrackIndex == audioIndex) { } else if (mediaExtractor.sampleTrackIndex == audioIndex) {
@ -77,12 +81,9 @@ open class MediaMuxController {
Log.e("MediaMuxController", "mux error=$e") Log.e("MediaMuxController", "mux error=$e")
happenError = true happenError = true
} finally { } finally {
try { // 5、release resource
mediaMuxer.release() mediaMuxer.release()
mediaExtractor.release() mediaExtractor.release()
} catch (e1: Exception) {
Log.e("MediaMuxController", "release error=$e1")
}
return !happenError return !happenError
} }
} }

@ -0,0 +1,100 @@
package com.frank.androidmedia.controller
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.PixelFormat
import android.hardware.display.DisplayManager
import android.media.ImageReader
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.os.Environment
import android.util.DisplayMetrics
import android.view.Surface
import android.view.WindowManager
import java.io.FileOutputStream
import java.lang.Exception
/**
* Using MediaProjectionManager to screenshot,
* and using MediaProjection recording screen.
*
* @author frank
* @date 2022/3/25
*/
open class MediaProjectionController(screenshot: Boolean) {
private var screenshot = true
private val requestCode = 1234
private var displayMetrics: DisplayMetrics? = null
private var mediaProjection: MediaProjection? = null
private var mediaProjectionManager: MediaProjectionManager? = null
init {
this.screenshot = screenshot
}
fun startScreenRecord(context: Context) {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
displayMetrics = DisplayMetrics()
windowManager.defaultDisplay.getMetrics(displayMetrics)
mediaProjectionManager = context.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
val intent = mediaProjectionManager?.createScreenCaptureIntent()
(context as Activity).startActivityForResult(intent, requestCode)
}
private fun saveBitmap(bitmap: Bitmap?, path: String) {
if (path.isEmpty() || bitmap == null)
return
var outputStream: FileOutputStream? = null
try {
outputStream = FileOutputStream(path)
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
} catch (e: Exception) {
} finally {
outputStream?.close()
}
}
private fun createVirtualDisplay(surface: Surface) {
mediaProjection?.createVirtualDisplay("hello", displayMetrics!!.widthPixels, displayMetrics!!.heightPixels,
displayMetrics!!.densityDpi, DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
surface, null, null)
}
private fun getBitmap() {
val imageReader = ImageReader.newInstance(displayMetrics!!.widthPixels,
displayMetrics!!.heightPixels, PixelFormat.RGBA_8888, 3)
createVirtualDisplay(imageReader.surface)
imageReader.setOnImageAvailableListener ({ reader: ImageReader ->
val image = reader.acquireNextImage()
val planes = image.planes
val buffer = planes[0].buffer
val pixelStride = planes[0].pixelStride
val rowStride = planes[0].rowStride
val rowPadding = rowStride - pixelStride * image.width
val bitmap = Bitmap.createBitmap(image.width + rowPadding / pixelStride, image.height, Bitmap.Config.ARGB_8888)
bitmap.copyPixelsFromBuffer(buffer)
val filePath = Environment.getExternalStorageDirectory().path + "/hello.jpg"
saveBitmap(bitmap, filePath)
image.close()
imageReader.close()
}, null)
}
fun onActivityResult(resultCode: Int, data: Intent) {
mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, data)
if (screenshot) {
getBitmap()
}
}
fun stopScreenRecord() {
mediaProjection?.stop()
}
}

@ -35,11 +35,11 @@ open class MediaRecordController {
mMediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4) mMediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mMediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC) mMediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mMediaRecorder?.setVideoEncoder(MediaRecorder.VideoEncoder.H264) mMediaRecorder?.setVideoEncoder(MediaRecorder.VideoEncoder.H264)
// mMediaRecorder?.setVideoSize(640, 480) mMediaRecorder?.setVideoSize(640, 480)
// mMediaRecorder?.setVideoEncodingBitRate(5000 * 1000) mMediaRecorder?.setVideoEncodingBitRate(5000 * 1000)
// mMediaRecorder?.setVideoFrameRate(25) mMediaRecorder?.setVideoFrameRate(25)
// mMediaRecorder?.setAudioChannels(2) mMediaRecorder?.setAudioChannels(2)
// mMediaRecorder?.setAudioSamplingRate(48000) mMediaRecorder?.setAudioSamplingRate(48000)
} }
mMediaRecorder?.setOutputFile(outputPath) mMediaRecorder?.setOutputFile(outputPath)
mMediaRecorder?.setPreviewDisplay(surface) mMediaRecorder?.setPreviewDisplay(surface)

Loading…
Cancel
Save