How can I implement caching in ExoPlayer? It is really bad that it always re-downloads the entire video...
I tried the following approach in my RendererBuilder:
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter(player.getMainHandler(),
null);
SimpleCache cache = (SimpleCache) Singleton.getSingleton(context).getCache();
// Always prints 0, that's the problem!
Log.d("CacheSize", String.valueOf(cache.getCacheSpace()));
DataSource dataSource = new DefaultUriDataSource(context, bandwidthMeter, userAgent);
CacheDataSource cacheDataSource = new CacheDataSource(cache, dataSource, false, false);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, cacheDataSource, allocator,
BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
And inside my Singleton's constructor:
this.cache = new SimpleCache(context.getApplicationContext().getCacheDir(), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 8));
But it seems that it's not working, as the video takes a while to load, and the printed cache space is always 0! Tried to do some searches on the subject, but every question about it is not answered, never saw a working example.
Related
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)
I have successfully able to play hls file with exoplayer but need example to play DASH file. Please give me the sample or overview of it. So can able play it. Thank you in advance
DataSource videoDataSource =
new DefaultUriDataSource(context, bandwidthMeter, userAgent);
ChunkSource videoChunkSource = new DashChunkSource(manifestFetcher,
DefaultDashTrackSelector.newVideoInstance(context, true, filterHdContent),
videoDataSource, new FormatEvaluator.AdaptiveEvaluator(bandwidthMeter), LIVE_EDGE_LATENCY_MS,
elapsedRealtimeOffset, mainHandler, (DashChunkSource.EventListener) player, VideoPlayer.TYPE_VIDEO);
ChunkSampleSource videoSampleSource =
new ChunkSampleSource(videoChunkSource, loadControl,
MAIN_BUFFER_SEGMENTS * BUFFER_SEGMENT_SIZE, mainHandler, player,
VideoPlayer.TYPE_VIDEO);
TrackRenderer videoRenderer =
new MediaCodecVideoTrackRenderer(context, videoSampleSource,
MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT,
5000,
drmSessionManager, true, mainHandler, player, 50);
I am using exo player in my android app to play video from server.
Video play in portrait mode for lollipop+, but for kitkat version video play in landscape mode.
Following is the code
Uri uri = Uri.parse(path);
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
DataSource dataSource = new DefaultUriDataSource(this, null, getUserAgent(this, "ExoPlayerExample"));
ExtractorSampleSource sampleSource = new ExtractorSampleSource(
uri, dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
MediaCodecVideoTrackRenderer videoRenderer = new MediaCodecVideoTrackRenderer(
this, sampleSource, MediaCodecSelector.DEFAULT, MediaCodec.VIDEO_SCALING_MODE_SCALE_TO_FIT);
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(
sampleSource, MediaCodecSelector.DEFAULT);
player = ExoPlayer.Factory.newInstance(RENDERER_COUNT);
player.prepare(videoRenderer, audioRenderer);
player.sendMessage(videoRenderer, MediaCodecVideoTrackRenderer.MSG_SET_SURFACE, surfaceView.getHolder().getSurface());
player.setPlayWhenReady(true);
I am currently looking to develop an application that utilises Dash through the ExoPlayer in Android.
To begin with I am going through the demo project however am having trouble with even creating a simple working instance of ExoPlayer that can stream mp3 or similar.
Would really appreciate any help anyone can give relating to getting a very simple exoplayer instance working from which i can adapt and build upon or if anyone has any leads for more references or guides which I can follow as there seems to be very little documentation available.
Thanks very much for all and any help!
First of all instantiate your ExoPlayer with this line:
exoPlayer = ExoPlayer.Factory.newInstance(RENDERER_COUNT, minBufferMs, minRebufferMs);
If you want to play audio only you can use these values:
RENDERER_COUNT = 1 //since you want to render simple audio
minBufferMs = 1000
minRebufferMs = 5000
Both buffer values can be tweaked according to your requirements
Now you have to create a DataSource. When you want to stream mp3 you can use the DefaultUriDataSource. You have to pass the Context and a UserAgent. To keep it simple play a local file and pass null as userAgent:
DataSource dataSource = new DefaultUriDataSource(context, null);
Then create the sampleSource:
ExtractorSampleSource sampleSource = new ExtractorSampleSource(
uri, dataSource, new Mp3Extractor(), RENDERER_COUNT, requestedBufferSize);
uri points to your file, as an Extractor you can use a simple default Mp3Extractor if you want to play mp3. requestedBufferSize can be tweaked again according to your requirements. Use 5000 for example.
Now you can create your audio track renderer using the sample source as follows:
MediaCodecAudioTrackRenderer audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
Finally call prepare on your exoPlayer instance:
exoPlayer.prepare(audioRenderer);
To start playback call:
exoPlayer.setPlayWhenReady(true);
Here is how you would do it using the new ExoPlayer 2 API, and the SimpleExoPlayer.
First create the player:
DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(context, bandwidthMeter);
TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
DefaultTrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
LoadControl loadControl = new DefaultLoadControl();
SimpleExoPlayer player = ExoPlayerFactory.newSimpleInstance(context, trackSelector, loadControl);
player.addListener(...); // To receive events from the player
Then create your MediaSource. For MP3 you can use ExtractorMediaSource:
ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
Uri uri = Uri.parse(mp3UriString);
Handler mainHandler = new Handler(Looper.getMainLooper());
MediaSource mediaSource = new ExtractorMediaSource(uri, dataSourceFactory, extractorsFactory, mainHandler, mediaSourceListener); // Listener defined elsewhere
Then prepare and play when ready:
player.prepare(mediaSource);
player.setPlayWhenReady(true);
For DASH you would use DashMediaSource instead of ExtractorMediaSource.
Today while working on a project, I found that this.myExoPlayer = ExoPlayerFactory.newSimpleInstance(getActivity()); and some others are now deprecated and Android studio suggested to use new way. So I did a quick Google for it but everywhere I found the old way. So I looked into the SimpleExoPlayer.java file, read some methods. So this is how you initialize simpleExoPlayer:
Activity activity = getActivity(); // if you are in a fragment
// Or, activity = YourActivity.this; if you are in an Activity
SimpleExoPlayer simpleExoPlayer = new SimpleExoPlayer.Builder(activity).build();
I hope this is helpful.
I'm traying to use ExoPlayer for playback video over http. And I want to save video after video was loaded and play it from cache. How Do implement cache and playback from cache? Can give me any samples.
You use cacheDataSource created using cache and dataSource. This cacheDataSource is then used by ExtractorSampleSource.Below is the code for audioRenderer, similarly can be done for videoRender; passing to exoplayerInstance.prepare(renderers).
Cache cache = new SimpleCache(mCtx.getCacheDir(), new LeastRecentlyUsedCacheEvictor(1024 * 1024 * 10));
DataSource dataSource = new DefaultUriDataSource(mCtx, "My Player");
CacheDataSource cacheDataSource = new CacheDataSource(cache, dataSource, false, false);
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
ExtractorSampleSource extractorSampleSource = new ExtractorSampleSource(trackURI, cacheDataSource, allocator, BUFFER_SEGMENT_COUNT*BUFFER_SEGMENT_SIZE, new Mp3Extractor());
MediaCodecAudioTrackRenderer audioTrackRenderer = new MediaCodecAudioTrackRenderer(extractorSampleSource);
What protocol are you using mpeg-dash or plain http.
You can override HttpDataSource and write incoming bytes to a file and when playing again check if file exists at the desired location and change the InputStream fed to the player from your file instead of HttpDataSource.
I use exoplayer with this library:
https://github.com/danikula/AndroidVideoCache
It helps you cache the video from a resource (URL, file)...
This is my sample code:
String mediaURL = "https://my_cool_vid.com/vi.mp4";
SimpleExoPlayer exoPlayer = ExoPlayerFactory.newSimpleInstance(getContext());
HttpProxyCacheServer proxyServer = HttpProxyCacheServer.Builder(getContext()).maxCacheSize(1024 * 1024 * 1024).build();
String proxyURL = proxyServer.getProxyUrl(mediaURL);
DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getContext(),
Util.getUserAgent(getContext(), getActivity().getApplicationContext().getPackageName()));
exoPlayer.prepare(new ProgressiveMediaSource.Factory(dataSourceFactory)
.createMediaSource(Uri.parse(proxyURL)););
This library is easy to use: https://github.com/danikula/AndroidVideoCache. You just need to have the initialization code found in the repo in an appcontroller.
For those using mediaitem, this is what you can do:
exoPlayer = new SimpleExoPlayer.Builder(context).build();
holder.exoPlayerView.setPlayer(exoPlayer);
HttpProxyCacheServer proxyServer = AppController.getProxy(context);
String streamingURL = shortVideosRecommendationsArrayList.get(holder.getAbsoluteAdapterPosition()).getStreamingURL();
String proxyURL = proxyServer.getProxyUrl(streamingURL);
MediaItem mediaItem = MediaItem.fromUri(proxyURL);
exoPlayer.setMediaItem(mediaItem);
exoPlayer.setRepeatMode(exoPlayer.REPEAT_MODE_ALL);
exoPlayer.prepare();
exoPlayer.setPlayWhenReady(true);