MediaProjection: How to record your Android device

James O'Brien
Jan 28, 2018 · 3 min read

For a recent project I tasked myself with finding a way to let the user record what they were seeing on the device. The nuts and bolts of the solution can be identified with two classes:

  • MediaProjection was introduced in Lollipop and gives us the ability to capture what’s on the screen.
  • MediaRecorder is pretty self explanatory, this class simplifies recording audio and video.
Image for post
Image for post

The first step is to request permission to capture the screen.

val manager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManagerstartActivityForResult(manager.createScreenCaptureIntent(), REQUEST_MEDIA_PROJECTION)
Image for post
Image for post

Launching this intent will show a confirmation dialog to the user which allows them to authorise the screen capturing.

Once they accept, you can use the result code and data intent returned in onActivityResult, we are able to create a MediaProjection.

projection = manager.getMediaProjection(resultCode, data) as MediaProjection

Next we need to define our MediaRecorder. I’m not too fussed about the specific details so I used the predefined high quality CamcorderProfile but you can create your own and specify everything from output format to bits per second. One slightly different thing is that I defined the height and width using the Window’s DisplayMetrics so it exactly matched the screen size.

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT)
mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE)
val profile: CamcorderProfile = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH)
profile.videoFrameHeight = metrics.heightPixels
profile.videoFrameWidth = metrics.widthPixels
mMediaRecorder.setProfile(profile)
mMediaRecorder.setOutputFile(filename)
mMediaRecorder.prepare()

One gotcha about the MediaRecorder is that the methods have to be defined in the correct order. For example, once setting the Camcorder Profile, you can’t change the AudioSource without crashing. The javadoc has more details to the state machine behind this.

Once we have the MediaRecorder and MediaProjection, we can create a virtual display that mirrors the projection and then bind it to the MediaRecorder’s SurfaceView. If you weren’t interested in the recording aspect of this demo, you could bind to your own SurfaceView.

mVirtualDisplay = mMediaProjection!!.createVirtualDisplay(VIRTUAL_DISPLAY_NAME,
metrics.widthPixels, metrics.heightPixels, metrics.densityDpi,
DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR,
mMediaRecorder.surface, null, null)

Now everything is set up, tell the MediaRecorder to start() recording and you’ll notice the cast icon appear in your phone’s status bar.

Image for post
Image for post

When you’re ready, call stop(). It’s also important to release the MediaProjection and VirtualDisplay too. The recording will then be saved to the location you define in setOutputFile.

mMediaRecorder?.stop()
mMediaProjection?.stop()
mVirtualDisplay?.release()

jamesob.com

Writings from James O’Brien

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store