In my app there is a recyclerview that with an exoplayer. When I leave my app or change the screen, the video keeps playing. I need to make it pause when I leave the screen.
I tried using the onViewRecycled method but the video is only paused when I return to the screen where the video is playing.
#Override
public void onViewRecycled(#NonNull MyViewHolder holder) {
super.onViewRecycled(holder);
if (holder.simpleExoPlayer != null) {
holder.positionExo = holder.simpleExoPlayer.getCurrentPosition();
holder.simpleExoPlayer.setPlayWhenReady(false);
}
}
My Adapter:
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
//...
holder.simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(context);
// Bind the player to the view.
holder.videoCnt.setPlayer(holder.simpleExoPlayer);
holder.videoUri = Uri.parse(content.getVideo());
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context,
Util.getUserAgent(context, context.getString( R.string.app_name)));
// This is the MediaSource representing the media to be played.
MediaSource videoSource = new ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(holder.videoUri);
// Prepare the player with the source.
holder.simpleExoPlayer.prepare(videoSource);
//...
}
How to pause the video correctly?
Related
I want to play Videos in my RecyclerView Items, kind of like Instagram. There is only one Item expanded at a time so the Videos don't have to be played at the same time.
Im currently using the ExoPlayer. I have a PlayerView inside my item for the RecyclerView.
The problem is, with the Player I have bad performance which is very bad when scrolling and expanding. The Performany is already bad with just having the Player in the item without loading and playing a Video but it gets even worse with loading it.
I have tried VideoView too but it doesn't seem to make a big difference.
To achieve a better performance I already do:
recyclerView.setHasFixedSize(true);
recyclerView.setItemViewCacheSize(10);
recyclerView.setDrawingCacheEnabled(true);
recyclerView.setDrawingCacheQuality(View.DRAWING_CACHE_QUALITY_HIGH);
adapter.hasStableIds();
This helps a little bit but its doesn't solve the performance problem.
Any Idea what the problem can be? I appreciate and thoughts.
EDIT:
this is the method I setup the ExoPlayer:
public void showTutuorItems(Context context, Boolean show, String resource) {
if (show) {
seperator.setVisibility(View.VISIBLE);
lytTutor.setVisibility(View.VISIBLE);
playerView = itemView.findViewById(R.id.exoPlayer);
playerView.setUseController(false);
playerView = itemView.findViewById(R.id.exoPlayer);
playerView.setUseController(false);
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(context),
new DefaultTrackSelector(), new DefaultLoadControl());
playerView.setPlayer(player);
player.setPlayWhenReady(true);
player.seekTo(0, 0);
player.setRepeatMode(Player.REPEAT_MODE_ALL);
player.setVolume(0);
Uri uri = Uri.parse(resource);
MediaSource mediaSource = buildMediaSource(uri);
player.prepare(mediaSource, true, false);
player.addListener(new Player.EventListener() {
//...
}
} else {
seperator.setVisibility(View.GONE);
lytTutor.setVisibility(View.GONE);
}
}
private MediaSource buildMediaSource(Uri uri) {
return new ExtractorMediaSource.Factory(
new DefaultHttpDataSourceFactory("exoplayer-codelab")).
createMediaSource(uri);
}
and this is in my OnCreateViewHolder to call this method:
if (workout.getCurrentExercsise().getTutor() != null) {
holder.showTutuorItems(activity, true, workout.getCurrentExercsise().getTutor().getItems().get(0).getResource());
} else {
holder.showTutuorItems(activity, false, null);
}
In my OnBindViewHolder is some UI stuff and handling the expand/collapse function. This shouldn't cause the problem because without the ExoPlayer it works just fine.
I am currently developing a live and movie player application. I chose ExoPlayer version 2 to play the movie and I do not know much about it. I want to let the user choose the quality of a movie on the player screen, for example, 720p or 1080p or etc.
But I do not know how to get a list of existing qualities and show them to the user.
and the below code is my implementation of SimpleExoPlayer :
private void initPlayer(String path){
Handler handler = new Handler();
// 1. Create a default TrackSelector
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveVideoTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
player = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
SimpleExoPlayerView playerView = (SimpleExoPlayerView) findViewById(R.id.player_view);
playerView.setPlayer(player);
playerView.setKeepScreenOn(true);
// Produces DataSource instances through which media data is loaded.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this, "ExoPlayer"));
// This is the MediaSource representing the media to be played.
MediaSource videoSource = new HlsMediaSource(Uri.parse(path),
dataSourceFactory,handler, null);
// Prepare the player with the source.
player.addListener(this);
player.prepare(videoSource);
playerView.requestFocus();
player.setPlayWhenReady(true); // to play video when ready. Use false to pause a video
}
// ExoPlayer Listener Methods :
#Override
public void onTimelineChanged(Timeline timeline, Object manifest) {
}
#Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
}
#Override
public void onLoadingChanged(boolean isLoading) {
}
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
switch (playbackState) {
case ExoPlayer.STATE_BUFFERING:
//You can use progress dialog to show user that video is preparing or buffering so please wait
progressBar.setVisibility(View.VISIBLE);
break;
case ExoPlayer.STATE_IDLE:
//idle state
break;
case ExoPlayer.STATE_READY:
// dismiss your dialog here because our video is ready to play now
progressBar.setVisibility(GONE);
//Toast.makeText(getApplicationContext(),String.valueOf(player.getCurrentTrackSelections().get(0).getSelectedFormat().bitrate),Toast.LENGTH_SHORT).show();
break;
case ExoPlayer.STATE_ENDED:
// do your processing after ending of video
break;
}
}
#Override
public void onPlayerError(ExoPlaybackException error) {
// show user that something went wrong. it can be a dialog
}
#Override
public void onPositionDiscontinuity() {
}
please help to solve this issue.
thanks a lot.
Everything you'd like to achieve is viewable in the ExoPlayer2 demo app. More specifically the PlayerActivity class.
You can also check out this good article on the topic.
The core points you'll want to look into are around track selection (via the TrackSelector) as well as the TrackSelectionHelper. I'll include the important code samples below which will hopefully be enough to get you going. But ultimately just following something similar in the demo app will get you where you need to be.
You'll hold onto the track selector you init the player with and use that for just about everything.
Below is just a block of code to ideally cover the gist of what you're trying to do since the demo does appear to over-complicate things a hair. Also I haven't run the code, but it's close enough.
// These two could be fields OR passed around
int videoRendererIndex;
TrackGroupArray trackGroups;
// This is the body of the logic for see if there are even video tracks
// It also does some field setting
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
for (int i = 0; i < mappedTrackInfo.length; i++) {
TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(i);
if (trackGroups.length != 0) {
switch (player.getRendererType(i)) {
case C.TRACK_TYPE_VIDEO:
videoRendererIndex = i;
return true;
}
}
}
// This next part is actually about getting the list. It doesn't include
// some additional logic they put in for adaptive tracks (DASH/HLS/SS),
// but you can look at the sample for that (TrackSelectionHelper#buildView())
// Below you'd be building up items in a list. This just does
// views directly, but you could just have a list of track names (with indexes)
for (int groupIndex = 0; groupIndex < trackGroups.length; groupIndex++) {
TrackGroup group = trackGroups.get(groupIndex);
for (int trackIndex = 0; trackIndex < group.length; trackIndex++) {
if (trackIndex == 0) {
// Beginning of a new set, the demo app adds a divider
}
CheckedTextView trackView = ...; // The TextView to show in the list
// The below points to a util which extracts the quality from the TrackGroup
trackView.setText(DemoUtil.buildTrackName(group.getFormat(trackIndex)));
}
// Assuming you tagged the view with the groupIndex and trackIndex, you
// can build your override with that info.
Pair<Integer, Integer> tag = (Pair<Integer, Integer>) view.getTag();
int groupIndex = tag.first;
int trackIndex = tag.second;
// This is the override you'd use for something that isn't adaptive.
override = new SelectionOverride(FIXED_FACTORY, groupIndex, trackIndex);
// Otherwise they call their helper for adaptives, which roughly does:
int[] tracks = getTracksAdding(override, trackIndex);
TrackSelection.Factory factory = tracks.length == 1 ? FIXED_FACTORY : adaptiveTrackSelectionFactory;
override = new SelectionOverride(factory, groupIndex, tracks);
// Then we actually set our override on the selector to switch the quality/track
selector.setSelectionOverride(rendererIndex, trackGroups, override);
As I mentioned above, this is a slight oversimplification of the process, but the core part is that you're messing around with the TrackSelector, SelectionOverride, and Track/TrackGroups to get this to work.
You could conceivably copy the demo code verbatim and it should work, but I'd highly recommend taking the time to understand what each piece is doing and tailor your solution to your use case.
If I had more time I'd get it to compile and run. But if you can get my sample going then feel free to edit my post.
Hope that helps :)
I avoid the way as above posted. My way is using the DefaultTrackSelector as follows:
trackSelector.setParameters(trackSelector.getParameters()
.withMaxVideoBitrate(bitrate)
.withMaxVideoSize(width, height));
I've tested with HLS videos and it seems to perform in the right way. I get the bitrate, width and height reading from the HlsManifest.
You can copy the sample codes form this link.
ExoPlayer Video Quality Control.
Note : Do not forget to add the exoplayer dependencies in the built.gradle file
implementation 'com.google.android.exoplayer:exoplayer-core:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.16.1'
implementation 'com.google.android.exoplayer:exoplayer:2.16.1'
I want to connect my implementation of exoplayer with the media session object. I set up a SimpleExoPlayerView to show a video. Every time a button is clicked, I want the media session callbacks to fire. I can only get the callbacks to fire when something like a pair of headphones is used. The code used in the app is written below
#OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void setUp(LifecycleOwner lifecycleOwner){
// Create a MediaSessionCompat
Log.i("Hoe8", "lco setup called");
mMediaSession = new MediaSessionCompat(activity, "this");
// Enable callbacks from MediaButtons and TransportControls
mMediaSession.setFlags(
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
// Do not let MediaButtons restart the player when the app is not visible
mMediaSession.setMediaButtonReceiver(null);
// Set an initial PlaybackState with ACTION_PLAY, so media buttons can start the player
mStateBuilder = new PlaybackStateCompat.Builder()
.setActions(
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PLAY_PAUSE);
mMediaSession.setPlaybackState(mStateBuilder.build());
// MySessionCallback has methods that handle callbacks from a media controller
mMediaSession.setCallback(new MediaSessionCompat.Callback() {
#Override
public void onPlay() {
super.onPlay();
Log.i("Hoe8", "MediaSession callback play called");
mMediaSession.setActive(true);
((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(true);
((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(true);
}
#Override
public void onPause() {
super.onPause();
((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
}
#Override
public void onStop() {
super.onStop();
mMediaSession.setActive(false);
((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(false);
}
});
// Create a MediaControllerCompat
MediaControllerCompat mediaController =
new MediaControllerCompat(activity, mMediaSession);
MediaControllerCompat.setMediaController(activity, mediaController);
//Handler mainHandler = new Handler();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
// 2. Create the player
player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector);
playerView.setPlayer(player);
MediaSessionConnector mediaSessionConnector =
new MediaSessionConnector(mMediaSession);
mediaSessionConnector.setPlayer(player, null,null );
}
Made some changes to the code
public class VideoLifeCyclerObserver implements LifecycleObserver {
MediaSessionCompat mMediaSession;
PlaybackStateCompat.Builder mStateBuilder;
AppCompatActivity activity;
SimpleExoPlayerView playerView;
SimpleExoPlayer player;
ExoPlayer.ExoPlayerComponent rv;
MediaSessionConnector mediaSessionConnector;
public VideoLifeCyclerObserver(AppCompatActivity activity, SimpleExoPlayerView playerView, ExoPlayer.ExoPlayerComponent rv){
this.activity = activity;
this.playerView = playerView;
this.activity.getLifecycle().addObserver(this);
this.rv = rv;
Log.i("Hoe8","video lco created");
}
#OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
public void setUp(LifecycleOwner lifecycleOwner){
// Create a MediaSessionCompat
Log.i("Hoe8", "lco setup called");
mMediaSession = new MediaSessionCompat(activity, "this");
// Create a MediaControllerCompat
MediaControllerCompat mediaController =
new MediaControllerCompat(activity, mMediaSession);
MediaControllerCompat.setMediaController(activity, mediaController);
mediaSessionConnector =
new MediaSessionConnector(mMediaSession, new PlayBackController());
}
#OnLifecycleEvent(Lifecycle.Event.ON_START)
public void startPlayer(LifecycleOwner lifecycleOwner){
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector =
new DefaultTrackSelector(videoTrackSelectionFactory);
player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector);
playerView.setPlayer(player);
mediaSessionConnector.setPlayer(player, null,null );
}
#OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
public void tearDown(LifecycleOwner lifecycleOwner){
player.stop();
player.release();
player.sendMessages(new ExoPlayer.ExoPlayerMessage(rv,1,player.getContentPosition()));
}
public class PlayBackController extends DefaultPlaybackController{
#Override
public void onPause(Player player) {
Log.i("Hoe8", "onPause called");
((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
super.onPause(player);
}
#Override
public void onPlay(Player player) {
Log.i("Hoe8", "MediaSession callback play called 2");
mMediaSession.setActive(true);
((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(true);
((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(true);
super.onPlay(player);
}
#Override
public void onStop(Player player) {
Log.i("Hoe8", "onStop called");
mMediaSession.setActive(false);
((JokesAdapter.VideoPostViewHolder) rv).setIsPlaying(false);
((JokesAdapter.VideoPostViewHolder) rv).setHasStarted(false);
super.onStop(player);
}
}
}
How can I get the buttons that show in the SimpleExoPlayerView to fire the media session callbacks?
In short:
delete all code in your onCreate starting from (inclusive)
// Enable callbacks from MediaButtons and TransportControls
to (exclusive)
// Create a MediaControllerCompat
:)
More lengthy:
I recommend firing media session callbacks by listening to state transitions of the player instead of by click on buttons. This saves you from doing this for each UI element interacting with the player. That's actually what the MediaSessionConnector does for you.
With the MediaSessionConnector you do not need to manipulate the MediaSession yourself. The connector mediates between the player instance and the media session. This means the connector listens to state transitions of the player and maps the player state to the media session state. The connector also listens for media actions sent by transport controls and delegates them to the player or your app. Note: Your app does not need to provide a MediaSessionCompat.Callback, the connector registers its own (and overrides yours as there can be only one per session).
In general: your app does only interact with the SimpleExoPlayer instance while the connector maps the player state to the session.
Let's start with the basic approach which maps the state of the player to the session which triggers appropriate MediaControllerCompat.Callback methods:
// code running in a activity or service where (this instanceof Context)
mediaSession = new MediaSessionCompat(this, getPackageName());
mediaSessionConnector = new MediaSessionConnector(mediaSession)
mediaSessionConnector.setPlayer(player, null, null);
mediaSession.setActive(true);
You can now prepare and use the player like before, like call setPlayWhenReady(true|false), seekTo(t) and the connector maintains the PlaybackStateCompat which is broadcast to controllers of the session.
The connector does receive and implement a couple of media actions at this level (no need for your own MediaSession.Callback):
PlaybackStateCompat.ACTION_PLAY_PAUSE |
PlaybackStateCompat.ACTION_PLAY |
PlaybackStateCompat.ACTION_PAUSE |
PlaybackStateCompat.ACTION_STOP |
PlaybackStateCompat.ACTION_SET_SHUFFLE_MODE |
PlaybackStateCompat.ACTION_SET_REPEAT_MODE;
PlayFromXYZ actions
You may want to support additional media actions like ACTION_PLAY_FROM_MEDIA_ID. You can do so by providing your PlaybackPreparer:
playbackPreparer = new YourPlaybackPreparer();
mediaSessionConnector.setPlayer(player, playbackPreparer, null);
The connector now delegates actions like ACTION_PLAY_FROM_MEDIA_ID or ACTION_PREPARE_FROM_MEDIA_ID to your playback preparer which creates a MediaSource for the given media ID to prepare the player.
Metadata and Queue management
Also interesting is the ability to map the Timeline of the player directly to queue and metadata of the media session. To do this you can provide a QueueNavigator. There is an abstract TimelineQueueNavigator provided by the extension:
QueueNavigator queueNavigator = new TimelineQueueNavigator(mediaSession) {
#Override
public MediaDescriptionCompat getMediaDescription(int windowIndex) {
// implement this method and read from your backing data:
getMediaDescriptionAtQueuePosition(windowIndex):
return mediaDescription;
}
}
mediaSessionConnector.setQueueNavigator(queueNavigator);
With this media controllers can now read metadata and queue of the session. The queue represents the current Timeline of the player and the metadata of the session describes the window in the Timeline which is currently playing. (more about playlists).
Provided a TimelineQueueNavigator, the connector listens for ACTION_SKIP_TO_NEXT, ACTION_SKIP_TO_PREVIOUS and ACTION_SKIP_TO_QUEUE_ITEM sent by transport controls and navigates along the timeline accordingly.
Lifecycle integration
Please note that you must create the player instance onStart/onResume and release it onPause/onStop. This makes sure codec resources you share with other apps are freed when you are in background. Your code sample does it only once onCreate which is not good citizenship :). See how the ExoPlayer demo app does it.
Please also consider the Medium blog about the MediaSessionConnector.
I want to play the video one by one from my sdcard using Texture view in android. I am using tetureview bcoz , I want to rotate the video at 90 degree.. so I can play the rotated video on device by implementing SurfaceTextureListener interface.
This is the code:
#Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
root = Environment.getExternalStorageDirectory();
ArrayList extList = new ArrayList<String>();
extList.add("mp4");
extList.add("3gp");
extList.add("ts");
extList.add("webm");
extList.add("mkv");
Intent intent = getIntent();
Bundle b = intent.getExtras();
vFiles = b.getStringArrayList("vFiles");
System.out.println("VFiles: " + vFiles);
iterator = vFiles.iterator();
videoPath = root + "/Video/";
if (iterator.hasNext()) {
System.out.println("Inside iterator: .......................................");
String video = videoPath + iterator.next();
mMediaPlayer = new MediaPlayer();
//mMediaPlayer.setDataSource(afd.getFileDescriptor(),
// afd.getStartOffset(), afd.getLength());
mMediaPlayer.setDataSource(video);
System.out.println("After Datasource: " + video);
mMediaPlayer.setSurface(sur);
// mMediaPlayer.setLooping(true);
mMediaPlayer.prepareAsync();
// mMediaPlayer.setOnBufferingUpdateListener((OnBufferingUpdateListener) this);
mMediaPlayer.setOnPreparedListener(this);
mMediaPlayer.setOnCompletionListener(this);
// Play video when the media source is ready for playback.
mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mediaPlayer) {
// mediaPlayer.setLooping(true);
mediaPlayer.start();
}
});
}
}
But By this code, Only one video is playing , after another video is not playing.. and I want when one video is finished then second video in the list should be play and so on..
I searched a lot about this on net... But no luck...
Can any one help me regarding this ?
onSurfaceTextureAvailable method doesn't get triggered when the MediaPlayer object has completed playback, it gets triggered when the Surface texture is ready to be used.
You need to implement MediaPlayer.OnCompletionListener, the onCompletion method gets triggered once the playback is completed.
Start the playback of the next video in the list once the playback of the first video is completed.
I have 10 video i need to play, once one is done, the next one starts to play.
I'm using Google's ExoPlayer, I use the example in the DEMO # GitHub.
I can play 1 video but if i try to play the next one, it wont start.
If i try to reInit the player, and the start playing again, it crashes.
private void loadvideo() {
Uri uri = Uri.parse(VIDEO_LIBRARY_URL + currentVideo + ".mp4");
sampleSource = new FrameworkSampleSource(this, uri, null, 2);
// 1. Instantiate the player.
// 2. Construct renderers.
videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
// 3. Inject the renderers through prepare.
player.prepare(videoRenderer, audioRenderer);
// 4. Pass the surface to the video renderer.
surface = surfaceView.getHolder().getSurface();
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surface);
// 5. Start playback.
player.setPlayWhenReady(true);
player.addListener(new ExoPlayer.Listener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
Log.d(TAG, "onPlayerStateChanged + " + playbackState);
if (playbackState == ExoPlayer.STATE_ENDED) {
currentVideo++;
loadNextVideo();
}
}
#Override
public void onPlayWhenReadyCommitted() {
}
#Override
public void onPlayerError(ExoPlaybackException error) {
}
});
}
What am i doing wrong?
How can i play videos continuity?
Thanks.
You can reuse the ExoPlayer up until the point that you call release(), and then it should no longer be used.
To change the media that it is currently playing, you essentially need to perform the following steps:
// ...enable autoplay...
player.stop();
player.seekTo(0L);
player.prepare(renderers);
Creating the renderers is a little bit more involved, but that's the flow you should follow and the player should be able to play back to back videos.
I'm using Exoplayer change mp4 video success. I use the example in the DEMO.
1.DEMO project in DemoPlayer.java:
private final RendererBuilder rendererBuilder;
//remove final,then modify that:
private RendererBuilder rendererBuilder;
//and add the set method:
public void setRendererBuilder(RendererBuilder rendererBuilder){
this.rendererBuilder = rendererBuilder;
}
//finally,add stop method
public void stop(){
player.stop();
}
2.DEMO project in PlayerActivity.java:
add method:
private void changeVideo(){
player.stop();
player.seekTo(0L);
//you must change your contentUri before invoke getRendererBuilder();
player.setRendererBuilder(getRendererBuilder());
player.prepare();
playerNeedsPrepare = false;
}
remember change param contentUri before invoke changeVideo method.
Use ConcatenatingMediaSource to play files in sequence.
For example, for playing 2 media Uris (firstVideoUri and secondVideoUri), use this code:
MediaSource firstSource =
new ExtractorMediaSource.Factory(...).createMediaSource(firstVideoUri);
MediaSource secondSource =
new ExtractorMediaSource.Factory(...).createMediaSource(secondVideoUri);
ConcatenatingMediaSource concatenatedSource =
new ConcatenatingMediaSource(firstSourceTwice, secondSource);
And then use concatenatedSource to play media files sequentially.
OK, Answering my own question.
on the example, google init the ExoPlayer at OnResume().
i had to re-init for every video like that:
player = ExoPlayer.Factory.newInstance(2, 1000, 5000);
if someone has a better idea, please let me know.
There is another solution, you could refer to ConcatenatingMediaSource to achieve auto play next media.
In Demo App example :
1. Launch ExoPlayer
2. Select Playlists
3. Choose Cats->Dogs