|
|
@ -8,12 +8,17 @@ import android.graphics.PixelFormat |
|
|
|
import android.hardware.display.DisplayManager |
|
|
|
import android.hardware.display.DisplayManager |
|
|
|
import android.hardware.display.VirtualDisplay |
|
|
|
import android.hardware.display.VirtualDisplay |
|
|
|
import android.media.ImageReader |
|
|
|
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.MediaProjection |
|
|
|
import android.media.projection.MediaProjectionManager |
|
|
|
import android.media.projection.MediaProjectionManager |
|
|
|
import android.os.Environment |
|
|
|
import android.os.Environment |
|
|
|
import android.util.DisplayMetrics |
|
|
|
import android.util.DisplayMetrics |
|
|
|
|
|
|
|
import android.util.Log |
|
|
|
import android.view.Surface |
|
|
|
import android.view.Surface |
|
|
|
import android.view.WindowManager |
|
|
|
import android.view.WindowManager |
|
|
|
|
|
|
|
import com.frank.androidmedia.listener.VideoEncodeCallback |
|
|
|
import java.io.FileOutputStream |
|
|
|
import java.io.FileOutputStream |
|
|
|
import java.lang.Exception |
|
|
|
import java.lang.Exception |
|
|
|
|
|
|
|
|
|
|
@ -39,10 +44,20 @@ open class MediaProjectionController(type: Int) { |
|
|
|
private var mediaProjection: MediaProjection? = null |
|
|
|
private var mediaProjection: MediaProjection? = null |
|
|
|
private var mediaProjectionManager: MediaProjectionManager? = 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 { |
|
|
|
init { |
|
|
|
this.type = type |
|
|
|
this.type = type |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fun setVideoEncodeListener(encodeCallback: VideoEncodeCallback) { |
|
|
|
|
|
|
|
videoEncodeCallback = encodeCallback |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fun startScreenRecord(context: Context) { |
|
|
|
fun startScreenRecord(context: Context) { |
|
|
|
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager |
|
|
|
val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager |
|
|
|
displayMetrics = DisplayMetrics() |
|
|
|
displayMetrics = DisplayMetrics() |
|
|
@ -95,10 +110,61 @@ open class MediaProjectionController(type: Int) { |
|
|
|
}, null) |
|
|
|
}, 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) { |
|
|
|
fun onActivityResult(resultCode: Int, data: Intent) { |
|
|
|
mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, data) |
|
|
|
mediaProjection = mediaProjectionManager?.getMediaProjection(resultCode, data) |
|
|
|
if (type == TYPE_SCREEN_SHOT) { |
|
|
|
if (type == TYPE_SCREEN_SHOT) { |
|
|
|
getBitmap() |
|
|
|
getBitmap() |
|
|
|
|
|
|
|
} else if (type == TYPE_SCREEN_LIVING) { |
|
|
|
|
|
|
|
initMediaCodec(displayMetrics!!.widthPixels, displayMetrics!!.heightPixels) |
|
|
|
|
|
|
|
startVideoEncoder() |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -110,6 +176,7 @@ open class MediaProjectionController(type: Int) { |
|
|
|
fun stopScreenRecord() { |
|
|
|
fun stopScreenRecord() { |
|
|
|
mediaProjection?.stop() |
|
|
|
mediaProjection?.stop() |
|
|
|
virtualDisplay?.release() |
|
|
|
virtualDisplay?.release() |
|
|
|
|
|
|
|
videoEncoder?.release() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |