Feature: add screen living stream

pull/209/head
xufuji456 3 years ago
parent 54d7f094bc
commit 6644456a95
  1. 67
      AndroidMedia/src/main/java/com/frank/androidmedia/controller/MediaProjectionController.kt
  2. 12
      AndroidMedia/src/main/java/com/frank/androidmedia/listener/VideoEncodeCallback.kt

@ -8,12 +8,17 @@ import android.graphics.PixelFormat
import android.hardware.display.DisplayManager
import android.hardware.display.VirtualDisplay
import android.media.ImageReader
import android.media.MediaCodec
import android.media.MediaCodecInfo
import android.media.MediaFormat
import android.media.projection.MediaProjection
import android.media.projection.MediaProjectionManager
import android.os.Environment
import android.util.DisplayMetrics
import android.util.Log
import android.view.Surface
import android.view.WindowManager
import com.frank.androidmedia.listener.VideoEncodeCallback
import java.io.FileOutputStream
import java.lang.Exception
@ -39,10 +44,20 @@ open class MediaProjectionController(type: Int) {
private var mediaProjection: MediaProjection? = null
private var mediaProjectionManager: MediaProjectionManager? = null
private var encodeThread: Thread? = null
private var videoEncoder: MediaCodec? = null
private var isVideoEncoding = false
private var videoEncodeData: ByteArray? = null
private var videoEncodeCallback: VideoEncodeCallback? = null
init {
this.type = type
}
fun setVideoEncodeListener(encodeCallback: VideoEncodeCallback) {
videoEncodeCallback = encodeCallback
}
fun startScreenRecord(context: Context) {
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
displayMetrics = DisplayMetrics()
@ -95,10 +110,61 @@ open class MediaProjectionController(type: Int) {
}, null)
}
private fun initMediaCodec(width: Int, height: Int) {
val mediaFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height)
mediaFormat.setInteger(MediaFormat.KEY_WIDTH, width)
mediaFormat.setInteger(MediaFormat.KEY_HEIGHT, height)
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 20)
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, width * height)
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 3)
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface)
videoEncoder = MediaCodec.createEncoderByType(MediaFormat.MIMETYPE_VIDEO_AVC)
videoEncoder?.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE)
createVirtualDisplay(videoEncoder!!.createInputSurface())
}
private fun startVideoEncoder() {
if (videoEncoder == null || isVideoEncoding)
return
encodeThread = Thread {
try {
val bufferInfo = MediaCodec.BufferInfo()
videoEncoder?.start()
while (isVideoEncoding && !Thread.currentThread().isInterrupted) {
val outputIndex = videoEncoder!!.dequeueOutputBuffer(bufferInfo, 30 * 1000)
if (outputIndex >= 0) {
val byteBuffer = videoEncoder!!.getOutputBuffer(outputIndex)
if (videoEncodeData == null || videoEncodeData!!.size < bufferInfo.size) {
videoEncodeData = ByteArray(bufferInfo.size)
}
if (videoEncodeCallback != null && byteBuffer != null) {
byteBuffer.get(videoEncodeData, bufferInfo.offset, bufferInfo.size)
videoEncodeCallback!!.onVideoEncodeData(videoEncodeData!!, bufferInfo.size,
bufferInfo.flags, bufferInfo.presentationTimeUs)
}
videoEncoder!!.releaseOutputBuffer(outputIndex, false)
} else {
Log.e("EncodeThread", "invalid index=$outputIndex")
}
}
} catch (e: Exception) {
isVideoEncoding = false
Log.e("EncodeThread", "encode error=$e")
}
}
isVideoEncoding = true
encodeThread?.start()
}
fun onActivityResult(resultCode: Int, data: Intent) {
mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, data)
if (type == TYPE_SCREEN_SHOT) {
getBitmap()
} else if (type == TYPE_SCREEN_LIVING) {
initMediaCodec(displayMetrics!!.widthPixels, displayMetrics!!.heightPixels)
startVideoEncoder()
}
}
@ -110,6 +176,7 @@ open class MediaProjectionController(type: Int) {
fun stopScreenRecord() {
mediaProjection?.stop()
virtualDisplay?.release()
videoEncoder?.release()
}
}

@ -0,0 +1,12 @@
package com.frank.androidmedia.listener
/**
* @author xufulong
* @date 4/1/22 1:44 PM
* @desc
*/
interface VideoEncodeCallback {
fun onVideoEncodeData(data: ByteArray, size: Int, flag: Int, timestamp: Long)
}
Loading…
Cancel
Save