Is it possible to display video thumbnails using Universal Image Loader, and how?
Asked Answered
C

2

5

I am experimenting with using Universal Image Loader (https://github.com/nostra13/Android-Universal-Image-Loader) for displaying video thumbnails in a grid view. I'm able to get it to show image thumbnails with no problems.

How I initialize UIL in the Application class:

@Override
public void onCreate() {
    super.onCreate();
    initUil();
}

private void initUil() {
    DisplayImageOptions displayOptions = new DisplayImageOptions.Builder()
            .cacheInMemory(true)
            .cacheOnDisc(true)
            .build();

    ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            .taskExecutor(ThreadPool.getExecutorService())
            .defaultDisplayImageOptions(displayOptions)
            .build();

    ImageLoader.getInstance().init(config);
}

How I use it to display thumbnails:

public class MediaCursorAdapter extends SimpleCursorAdapter implements Filterable {
    @Override
    public void bindView(View rowView, Context context, Cursor cursor) {
        String contentUri = getContentUri(cursor);

        ImageView imgThumb = (ImageView) rowView.findViewById(R.id.imgThumb);

        ImageLoader.getInstance().displayImage(contentUri, imgThumb);
    }
}

Some code is omitted for simplicity. contentUri may be either an image URI or a video URI, in both cases it is of the form content://...

Is it possible to display video thumbnails from a video content URI using this library? How?

Cheroot answered 5/1, 2014 at 8:29 Comment(0)
C
10

Ok, I figured it out. ImageLoaderConfiguration has an option where you can pass in an image decoder.

Here is how I changed the initialization:

ImageDecoder smartUriDecoder = new SmartUriDecoder(getContentResolver(), new BaseImageDecoder(false));

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
            .taskExecutor(ThreadPool.getExecutorService())
            .defaultDisplayImageOptions(displayOptions)
            .imageDecoder(smartUriDecoder)
            .build();

And the SmartUriDecoder class:

public class SmartUriDecoder implements ImageDecoder {
    private final ContentResolver m_contentResolver;
    private final BaseImageDecoder m_imageUriDecoder;

    public SmartUriDecoder(ContentResolver contentResolver, BaseImageDecoder imageUriDecoder) {
        if (imageUriDecoder == null) {
            throw new NullPointerException("Image decoder can't be null");
        }

        m_contentResolver = contentResolver;
        m_imageUriDecoder = imageUriDecoder;
    }

    @Override
    public Bitmap decode(ImageDecodingInfo info) throws IOException {
        if (TextUtils.isEmpty(info.getImageKey())) {
            return null;
        }

        String cleanedUriString = cleanUriString(info.getImageKey());
        Uri uri = Uri.parse(cleanedUriString);
        if (isVideoUri(uri)) {
            return makeVideoThumbnail(info.getTargetSize().getWidth(), info.getTargetSize().getHeight(), getVideoFilePath(uri));
        }
        else {
            return m_imageUriDecoder.decode(info);
        }
    }

    private Bitmap makeVideoThumbnail(int width, int height, String filePath) {
        if (filePath == null) {
            return null;
        }
        Bitmap thumbnail = ThumbnailUtils.createVideoThumbnail(filePath, MediaStore.Video.Thumbnails.MINI_KIND);
        Bitmap scaledThumb = scaleBitmap(thumbnail, width, height);
        thumbnail.recycle();
        return scaledThumb;
    }

    private boolean isVideoUri(Uri uri) {
        String mimeType = m_contentResolver.getType(uri);
        return mimeType.startsWith("video/");
    }

    private String getVideoFilePath(Uri uri) {
        String columnName = MediaStore.Video.VideoColumns.DATA;
        Cursor cursor = m_contentResolver.query(uri, new String[] { columnName }, null, null, null);
        try {
            int dataIndex = cursor.getColumnIndex(columnName);
            if (dataIndex != -1 && cursor.moveToFirst()) {
                return cursor.getString(dataIndex);
            }
        }
        finally {
            cursor.close();
        }
        return null;
    }

    private Bitmap scaleBitmap(Bitmap origBitmap, int width, int height) {
        float scale = Math.min(
                ((float)width) / ((float)origBitmap.getWidth()),
                ((float)height) / ((float)origBitmap.getHeight())
        );
        return Bitmap.createScaledBitmap(origBitmap,
                (int)(((float)origBitmap.getWidth()) * scale),
                (int)(((float)origBitmap.getHeight()) * scale),
                false
        );
    }

    private String cleanUriString(String contentUriWithAppendedSize) {
        // replace the size at the end of the URI with an empty string.
        // the URI will be in the form "content://....._256x256
        return contentUriWithAppendedSize.replaceFirst("_\\d+x\\d+$", "");
    }
}

In UIL's documentation it says that info.getImageKey() will return the original URI specified for this image, but with an appended size at the end, and I couldn't find a way to get the original URI. Hence the reason for cleanUriString()'s code smell.

Cheroot answered 5/1, 2014 at 23:34 Comment(6)
Heads up, I tried out this approach, but I noticed a large slow down when I generated thumbnails for a bunch of media items. It looks like UIL is creating a cache entry for the video itself in the data directory which means a lot of processing time and large files (seeing 50 mb files etc). I'm still looking at it, but thanks for a great start towards integrating vids with uil.Pallaten
I noticed this as well, but it only happens the first time around. I assumed it's because the thumbnails for the videos weren't there in the MediaStore, so the call to ThumbnailUtils.createVideoThumbnail() forced the creation of all the video thumbnails. But I don't know for sure how that method works, so I may be totally wrong here.Cheroot
Hi, i tried to make my custom ImageDecoder based on your work but when i try to use it , the decoder fail with this error : E/ImageLoader﹕ null java.lang.NullPointerException? Any clue why ?Lavery
You should look at the stacktrace to see where exactly it fails.Cheroot
@DanielGabriel : Sorry, looks like your smart decoder can support really good for video, but can not load photo ImageDecoder exception was happened when try to load photos. Which methods need put into Smart Decoder, please tell us?Eleazar
I know what is problem. Your case apply for the file load from sdcard case, so in case people load file from http (server). Your codes will not work and causes NullPointerException as people said. I will edit to improve your answer.Eleazar
K
0

I would check out this answer seems like this person solved but it doesnt use the universal-image-loader.

Android: Is it possible to display video thumbnails?

Kozlowski answered 5/1, 2014 at 8:41 Comment(1)
I know how to generate video thumbnails but I'm looking for a configurable solution with caching and synchronization, and UIL seems like a perfect candidate.Cheroot

© 2022 - 2024 — McMap. All rights reserved.