Android: How do I get thumbnail from a Video (Uri) - android

I want thumbnail from a video at any specific position. I am using ThumbnailUtils in order to get thumbnail from video uri and assigning to bitmap but I am getting null value on bitmap.
Any reasons how this is happening and how do I fix this?
selectedVideoUri = data.getData();
bitmap = ThumbnailUtils.createVideoThumbnail(getRealPathFromURI(videoUri),
MediaStore.Images.Thumbnails.MINI_KIND);
public String getRealPathFromURI(Uri contentUri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);
if(cursor.moveToFirst()){;
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}

You can use Glide to load thumb directly to imageview
Glide.with(activity).load(videoPath).into(imageview);

First Load Video List with its path in Your array list using below method
private void loadData(String currentAppPath) {
hiddenpath = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + currentAppPath);
String[] fileName = hiddenpath.list();
try{
for(String f : fileName){
if(HelpperMethods.isVideo(f)){
videoFiles.add(hiddenpath.getAbsolutePath()+"/"+f);
}
}
new Loader().loadImages(Environment.getExternalStorageState());
}catch (Exception e){
}
}
You need Loader().loadImages method so i declare this method in separate class file. see below code
public class Loader {
String[] imagieFiles;
public void loadImages(String path){
Log.e("path",path);
System.out.println(path);
} }
Then after You can use below Code to Get Video Thumbnail. By default Each Video Store two size Thumbnail.
1) MINI -- MediaStore.Images.Thumbnails.MINI_KIND and
2) MICRO -- MediaStore.Images.Thumbnails.MICRO_KIND
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(filePath,
MediaStore.Images.Thumbnails.MINI_KIND);
BitmapDrawable bitmapDrawable = new BitmapDrawable(thumb);
contentViewHolder.videoView.setImageBitmap(thumb);

This is supported by Android natively using MediaPlayer SeekTo method
If you just want to show the video placeholder to display then you can use below code:
video_view.setVideoPath(videoPath);
video_view.seekTo(3000); // in milliseconds i.e. 3 seconds

ThumbnailUtils returns null when file or video is corrupted.
but I wanted to only use Uri and this is a good solution to do this:
val mmr = MediaMetadataRetriever()
mmr.setDataSource(videoUri)
val thummbnailBitmap = mmr.frameAtTime
imageView.setImageBitmap(thummbnailBitmap)

Related

ThumbnailUtils.createVideoThumbnail return null bitmap for mp4 file

