Skip to main content

Working with Video Features

1. Configuring Video Source

Property Description Values Notes
source Specifies the video source uri, asset, file Required for video playback
uri URL or file path to the video string Supports local and remote video sources
asset Asset reference to a video file Asset Used for bundled assets in Expo
file File path to the video on device string Must be a valid file path on the device

Example: Setting Video Source from URI

import { Video } from 'expo-av';

const VideoPlayer = () => {
  return (
    <Video
      source={{ uri: 'https://example.com/video.mp4' }}
      useNativeControls
      style={{ width: '100%', height: 300 }}
    />
  );
};

Example: Setting Video Source from Asset

import { Video } from 'expo-av';
import { Asset } from 'expo-asset';

const VideoPlayer = () => {
  const videoAsset = Asset.fromModule(require('./assets/video.mp4'));

  return (
    <Video
      source={{ asset: videoAsset }}
      useNativeControls
      style={{ width: '100%', height: 300 }}
    />
  );
};

2. Setting Poster Image

Property Description Default Notes
poster URL or local asset path for the video poster image null Used when video is not playing or loading
posterResizeMode How to resize the poster image "cover" Options: "contain", "cover", "fill", "none", "repeat"

Example: Setting a Poster Image

import { Video } from 'expo-av';

<Video
  source={{ uri: 'https://example.com/video.mp4' }}
  poster={require('./assets/poster.jpg')}
  posterResizeMode="cover"
  style={{ width: 300, height: 200 }}
/>
Note: The poster image is displayed while the video is loading or paused. It should be a static image that represents the content of the video.

3. Using Resize Modes

Mode Description Usage
cover Cover the entire area, maintaining aspect ratio. May crop. resizeMode: 'cover'
contain Fit the entire video within the area, maintaining aspect ratio. May leave empty space. resizeMode: 'contain'
stretch Stretch the video to fill the entire area. May distort aspect ratio. resizeMode: 'stretch'
repeat Repeat the video to fill the area. Not supported on all platforms. resizeMode: 'repeat'
center Center the video within the area, maintaining aspect ratio. resizeMode: 'center'

Example: Setting Resize Mode

import { Video } from 'expo-av';

<Video
  source={{ uri: 'https://example.com/video.mp4' }}
  resizeMode="cover"
  style={{ width: 300, height: 200 }}
/>

4. Implementing Fullscreen Mode

Example: Toggle fullscreen mode

import { Video } from 'expo-av';
import { TouchableOpacity, Text } from 'react-native';

const VideoPlayer = () => {
  const [isFullscreen, setIsFullscreen] = useState(false);

  const toggleFullscreen = () => {
    setIsFullscreen(!isFullscreen);
  };

  return (
    <Video
      source={{ uri: 'https://example.com/video.mp4' }}
      style={{
        width: isFullscreen ? '100%' : 300,
        height: isFullscreen ? '100%' : 200,
      }}
      resizeMode={isFullscreen ? 'contain' : 'cover'}
      controls={true}
    />
  );
};
Property Description Values
fullscreen Enables or disables fullscreen mode true | false
resizeMode How the video should be resized to fit its container 'contain' | 'cover' | 'stretch'
Note: Fullscreen mode requires handling device orientation changes and layout adjustments for optimal user experience.
Warning: On some devices, entering fullscreen mode might cause the app to lose focus or trigger system UI changes.

5. Handling Video Events

Event Description Properties
onLoad Fired when the video is loaded and ready to play duration, width, height
onProgress Fired periodically as the video plays currentTime, seekable
onEnd Fired when the video finishes playing didComplete
onError Fired when an error occurs during video playback error
onPlay Fired when the video starts playing isPlaying
onPause Fired when the video is paused isPlaying

Example: Handling Video Events

import { Video } from 'expo-av';

const handleVideoEvent = (event) => {
  if (event.type === 'onLoad') {
    console.log('Video loaded:', event.data.duration);
  } else if (event.type === 'onProgress') {
    console.log('Current time:', event.data.currentTime);
  } else if (event.type === 'onEnd') {
    console.log('Video ended');
  }
};

<Video
  source={{ uri: 'https://example.com/video.mp4' }}
  onLoad={handleVideoEvent}
  onProgress={handleVideoEvent}
  onEnd={handleVideoEvent}
  onError={handleVideoEvent}
