Media items

The playlist API is based on MediaItem instances, which can be conveniently built using MediaItem.Builder. Inside the player, a MediaItem is converted into a playable MediaSource by a MediaSource.Factory. Without custom configuration, this conversion is carried out by a DefaultMediaSourceFactory, which is capable of building complex media sources corresponding to the properties of the media item. Some of the properties that can be set on media items are outlined below.

Simple media items

A media item consisting only of the stream URI can be built with the fromUri convenience method:

Kotlin

val mediaItem = MediaItem.fromUri(videoUri)

Java

MediaItem mediaItem = MediaItem.fromUri(videoUri);

For all other cases, a MediaItem.Builder can be used. In the following example, a media item is built with an ID and some attached metadata:

Kotlin

val mediaItem = MediaItem.Builder().setMediaId(mediaId).setTag(myAppData).setUri(videoUri).build()

Java

MediaItem mediaItem =
    new MediaItem.Builder().setMediaId(mediaId).setTag(myAppData).setUri(videoUri).build();

Attaching metadata can be useful for updating your app's UI when playlist transitions occur.

Handling non-standard file extensions

ExoPlayer provides adaptive media sources for DASH, HLS, and SmoothStreaming. If the URI of such an adaptive media item ends with a standard file extension, the corresponding media source is automatically created. If the URI has a non-standard extension or no extension at all, then the MIME type can be set explicitly to indicate the type of the media item:

Kotlin

val mediaItem = MediaItem.Builder().setUri(hlsUri).setMimeType(MimeTypes.APPLICATION_M3U8).build()

Java

MediaItem mediaItem =
    new MediaItem.Builder().setUri(hlsUri).setMimeType(MimeTypes.APPLICATION_M3U8).build();

For progressive media streams a MIME type is not required.

Protected content

For protected content, the media item's DRM properties should be set:

Kotlin

val mediaItem =
  MediaItem.Builder()
    .setUri(videoUri)
    .setDrmConfiguration(
      MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
        .setLicenseUri(licenseUri)
        .setMultiSession(true)
        .setLicenseRequestHeaders(httpRequestHeaders)
        .build()
    )
    .build()

Java

MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setDrmConfiguration(
            new MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID)
                .setLicenseUri(licenseUri)
                .setMultiSession(true)
                .setLicenseRequestHeaders(httpRequestHeaders)
                .build())
        .build();

This example builds a media item for Widevine protected content. Inside the player, DefaultMediaSourceFactory will pass these properties to a DrmSessionManagerProvider to obtain a DrmSessionManager, which is then injected into the created MediaSource. DRM behaviour can be further customized to your needs.

Sideloading subtitle tracks

To sideload subtitle tracks, MediaItem.Subtitle instances can be added when building a media item:

Kotlin

val subtitle =
  SubtitleConfiguration.Builder(subtitleUri)
    .setMimeType(mimeType) // The correct MIME type (required).
    .setLanguage(language) // The subtitle language (optional).
    .setSelectionFlags(selectionFlags) // Selection flags for the track (optional).
    .build()
val mediaItem =
  MediaItem.Builder().setUri(videoUri).setSubtitleConfigurations(listOf(subtitle)).build()

Java

MediaItem.SubtitleConfiguration subtitle =
    new MediaItem.SubtitleConfiguration.Builder(subtitleUri)
        .setMimeType(mimeType) // The correct MIME type (required).
        .setLanguage(language) // The subtitle language (optional).
        .setSelectionFlags(selectionFlags) // Selection flags for the track (optional).
        .build();
MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setSubtitleConfigurations(ImmutableList.of(subtitle))
        .build();

Internally, DefaultMediaSourceFactory will use a MergingMediaSource to combine the content media source with a SingleSampleMediaSource for each subtitle track. DefaultMediaSourceFactory does not support sideloading subtitles for multi-period DASH.

Clipping a media stream

To clip the content referred to by a media item, set custom start and end positions:

Kotlin

val mediaItem =
  MediaItem.Builder()
    .setUri(videoUri)
    .setClippingConfiguration(
      MediaItem.ClippingConfiguration.Builder()
        .setStartPositionMs(startPositionMs)
        .setEndPositionMs(endPositionMs)
        .build()
    )
    .build()

Java

MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setClippingConfiguration(
            new ClippingConfiguration.Builder()
                .setStartPositionMs(startPositionMs)
                .setEndPositionMs(endPositionMs)
                .build())
        .build();

Internally, DefaultMediaSourceFactory will use a ClippingMediaSource to wrap the content media source. There are additional clipping properties. See the MediaItem.Builder Javadoc for more details.

Ad insertion

To insert ads, a media item's ad tag URI property should be set:

Kotlin

val mediaItem =
  MediaItem.Builder()
    .setUri(videoUri)
    .setAdsConfiguration(MediaItem.AdsConfiguration.Builder(adTagUri).build())

Java

MediaItem mediaItem =
    new MediaItem.Builder()
        .setUri(videoUri)
        .setAdsConfiguration(new MediaItem.AdsConfiguration.Builder(adTagUri).build())
        .build();

Internally, DefaultMediaSourceFactory will wrap the content media source in an AdsMediaSource to insert ads as defined by the ad tag. For this to work, the the player also needs to have its DefaultMediaSourceFactory configured accordingly.