Api has a token header that i need to set but the video is not encrypted.
I have two questions:
How can i play .mpg,.mpeg,.3gp,.mov and other files from disk with exoplayer?
How can i set headers with exoplayer and stream mp4 video from url?
Figured out the answer:
DefaultHttpDataSource source = new DefaultHttpDataSource(userAgent, null);
source.setRequestProperty("Authorization", "your auth code");
source.setRequestProperty("Accept", "...");
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, source, extractor, 2,
BUFFER_SIZE);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(sampleSource,
null, true, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING, 5000, null, player.getMainHandler(),
player, 50);
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource,
null, true, player.getMainHandler(), player);
// (1) Create method returns 'DataSource.Factory'
public DataSource.Factory headers() {
Map<String, String> headersMap = new HashMap<>();
headersMap.put("iid", "aaa123 ");
headersMap.put("version", "1.4");
headersMap.put("agent", "phone");
headersMap.put("token", "dfdf4f4yt5yf5fh4f5");
return new DefaultHttpDataSource.Factory().setDefaultRequestProperties(headersMap);
}
// (2) Add headers() method call to the player
SimpleExoPlayer player = new SimpleExoPlayer.Builder(context)
.setMediaSourceFactory(new
DefaultMediaSourceFactory(headers()))
.build();
ON exoplayer 2.13.2, DefaultDataSourceFactory constructor method is deprecated, you can use Factory instead.
val dataSourceFactory: DataSource.Factory = DefaultHttpDataSource.Factory()
.setUserAgent("")
.setDefaultRequestProperties(hashMapOf("" to ""))
.setDefaultRequestProperties(hashMapOf("" to ""))
val mediaSource: MediaSource = ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(MediaItem.fromUri(url))
val player = SimpleExoPlayer
.Builder(this)
.build()
binding.videoPlayerView.player = player
player.setMediaSource(mediaSource)
player.prepare()
player.play()
// 1. Create a default TrackSelector
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory = new
AdaptiveTrackSelection.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 = new SimpleExoPlayerView(this);
simpleExoPlayerView = (SimpleExoPlayerView)
findViewById(R.id.player_view);
//Set media controller
simpleExoPlayerView.setUseController(true);
simpleExoPlayerView.requestFocus();
// Bind the player to the view.
simpleExoPlayerView.setPlayer(player);
String username = "username";
String password = "password";
// encrypt Authdata
byte[] toEncrypt = (username + ":" + password).getBytes();
encoded = Base64.encodeToString(toEncrypt, Base64.DEFAULT);
DefaultHttpDataSourceFactory dataSourceFactory = new
DefaultHttpDataSourceFactory(Util.getUserAgent(this,
"exoplayer2example"));
DefaultHttpDataSource source = new DefaultHttpDataSource(Util.getUserAgent(this, "exoplayer2example"),null);
dataSourceFactory.setDefaultRequestProperty("Authorization","Basic "+encoded);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
MediaSource videoSource = new ExtractorMediaSource(Uri.parse("https://example.com/assets/video/SampleVideo.mp4"),
dataSourceFactory, extractorsFactory, null, null);
final LoopingMediaSource loopingSource = new LoopingMediaSource(videoSource);
exoplayer.prepare(videoSource);
How can i set headers with exoplayer and stream mp4 video from url?
I implemented basic authorisation so:
private SimpleExoPlayer player;
private PlayerView playerView;
private void initializePlayer() {
player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(),
new DefaultLoadControl());
playerView.setPlayer(player);
player.setPlayWhenReady(true);
player.seekTo(0, 0);
Uri uri = Uri.parse(getString(R.string.media_url));
MediaSource mediaSource = buildMediaSource(uri);
player.prepare(mediaSource, true, false);
}
private MediaSource buildMediaSource(final Uri uri) {
HttpDataSource.BaseFactory myDSFactory = new HttpDataSource.BaseFactory() {
#Override
protected HttpDataSource createDataSourceInternal(HttpDataSource.RequestProperties defaultRequestProperties) {
byte[] toEncrypt = uri.getUserInfo().getBytes();
String encoded = "Basic " + Base64.encodeToString(toEncrypt, Base64.DEFAULT).trim();
DefaultHttpDataSourceFactory dsf = new DefaultHttpDataSourceFactory("exoplayer-codelab");
HttpDataSource ds = dsf.createDataSource();
ds.setRequestProperty("Authorization", encoded);
return ds;
}
};
ExtractorMediaSource.Factory emf = new ExtractorMediaSource.Factory(myDSFactory);
return emf.createMediaSource(uri);
}
Related
I'm using ExoPlayer and I have a file which must auto play after finishing movie play from top again.
I used LoopingMediaSource but here is the problem every time that movie start from the beginning it start download the file again but I expect after the first time movie display offline
here is my custom CacheDataSourceFactory class
public class CacheDataSourceFactory implements DataSource.Factory {
private final Context context;
private final DefaultDataSourceFactory defaultDatasourceFactory;
private final long maxFileSize, maxCacheSize;
public static CacheDataSourceFactory cacheDataSourceFactory;
SimpleCache simpleCache;
public static CacheDataSourceFactory getInstance(Context context, long maxCacheSize, long maxFileSize) {
if (cacheDataSourceFactory==null) {
cacheDataSourceFactory = new CacheDataSourceFactory(context , maxCacheSize , maxFileSize);
}
return cacheDataSourceFactory;
}
private 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));
LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize);
simpleCache = new SimpleCache(new File(context.getCacheDir(), "media"), evictor);
}
#Override
public DataSource createDataSource() {
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 here is my exo player code
defaultBandwidthMeter = new DefaultBandwidthMeter();
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
TrackSelection.Factory videoTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
player = ExoPlayerFactory.newSimpleInstance(context, trackSelector, loadControl);
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
dataSourceFactory = new DefaultDataSourceFactory(context,
Util.getUserAgent(context, context.getResources().getString(R.string.app_name)), defaultBandwidthMeter);
MediaSource mediaSource =
new ExtractorMediaSource(
Uri.parse(banner.getImagePath()),
CacheDataSourceFactory.getInstance(context, 100 * 1024 * 1024, 10 * 1024 * 1024), extractorsFactory, null, null);
holder.player_view.hideController();
LoopingMediaSource loopingSource = new LoopingMediaSource(mediaSource);
player.prepare(loopingSource, false, false);
player.setPlayWhenReady(true);
Once the download is complete you need to save this url and it's download state in your mobile db
//if(check already downloaded then execute this
dataSourceFactory = new CacheDataSourceFactory(simpleCache ,
DefaultHttpDataSourceFactory("test"));
mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(yourUri));
player.prepare(mediaSource);
else {
// download /play }
I have the playlist of dash videos and this was the code I used to play the media when the version was 2.7.3. Now I have updated to 2.9.5, I'm facing issues.
My init and mediasource methods :
private void initializePlayer() {
if (player == null) {
// a factory to create an AdaptiveVideoTrackSelection
TrackSelection.Factory adaptiveTrackSelectionFactory =
new AdaptiveTrackSelection.Factory(BANDWIDTH_METER);
player = ExoPlayerFactory.newSimpleInstance(
new DefaultRenderersFactory(this),
new DefaultTrackSelector(adaptiveTrackSelectionFactory),
new DefaultLoadControl());
player = ExoPlayerFactory.newSimpleInstance(new DefaultRenderersFactory(this),
new DefaultTrackSelector(), new DefaultLoadControl());
playerView.setPlayer(player);
player.addListener(new PlayerEventListener());
/*player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);*/
}
playListMediaSources = buildPlayListMediaSource(serialURLs);
concatenatingMediaSource = new ConcatenatingMediaSource(playListMediaSources);
player.prepare(concatenatingMediaSource, true, false);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);
}
private MediaSource buildMediaSource(Uri uri) {
/* DefaultExtractorsFactory defaultExtractorsFactory = new DefaultExtractorsFactory();
DefaultHttpDataSourceFactory defaultHttpDataSourceFactory = new DefaultHttpDataSourceFactory("user-agent");*/
DataSource.Factory manifestDataSourceFactory =
new DefaultHttpDataSourceFactory("ua");
DashChunkSource.Factory dashChunkSourceFactory =
new DefaultDashChunkSource.Factory(
new DefaultHttpDataSourceFactory("ua", BANDWIDTH_METER));
return new DashMediaSource.Factory(dashChunkSourceFactory,
manifestDataSourceFactory).createMediaSource(uri);
}
private MediaSource[] buildPlayListMediaSource(String[] serialURLs) {
MediaSource[] mediaSources = new MediaSource[serialURLs.length];
Uri uri;
for (int i = 0; i < serialURLs.length; i++) {
uri = Uri.parse(serialURLs[i]);
mediaSources[i] = buildMediaSource(uri);
}
return mediaSources;
}
I modified my init code to this :
private void initializePlayer() {
if (player == null) {
TrackSelection.Factory adaptiveTrackSelectionFactory = new AdaptiveTrackSelection.Factory();
player = ExoPlayerFactory.newSimpleInstance(this,
new DefaultRenderersFactory(this),
new DefaultTrackSelector(adaptiveTrackSelectionFactory),
new DefaultLoadControl());
player = ExoPlayerFactory.newSimpleInstance(this,new DefaultRenderersFactory(this),
new DefaultTrackSelector(), new DefaultLoadControl());
}
if (serialURLs != null) {
playListMediaSources = buildPlayListMediaSource(serialURLs);
concatenatingMediaSource = new ConcatenatingMediaSource(playListMediaSources);
player.prepare(concatenatingMediaSource, true, false);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);
}
}
But failed to play the video. My guess is I have to make some changes in Media sources methods as well, but I'm unable to figure out the changes. With my current code, the log shows the following error :
E/AndroidRuntime: FATAL EXCEPTION: ExoPlayerImplInternal:Handler
Process: com.packagename, PID: 2731
java.lang.AbstractMethodError: abstract method "void com.google.android.exoplayer2.source.BaseMediaSource.prepareSourceInternal(com.google.android.exoplayer2.upstream.TransferListener)"
at com.google.android.exoplayer2.source.BaseMediaSource.prepareSource(BaseMediaSource.java:140)
at com.google.android.exoplayer2.ExoPlayerImplInternal.prepareInternal(ExoPlayerImplInternal.java:398)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:285)
at android.os.Handler.dispatchMessage(Handler.java:101)
at android.os.Looper.loop(Looper.java:164)
at android.os.HandlerThread.run(HandlerThread.java:65)
I'm adding this text to avoid mostly code error. Any help is appreciated. Thanks in advance.
Both com.google.android.exoplayer:exoplayer-core and com.google.android.exoplayer:exoplayer-dash needs to be the same version in your build.gradle.
implementation 'com.google.android.exoplayer:exoplayer-core:2.9.6'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.9.6'
Finally i settled for this:
private void initializePlayer() {
if (player == null) {
TrackSelection.Factory adaptiveTrackSelection = new AdaptiveTrackSelection.Factory();
TrackSelector trackSelector = new DefaultTrackSelector(adaptiveTrackSelection);
DefaultLoadControl loadControl = new DefaultLoadControl.Builder().setBufferDurationsMs(64*1024, 128*1024, 1024, 1024).createDefaultLoadControl();
//LoadControl loadControl = new DefaultLoadControl();
// HttpDataSource.Factory factory = new DefaultHttpDataSourceFactory(Util.getUserAgent(this, "Exo2"));
player = ExoPlayerFactory.newSimpleInstance(this,new DefaultRenderersFactory(this), trackSelector, loadControl);
playerView.setPlayer(player);
player.addListener(new PlayerEventListener());
}
if (isPlaylist) {
if (serialURLs != null) {
nextBtn.setVisibility(View.VISIBLE);
playListMediaSources = buildPlayListMediaSource(serialURLs);
concatenatingMediaSource = new ConcatenatingMediaSource(playListMediaSources);
readLastSeen(contentName, isWebSeries);
player.prepare(concatenatingMediaSource, true, false);
player.setPlayWhenReady(playWhenReady);
player.seekTo(currentWindow, playbackPosition);
} else {
// previousBtn.setVisibility(View.GONE);
//nextBtn.setVisibility(View.GONE);
Uri uri = Uri.parse(getString(R.string.sample_video));
mediaSource = buildMediaSource(uri);
Toast.makeText(MediaPlayerActivity.this, "Playing sample video..", Toast.LENGTH_LONG).show();
player.prepare(mediaSource, true, false);
player.setPlayWhenReady(playWhenReady);
player.seekTo(playbackPosition);
}
} else {
if (videoURL != null) {
Uri uri = Uri.parse(videoURL);
mediaSource = buildMediaSource(uri);
}
player.prepare(mediaSource, true, false);
player.setPlayWhenReady(playWhenReady);
player.seekTo(playbackPosition);
}
}
private MediaSource buildMediaSource(Uri uri) {
DataSource.Factory dataSourceFactory =
new DefaultDataSourceFactory(MediaPlayerActivity.this, "ua");
return new DashMediaSource.Factory(dataSourceFactory)
.createMediaSource(uri);
}
and these are my dependencies :
implementation 'com.google.android.exoplayer:exoplayer-core:2.10.0'
implementation 'com.google.android.exoplayer:exoplayer-dash:2.10.0'
implementation 'com.google.android.exoplayer:extension-mediasession:2.8.4'
implementation 'com.google.android.exoplayer:exoplayer-ui:2.8.+'
implementation 'com.google.android.exoplayer:exoplayer:r2.4.0'
I am trying to sideload a subtitle file with my video, but it does not work.
Code:
private MediaSource buildMediaSourceWithSubtitle(Uri uri, #Nullable String overrideExtension, Uri subtitle) {
Format subtitleFormat = Format.createTextSampleFormat(null, MimeTypes.APPLICATION_SUBRIP, 0, null);
MediaSource subtitleSource = new SingleSampleMediaSource.Factory(dataSourceFactory).createMediaSource(subtitle, subtitleFormat, C.TIME_UNSET);
MediaSource mediaSource = null;
#ContentType int type = Util.inferContentType(uri, overrideExtension);
switch (type) {
case C.TYPE_DASH:
mediaSource = new DashMediaSource.Factory(dataSourceFactory).setManifestParser(
new FilteringManifestParser < >(new DashManifestParser(), getOfflineStreamKeys(uri))).createMediaSource(uri);
return new MergingMediaSource(mediaSource, subtitleSource);
case C.TYPE_SS:
mediaSource = new SsMediaSource.Factory(dataSourceFactory).setManifestParser(
new FilteringManifestParser < >(new SsManifestParser(), getOfflineStreamKeys(uri))).createMediaSource(uri);
return new MergingMediaSource(mediaSource, subtitleSource);
case C.TYPE_HLS:
mediaSource = new HlsMediaSource.Factory(dataSourceFactory).setPlaylistParserFactory(
new DefaultHlsPlaylistParserFactory(getOfflineStreamKeys(uri))).createMediaSource(uri);
return new MergingMediaSource(mediaSource, subtitleSource);
case C.TYPE_OTHER:
mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(uri);
return new MergingMediaSource(mediaSource, subtitleSource);
default:
{
throw new IllegalStateException("Unsupported type: " + type);
}
}
}
MediaSource videoSource = new ExtractorMediaSource(
videoUri,
dataSourceFactory,
new DefaultExtractorsFactory(),
null,
null);
Format subtitleFormat = Format.createTextSampleFormat(
null,
MimeTypes.APPLICATION_SUBRIP,
C.SelectionFlags,
"en");
MediaSource textMediaSource = new SingleSampleMediaSource(
Uri.parse("http://www.storiesinflight.com/js_videosub/jellies.srt"),
dataSourceFactory,
subtitleFormat,
C.TIME_UNSET);
source = new MergingMediaSource(videoSource, textMediaSource); // to be used later
// nested to some class that has SubtitleView as member
class SomeListener implements ..., TextRenderer.Output, ... {
...
// this function doesn't seem to be invoked
public void onCues(List cues) {
// some logging here
if (subtitleView != null) {
subtitleView.onCues(cues);
}
}
...
}
player.setTextOutput(listener);
...
// later, play the video assuming its prepared and whatnot
player.setPlayWhenReady(true);
In Exoplayer 2.16.1 I used this code and worked properly:
val subtitle = MediaItem.SubtitleConfiguration.Builder(srtUri)
.setMimeType(MimeTypes.APPLICATION_SUBRIP)
.setLanguage("en")
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
.build()
val mediaItem = MediaItem.Builder()
.setUri(videoUrl)
.setSubtitleConfigurations(ImmutableList.of(subtitle))
.build()
player?.setMediaItem(mediaItem)
I have the next problem, in DataSourceFactory, when I create new DefaultDataSourceFactory, I have the next error 'Wrong 1st argument type Found 'android.View.OnClicklistener' required 'android...Context' in Util.getUserAgent(this...)
play.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
final ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
TrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(this, Util.getUserAgent(this,
getPackageName()), bandwidthMeter);
MediaSource mediaSource = new ExtractorMediaSource(Uri.parse(cuento.getUrl()),
dataSourceFactory, extractorsFactory, new Handler(), Throwable::printStackTrace);
}
});
Why? I tried with getApplicationContext(), or Myclass.this, or private Context mContext, but nothing solve the problem.
Because you are inside a inner class this passes a reference to the inner class, so you need to call getContext() or YourAcitivty.this
but from what you explained the error is about Util.getUserAgent, so replace you code with the following.
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getContext(), Util.getUserAgent(getContext(),
getPackageName()), bandwidthMeter);
I have to play video A once, and after it finished, loop video B indefinitely. I'm trying to use ConcatenatingMediaSource for that:
private SimpleExoPlayer initPlayer(ViewGroup layout, int playerViewId, ExoPlayer.EventListener eventListener) {
// 1. Create a default TrackSelector
TrackSelector trackSelector = new DefaultTrackSelector();
// 2. Create a default LoadControl
LoadControl loadControl = new DefaultLoadControl();
// 3. Create the player
this.player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, loadControl);
SimpleExoPlayerView simpleExoPlayerView = (SimpleExoPlayerView) layout.findViewById(playerViewId);
// Bind the player to the view.
simpleExoPlayerView.setUseController(false);
simpleExoPlayerView.setPlayer(player);
if (eventListener != null)
player.addListener(eventListener);
// Prepare the player with the source.
player.setPlayWhenReady(true);
return player;
}
public void startPlayer(String firstURL, String loopingURL) {
initProxy();
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
MediaSource firstSource = getVideoPlayerMediaSource(bandwidthMeter, firstURL);
MediaSource secondSource = new LoopingMediaSource(getVideoPlayerMediaSource(bandwidthMeter, loopingURL));
ConcatenatingMediaSource concatenatedSource =
new ConcatenatingMediaSource(firstSource, secondSource);
player.setPlayWhenReady(true);
player.prepare(concatenatedSource);
player.setVideoScalingMode(C.VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
setPlayerPlaying(true);
}
private void initProxy() {
if (proxy == null)
proxy = VideoCache.getProxy(getContext());
}
#NonNull
private MediaSource getVideoPlayerMediaSource(DefaultBandwidthMeter bandwidthMeter, String videoUrl) {
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getContext(),
Util.getUserAgent(getContext(), "com.myapp"), bandwidthMeter);
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
Uri url = Uri.parse(videoUrl);
MediaSource videoSource;
if (videoUrl.contains(".mp4")) {
url = Uri.parse(proxy.getProxyUrl(videoUrl));
videoSource = new ExtractorMediaSource(url,
dataSourceFactory, extractorsFactory, null, null);
} else {
videoSource = new HlsMediaSource(url, dataSourceFactory, null, null);
}
return videoSource;
}
But this throws:
Internal runtime error.
java.lang.IndexOutOfBoundsException
at com.google.android.exoplayer2.util.Assertions.checkIndex(Assertions.java:66)
at com.google.android.exoplayer2.ExoPlayerImplInternal.getPeriodPosition(ExoPlayerImplInternal.java:1077)
at com.google.android.exoplayer2.ExoPlayerImplInternal.getPeriodPosition(ExoPlayerImplInternal.java:1059)
at com.google.android.exoplayer2.ExoPlayerImplInternal.getPeriodPosition(ExoPlayerImplInternal.java:1050)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleSourceInfoRefreshed(ExoPlayerImplInternal.java:872)
at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:320)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:148)
at android.os.HandlerThread.run(HandlerThread.java:61)
at com.google.android.exoplayer2.util.PriorityHandlerThread.run(PriorityHandlerThread.java:40)
The problem happens only when using the secondSource as LoopingMediaSource. It works without it, but obviously doesn't loop the second video.
(ExoPlayer version r2.3.1)
Try using the other constructor for your LoopingMediaSource, where you specify a loop count and see if that works:
public LoopingMediaSource(MediaSource childSource, int loopCount) {
Assertions.checkArgument(loopCount > 0);
this.childSource = childSource;
this.loopCount = loopCount;
}
It looks like you are getting a handleSourceInfoRefreshed message, which is sent from the LoopingMediaSource prepareSource() method:
#Override
public void prepareSource(ExoPlayer player, boolean isTopLevelSource, final Listener listener) {
childSource.prepareSource(player, false, new Listener() {
#Override
public void onSourceInfoRefreshed(Timeline timeline, Object manifest) {
childPeriodCount = timeline.getPeriodCount();
listener.onSourceInfoRefreshed(new LoopingTimeline(timeline, loopCount), manifest);
}
});
}
But that creates a new LoopingTimeline object and passes it loopCount, which is 0 in your case. The LoopingTimeline class overrides getWindowCount():
#Override
public int getWindowCount() {
return childWindowCount * loopCount;
}
Which will return 0 if the loopCount is 0.
If that works, then you can get your video to loop indefinitely by passing (Integer.MAX_VALUE - 1) as the loopCount, since the LoopingTimeline will cap the loop count anyway.