When I get bitmap for mp4 file with: ThumbnailUtils.createVideoThumbnail(mediaFile.getAbsolutePath(), MediaStore.Video.Thumbnails.MINI_KIND); return null
Try this, May be you media file path was wrong. Use below method you will get exact path. Its working for me
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(getPath(outputFileUri),
MediaStore.Images.Thumbnails.MINI_KIND);
photo_Img.setImageBitmap(thumb);
/**
* Get file path
*/
public static String getPath(Uri uri) {
String[] projection = { MediaStore.Images.Media.DATA };
Cursor cursor = context.managedQuery(uri, projection, null, null, null);
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
I think you must set requires permission in AndroidManifest <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
File file = new File(filepath);
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(file.getAbsolutePath(), MediaStore.Video.Thumbnails.FULL_SCREEN_KIND);
From android docs:
public static Bitmap createVideoThumbnail (String filePath, int kind)
Create a video thumbnail for a video. May return null if the video is corrupt or the format is not supported.
Hence, I guess you need to re-check the mp4 file.

Download image from new Google+ (plus) Photos Application

Recently Google added the Photos app for Google+ (plus) and it shows up when you launch an Intent to choose an image. However, if I select an image from Google+ Photos and try to use it in my application none of my current logic is able to return a usable URI or URL to actually get an image that I can download and manipulate. I'm currently using the "common" methods to try to manipulate the URI that can be found here on Stack Overflow and elsewhere. I can provide code if needed, but at this point I think it's kind of irrelevant since it works well for everything else except this new app. Any ideas on how to get a usable image?
The URI looks something like the following:
content://com.google.android.apps.photos.content/0/https%3A%2F%2Flh5.googleusercontent.com%<a bunch of letters and numbers here>
The MediaColumns.DATA info always returns null and the MediaColumns.DISPLAY_NAME always returns image.jpg no matter what I select from the Google Photos app. If I try to paste everything from https to the end in my browser, nothing comes up. Not sure how to get usable info from this.
When receiving the data intent, you should use the contentResolver to get the photos.
Here's what you should do:
String url = intent.getData().toString();
Bitmap bitmap = null;
InputStream is = null;
if (url.startsWith("content://com.google.android.apps.photos.content")){
is = getContentResolver().openInputStream(Uri.parse(url));
bitmap = BitmapFactory.decodeStream(is);
}
I did faced issues selecting images from new Google Photos app. I was able to resolve it by below code.
It works for me, basically what i did is i am checking if there is any authority is there or not in content URI. If it is there i am writing to temporary file and returning path of that temporary image. You can skip compression part while writing to temporary image
public static String getImageUrlWithAuthority(Context context, Uri uri) {
InputStream is = null;
if (uri.getAuthority() != null) {
try {
is = context.getContentResolver().openInputStream(uri);
Bitmap bmp = BitmapFactory.decodeStream(is);
return writeToTempImageAndGetPathUri(context, bmp).toString();
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return null;
}
public static Uri writeToTempImageAndGetPathUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
P.S. : I have answered a similar question here
You have to use projection in order to get ImageColumns.DATA (or MediaColumns.DATA):
private String getRealPathFromURI(Uri contentURI) {
// Projection makes ContentResolver to get needed columns only
String[] medData = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(contentURI, medData, null, null, null);
// this is how you can simply get Bitmap
Bitmap bmp = MediaStore.Images.Media.getBitmap(getContentResolver(), contentURI);
// After using projection cursor will have needed DATA column
cursor.moveToFirst();
final int idx = cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA);
return cursor.getString(idx);
}

File doesn't exists when i select a gallery photo android

When I select an image from the gallery, I grab the intent Uri via the parameter that is passed by the onActivityResult. When doing: new File(String_Uri_given_to_me) and do File.Exists(), gives me null...
What I can do?
It seems you may try:
new File(Uri_given_to_you.getpath())
It may be okay.
If answer above doesn't solve your problem use this code
private final synchronized String getPath(Uri uri) {
String res = null;
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = getContentResolver().query(uri, proj,
null, null, null);
if (cursor.moveToFirst()) {
int column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
res = cursor.getString(column_index);
}
cursor.close();
return res;
}
I was having a hard time with this issue. I was not able to get some images Path (Even using Maxim Efivmov code) and finally decided to use Google's documentation on this topic. https://developer.android.com/guide/topics/providers/document-provider.html
This piece of code worked to get the bitmap
private Bitmap getBitmapFromUri(Uri uri) throws IOException {
ParcelFileDescriptor parcelFileDescriptor =
getContentResolver().openFileDescriptor(uri, "r");
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
Bitmap image = BitmapFactory.decodeFileDescriptor(fileDescriptor);
parcelFileDescriptor.close();
return image;
}
You can use this bitmap to display it in an Image View.

Referencing a file on SD-Card, Android

I currently trying to carry out the same operation (OCR) on images in android, one option is to use the camera and the other is to load an image from the SD-CARD. The code works when taken from a camera where the code is
Bitmap bitmap = BitmapFactory.decodeFile(_path,options);
where _path is equal to the last image taken using the application ( _path = DATA_PATH + "ocr.jpg"; ) . However when I try to use an image selected from the gallery where _path would equal,
imageCaptureUri = data.getData();
_path = imageCaptureUri.getPath();
The program locks up with the error
Failure deleiving result ResultInfo{who=null, request = 2, result = -1, data=intent {dat=content://media/external/images/media/26 typ=image/jpeg(has extras)}} to activity{com.project.projectActivity}: java.lang.NullPointerException
If anybody has an idea of whats going on I'd like to hear from you !!
You can get path of the image as..
_path = getPath(imageCaptureUri);
public String getPath(Uri uri) {
String[] projection = { MediaColumns.DATA };
Cursor cursor = managedQuery(uri, projection, null, null, null);
column_index = cursor
.getColumnIndexOrThrow(MediaColumns.DATA);
cursor.moveToFirst();
imagePath = cursor.getString(column_index);
return cursor.getString(column_index);
}
and then
Bitmap bitmap = BitmapFactory.decodeFile(_path,options);
Note : If you are cropping image then this method does not work in this case Gallery will generate cropped image on same directory of image which you are cropping.
The Gallery returns you an Uri to access the image.
You need to use the decodeStream method from BitmapFactory, and for that you need to open an InputStream on the Uri given :
InputStream is = getContentResolver().openInputStream(imageCaptureUri);
Bitmap bitmap = BitmapFactory.decodeStream(is, options);

How to get thumbnail for video in my /sdcard/Android/data/mypackage/files folder?

Query to MediaStore.Video.Media.EXTERNAL_CONTENT_URI returns only video in /sdcard/DCIM/100MEDIA
But I want to get thumbnails for video in my /sdcard/Android/data/mypackage/files folder. Is it possible ?
Here is part of my code:
ContentResolver cr = getContentResolver();
String[] proj = {
BaseColumns._ID
};
Cursor c = cr.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, proj, null, null, null);
if (c.moveToFirst()) {
do
{
int id = c.getInt(0);
Bitmap b = MediaStore.Video.Thumbnails.getThumbnail(cr, id, MediaStore.Video.Thumbnails.MINI_KIND, null);
Log.d("*****My Thumbnail*****", "onCreate bitmap " + b);
ImageView iv = (ImageView) findViewById(R.id.img_thumbnail);
iv.setImageBitmap(b);
}
while( c.moveToNext() );
}
c.close();
If you are on android-8 (Froyo) or above, you can use ThumbnailUtils.createVideoThumbnail:
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
Use Glide it will fetch the thumbnail in async.
Glide.with(context)
.load(videoFilePath) // or URI/path
.into(imgView); //imageview to set thumbnail to
3 ways to get a thumbnail from a video:
The best way is to use Glide. It will do all the work in the background, load the thumbnail right into the ImageView and even can show animation when loading. It can work with Uri, byte[] and many other sources.
As #Ajji mentioned:
Glide.with(context)
.load(videoFilePath) // or URI/path
.into(imgView); //imageview to set thumbnail to
If you just need a bitmap in the most efficient way - use ThumbnailUtils.
In my case, it produced a bitmap with a size of 294 912 bytes (video taken with a camera of Nexus5X - 1280x720) and the quality was the same as in the next approach. After you compress into JPEG with 90 it will generate a jpeg file of ~30Kb.
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
The last approach is to use MediaMetadataRetriever. But in my case, it produced a bitmap with size more than 6 times bigger than you got with ThumbnailUtils (with the same quality). So consider it as a last resort.
MediaMetadataRetriever mMMR = new MediaMetadataRetriever();
mMMR.setDataSource(mContext, mAttachment.getUri());
bmp = mMMR.getFrameAtTime();
P.S.: Don't forget that images in Bitmap, byte[] and real file .jpeg formats can be easily converted in any direction within these types. In case of Uri's you often don't have real path to the source file but you can always get the byte stream from it like this:
InputStream in = mContext.getContentResolver().openInputStream(uri);
and with this input stream you can do whatever you want.
You can just use FFmpegMediaMetadataRetriever and forget the reflection:
/**
*
* #param path
* the path to the Video
* #return a thumbnail of the video or null if retrieving the thumbnail failed.
*/
public static Bitmap getVideoThumbnail(String path) {
Bitmap bitmap = null;
FFmpegMediaMetadataRetriever fmmr = new FFmpegMediaMetadataRetriever();
try {
fmmr.setDataSource(path);
final byte[] data = fmmr.getEmbeddedPicture();
if (data != null) {
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
if (bitmap == null) {
bitmap = fmmr.getFrameAtTime();
}
} catch (Exception e) {
bitmap = null;
} finally {
fmmr.release();
}
return bitmap;
}
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDither = false;
options.inPreferredConfig = Bitmap.Config.ARGB_8888;
Bitmap bitmapThumb = MediaStore.Video.Thumbnails.getThumbnail(mActivity.getContentResolver(),
Long.parseLong(video_id),
Images.Thumbnails.MINI_KIND,
options);
Use Options to load bitmap of decrease the bitmap size..
see #Ajji 's answer :
Glide.with(context)
.load(videoFilePath) // or URI/path
.into(imgView); //imageview to set thumbnail to
It sometimes returns black image, this issue is already mentioned in Glide library's issues
Use this code:
BitmapPool bitmapPool = Glide.get(activity).getBitmapPool();
int microSecond = 6000000;// 6th second as an example
VideoBitmapDecoder videoBitmapDecoder = new VideoBitmapDecoder(microSecond);
FileDescriptorBitmapDecoder fileDescriptorBitmapDecoder = new FileDescriptorBitmapDecoder(videoBitmapDecoder, bitmapPool, DecodeFormat.PREFER_ARGB_8888);
Glide.with(activity)
.load(videoPath)
.asBitmap()
.override(50,50)// Example
.videoDecoder(fileDescriptorBitmapDecoder)
.into(holder.ivFirstUpload);
Get video thumbnail from VIDEO_ID:
public static Drawable getVideoThumbnail(Context context, int videoID) {
try {
String[] projection = {
MediaStore.Video.Thumbnails.DATA,
};
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(
MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
projection,
MediaStore.Video.Thumbnails.VIDEO_ID + "=?",
new String[] { String.valueOf(videoID) },
null);
cursor.moveToFirst();
return Drawable.createFromPath(cursor.getString(0));
} catch (Exception e) {
}
return null;
}
Here is a similar answer to Matthew Willis but with added reflection. Why? because science.
/**
*
* #param path
* the path to the Video
* #return a thumbnail of the video or null if retrieving the thumbnail failed.
*/
public static Bitmap getVidioThumbnail(String path) {
Bitmap bitmap = null;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
bitmap = ThumbnailUtils.createVideoThumbnail(path, Thumbnails.MICRO_KIND);
if (bitmap != null) {
return bitmap;
}
}
// MediaMetadataRetriever is available on API Level 8 but is hidden until API Level 10
Class<?> clazz = null;
Object instance = null;
try {
clazz = Class.forName("android.media.MediaMetadataRetriever");
instance = clazz.newInstance();
final Method method = clazz.getMethod("setDataSource", String.class);
method.invoke(instance, path);
// The method name changes between API Level 9 and 10.
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD) {
bitmap = (Bitmap) clazz.getMethod("captureFrame").invoke(instance);
} else {
final byte[] data = (byte[]) clazz.getMethod("getEmbeddedPicture").invoke(instance);
if (data != null) {
bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
if (bitmap == null) {
bitmap = (Bitmap) clazz.getMethod("getFrameAtTime").invoke(instance);
}
}
} catch (Exception e) {
bitmap = null;
} finally {
try {
if (instance != null) {
clazz.getMethod("release").invoke(instance);
}
} catch (final Exception ignored) {
}
}
return bitmap;
}
If you are directly creating thumbnails as follows
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
Then there is a problem with this method if your are creating thumbnails for large video set(for large number of videos). the application will freeze until all the thumbnails are loaded because all the process are executing in the main thread.
Use SuziLoader
This loader will load the thumbnails for the videos which is locally stored on your filesystem in background.
String path = Environment.getExternalStorageDirectory().getAbsolutePath() + "/video.mp4";
ImageView mThumbnail = (ImageView) findViewById(R.id.thumbnail);
SuziLoader loader = new SuziLoader(); //Create it for once
loader.with(MainActivity.this) //Context
.load(path) //Video path
.into(mThumbnail) // imageview to load the thumbnail
.type("mini") // mini or micro
.show(); // to show the thumbnail
To get this dependency use the following steps
Step 1. Add the JitPack repository to your build file
Add it in your root build.gradle at the end of repositories:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
Step 2. Add the dependency
dependencies {
compile 'com.github.sushinpv:SuziVideoThumbnailLoader:0.1.0'
}
ADD READ EXTERNAL STORAGE Permission in manifest
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Try something similar to this code snippet:
img.setImageBitmap(ThumbnailUtils.createVideoThumbnail(
Environment.getExternalStorageDirectory().getPath() + "/WhatsApp/Media/WhatsApp Video/"+getItem(position),
MediaStore.Video.Thumbnails.FULL_SCREEN_KIND));
Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
String[] projection = { MediaStore.Video.VideoColumns.DATA };
Cursor c = getContentResolver().query(uri, projection, null, null, null);
int vidsCount = 0;
if (c != null) {
vidsCount = c.getCount();
while (c.moveToNext()) {
String path = c.getString(0);
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(path,
MediaStore.Images.Thumbnails.MINI_KIND);
}
c.close();
}
You can use this method with any Uri:
public static Bitmap getVideoFrame(Uri uri, Context context) {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(context, uri);
return retriever.getFrameAtTime();
}

Categories

Resources