7

I want to show a video thumbnail in an ImageView from a video path on storage. Is there a function that takes a video path and returns a bitmap of a thumbnail? I get the video path by this code:

public ArrayList<String> getAllMedia() {
  HashSet<String> videoItemHashSet = new HashSet<>();
  String[] projection = {MediaStore.Video.VideoColumns.DATA, MediaStore.Video.Media.DISPLAY_NAME};
  Cursor cursor = getContext().getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
  try {
    cursor.moveToFirst();
    do {
      videoItemHashSet.add((cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))));
    } while(cursor.moveToNext());
    cursor.close();
  } catch(Exception e) {
    e.printStackTrace();
  }
  ArrayList<String> downloadedList = new ArrayList<>(videoItemHashSet);
  return downloadedList;
}
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
john
  • 345
  • 1
  • 4
  • 20
  • 2
    Possible duplicate of [How to create video thumbnail from video file path in Android](https://stackoverflow.com/questions/32517124/how-to-create-video-thumbnail-from-video-file-path-in-android) – dan Apr 28 '18 at 06:23

6 Answers6

10

It is the default way to create a thumbnail.

For Mini Kind

Bitmap thumb;
//MINI_KIND, size:  512 x 384 thumbnail 
    thumb = ThumbnailUtils.createVideoThumbnail(filePath, MediaStore.Video.Thumbnails.MINI_KIND);
            img_tumbnail.setImageBitmap(thumb);

For Micro Kind

Bitmap thumb;
//MICRO_KIND, size: 96 x 96 thumbnail
thumb= ThumbnailUtils.createVideoThumbnail(filePath, Thumbnails.MICRO_KIND);
img_tumbnail.setImageBitmap(thumb);

Also, you can use Glide for Url as well as Video path of Device.

Glide.with(context).with(this)
                    .asBitmap()
                    .load(videoFilePath) // or URI/path
                    .into(imgView); //imageview to set thumbnail to

also, you can resize thumbnail by using .override(50,50) with Glide.

Farhana Naaz Ansari
  • 7,524
  • 26
  • 65
  • 105
  • I tested your code but did not work. when I tried to use glide to load picture android studio got an error: Error:Execution failed for task ':app:transformDexArchiveWithExternalLibsDexMergerForDebug'. > java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Unable to merge dex – john Apr 28 '18 at 10:09
  • enable `multidexing` , this is the different problem and what error is showing? – Farhana Naaz Ansari Apr 28 '18 at 10:11
  • this is the error:Error:Execution failed for task ':app:transformDexArchiveWithExternalLibsDexMergerForDebug'. > java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Unable to merge dex – – john Apr 28 '18 at 10:18
  • have you enabled `multidexing` in Gradle , if you did not, then use `android { defaultConfig { multiDexEnabled true } }` in app/build.gradle – Farhana Naaz Ansari Apr 28 '18 at 10:20
6

Use Glide lib

to show thumbnail from local storage

String filePath = "/storage/emulated/0/Pictures/example_video.mp4";

GlideApp  
    .with(context)
    .asBitmap()
    .load(Uri.fromFile(new File(filePath)))
    .into(imageViewGifAsBitmap);
Milind Mevada
  • 3,145
  • 1
  • 14
  • 22
  • I tested your code but did not work. when I tried to use glide to load picture android studio got an error: Error:Execution failed for task ':app:transformDexArchiveWithExternalLibsDexMergerForDebug'. > java.lang.RuntimeException: com.android.builder.dexing.DexArchiveMergerException: Unable to merge dex – john Apr 28 '18 at 10:11
  • This error is related multidex. enable multidex for your project and try – Milind Mevada Apr 29 '18 at 09:57
3

You can use ThumbnailUtils to load video thumb in 3 format:

  • MINI_KIND : Good for media detail view
  • FULL_SCREEN_KIND : Good for header
  • MICRO_KIND : Good for recycleView

Ex:

holder.videoThumb.setImageBitmap(ThumbnailUtils.createVideoThumbnail(getItem(position).videoURL, MediaStore.Images.Thumbnails.MICRO_KIND))

The biggest drawback is that ThumbnailUtils operate on UI thread so if you try to use this method in a recycleView then it gone make your app skip frames. Your RecycleView will have laggy scroll and if you have more than 7 items then your app will start throwing ANR.

That means you need to create AsyncTask or Threads which again might lead to memory leaks.

Conclusion; Glide is better in loading video thumbs.

Here DiskCacheStrategy.RESULT is important parameter which worked for me and give a smooth fast scroll in recycle view.

            Glide.with(context).load(getItem(position).videoURL)
                    .asBitmap()
                    .placeholder(R.drawable.app_icon)
                    .centerCrop()
                    .diskCacheStrategy(DiskCacheStrategy.RESULT)
                    .into(holder.videoThumb)
ppreetikaa
  • 1,149
  • 2
  • 15
  • 22
Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
2

I have 3rd method to set thumbnail of image/video. Hope it will help you.

1) ThumbnailUtils --> Effective but Slow

