Thumbnail previews
To test this feature and view the example code, please see the Android SDK 4 Example Code Quick Start guide.
The SDK can display thumbnails to show the user a preview of where in the stream a seek using the scrubber bar will take them.
For more information about the thumbnail mosaic structure and how it is described in WebVTT, see https://docs.jwplayer.com/platform/docs.
NAGRA suggests there should be no more than 300 Standard Definition thumbnails for any asset.
Prerequisites
A test stream with an accompanying set of image file(s) containing a mosaic of thumbnails and the associated WebVTT file describing the timing and placement of the thumbnails within the mosaic.
Example code
Design/layout
The layout of your application needs to accommodate the placement of a thumbnail image in the desired location. For example an ImageView
whose horizontal position can be adjusted to reflect the destination of the potential seek position:
<ImageView
android:id="@+id/thumbnail_preview"
android:layout_width="200dp"
android:layout_height="130dp"
android:layout_marginBottom="10dp"
android:adjustViewBounds="true"
android:background="@android:color/black"
android:contentDescription="preview"
android:scaleType="fitCenter"
android:visibility="invisible"/>
Preparation
The API footprint for this feature is very simple, the application simply needs to implement the ThumbnailsListener
interface and instantiate the AssetThumbnails
class. For example:
private AssetThumbnails mThumbnailHandler = new AssetThumbnails();
private ThumbnailsListener mThumbnailListener = new ThumbnailsListener() {
@Override
public void prepared() {
mThumbnailMap = mThumbnailHandler.thumbnails();
// Calling this method absolves the SDK of responsibility for the thumbnail bitmaps,
// any further calls to .thumbnails() without calling .prepareThumbs() will return null.
mProgress.setOnSeekBarChangeListener(mThumbUpdater);
}
@Override
public void failed(ThumbnailError thumbnailError, String s) {
mThumbnailMap = null;
}
};
Then it is a case of calling the AssetThumbnails
class prepareThumbnails()
method supplying the URL of the WebVTT file and a reference to the instance of the listener, for example:
mThumbnailHandler.prepareThumbnails(url, mThumbnailListener);
Determining the thumbnail to paint
The prepared map of thumbnails stored above can be queried using the following example method which returns the relevant Drawable for the provided progress in milliseconds.
private Drawable getThumb(long progress) {
ColorDrawable placeholder = new ColorDrawable(Color.BLACK);
if (mThumbnailMap == null) {
return placeholder;
}
Long[] startTimes = mThumbnailMap.first;
for(long key : startTimes){
if(key >= progress) {
return new BitmapDrawable(this.getResources(), mThumbnailMap.second.get(key));
}
}
return placeholder;
}
Event handling (handheld)
To react to touch related seeking events, an OnSeekBarChangeListener
needs to be declared with overrides for the onStartTrackingTouch()
, onProgressChanged()
and onStopTrackingTouch()
methods to react to the seeking start, changes and seeking stop respectively. These methods allow your application to be able to hide, show and update the position of the thumbnails as appropriate.
private OnSeekBarChangeListener mThumbUpdater = new OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar bar, int progress, boolean fromuser) {
mSeekedTime = progress;
if (!fromuser || !mThumbnailsVisible) {
// We're not interested in programmatically generated changes to
// the progress bar's position.
return;
}
int duration = mPlayer.getDuration();
if (duration > 0) {
int width = bar.getWidth() - bar.getPaddingLeft() - bar.getPaddingRight();
int thumbCenter = (width * bar.getProgress()) / bar.getMax() + bar.getThumb().getBounds().width()/2;
mThumbnailPreview.setX(thumbCenter);
mThumbnailPreview.setImageDrawable(getThumb(mSeekedTime));
mThumbnailPreview.setVisibility(VISIBLE);
}
}
@Override
public void onStartTrackingTouch(SeekBar bar) {
setSeeking(true);
}
@Override
public void onStopTrackingTouch(SeekBar bar) {
if (mSeeking) {
mPlayer.seekTo(mSeekedTime);
}
hideThumbnail();
setSeeking(false);
}
};
Teardown
The AssetThumbnails
class has a reset()
method which must be called on destruction of the view.
@Override
public void onDestroyView() {
mThumbnailHandler.reset();
}