MediaProjection 캡처 정리에 이어서 녹화도 정리하려고 합니다. (원래 한 게시글에 정리하고 싶었지만.. 너무 지저분해지는 것 같아서 나눴습니다ㅠㅠ) 이전 글과 중복되는 내용은 생략해서 정리하려고 해요..! 이해를 위해서 이전글을 확인해주시...

[안드로이드] MediaProjection 화면녹화 예제&정리


MediaProjection 캡처 정리에 이어서 녹화도 정리하려고 합니다.

(원래 한 게시글에 정리하고 싶었지만.. 너무 지저분해지는 것 같아서 나눴습니다ㅠㅠ)

이전 글과 중복되는 내용은 생략해서 정리하려고 해요..!

이해를 위해서 이전글을 확인해주시면 좋을 것 같습니다.

[안드로이드] MediaProjection 캡처 예제&정리 (ForegroundService, PermissionOnce)

 

 

 

 

1. 예제 다운로드

해당 예제는 MediaProjection 화면 캡처/녹화 가 포함되어있습니다.

https://github.com/bictoselfdev/MediaProjectionEx

 



 

 

2. MediaProjection 권한 받기

startActivityForResult 를 통해서 권한 요청을 합니다.

이때, prevIntentData / prevResultCode 를 통해 이전값을 재사용해서 최초 한번만 권한을 받도록 하였습니다.

fun screenRecording(activity: Activity, action: Action?) {
startRecordCompletedAction = action

if (prevIntentData != null) {
// If you have received permission even once, proceed without requesting permission
getMediaProjectionRecord(activity, prevResultCode, prevIntentData)
} else {
// permission request
projectionManager = activity.getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
activity.startActivityForResult(projectionManager?.createScreenCaptureIntent(), mediaScreenRecord)
}
}

 

정상적으로 권한을 받았다면 MediaProjectionManager 를 통해서 MediaProjection 을 가져올 수 있습니다.

fun getMediaProjectionRecord(activity: Activity, resultCode: Int, intentData: Intent?) {
projectionRecord = projectionManager?.getMediaProjection(resultCode, intentData!!)

if (projectionRecord != null) {
prevIntentData = intentData
prevResultCode = resultCode

// Create virtualDisplay
createVirtualDisplayRecord(activity)

// MediaRecorder Start
if (virtualDisplayRecord != null) {
startRecording(activity)
}
}
}

 

 

 

 

3. Create Virtual Display

녹화 데이터를 가져오기 위해서 MediaRecorder 의 surface 를 사용합니다.

MediaRecorder 를 활용해서 녹화를 Start/Stop 하기 위해서 prepare() 가 선행되어야 합니다.

그리고 createVirualDisplay 인자에 MediaRecorder.surface 를 넣어줘서 가상화면을 생성합니다.
private fun createVirtualDisplayRecord(activity: Activity) {
val metrics = activity.resources?.displayMetrics!!
val density = metrics.densityDpi
val flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR

width = metrics.widthPixels
height = metrics.heightPixels

// MediaRecorder Prepare
mediaRecorder = MediaRecorder()
prepareRecording(activity)

// MediaRecorder Surface rendering
virtualDisplayRecord = projectionRecord?.createVirtualDisplay(
"screenRecord", width, height, density, flags,
mediaRecorder?.surface, null, null
)
}

 

녹화 시 기본적인 설정들을 해줍니다.

이중에 저장되는 파일(setOutputFile)은 MediaStore 공용폴더에 저장되도록 하였습니다.

private fun prepareRecording(activity: Activity) {

fileDescriptor = createFile(activity) // Create file to save

mediaRecorder?.apply {

setOutputFile(fileDescriptor?.fileDescriptor)
setVideoSource(MediaRecorder.VideoSource.SURFACE)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setVideoEncodingBitRate(5 * 1024 * 1000)
setVideoFrameRate(30)
setVideoEncoder(MediaRecorder.VideoEncoder.DEFAULT)
setVideoSize(width, height)
prepare()
}
}
fun createFile(activity: Activity): ParcelFileDescriptor? {

val contentValues = ContentValues()
val currentTime = Date(System.currentTimeMillis())
val currentTimeStamp = SimpleDateFormat("yyyyMMddHHmmss", Locale.KOREA).format(currentTime)

contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "MediaProjectionEx$currentTimeStamp.mp4")
contentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
contentValues.put(MediaStore.Video.Media.DATE_ADDED, System.currentTimeMillis());

val contentResolver = activity.contentResolver
val collectionUri = contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues)

return contentResolver.openFileDescriptor(collectionUri!!, "w")
}

 

Virtual Display 를 정상적으로 생성하였고, MediaRecorder prepare 가 선행되었다면

언제든지 startRecording 을 호출하여 녹화를 시작할 수 있습니다.

저 같은 경우는 Virtual Display 가 생성되면 바로 시작하도록 하였습니다.

private fun startRecording(activity: Activity) {
if (mediaRecorder != null) {
try {
mediaRecorder?.start()

isRecording.value = true

startRecordCompletedAction?.run()

Toast.makeText(activity, "screenRecording...", Toast.LENGTH_SHORT).show()

} catch (e: Exception) {
System.err.println("[MediaProjection] start error : $e")
}
}
}

 

stopRecording 을 호출하게 되면 미리 설정해둔 경로에 파일이 저장되는 것을 확인 할 수 있습니다. 

fun stopRecording(activity: Activity, action: Action?) {
if (mediaRecorder != null) {
try {
mediaRecorder?.stop()
mediaRecorder?.reset()

virtualDisplayRecord?.release()

projectionRecord?.stop()

isRecording.value = false

fileDescriptor?.close()

action?.run()

Toast.makeText(activity, "stopRecording, File has been saved.", Toast.LENGTH_SHORT).show()

} catch (e: Exception) {
System.err.println("[MediaProjection] start error : $e")
}
}
}

 

 

 

[Related Post]

[안드로이드] MediaProjection 캡처 예제&정리 (ForegroundService, PermissionOnce)

 

 

 

 

 


0 comments: