Android Exo Player Play .m3u8 from Android Resources - android

I am unable to play .m3u8 file from a web server like http://example.com/file.m3u8
I have added the play list file in android resource but it is not playing.
How to play the same file from local resources.
Thanks,

From ExoPlayer Demo:
public void init(Context context, PlayerView playerView) {
// Create a default track selector.
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
// Create a player instance.
player = ExoPlayerFactory.newSimpleInstance(context, trackSelector);
// Bind the player to the view.
playerView.setPlayer(player);
// This is the MediaSource representing the content media (i.e. not the ad).
String contentUrl = context.getString(R.string.content_url);
MediaSource contentMediaSource =
buildMediaSource(Uri.parse(contentUrl), /* handler= */ null, /* listener= */ null);
// Compose the content media source into a new AdsMediaSource with both ads and content.
MediaSource mediaSourceWithAds =
new AdsMediaSource(
contentMediaSource,
/* adMediaSourceFactory= */ this,
adsLoader,
playerView.getOverlayFrameLayout(),
/* eventHandler= */ null,
/* eventListener= */ null);
// Prepare the player with the source.
player.seekTo(contentPosition);
player.prepare(mediaSourceWithAds);
player.setPlayWhenReady(true);
}
Strings.xml:
<string name="content_url"><![CDATA[https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8]]></string>
Upd:
I'm not sure that using *.m3u8 files from local storage would be a good idea, but you can play with the media files from your apk:
1) raw
MediaSource contentMediaSource = buildMediaSource(
RawResourceDataSource.buildRawResourceUri(R.raw.sample_video),
/* handler= */ null, /* listener= */ null);
2) asset
MediaSource contentMediaSource = buildMediaSource(
Uri.fromFile(new File("//android_asset/sample_video.mp4")),
/* handler= */ null, /* listener= */ null);

Related

Exoplayer can't play only audio for HLS

I have link only audio https://storage.googleapis.com/as-piepme/1465/livestream/1465.fef238cdc9d9eb0b958d4eb23080e28b/index.m3u8 but Exoplayer can't play above link,
it return "source error". But both IOS and Chrome run fine. My code:
SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build();
player.setMediaItem(MediaItem.fromUri(Uri.parse(linkPlay)));
player.prepare();
player.setPlayWhenReady(true);
Update my solution:
MediaItem mediaItem = new MediaItem.Builder()
.setUri(Uri.parse("https://storage.googleapis.com/as-piepme/1465/livestream/1465.fef238cdc9d9eb0b958d4eb23080e28b/index.m3u8"))
.build();
DefaultHlsExtractorFactory defaultHlsExtractorFactory = new DefaultHlsExtractorFactory(DefaultTsPayloadReaderFactory.FLAG_IGNORE_H264_STREAM, false);
MediaSource mediaSource = new HlsMediaSource.Factory(new DefaultHlsDataSourceFactory(new DefaultDataSourceFactory(context)))
.setExtractorFactory(defaultHlsExtractorFactory)
.setAllowChunklessPreparation(true)
.createMediaSource(mediaItem);
player.setMediaSource(mediaSource);
You need to use a Media source.
Try this sample code.
DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory();
// Create a HLS media source pointing to a playlist uri.
HlsMediaSource hlsMediaSource =
new HlsMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(hlsUri));
// Create a player instance.
SimpleExoPlayer player = new SimpleExoPlayer.Builder(context).build();
// Set the media source to be played.
player.setMediaSource(hlsMediaSource);
// Prepare the player.
player.prepare();
For more details check the documentation.
Update
Use this one.
DefaultTrackSelector trackSelector = new DefaultTrackSelector(this, new AdaptiveTrackSelection.Factory());
DefaultTrackSelector.Parameters trackSelectorParameters = trackSelector.buildUponParameters().setMaxAudioChannelCount(0).build();
trackSelector.setParameters(trackSelectorParameters);
RenderersFactory renderersFactory = new DefaultRenderersFactory(this);
SimpleExoPlayer audioPlayer = = new SimpleExoPlayer.Builder(this, renderersFactory).setTrackSelector(trackSelector).build();
HttpDataSource.Factory factory = new DefaultHttpDataSourceFactory("Online Audio Player", DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS, DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS, true);
audioPlayer.setMediaSource(new ProgressiveMediaSource.Factory(factory).createMediaSource(MediaItem.fromUri("https://storage.googleapis.com/as-piepme/1465/livestream/1465.fef238cdc9d9eb0b958d4eb23080e28b/index.m3u8")));
audioPlayer.prepare();
audioPlayer.setPlayWhenReady(true);

Exoplayer - How to prevent rebuffering when it's on Repeat mode?

I'm using exoplayer 2, and have Repeat mode on, meaning it will keep playing the video once it reaches the end. However, after the video ends and plays again, it keeps rebuffering (reloading the video). How do I prevent this from happening?
player = new SimpleExoPlayer.Builder(mContext).build();
player.setPlayWhenReady(false);
player.setRepeatMode(Player.REPEAT_MODE_ONE);
Edit1:
Have tried using LoopingMediaSource, not sure if I am doing it correctly though?
Because it still rebuffers when it automatically replays the video.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(mContext,
Util.getUserAgent(mContext, "yourApplicationName"));
Uri uri = Uri.parse(mUrl);
MediaSource videoSource =
new ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(uri);
LoopingMediaSource loopingMediaSource = new LoopingMediaSource(videoSource);
player.prepare(loopingMediaSource);
When it comes to video buffering this is inevitable, as only a portion of the video is kept in memory.
What you can try is to adjust the buffering duration by setting a custom load control. Tune the setBufferDurationsMs parameters to achieve your expected results.
final DefaultTrackSelector trackSelector = new DefaultTrackSelector(context);
final DefaultLoadControl loadControl = new DefaultLoadControl
.Builder()
.setBufferDurationsMs(25000, 50000, 1500, 2000)
.build();
player = new SimpleExoPlayer
.Builder(context)
.setTrackSelector(trackSelector)
.setLoadControl(loadControl)
.build();
If by adjusting the parameters in setBufferDurationMs you can't still get the desired results, then you may need to implement the drip-feeding technique to improve rebuffering. Next a tutorial about how to implement such technique, targeted at ExoPlayer:
https://medium.com/#filipluch/how-to-improve-buffering-by-4-times-with-drip-feeding-technique-in-exoplayer-on-android-b59eb0c4d9cc
You need cache data in ExoPlayer
Create a custom cache data source factory
public class CacheDataSourceFactory implements DataSource.Factory {
private final Context context;
private final DefaultDataSourceFactory defaultDatasourceFactory;
private final long maxFileSize, maxCacheSize;
public CacheDataSourceFactory(Context context, long maxCacheSize, long maxFileSize) {
super();
this.context = context;
this.maxCacheSize = maxCacheSize;
this.maxFileSize = maxFileSize;
String userAgent = Util.getUserAgent(context, context.getString(R.string.app_name));
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
defaultDatasourceFactory = new DefaultDataSourceFactory(this.context,
bandwidthMeter,
new DefaultHttpDataSourceFactory(userAgent, bandwidthMeter));
}
#Override
public DataSource createDataSource() {
LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize);
SimpleCache simpleCache = new SimpleCache(new File(context.getCacheDir(), "media"), evictor);
return new CacheDataSource(simpleCache, defaultDatasourceFactory.createDataSource(),
new FileDataSource(), new CacheDataSink(simpleCache, maxFileSize),
CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR, null);
}
}
And the player
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector);
MediaSource audioSource = new ExtractorMediaSource(Uri.parse(url),
new CacheDataSourceFactory(context, 100 * 1024 * 1024, 5 * 1024 * 1024), new DefaultExtractorsFactory(), null, null);
exoPlayer.setPlayWhenReady(true);
exoPlayer.prepare(audioSource);
Try to use LoopingMediaSource and put it to player by:
player.prepare(loopingMediaSource)

How to re-add a mediasource after the exoplayer has been prepared?

I'm creating a playlist video player in exoplayer in android studio. I'm adding the first video extracted from a server and it is being played by the exoplayer perfectly. But when I add the second part, the exoplayer does not play that video. I want to add the second video after the exoplayer has been prepared. I want to know how to do that. Please Help me.
My MainActivity.java:
public class MainActivity extends AppCompatActivity
{
SimpleExoPlayer video_player;
PlayerView player_screen;
DefaultTrackSelector track_selector;
DefaultBandwidthMeter band_width_meter = new DefaultBandwidthMeter();
ArrayList<MediaSource> mediaSources_contents = new ArrayList<>();
ConcatenatingMediaSource concatenating_mediaSource_contents;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
player_screen = (PlayerView) findViewById(R.id.player_screen);
player_screen.requestFocus();
TrackSelection.Factory video_track_selection_factory = new AdaptiveTrackSelection.Factory(band_width_meter);
track_selector = new DefaultTrackSelector(video_track_selection_factory);
video_player = ExoPlayerFactory.newSimpleInstance(this, track_selector);
player_screen.setPlayer(video_player);
video_player.setPlayWhenReady(true);
Uri url1 = Uri.parse("THE - URL - OF - FIRST - VIDEO");
DataSource.Factory data_source_factory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "Application Name"), band_width_meter);
MediaSource source1 = new ExtractorMediaSource.Factory(data_source_factory).createMediaSource(url1);
mediaSources_contents.add(source1);
concatenating_mediaSource_contents = new ConcatenatingMediaSource(mediaSources_contents.toArray(new MediaSource[mediaSources_contents.size()]));
video_player.prepare(concatenating_mediaSource_contents);
// The lines below this point adds the second video to the media source. But it is not being played by the exoplayer.
Uri url2 = Uri.parse("THE - URL - OF - SECOND - VIDEO");
MediaSource source2 = new ExtractorMediaSource.Factory(data_source_factory).createMediaSource(url2);
mediaSources_contents.add(source2);
}
}
At Prepared Time
Initialize ConcatenatingMediaSource
ConcatenatingMediaSource mediaSource = new ConcatenatingMediaSource();
MediaSource firstSource = new ProgressiveMediaSource.Factory(new FileDataSourceFactory()).createMediaSource(Uri.parse(uri.get(0)));
MediaSource secondSource= new ProgressiveMediaSource.Factory(new FileDataSourceFactory()).createMediaSource(Uri.parse(uri.get(1)));
mediaSource.addMediaSources(firstSource);
mediaSource.addMediaSources(secondSource);
player.prepare(mediaSource, true, false);
After Prepare Add mediasource
MediaSource thirdSource= new ProgressiveMediaSource.Factory(new FileDataSourceFactory()).createMediaSource(Uri.parse(uri.get(3)));
mediaSource.addMediaSources(thirdSource);// mediaSource is refrance of ConcatenatingMediaSource
Try add this concatenating_mediaSource_contents.addMediaSource(source2); instead mediaSources_contents.add(source2);and for first media source also (not necessary, for better readability)

How to auto start a video using exoplayer?

I have a video loaded in a com.google.android.exoplayer2.ui.SimpleExoPlayerView view but I want to make it automatically start when the view loads. Right now, the user has to click the play button.
SimpleExoPlayer works well with a SurfaceView, there are methods to set the surface of the player.
This is how I create the SimpleExoPlayer:
/** Create a default TrackSelector **/
TrackSelector trackSelector = new DefaultTrackSelector(new Handler());
/** Create a default LoadControl **/
LoadControl loadControl = new DefaultLoadControl();
/** Create the player **/
mPlayer = ExoPlayerFactory.newSimpleInstance(context, trackSelector, loadControl);
/** Make the ExoPlayer play when its data source is prepared **/
mPlayer.setPlayWhenReady(true);
I hold these factories so I don't have to create them each time I set a new data source.
/** Produces Extractor instances for parsing the media data **/
mExtractorsFactory = new DefaultExtractorsFactory();
/** Produces DataSource instances through which media data is loaded **/
mDataSourceFactory = new DefaultDataSourceFactory(
context, Util.getUserAgent(context, "AppName")
);
I use the following method to set a new data source on the player. This method uses the factories created earlier.
For me, the String source is a URI to an MP4 file held on the device's SD card. Having setPlayWhenReady(true) earlier, once this video is prepared & ready to play it will begin immediately.
public void setDataSource(SurfaceView view, String source) {
stopMedia();
mPlayer.setVideoSurfaceView(view);
view.requestFocus();
// Create the media source
mVideoSource = new ExtractorMediaSource(Uri.fromFile(
new File(source)),
mDataSourceFactory, mExtractorsFactory, null, null);
// Prepare the player with the source.
mPlayer.prepare(mVideoSource);
}
just use:
player.setRepeatMode(Player.REPEAT_MODE_ALL);

How to detect HLS video is for Live, VOD or Event in Exoplayer android

I have integrated android exoplayer in my application. I have to detect the HLS (.m3u8) stream received is for Live or VOD or Event, so depending on that controller has to be modified for the player. I have only one instance of player so that should handle all the supported media like vod or live or event.
I am looking for some debug points to know working of m3u8 parser in exoplayer so that I can able to receive this parameters.
You can use below code to play .m3u8 file:-
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
//Create the player using ExoPlayerFactory
videoPlayer = ExoPlayerFactory.newSimpleInstance(context,trackSelector);
Handler mHandler = new Handler();
String userAgent = Util.getUserAgent(context, "Exo Player");
DataSource.Factory dataSourceFactory = new DefaultHttpDataSourceFactory(
userAgent, null,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
1800000,
true);
HlsMediaSource mediaSource = new HlsMediaSource(Uri.parse(mediaUrl),dataSourceFactory, 1800000,mHandler, null);
if (mediaUrl != null) {
videoPlayer.prepare(mediaSource);
videoPlayer.setPlayWhenReady(true);
}
Live vs Event differentiation is not supported, yet. For Live vs Event you can check the current Timeline, but that's not HLS specific. For distinguish a live stream from a vod one by querying the player's duration after it is prepared. Live streams will return UNKNOWN_TIME, where-as vod streams will return the known duration of the stream.

Categories

Resources