/>

6. Using Picture-in-Picture

Property Description Notes
pictureInPicture Enables or disables Picture-in-Picture mode for a video element. Available on iOS and Android (requires Expo AV)

Example: Enabling Picture-in-Picture

import { Video } from 'expo-av';\n\nconst MyVideoPlayer = () => {\n  const videoRef = useRef(null);\n\n  const togglePictureInPicture = async () => {\n    if (videoRef.current) {\n      await videoRef.current.setPictureInPicture(true);\n    }\n  };\n\n  return (\n    <Video\n      ref={videoRef}\n      source={{ uri: 'https://example.com/video.mp4' }}\n      style={{ width: '100%', height: 300 }}\n      pictureInPicture={true}\n    /\>\n  );\n};
Note: Picture-in-Picture is only supported on iOS 14+ and Android 8.0+.

7. Setting Playback Rate

Property Values Description
rate 0.25, 0.5, 1.0, 1.5, 2.0 Playback speed multiplier. 1.0 is normal speed.

Example: Setting Playback Rate

import { Video } from 'expo-av';

<Video
  source={{ uri: 'https://example.com/video.mp4' }}
  rate={1.5}
  style={{ width: 300, height: 200 }}
/>
Note: The rate property affects how fast the video plays, but does not change audio pitch.

8. Implementing Video Controls

Property Description Values
controls Enables or disables video controls true / false
paused Pauses or resumes the video playback true / false
muted Mutes or unmutes the video audio true / false
volume Sets the volume level (0.0 to 1.0) 0.0 - 1.0
rate Adjusts playback speed (1.0 = normal) 0.0 - 2.0

Example: Basic Video Controls

import { Video } from 'expo-av';

<Video
  source={{ uri: 'https://example.com/video.mp4' }}
  controls={true}
  paused={false}
  muted={false}
  volume={1.0}
  rate={1.0}
  style={{ width: '100%', height: 300 }}
/>

Example: Custom Video Controls

import { Video, Audio } from 'expo-av';
import { useState } from 'react';

const VideoPlayer = () => {
  const [isPaused, setIsPaused] = useState(false);
  const [isMuted, setIsMuted] = useState(false);
  const [volume, setVolume] = useState(1.0);

  return (
    <Video
      source={{ uri: 'https://example.com/video.mp4' }}
      paused={isPaused}
      muted={isMuted}
      volume={volume}
      style={{ width: '100%', height: 300 }}
    />
  );
};
Note: The controls prop enables default system controls, which may not be customizable. For fully custom controls, you must implement them separately using buttons and state management.

9. Seeking to Position

Property Description Values Notes
position The position to seek to in seconds number Must be a positive number or zero
seek Method to seek to a specific position function(position: number): void Triggers video playback to jump to the specified position

Example: Seeking to a Position

import { Video } from 'expo-av';

const videoRef = useRef(null);

const seekToPosition = () => {
  if (videoRef.current) {
    videoRef.current.seek(30); // Seeks to 30 seconds
  }
};

// In JSX:
<Video
  ref={videoRef}
  source={{ uri: 'https://example.com/video.mp4' }}
  useNativeControls
  onPlaybackStatusUpdate={status => {
    if (status.positionMillis >= 30000) {
      // Optional: Handle position reached
    }
  }}
/>
Note: The seek method works only if the video is loaded and ready to play.

10. Handling Buffering State

Property Description Values
buffering Indicates if the video is currently buffering true or false
buffered Information about the buffered time ranges Array<{ start: number, end: number }>
loading Indicates if the video is loading true or false

Example: Handling Buffering State

import React, { useState } from 'react';
import { Video } from 'expo-av';

const VideoPlayer = () => {
  const [isBuffering, setIsBuffering] = useState(false);
  const [bufferedTime, setBufferedTime] = useState([]);

  const onBuffer = (info) => {
    setIsBuffering(info.isBuffering);
    setBufferedTime(info.buffered);
  };

  return (
    <Video
      source={{ uri: 'https://example.com/video.mp4' }}
      onBuffer={onBuffer}
      useNativeControls
    />
  );
};

export default VideoPlayer;
Note: The onBuffer event provides real-time updates on buffering state, useful for UI feedback.

Was this article helpful?