1*30877f79SAndroid Build Coastguard Worker--- 2*30877f79SAndroid Build Coastguard Workertitle: Media items 3*30877f79SAndroid Build Coastguard Worker--- 4*30877f79SAndroid Build Coastguard Worker 5*30877f79SAndroid Build Coastguard WorkerThe [playlist API][] is based on `MediaItem`s, which can be conveniently built 6*30877f79SAndroid Build Coastguard Workerusing `MediaItem.Builder`. Inside the player, media items are converted into 7*30877f79SAndroid Build Coastguard Workerplayable `MediaSource`s by a `MediaSource.Factory`. Without 8*30877f79SAndroid Build Coastguard Worker[custom configuration]({{ site.baseurl }}/media-sources.html#customizing-media-source-creation), 9*30877f79SAndroid Build Coastguard Workerthis conversion is carried out by a `DefaultMediaSourceFactory`, which is 10*30877f79SAndroid Build Coastguard Workercapable of building complex media sources corresponding to the properties of the 11*30877f79SAndroid Build Coastguard Workermedia item. Some of the properties that can be set on media items are outlined 12*30877f79SAndroid Build Coastguard Workerbelow. 13*30877f79SAndroid Build Coastguard Worker 14*30877f79SAndroid Build Coastguard Worker## Simple media items ## 15*30877f79SAndroid Build Coastguard Worker 16*30877f79SAndroid Build Coastguard WorkerA media item consisting only of the stream URI can be built with the `fromUri` 17*30877f79SAndroid Build Coastguard Workerconvenience method: 18*30877f79SAndroid Build Coastguard Worker 19*30877f79SAndroid Build Coastguard Worker~~~ 20*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = MediaItem.fromUri(videoUri); 21*30877f79SAndroid Build Coastguard Worker~~~ 22*30877f79SAndroid Build Coastguard Worker{: .language-java} 23*30877f79SAndroid Build Coastguard Worker 24*30877f79SAndroid Build Coastguard WorkerFor all other cases a `MediaItem.Builder` can be used. In the example below, a 25*30877f79SAndroid Build Coastguard Workermedia item is built with an ID and some attached metadata: 26*30877f79SAndroid Build Coastguard Worker 27*30877f79SAndroid Build Coastguard Worker~~~ 28*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = new MediaItem.Builder() 29*30877f79SAndroid Build Coastguard Worker .setUri(videoUri) 30*30877f79SAndroid Build Coastguard Worker .setMediaId(mediaId) 31*30877f79SAndroid Build Coastguard Worker .setTag(metadata) 32*30877f79SAndroid Build Coastguard Worker .build(); 33*30877f79SAndroid Build Coastguard Worker~~~ 34*30877f79SAndroid Build Coastguard Worker{: .language-java} 35*30877f79SAndroid Build Coastguard Worker 36*30877f79SAndroid Build Coastguard WorkerAttaching metadata can be useful for 37*30877f79SAndroid Build Coastguard Worker[updating your app's UI]({{ site.baseurl }}/playlists.html#detecting-when-playback-transitions-to-another-media-item) 38*30877f79SAndroid Build Coastguard Workerwhen playlist transitions occur. 39*30877f79SAndroid Build Coastguard Worker 40*30877f79SAndroid Build Coastguard Worker## Handling non-standard file extensions 41*30877f79SAndroid Build Coastguard Worker 42*30877f79SAndroid Build Coastguard WorkerThe ExoPlayer library provides adaptive media sources for DASH, HLS and 43*30877f79SAndroid Build Coastguard WorkerSmoothStreaming. If the URI of such an adaptive media item ends with a standard 44*30877f79SAndroid Build Coastguard Workerfile extension, the corresponding media source is automatically created. If the 45*30877f79SAndroid Build Coastguard WorkerURI has a non-standard extension or no extension at all, then the MIME type can 46*30877f79SAndroid Build Coastguard Workerbe set explicitly to indicate the type of the media item: 47*30877f79SAndroid Build Coastguard Worker 48*30877f79SAndroid Build Coastguard Worker~~~ 49*30877f79SAndroid Build Coastguard Worker// Use the explicit MIME type to build an HLS media item. 50*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = new MediaItem.Builder() 51*30877f79SAndroid Build Coastguard Worker .setUri(hlsUri) 52*30877f79SAndroid Build Coastguard Worker .setMimeType(MimeTypes.APPLICATION_M3U8) 53*30877f79SAndroid Build Coastguard Worker .build(); 54*30877f79SAndroid Build Coastguard Worker~~~ 55*30877f79SAndroid Build Coastguard Worker{: .language-java} 56*30877f79SAndroid Build Coastguard Worker 57*30877f79SAndroid Build Coastguard WorkerFor progressive media streams a MIME type is not required. 58*30877f79SAndroid Build Coastguard Worker 59*30877f79SAndroid Build Coastguard Worker## Protected content ## 60*30877f79SAndroid Build Coastguard Worker 61*30877f79SAndroid Build Coastguard WorkerFor protected content, the media item's DRM properties should be set: 62*30877f79SAndroid Build Coastguard Worker 63*30877f79SAndroid Build Coastguard Worker~~~ 64*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = new MediaItem.Builder() 65*30877f79SAndroid Build Coastguard Worker .setUri(videoUri) 66*30877f79SAndroid Build Coastguard Worker .setDrmConfiguration( 67*30877f79SAndroid Build Coastguard Worker new MediaItem.DrmConfiguration.Builder(C.WIDEVINE_UUID) 68*30877f79SAndroid Build Coastguard Worker .setLicenseUri(licenseUri) 69*30877f79SAndroid Build Coastguard Worker .setMultiSession(true) 70*30877f79SAndroid Build Coastguard Worker .setLicenseRequestHeaders(httpRequestHeaders) 71*30877f79SAndroid Build Coastguard Worker .build()) 72*30877f79SAndroid Build Coastguard Worker .build(); 73*30877f79SAndroid Build Coastguard Worker~~~ 74*30877f79SAndroid Build Coastguard Worker{: .language-java} 75*30877f79SAndroid Build Coastguard Worker 76*30877f79SAndroid Build Coastguard WorkerThis example builds a media item for Widevine protected content. Inside the 77*30877f79SAndroid Build Coastguard Workerplayer, `DefaultMediaSourceFactory` will pass these properties to a 78*30877f79SAndroid Build Coastguard Worker`DrmSessionManagerProvider` to obtain a `DrmSessionManager`, which is then 79*30877f79SAndroid Build Coastguard Workerinjected into the created `MediaSource`. DRM behaviour can be 80*30877f79SAndroid Build Coastguard Worker[further customized]({{ site.baseurl }}/drm.html#using-a-custom-drmsessionmanager) 81*30877f79SAndroid Build Coastguard Workerto your needs. 82*30877f79SAndroid Build Coastguard Worker 83*30877f79SAndroid Build Coastguard Worker## Sideloading subtitle tracks ## 84*30877f79SAndroid Build Coastguard Worker 85*30877f79SAndroid Build Coastguard WorkerTo sideload subtitle tracks, `MediaItem.Subtitle` instances can be added when 86*30877f79SAndroid Build Coastguard Workerwhen building a media item: 87*30877f79SAndroid Build Coastguard Worker 88*30877f79SAndroid Build Coastguard Worker~~~ 89*30877f79SAndroid Build Coastguard WorkerMediaItem.SubtitleConfiguration subtitle = 90*30877f79SAndroid Build Coastguard Worker new MediaItem.SubtitleConfiguration.Builder(subtitleUri) 91*30877f79SAndroid Build Coastguard Worker .setMimeType(MimeTypes.APPLICATION_SUBRIP) // The correct MIME type (required). 92*30877f79SAndroid Build Coastguard Worker .setLanguage(language) // The subtitle language (optional). 93*30877f79SAndroid Build Coastguard Worker .setSelectionFlags(selectionFlags) // Selection flags for the track (optional). 94*30877f79SAndroid Build Coastguard Worker .build(); 95*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = 96*30877f79SAndroid Build Coastguard Worker new MediaItem.Builder() 97*30877f79SAndroid Build Coastguard Worker .setUri(videoUri) 98*30877f79SAndroid Build Coastguard Worker .setSubtitleConfigurations(ImmutableList.of(subtitle)) 99*30877f79SAndroid Build Coastguard Worker .build(); 100*30877f79SAndroid Build Coastguard Worker~~~ 101*30877f79SAndroid Build Coastguard Worker{: .language-java} 102*30877f79SAndroid Build Coastguard Worker 103*30877f79SAndroid Build Coastguard WorkerInternally, `DefaultMediaSourceFactory` will use a `MergingMediaSource` to 104*30877f79SAndroid Build Coastguard Workercombine the content media source with a `SingleSampleMediaSource` for each 105*30877f79SAndroid Build Coastguard Workersubtitle track. 106*30877f79SAndroid Build Coastguard Worker 107*30877f79SAndroid Build Coastguard Worker## Clipping a media stream ## 108*30877f79SAndroid Build Coastguard Worker 109*30877f79SAndroid Build Coastguard WorkerIt's possible to clip the content referred to by a media item by setting custom 110*30877f79SAndroid Build Coastguard Workerstart and end positions: 111*30877f79SAndroid Build Coastguard Worker 112*30877f79SAndroid Build Coastguard Worker~~~ 113*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = 114*30877f79SAndroid Build Coastguard Worker new MediaItem.Builder() 115*30877f79SAndroid Build Coastguard Worker .setUri(videoUri) 116*30877f79SAndroid Build Coastguard Worker .setClippingConfiguration( 117*30877f79SAndroid Build Coastguard Worker new ClippingConfiguration.Builder() 118*30877f79SAndroid Build Coastguard Worker .setStartPositionMs(startPositionMs) 119*30877f79SAndroid Build Coastguard Worker .setEndPositionMs(endPositionMs) 120*30877f79SAndroid Build Coastguard Worker .build()) 121*30877f79SAndroid Build Coastguard Worker .build(); 122*30877f79SAndroid Build Coastguard Worker~~~ 123*30877f79SAndroid Build Coastguard Worker{: .language-java} 124*30877f79SAndroid Build Coastguard Worker 125*30877f79SAndroid Build Coastguard WorkerInternally, `DefaultMediaSourceFactory` will use a `ClippingMediaSource` to wrap 126*30877f79SAndroid Build Coastguard Workerthe content media source. There are additional clipping properties. See the 127*30877f79SAndroid Build Coastguard Worker[`MediaItem.Builder` Javadoc][] for more details. 128*30877f79SAndroid Build Coastguard Worker 129*30877f79SAndroid Build Coastguard WorkerWhen clipping the start of a video file, try to align the start position with a 130*30877f79SAndroid Build Coastguard Workerkeyframe if possible. If the start position is not aligned with a keyframe then 131*30877f79SAndroid Build Coastguard Workerthe player will need to decode and discard data from the previous keyframe up to 132*30877f79SAndroid Build Coastguard Workerthe start position before playback can begin. This will introduce a short delay 133*30877f79SAndroid Build Coastguard Workerat the start of playback, including when the player transitions to playing a 134*30877f79SAndroid Build Coastguard Workerclipped media source as part of a playlist or due to looping. 135*30877f79SAndroid Build Coastguard Worker{:.info} 136*30877f79SAndroid Build Coastguard Worker 137*30877f79SAndroid Build Coastguard Worker## Ad insertion ## 138*30877f79SAndroid Build Coastguard Worker 139*30877f79SAndroid Build Coastguard WorkerTo insert ads, a media item's ad tag URI property should be set: 140*30877f79SAndroid Build Coastguard Worker 141*30877f79SAndroid Build Coastguard Worker~~~ 142*30877f79SAndroid Build Coastguard WorkerMediaItem mediaItem = new MediaItem.Builder() 143*30877f79SAndroid Build Coastguard Worker .setUri(videoUri) 144*30877f79SAndroid Build Coastguard Worker .setAdsConfiguration( 145*30877f79SAndroid Build Coastguard Worker new MediaItem.AdsConfiguration.Builder(adTagUri).build()) 146*30877f79SAndroid Build Coastguard Worker .build(); 147*30877f79SAndroid Build Coastguard Worker~~~ 148*30877f79SAndroid Build Coastguard Worker{: .language-java} 149*30877f79SAndroid Build Coastguard Worker 150*30877f79SAndroid Build Coastguard WorkerInternally, `DefaultMediaSourceFactory` will wrap the content media source in an 151*30877f79SAndroid Build Coastguard Worker`AdsMediaSource` to insert ads as defined by the ad tag. For this to work, the 152*30877f79SAndroid Build Coastguard Workerthe player also needs to have its `DefaultMediaSourceFactory` 153*30877f79SAndroid Build Coastguard Worker[configured accordingly]({{ site.baseurl }}/ad-insertion.html#declarative-ad-support). 154*30877f79SAndroid Build Coastguard Worker 155*30877f79SAndroid Build Coastguard Worker[playlist API]: {{ site.baseurl }}/playlists.html 156*30877f79SAndroid Build Coastguard Worker[`MediaItem.Builder` Javadoc]: {{ site.exo_sdk }}/MediaItem.Builder.html 157