Video Playback and Recording
Overview
In Android apps, there are often cases where we need to play video files. Checking the Supported Media Formats we can see that several video formats (H.264, MPEG-4) are playable by default.
In this guide we will take a look at how to play video content using the VideoView and capture video with the MediaRecorder.
Video Playback
Playing Local Video
Playing local video in a supported format can be done using the VideoView. First, setup the VideoView in your layout:
<VideoView
android:id="@+id/video_view"
android:layout_width="320px"
android:layout_height="240px" />
Next, we can store a local file such as a short sample clip (for example, Google’s Big Buck Bunny sample video used by the official ExoPlayer codelab) in res/raw/small_video.mp4 and then play the video in the view with:
VideoView mVideoView = (VideoView) findViewById(R.id.video_view);
mVideoView.setVideoURI(Uri.parse("android.resource://" + getPackageName() +"/"+R.raw.small_video));
mVideoView.setMediaController(new MediaController(this));
mVideoView.requestFocus();
mVideoView.start();
See this tutorial for playing a video full-screen with a VideoView. See this other edumobile tutorial for a more detailed look at using VideoView.
Playing Streaming Video
To play back remote video in a supported format, we can still use the VideoView. First, setup the correct permissions in the Android Manifest.xml:
<uses-permission android:name="android.permission.INTERNET" />
Now, we can play remote video with:
final VideoView mVideoView = (VideoView) findViewById(R.id.video_view);
mVideoView.setVideoPath("https://storage.googleapis.com/androiddevelopers/samples_assets/exoplayer-test-media-0/BigBuckBunny_320x180.mp4");
MediaController mediaController = new MediaController(this);
mediaController.setAnchorView(mVideoView);
mVideoView.setMediaController(mediaController);
mVideoView.requestFocus();
mVideoView.setOnPreparedListener(new OnPreparedListener() {
// Close the progress bar and play the video
public void onPrepared(MediaPlayer mp) {
mVideoView.start();
}
});
You can see a more complete example of remote streaming with this androidbegin tutorial.
VideoView Controls
We can remove the VideoView media controls with:
mVideoView.setMediaController(null)
We can hide or show the media UI controls at runtime with:
// Get instance to media controller
MediaController controller = new MediaController(this);
videoHolder.setMediaController(controller);
// Hide the controller
controller.setVisibility(View.GONE);
// Show the controller
controller.setVisibility(View.VISIBLE);
VideoView Limitations and Improved Libraries
VideoView should not be embedded in a ListView or any scrolling view due to a known bug with Android. Instead of using a VideoView which extends SurfaceView, in order to enable scrolling we need to use a TextureView instead. The easiest workaround is to use a library such as Android-ScalableVideoView, VideoPlayerManager, or fenster.
You can read about how fenster was developed as well. If you are using fenster and running into a permissions error related to write_settings on an Android >= 6.0 device, check out this snippet as a workaround.
Streaming from YouTube
Google’s official YouTube Android Player API has been discontinued — its documentation and download pages have been removed. To play YouTube videos within an Android app today, use the official YouTube IFrame Player API or, more conveniently, the actively maintained open-source android-youtube-player library, which wraps the IFrame player in a native YouTubePlayerView.
Refer to the Streaming Youtube Videos with YouTubePlayerView guide for detailed instructions.
Streaming Via Exoplayer
You can check out our Playing Media with ExoPlayer or TubiPlayer or Quickstart with Exoplayer for step-by-step instructions on using a more advanced third-party embedded video player.
Capturing Video
Using Intents
Capturing video can be done using intents to capture video using the camera. The snippet below saves the recording into the app’s own external-files directory (getExternalFilesDir), which requires no storage permissions — the legacy WRITE_EXTERNAL_STORAGE approach with a shared-storage path no longer works under scoped storage. The output file is exposed to the camera app through a content:// URI created with FileProvider.getUriForFile(...) — a raw file:// URI from Uri.fromFile(...) throws a FileUriExposedException on Android 7.0+ (API 24+). This requires a one-time FileProvider declaration in the manifest — see the FileProvider setup, and add an <external-files-path name="videos" path="Movies" /> entry to its paths XML so the Movies directory used below is covered.
To receive the capture result, use the AndroidX Activity Result APIs — Google strongly recommends them over the legacy startActivityForResult() / onActivityResult() pair. Register an ActivityResultLauncher as a field (registration must happen unconditionally every time the activity is created — a field initializer or onCreate() both work; registering lazily inside a click handler is too late), then launch the capture intent through it. Note also the camera check below uses PackageManager.FEATURE_CAMERA_ANY, which matches a camera facing any direction — FEATURE_CAMERA_FRONT would wrongly report “no camera” on a device with only a back camera.
Uri videoUri;
// Register the launcher unconditionally as a field so the callback is
// available again after the process or activity is recreated
private final ActivityResultLauncher<Intent> videoCaptureLauncher =
registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (result.getResultCode() == RESULT_OK) {
Toast.makeText(this, "Video has been saved to:\n" + videoUri, Toast.LENGTH_LONG).show();
playbackRecordedVideo();
} else if (result.getResultCode() == RESULT_CANCELED) {
Toast.makeText(this, "Video recording cancelled.", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(this, "Failed to record video", Toast.LENGTH_LONG).show();
}
});
public void startRecordingVideo() {
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
Intent intent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
File mediaFile = new File(
getExternalFilesDir(Environment.DIRECTORY_MOVIES), "myvideo.mp4");
// Wrap the file in a content:// URI; the authority must match the
// FileProvider declared in AndroidManifest.xml
videoUri = FileProvider.getUriForFile(this,
getApplicationContext().getPackageName() + ".fileprovider", mediaFile);
intent.putExtra(MediaStore.EXTRA_OUTPUT, videoUri);
videoCaptureLauncher.launch(intent);
} else {
Toast.makeText(this, "No camera on device", Toast.LENGTH_LONG).show();
}
}
Once the video has been captured, the result callback registered above runs and we can play the recording back from the videoUri we handed to the camera app. Per the ACTION_VIDEO_CAPTURE contract, the recording’s Uri is only promised “in the data field” of the result when EXTRA_OUTPUT is not present — since we set EXTRA_OUTPUT, we keep our own reference in a field:
public void playbackRecordedVideo() {
VideoView mVideoView = (VideoView) findViewById(R.id.video_view);
mVideoView.setVideoURI(videoUri);
mVideoView.setMediaController(new MediaController(this));
mVideoView.requestFocus();
mVideoView.start();
}
For a more detailed look, check out the techtopia tutorial on video recording.
Using MediaRecorder
If we want to record video from within an app directly, we’ll want to use the MediaRecorder. We can find good references for using the recorder in the following resources below:
- Grabbing a video using MediaRecorder
- Recording and Playing Video on Android
- Google Video Recorder Sample
For more advanced usage, see this video recording and processing guide.
Configuring Encoding
The MediaRecorder can be configured to select the encoding, quality and compression settings:
// Create MediaRecorder
recorder.setVideoSize(640, 480);
recorder.setVideoFrameRate(16); //might be auto-determined due to lighting
recorder.setVideoEncodingBitRate(3000000);
recorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);// MPEG_4_SP
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
You can also configure using preset qualities with CamcorderProfile:
CamcorderProfile cpHigh = CamcorderProfile.get(CamcorderProfile.QUALITY_HIGH);
recorder.setProfile(cpHigh);
See the available options here. You can also review this stackoverflow post for more details.
References
- http://mrbool.com/how-to-play-video-formats-in-android-using-videoview/28299
- https://developer.android.com/media/platform/mediaplayer
- https://developer.android.com/media/platform/supported-formats
- https://developers.google.com/youtube/iframe_api_reference
- https://www.vogella.com/tutorials/AndroidMedia/article.html
- http://www.edumobile.org/android/android-beginner-tutorials/how-to-play-a-video-file/
- http://www.androidbegin.com/tutorial/android-video-streaming-videoview-tutorial/
- https://developer.android.com/reference/android/media/MediaPlayer
