3

Within this project there is a 'SimpleExoPlayer' and the version of the player is 'exoplayer:r2.5.3'. After running the app 'SimpleExoPlayer' buffering the content of the video and playing smoothly. But the user set the 'SeekBar' to previous position, the 'SimpleExoPlayer' re-buffering to displaying the video. It is time consuming process for large file size of '.mp4' videos. Helping for solve this issue is kindly appreciated.

below is my code.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:padding="10dp">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fillViewport="true">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="300dp"
                android:orientation="vertical">

                <com.google.android.exoplayer2.ui.SimpleExoPlayerView
                    android:id="@+id/simple_expo_player"
                    android:layout_width="match_parent"
                    android:layout_height="match_parent">


                </com.google.android.exoplayer2.ui.SimpleExoPlayerView>


            </LinearLayout>


        </LinearLayout>

    </ScrollView>


</LinearLayout>

MainActivity.java

public class MainActivity extends AppCompatActivity {

    private SimpleExoPlayerView simpleExoPlayerView;

    SimpleExoPlayer player;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initUi();
    }

    public void initUi(){

// 1. Create a default TrackSelector
        BandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
        TrackSelection.Factory videoTrackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
        TrackSelector trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);

// 2. Create the player

        player = ExoPlayerFactory.newSimpleInstance(getApplicationContext(), trackSelector);


// 3. Produces DataSource instances through which media data is loaded.
        DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(getApplicationContext(), Util.getUserAgent(getApplicationContext(), "com.a3iteam.exoplayertest"));

// 4. Produces Extractor instances for parsing the media data.
        ExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();

// 5. This is the MediaSource representing the media to be played.

        MediaSource videoSource = new ExtractorMediaSource(Uri.parse("https://www.w3schools.com/html/mov_bbb.mp4"),dataSourceFactory, extractorsFactory, null, null);


// 6. Prepare the player with the source.

        simpleExoPlayerView = (SimpleExoPlayerView) findViewById(R.id.simple_expo_player);

        simpleExoPlayerView.setPlayer(player);


    }


}
Nuwan Withanage
  • 393
  • 7
  • 19

3 Answers3

2

There is not much which prevents the player from buffering when the user seeks backwards. Past data is discarded after playback and you can not easily change this behaviour.

There are options to minimize the latency when seeking backwards:

1. Make sure your server supports range requests

Support for range requests is IMO a must when serving video files and not only for backwards seeking but seeking in general.

It is time consuming process for large file size of '.mp4' videos.

The size of the mp4 file should not have an effect on the latency when seeking backwards. Your notion of 'large file size' make me think your server might not support http range requests. I may be wrong though. Just to make sure. :)

You can check like so:

curl -I https://i.stack.imgur.com/uLNHM.jpg

HTTP/1.1 200 OK ... Accept-Ranges: bytes

If you see the 'Accept-Ranges: bytes' header, range requests are supported.

2. Using a cache

The ExoPlayer library comes with a CacheDataSource and a corresponding CacheDataSourceFactory. Hence you can easily cache what's downloaded by wrapping your data source factory:

DataSource.Factory dataSourceFactory = new DefaultDataSourceFactory(
    getApplicationContext(), Util.getUserAgent(getApplicationContext(),
    "com.a3iteam.exoplayertest"));
Cache cache = new SimpleCache(cacheDir, 
    new LeastRecentlyUsedCacheEvictor(maxBytes));
dataSourceFactory = new CacheDataSourceFactory(cache,
    dataSourceFactory);

When a user seeks backwards, the the media is loaded from local disk instead of downloading which decreases latency. Not sure if you want to generally cache everything just for the backwards-seek use case. Maybe restrict it to mobile networks. On wifi buffering with http range request should be good enough.

Either way: delete cached data as quickly as possible.

marcbaechinger
  • 2,759
  • 18
  • 21
  • What if the current system uses Exoplayer 1 and DataSource rather than DataSourceFactory and upgrading to exoplayer 2 is not an option as of now? Is there any way to integrate caching for exoplayer 1? – Mohaimanul Chowdhury Nov 01 '18 at 18:59
1

We can specify backBufferDurationMs in LoadControl and use it to keep previous data buffered.

From the javaDoc it is: the duration of media to retain in the buffer prior to the current playback position, for fast backward seeking

        val dataSource = AudioUtil.getMediaSourceFactory(this)
        val loadControl = DefaultLoadControl.Builder()
            .setBackBuffer(/* backBufferDurationMs= */ 1000 * 60 * 60, true) //for retaining previously loaded one hour data in buffer
            .build()

        player = ExoPlayer.Builder(this)
            .setMediaSourceFactory(dataSource)
            .setLoadControl(loadControl)
            .build()
ahsanali274
  • 471
  • 2
  • 14
0

I have discovered something about this caching mechanism. It looks like if you don't seek until the end of the video, the cache will be completed. Otherwise it caches again. I have verified this by completely cutting off the internet on my phone and emulator. It worked fine and i was able to seek anywhere in the video without internet connection. The key is wait for the whole video to finish before seeking. You can try the code below to create an exoplayer with cache.

private void prepare_player()
{
    File downloadDirectory = context.getExternalFilesDir(null);
    downloadDirectory = context.getFilesDir();
    SimpleCache simple_cache = new SimpleCache(downloadDirectory, new NoOpCacheEvictor(), new ExoDatabaseProvider(getApplicationContext()));
    MediaItem media_item = MediaItem.fromUri(video_uri);
    CacheDataSource.Factory cache_datasource_factory = new CacheDataSource.Factory().setCache(simple_cache).setUpstreamDataSourceFactory(new DefaultHttpDataSource.Factory().setUserAgent("<your_app>"));
    MediaSource media_source = new ProgressiveMediaSource.Factory(cache_datasource_factory).createMediaSource(media_item);
    exo_player = new SimpleExoPlayer.Builder(this).build();
    exo_player.setMediaSource(media_source);
    exo_player.setPlayWhenReady(true);
    exo_player.prepare();
    player_view.setPlayer(exo_player);
}
Numan Karaaslan
  • 1,365
  • 1
  • 17
  • 25