Bitmap thumb = ThumbnailUtils.createVideoThumbnail(thumbPath, MediaStore.Video.Thumbnails.MINI_KIND);
        holder.ivThumb.setImageBitmap(thumb);

2) FFmpegMediaMetadataRetriever --> Very Effective but Slow

FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
    try {
        retriever.setDataSource(thumbPath);
       thumb.setImageBitmap(retriever.getFrameAtTime(0));
    } catch (Exception ex) {
        // Assume this is a corrupt  file
    }

3) Glide --> Effective and Fast

   RequestOptions options = new RequestOptions()
            .centerCrop()
            .placeholder(android.R.drawable.stat_notify_error)
            .error(android.R.drawable.stat_notify_error);

    Glide.with(context)
            .load(thumPath)
            .apply(options)
            .into(thumb);
Tushar Lathiya
  • 940
  • 9
  • 26
1

If anyone is looking for a Kotlin version. You can try this extension function. It is using coil.

/**
 * https://github.com/coil-kt/coil/issues/413
 */
fun ImageView.setThumbnail(uri: Uri, frameMillis: Long = 2000) {

    val imageLoader = ImageLoader.Builder(context)
        .componentRegistry {
            add(VideoFrameFileFetcher(context))
            add(VideoFrameUriFetcher(context))
        }.build()

    val request = ImageRequest.Builder(context)
        .data(uri)
        .videoFrameMillis(frameMillis)
        .target(this)
        .fetcher(VideoFrameUriFetcher(context))
        .build()

    findViewTreeLifecycleOwner()?.lifecycleScope?.launch(Dispatchers.Main) {
        imageLoader.execute(request)
    }
}
OhhhThatVarun
  • 3,981
  • 2
  • 26
  • 49
0

In some devices not working for me without FileDescriptorBitmapDecoder

So I used following code with FileDescriptorBitmapDecoder

 public static void loadLocalVideoThumbanail(Context context, String path, final ImageView imageView) {
    try {
        if (path == null || path.isEmpty())
            return;

        BitmapPool bitmapPool = Glide.get(context).getBitmapPool();
        int microSecond = 1000000;// 1st second as an example
        VideoBitmapDecoder videoBitmapDecoder = new VideoBitmapDecoder(microSecond);
        FileDescriptorBitmapDecoder fileDescriptorBitmapDecoder = new FileDescriptorBitmapDecoder(videoBitmapDecoder, bitmapPool, DecodeFormat.PREFER_ARGB_8888);


        Glide.with(context).load(path).asBitmap().thumbnail(0.6f)
                .diskCacheStrategy(DiskCacheStrategy.RESULT)
                .dontAnimate()
                .videoDecoder(fileDescriptorBitmapDecoder)
                .override(200,200)
                .into(imageView);
    } catch (Exception e) {
        MyLog.e(TAG, "LoadImage: ", e);
    }
}
Ranjithkumar
  • 16,071
  • 12
  • 120
  • 159