diff --git a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaProjectionController.kt b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaProjectionController.kt index 990e509..31824e4 100644 --- a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaProjectionController.kt +++ b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaProjectionController.kt @@ -6,6 +6,7 @@ import android.content.Intent import android.graphics.Bitmap import android.graphics.PixelFormat import android.hardware.display.DisplayManager +import android.hardware.display.VirtualDisplay import android.media.ImageReader import android.media.projection.MediaProjection import android.media.projection.MediaProjectionManager @@ -23,16 +24,23 @@ import java.lang.Exception * @author frank * @date 2022/3/25 */ -open class MediaProjectionController(screenshot: Boolean) { +open class MediaProjectionController(type: Int) { - private var screenshot = true - private val requestCode = 1234 + companion object { + const val TYPE_SCREEN_SHOT = 0 + const val TYPE_SCREEN_RECORD = 1 + const val TYPE_SCREEN_LIVING = 2 + } + + private var type = TYPE_SCREEN_SHOT + private val requestCode = 123456 + private var virtualDisplay: VirtualDisplay? = null private var displayMetrics: DisplayMetrics? = null private var mediaProjection: MediaProjection? = null private var mediaProjectionManager: MediaProjectionManager? = null init { - this.screenshot = screenshot + this.type = type } fun startScreenRecord(context: Context) { @@ -44,6 +52,13 @@ open class MediaProjectionController(screenshot: Boolean) { (context as Activity).startActivityForResult(intent, requestCode) } + fun createVirtualDisplay(surface: Surface) { + virtualDisplay = mediaProjection?.createVirtualDisplay("hello", displayMetrics!!.widthPixels, + displayMetrics!!.heightPixels, displayMetrics!!.densityDpi, + DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR, + surface, null, null) + } + private fun saveBitmap(bitmap: Bitmap?, path: String) { if (path.isEmpty() || bitmap == null) return @@ -58,12 +73,6 @@ open class MediaProjectionController(screenshot: Boolean) { } } - 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) @@ -76,7 +85,8 @@ open class MediaProjectionController(screenshot: Boolean) { 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) + 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) @@ -87,14 +97,19 @@ open class MediaProjectionController(screenshot: Boolean) { fun onActivityResult(resultCode: Int, data: Intent) { mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, data) - if (screenshot) { + if (type == TYPE_SCREEN_SHOT) { getBitmap() } } + fun getRequestCode(): Int { + return requestCode + } + fun stopScreenRecord() { mediaProjection?.stop() + virtualDisplay?.release() } } \ No newline at end of file diff --git a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaRecordController.kt b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaRecordController.kt index a2136e5..3e72303 100644 --- a/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaRecordController.kt +++ b/AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaRecordController.kt @@ -1,5 +1,7 @@ package com.frank.androidmedia.controller +import android.content.Context +import android.content.Intent import android.hardware.Camera import android.media.CamcorderProfile import android.media.MediaRecorder @@ -16,17 +18,22 @@ open class MediaRecordController { private val usingProfile = true private var mCamera: Camera? = null + private var mOutputPath: String? = null private var mMediaRecorder: MediaRecorder? = null + private var mMediaProjectionController: MediaProjectionController? = null - private fun initMediaRecord(surface: Surface, outputPath: String) { - // open camera - mCamera = Camera.open() - mCamera!!.setDisplayOrientation(90) - mCamera!!.unlock() + private fun initMediaRecord(videoSource: Int, surface: Surface?, outputPath: String) { + if (videoSource == MediaRecorder.VideoSource.CAMERA + || videoSource == MediaRecorder.VideoSource.DEFAULT) { + // open camera + mCamera = Camera.open() + mCamera!!.setDisplayOrientation(90) + mCamera!!.unlock() + mMediaRecorder?.setCamera(mCamera) + } // Note: pay attention to calling order - mMediaRecorder?.setCamera(mCamera) + mMediaRecorder?.setVideoSource(videoSource) mMediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC) - mMediaRecorder?.setVideoSource(MediaRecorder.VideoSource.CAMERA) if (usingProfile) { // QUALITY_480P QUALITY_720P QUALITY_1080P QUALITY_2160P val profile = CamcorderProfile.get(CamcorderProfile.QUALITY_720P) @@ -42,34 +49,74 @@ open class MediaRecordController { mMediaRecorder?.setAudioSamplingRate(48000) } mMediaRecorder?.setOutputFile(outputPath) - mMediaRecorder?.setPreviewDisplay(surface) - } - - fun startRecord(surface: Surface, outputPath: String) { - if (mMediaRecorder == null) { - mMediaRecorder = MediaRecorder() + if (surface != null && (videoSource == MediaRecorder.VideoSource.CAMERA + || videoSource == MediaRecorder.VideoSource.DEFAULT)) { + mMediaRecorder?.setPreviewDisplay(surface) } + } - initMediaRecord(surface, outputPath) - + private fun startRecordInternal(videoSource: Int, surface: Surface?, outputPath: String) { + initMediaRecord(videoSource, surface, outputPath) try { mMediaRecorder?.prepare() + if (videoSource == MediaRecorder.VideoSource.SURFACE) { + mMediaProjectionController?.createVirtualDisplay(mMediaRecorder?.surface!!) + } mMediaRecorder?.start() } catch (e: Exception) { Log.e("MediaRecorder", "start recorder error=$e") } + } + + /** + * Start record camera or screen + * @param videoSource the source of video, see {@link MediaRecorderVideoSource.CAMERA} + * or {@link MediaRecorder.VideoSource.SURFACE} + * @param surface the Surface to preview, when videoSource = MediaRecorderVideoSource.CAMERA + * @param context the Context of Activity + * @param outputPath the output path to save media file + */ + fun startRecord(videoSource: Int, surface: Surface?, context: Context, outputPath: String) { + if (mMediaRecorder == null) { + mMediaRecorder = MediaRecorder() + } + + if (videoSource == MediaRecorder.VideoSource.SURFACE) { + mOutputPath = outputPath + mMediaProjectionController = MediaProjectionController(MediaProjectionController.TYPE_SCREEN_RECORD) + mMediaProjectionController?.startScreenRecord(context) + return + } + + startRecordInternal(videoSource, surface, outputPath) Log.i("MediaRecorder", "startRecord...") } + /** + * Stop recording camera or screen, + * and release everything. + */ fun stopRecord() { if (mMediaRecorder != null) { mMediaRecorder?.stop() mMediaRecorder?.reset() } - mCamera?.stopPreview() + if (mCamera != null) { + mCamera!!.stopPreview() + } + if (mMediaProjectionController != null) { + mMediaProjectionController!!.stopScreenRecord() + } Log.i("MediaRecorder", "stopRecord...") } + fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) { + if (requestCode == mMediaProjectionController?.getRequestCode()) { + mMediaProjectionController?.onActivityResult(resultCode, data) + startRecordInternal(MediaRecorder.VideoSource.SURFACE, mMediaRecorder?.surface, mOutputPath!!) + } + } + fun release() { if (mMediaRecorder != null) { mMediaRecorder?.release()