We are trying to play multiple .mp4 files from local storage using ConcatenatingMediaSource like below:
E.x:
File file = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES);
File file1 = new File(file,"file1.mp4");
File file2 = new File(file,"file2.mp4");
File file3 = new File(file,"file3.mp4");
MediaSource firstSource = new ExtractorMediaSource(Uri.parse(file1.getAbsolutePath()),mediaDataSourceFactory,new DefaultExtractorsFactory(),
mainHandler,eventLogger);
MediaSource secondSource = new ExtractorMediaSource(Uri.parse(file2.getAbsolutePath()),mediaDataSourceFactory,new DefaultExtractorsFactory(),
mainHandler,eventLogger);
MediaSource thirdSource = new ExtractorMediaSource(Uri.parse(file3.getAbsolutePath()),mediaDataSourceFactory,new DefaultExtractorsFactory(),
mainHandler,eventLogger);
return new ConcatenatingMediaSource(firstSource,secondSource,thirdSource);
Is it possible to have single seekbar with time length = f1 + f2 + f3 for all the above 3 files so that user can move back and forth between them?
It would not be hugely difficult to make a variant of ConcatenatingMediaSource that did this, provided all of the sub-sources are on-demand with known duration. It's not something we support currently, however. Marking as an enhancement.
@ojw28 cool,Thanks!
Quick question - If I am looking to implement ConcatenatingMediaSource variant to implement above mentioned functionality will that involved entirely rewriting ConcatenatingMediaSource kind of class or changing some methods implementation should suffice?
Would love some pointers from you.
Thanks again for your time.
If you were to use ConcatenatingMediaSource as a starting point, the adjustment that you'd need to make is to change ConcatenatedTimeline so that it exposes a single window containing all of the individual periods, rather than a separate window for each of the sources that you've concatenated. It's probably quite fiddly to get this just right. The Javadoc for Timeline, Timeline.Window and Timeline.Period would be a good place to start.
It may also be possible (and quite likely easier) to support this just at the UI layer, by editing PlaybackControlView to consider the progress bar as extending over all windows, rather than just the current one.
@ojw28 Thanks for the pointers.Makes much more sense to go with 2nd option of changing things at UI layer.
@ojw28 Sorry for troubling you again.
I was trying out the changes suggested by you in previous comment but unfortunately couldn't figure out a way to make single progress bar as extending over all windows(for 3 merged media sources).
Inside updateProgress() method of PlaybackControlView class.
Seekbar is updated using the duration and position values which are calculated like below:
long duration = player == null ? 0 : player.getDuration();
long position = player == null ? 0 : player.getCurrentPosition();
But, since player.getDuration() and player.getCurrentPosition() method implementation
return the duration of the current window in milliseconds and the playback position in the current window respectively.
Is it possible to get total duration of all merged media sources without overriding those 2 methods in ExoPlayerImpl?
OR
is there something in ExoPlayer API which i am missing here?
Kindly suggest.
You can use ExoPlayer.getCurrentTimeline to get the media Timeline. Once you have the Timeline you can query the number of windows and their properties (including duration). Hence you can iterate over the windows exposed by the timeline and add the durations. If it's possible that one of the pieces of media might have an unknown duration, you should take care to handle this case correctly. The end result should also be unknown in that case.
@PunitD did you get this working? I've written my own implementation of summing up the parts
Timeline timeline = mPlayer.getCurrentTimeline();
int currentWindowIndex = mPlayer.getCurrentWindowIndex();
long currentPosition = mPlayer.getCurrentPosition();
long totalTime = 0;
Window tmpWindow = new Window();
if (timeline != null) {
for (int i = 0; i < timeline.getWindowCount(); i++) {
long windowDuration = timeline.getWindow(i, tmpWindow).getDurationMs();
totalTime += windowDuration;
if (i < currentWindowIndex) {
currentPosition += windowDuration;
}
}
}
The issue I'm having is that the second data source I have in the list has a negative duration I believe this is because it hasn't been prepared yet. Also, @ojw28 any insight would be appreciated.
We recently pushed support for showing a multi-window time bar in DefaultPlaybackControlView.setShowMultiWindowTimeBar(boolean) to dev-v2. The implementation iterates over all windows in the timeline when calculating a position/duration, rather than just using the current window.
Important caveat: this mode relies on knowing the durations of all periods in the timeline, so, for example, it won't work properly when using ConcatenatingMediaSource until all periods have been prepared. As a workaround, if you know the durations of the constituent sources in advance you can wrap each one in a ClippingMediaSource, so that its period duration is known immediately. We might provide an alternative way to do this later (TBD).
wow, this feature is really useful, you should highlight this feature at homepage.
Most helpful comment
We recently pushed support for showing a multi-window time bar in DefaultPlaybackControlView.setShowMultiWindowTimeBar(boolean) to
dev-v2. The implementation iterates over all windows in the timeline when calculating a position/duration, rather than just using the current window.Important caveat: this mode relies on knowing the durations of all periods in the timeline, so, for example, it won't work properly when using
ConcatenatingMediaSourceuntil all periods have been prepared. As a workaround, if you know the durations of the constituent sources in advance you can wrap each one in aClippingMediaSource, so that its period duration is known immediately. We might provide an alternative way to do this later (TBD).