How to record screen in android using MediaProjectionManager
Starting from the Android lollipop there is a new api called MediaProjectionManager for recording mobile device screen video.
In this session we will learn how it works in android.
First we get the MediaProjectionManager using getSystemService()(Available on any context)which provides the interface for Video recording permission intent and handling this intent creates MediaProjection instance. startActivityForResult() launches the permission intent and handled in onActivityResult().
First get the MediaProjetionManager instance.
private MediaProjectionManager mediaProjectionManager;
mediaProjectionManager = getSystemService(
android.content.Context.MEDIA_PROJECTION_SERVICE);
Create the recording permission intent and show to the userprivate static final int REQUEST_CODE_CAPTURE = 1000;
Intent recordingPermissionIntent = mediaProjectionManager.createScreenCaptureIntent();
startActivityForResult(recordingPermissionIntent, REQUEST_CODE_CAPTURE);
private MediaProjection mediaProjection;
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
if (resultCode == RESULT_OK) {
mMediaProjection = mediaProjectionManager.getMediaProjection(resultCode, intent);
} else {
// user did not grant permissions
}
}
Once the MediaProjection instance is available, We can create the virtual display and tell android on what surface you want to copy or record. First initialize the video encoder.private static final String VIDEO_MIME_TYPE = "video/avc";
private static final int VIDEO_WIDTH = 1280;
private static final int VIDEO_HEIGHT = 720;
private Surface inputSurface;
private MediaCodec videoEncoder;
MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
MediaFormat mediaFormat = MediaFormat.createVideoFormat(VIDEO_MIME_TYPE, VIDEO_WIDTH, VIDEO_HEIGHT);
int frameRate = 30; // 30 fps
// Set some required properties. The media codec may fail if these aren't defined.
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,
MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, 6000000); // 6Mbps
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
mediaFormat.setInteger(MediaFormat.KEY_CAPTURE_RATE, frameRate);
mediaFormat.setInteger(MediaFormat.KEY_REPEAT_PREVIOUS_FRAME_AFTER, 1000000 / frameRate);
mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); // 1 seconds between I-frames
// Create a MediaCodec encoder and configure it. Get a Surface we can use for recording into.
try {
videoEncoder = MediaCodec.createEncoderByType(VIDEO_MIME_TYPE);
videoEncoder.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
inputSurface = videoEncoder.createInputSurface();
videoEncoder.start();
} catch (IOException e) {
e.printStackTrace();
//RELEASE ENCODERS
}
private MediaMuxer mMuxer;
try {
mMuxer = new MediaMuxer("/sdcard/video.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
} catch (IOException ioe) {
throw new RuntimeException("MediaMuxer creation failed", ioe);
}
// Get the display size and density.
DisplayMetrics metrics = getResources().getDisplayMetrics();
int screenWidth = metrics.widthPixels;
int screenHeight = metrics.heightPixels;
int screenDensity = metrics.densityDpi;
// Start the video input.
mediaProjection.createVirtualDisplay("Recording Display", screenWidth,
screenHeight, screenDensity, 0 /* flags */, inputSurface,
null /* callback */, null /* handler */);
Now it's time to drain the encoder. It fetches an output buffer from the encoder and writes all the bytes to
the muxer. This means that all the recently recorded video will be
written to the file produced by the muxer. We use a handler with a ten
millisecond delay to call repeatedly until the resources are released.
private boolean mMuxerStarted = false;
private int mTrackIndex = -1;
private final Handler mDrainHandler = new Handler(Looper.getMainLooper());
private Runnable mDrainEncoderRunnable = new Runnable() {
@Override
public void run() {
// DRAIN ENCODER
}
};
mDrainHandler.removeCallbacks(mDrainEncoderRunnable);
while (true) {
int bufferIndex = videoEncoder.dequeueOutputBuffer(videoBufferInfo, 0);
if (bufferIndex == MediaCodec.INFO_TRY_AGAIN_LATER) {
// nothing available yet
break;
} else if (bufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
// should happen before receiving buffers, and should only happen once
if (mTrackIndex >= 0) {
throw new RuntimeException("format changed twice");
}
mTrackIndex = mMuxer.addTrack(videoEncoder.getOutputFormat());
if (!mMuxerStarted && mTrackIndex >= 0) {
mMuxer.start();
mMuxerStarted = true;
}
} else if (bufferIndex < 0) {
// not sure what's going on, ignore it
} else {
ByteBuffer encodedData = videoEncoder.getOutputBuffer(bufferIndex);
if (encodedData == null) {
throw new RuntimeException("couldn't fetch buffer at index " + bufferIndex);
}
if ((videoBufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) {
videoBufferInfo.size = 0;
}
if (videoBufferInfo.size != 0) {
if (mMuxerStarted) {
encodedData.position(videoBufferInfo.offset);
encodedData.limit(videoBufferInfo.offset + videoBufferInfo.size);
mMuxer.writeSampleData(mTrackIndex, encodedData, videoBufferInfo);
} else {
// muxer not started
}
}
videoEncoder.releaseOutputBuffer(bufferIndex, false);
if ((videoBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
break;
}
}
}
mDrainHandler.postDelayed(mDrainEncoderRunnable, 10);
When recording is finished release the encoder and other resourcesmDrainHandler.removeCallbacks(mDrainEncoderRunnable);
if (mMuxer != null) {
if (mMuxerStarted) {
mMuxer.stop();
}
mMuxer.release();
mMuxer = null;
mMuxerStarted = false;
}
if (videoEncoder != null) {
videoEncoder.stop();
videoEncoder.release();
videoEncoder = null;
}
if (inputSurface != null) {
inputSurface.release();
inputSurface = null;
}
if (mediaProjection != null) {
mediaProjection.stop();
mediaProjection = null;
}
videoBufferInfo = null;
mDrainEncoderRunnable = null;
mTrackIndex = -1;
Never forget to give READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE permissions.
Hello, in your case only only video screen is working, not audio
ReplyDelete