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

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

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