ExoPlayer cache - android

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);

Related

How to implement seekTo() when using HLS with the ExoPlayer

I am trying to implement a basic radio player that can pause the live stream, rewind it and then fast forward it again.
I think that this functionality should be natively supported from version 2.1 of the ExoPlayer.
However, the rewind and fast-forward controls are grayed out when streaming even though they work when playing local content.
Here is how I am creating the player:
private void initExoPlayer(){
Handler mHandler = new Handler();
String userAgent = "userAgent";
Uri uri = Uri.parse(urlSourceOfStream);
dataSourceFactory = new DefaultHttpDataSourceFactory(
userAgent, null,
DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
1800000,
true);
mediaSource = new ExtractorMediaSource(uri,dataSourceFactory, Mp3Extractor.FACTORY,
mHandler, null);
bandwidthMeter = new DefaultBandwidthMeter();
trackSelectionFactory =
new AdaptiveTrackSelection.Factory(bandwidthMeter);
trackSelector = new DefaultTrackSelector(trackSelectionFactory);
loadControl = new DefaultLoadControl();
exoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
exoPlayer.prepare(mediaSource);
((SimpleExoPlayerView) findViewById(R.id.exoPlayer)).setPlayer(exoPlayer);
}
The player can pause successfully, and it seems to be caching the content as I can resume the player after it has been paused for minutes. This also indicates that there should be some cache that can allow me to rewind the content.
I've also tried using the OkHttpDataSourceFactory :
OkHttpClient client = new OkHttpClient.Builder().cache(new Cache(getFilesDir() , 1000)).build();
OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(client, userAgent, null);
Trying to rewind the player like this makes the player play from the live stream position and does not rewind the content:
exoPlayer.seekTo(Math.max(exoPlayer.getCurrentPosition() - 1000, 0));
My question in a nutshell: How can I rewind and fast-forward an HLS with the ExoPlayer?
Thanks in advance.
It looks like there is a bug, https://github.com/google/ExoPlayer/issues/87 discussing this, and it's been closed. But I'm not sure if its reached the v2 release, and rather it might be in the dev release, here

Android: ExoPlayer: create MediaSource from DefaultHttpDataSource

I use ExoPlayer for playback of videos from url in my app and need to set an authorization header for each video. DefaultHttpDataSource can be used for that. For example,
DefaultHttpDataSource source = new DefaultHttpDataSource(Util.getUserAgent(mContext, "appAgent"), null);
source.setRequestProperty("Authorization", authToken);
MediaSource is needed to prepare the player. The question is how to create a MediaSource based on DefaultHttpDataSource?
Both of the constructors of ExtractorMediaSource require DataSource.Factory, not DataSource.
This returns a Datasource.Factory object:
return new DefaultDataSourceFactory(this, null, new DefaultHttpDataSourceFactory(Util.getUserAgent(mContext, "appAgent"), null));

ExoPlayer: get songs metadata from HTTP stream

I use the following code to play a music stream through ExoPlayer:
exoPlayer = ExoPlayer.Factory.newInstance(numRenderers, minBufSize, maxBufSize);
String url = Helper.getPr().getString("url", "http://mp3.nashe.ru:80/ultra-128.mp3");
Uri uri = Uri.parse(url);
Log.i(TAG, "Going to open " + url);
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
DataSource dataSource = new DefaultUriDataSource(getApplicationContext(), USER_AGENT);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
exoPlayer.addListener(this);
exoPlayer.sendMessage(audioRenderer, MediaCodecAudioTrackRenderer.MSG_SET_VOLUME, volume);
exoPlayer.prepare(audioRenderer);
exoPlayer.setPlayWhenReady(true);
I can't find any info on how to get metadata like artist and name of the current song. Is it possible to get the metadata and if yes, how?
Thanks a lot.
There are many types of metadata in many types of media, It's depending on your stream. But currently Exoplayer itself, only parse metadata from HLS streams (HTTP Live Streaming) they get ID3 data from the stream.
As you can see on there github repository issue,this is the current state of metadata in Exoplayer lib (August 2015):
https://github.com/google/ExoPlayer/issues/704
If it's your stream case, I will recommend you to download the Exoplayer demo on github (https://github.com/google/ExoPlayer/tree/release-v2/demos).
One of the examples in the demo display stream ID3 metadata on LogCat.
If it's not your case, nothing will help you in ExoPlayer lib right now.
But there is an alternative solution, which I have used for a radio stream application, and it work well:
IcyStreamMeta to get meta data from online stream radio :
Getting metadata from SHOUTcast using IcyStreamMeta
but not sure it will work with simple mp3 file.
I am late But with Exoplayer-2. You can use an extension created by #saschpe. https://github.com/sandeeprana011/android-exoplayer2-ext-icy
For example see this app: https://play.google.com/store/apps/details?id=com.zilideus.jukebox_new
gradle
implementation 'saschpe.android:exoplayer2-ext-icy:1.0.1'
So it includes an Extra Header "Icy-Metadata" with value 1
and on the response, it extracts the metadata from the stream data.
Usage:
IcyHttpDataSourceFactory factory = new IcyHttpDataSourceFactory.Builder(Util.getUserAgent(this, getResources().getString(R.string.app_name)))
.setIcyHeadersListener(this)
.setIcyMetadataChangeListener(this).build();
DefaultDataSourceFactory datasourceFactory = new DefaultDataSourceFactory(getApplicationContext(), null, factory);
ExtractorMediaSource mediaSource = new ExtractorMediaSource.Factory(datasourceFactory)
.setExtractorsFactory(new DefaultExtractorsFactory())
.createMediaSource(uri);
Exo.resetPlayer();
Exo.getPlayer(this).prepare(mediaSource);
In the case of Icy metadata, exoplayer has built in support as of version 2.10. see: https://stackoverflow.com/a/56333429/1898380
You probably should use MediaMetadataRetriever
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(getActivity(), uri);
String artist = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
You could use the follow code to do that(Maybe you should download the mp3 file first):
MediaMetadataRetriever metaRetriver = new MediaMetadataRetriever();
metaRetriver.setDataSource("LOCAL MP3 FILE PATH");
byte[] picArray = metaRetriver.getEmbeddedPicture();
Bitmap songImage = BitmapFactory .decodeByteArray(picArray, 0, picArray.length);
String albumName = metaRetriver .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
String artistName = metaRetriver .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
String songGenre = metaRetriver .extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
source:http://mrbool.com/how-to-extract-meta-data-from-media-file-in-android/28130#ixzz3s8PUd9E7

How to implement caching in ExoPlayer?

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.

Creating a simple instance of ExoPlayer

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.

Categories

Resources