Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quick seek on ExoPlayer

I want to implement a scrubber for ExoPlayer, to show a thumbnail preview of the position the user is seeking to. While my current implementation is working, the thumbnail only refreshes after the user has stopped dragging the seekbar view, or paused for an instant. It appears as if the seek command on ExoPlayer is implementing something like a debounce function, to prevent too many seeks in succession.

While I can work around this by doing my own throttling on the seekbar callback and send a seek request every x milliseconds, I would like to know if there is a way to tell ExoPlayer to not drop seek requests so the thumbnail can update in real time.

For reference, this is my current implementation:

Subject for throttling:

private final Subject<Long> subject = PublishSubject.create();

Observer for seek requests with throttling:

subject
        .throttleLast(400L, TimeUnit.MILLISECONDS)
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(position -> exoPlayer.seekTo(position));

Seekbar callback:

@Override
public void onProgressChanged(@NonNull final SeekBar seekBar,
                              final int progress,
                              final boolean fromUser) {
    if (fromUser) {
        final long position = computePosition(progress);
        subject.onNext(position);
    }
}
like image 668
Francesc Avatar asked May 24 '17 03:05

Francesc


2 Answers

This is old, but might be useful for someone:

As of 2.7.0 ExoPlayer has the method Player.setSeekParameters() If you want to snap the seek position to the closest keyframe use SeekParameters.CLOSEST_SYNC (faster but less accurate). To see to a exact frame (the frame before the requested position, even if it's not a keyframe) use SeekParameters.EXACT.

like image 20
Belzebub Avatar answered Nov 09 '22 21:11

Belzebub


I don't know if this is the optimal solution, but you can look at this open source project which achieves roughly something you're looking for. Here is the Github.

It looks like they use a custom LoadControl to get ExoPlayer to render frames quicker. And I believe they're compounding that with selection of the worst quality so it loads even faster.

This is the code they use in that library's onProgressChange(...):

@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
    if(fromUser){
        int offset = (float) progress / seekBar.getMax()
        // Round the offset before seeking. The sample uses 1% or 10% of the video per each thumbnail
        previewPlayer.seekTo((long) (offset * previewPlayer.getDuration()));
        previewPlayer.setPlayWhenReady(false);
    }
}

Another way to do this is to actually grab a thumbnail off of the TextureView - which they cover in this issue. The caveat being there are some limitations to using multiple renderers.

like image 109
Kyle Venn Avatar answered Nov 09 '22 21:11

Kyle Venn