I am trying to load all video files from sdcard in a recycler view. I also want the thumbnail of the video so here is my code to retrieve thumbnail of videos
var thumbColumns = arrayOf(MediaStore.Video.Thumbnails.DATA)
fun getThumbnailPathForLocalFile(fileId:Long): String?{
var thumbCursor: Cursor? = null
try {
thumbCursor = contentResolver.query(
MediaStore.Video.Thumbnails.EXTERNAL_CONTENT_URI,
thumbColumns, MediaStore.Video.Thumbnails.VIDEO_ID + " = "
+ fileId, null, null)
if (thumbCursor!!.moveToFirst()) {
Toast.makeText(applicationContext, thumbCursor.getString(thumbCursor
.getColumnIndex(MediaStore.Video.Thumbnails.DATA)),Toast.LENGTH_LONG).show()
return thumbCursor.getString(thumbCursor
.getColumnIndex(MediaStore.Video.Thumbnails.DATA))
}
} finally {
thumbCursor?.close()
}
return null
}
The method returns the following path /storage/emulated/0/DCIM/.thumbnails/1526834275076.jpg
Following are the ways in which I tried loading the image with glide
video.thumbnailUrl is /storage/emulated/0/DCIM/.thumbnails/1526834275076.jpg
1)
GlideApp.with(context)
.load(Uri.fromFile(File(video.thumbnailUrl)))
.into(holder.thumbnail)
2)
GlideApp.with(context)
.load("file:///"+video.thumbnailUrl)
.into(holder.thumbnail)
3)
GlideApp.with(context)
.load("file://"+video.thumbnailUrl)
.into(holder.thumbnail)
4)
GlideApp.with(context)
.load(video.thumbnailUrl)))
.into(holder.thumbnail)
Same thing is done with Picasso. I even tried using Older version of Glide but still nothing. Most of the Stack Overflow questions mentions the first way but it is not working for me. I have tried from all Android Versions from 19 to 27 but couldn't load the image.
I am getting no such file or directory for all the cases but clearly the file is present otherwise I wouldn't get the path from getThumbnailPathForLocalFile function. I have added the read storage permission. Am I fetching the video thumbnails the right way?
First use picasso latest gradle:
implementation 'com.squareup.picasso:picasso:2.71828'
Then you can simply do like this:
String filePath = "/mnt/sdcard/myimg.png";
Picasso.get().load(new File(filePath)).into(imageView);
Related
I'm building a built-in file manager for my app and I'm using MediaStore to query for the files.
I got everything working, except that the URI I get back is not to Glide's liking.
class java.io.FileNotFoundException: /external/images/media/37: open failed: ENOENT (No such file or directory)
I understand the issue at hand is that there's no protocol added so glide doesn't know how to read it, but I don't know how to add the protocol, I was under the impression that using ContentUris.withAppendedId would handle that for me but it appears to not be.
val mediaList = mutableListOf<Uri>()
val query = buildQuery(folderId, onlyImages)
query?.use { cursor ->
val columnIndexId = cursor.getColumnIndexOrThrow(MediaStore.Files.FileColumns._ID)
val columnIndexMimeType = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE)
val columnIndexDuration = cursor.getColumnIndexOrThrow(MediaStore.Video.VideoColumns.DURATION)
while (cursor.moveToNext())
{
val id = cursor.getLong(columnIndexId)
val contentUri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, id)
mediaList.add(contentUri)
}
}
return mediaList
I'm trying to void using DATA as I already know that's depreciated and I just need this solution work with Android 8+.
Are you converting the contentUri to a path? You shouldn't be doing that. Your contentUri should look like it does below, and then Glide will accept it:
content://media/external/images/media/37
binding.btnShareOne.setOnClickListener {
val intent = Intent(Intent.ACTION_SEND).setType("image/*")
val bitmapDrawable = binding.ivLayoutOne.drawable.toBitmap()
val path = MediaStore.Images.Media.insertImage(
contentResolver,
bitmapDrawable,
"tempimage",
null
)
val uri = Uri.parse(path)
intent.putExtra(Intent.EXTRA_STREAM, uri)
startActivity(Intent.createChooser(intent, "Share Image"))
}
This is my code. I want to get the path from the bitmap and pass it to Uri. When I run my current code it gives me " java.lang.NullPointerException: uriString " error.
I have researched a bit and I think it will be solved by scoped storage but I cannot seem to implement it.
Since .insertImage() is deprecated and also Uri is returning null, this method of mine is not working to get image from image view and share it.
Please help.
A bitmap object doesn't have a path. A Bitmap object is an in memory object. Its just raw bytes. Even if it came from a file, that association isn't kept around.
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;
}
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.
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);
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)
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);
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)
}
}
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);
}
}
I am trying to do the image upload and download for a user profile, when I save a photo I save it with the userId so I can replace it everytime he changes his photo, now what I need is to get that photo with picasso, the thing is, I don't know how to get the photo, it can have different formats and other stuffs like jpeg, png, I just want to get the image when the userID match, I tried this:
storageRef = storage.getReferenceFromUrl("gs://friendlymanager-3b7a2.appspot.com");
Picasso.with(UserSettings.this).load(storageRef + "/Photos/" + userId).into(userImage);
my userImage is my imageView, i don't get any erros just a blank image, i already have a photo for the specific user.
Any help?
you will have to get download link like this,
StorageReference storageRef = storage.getReference().child("users").child(FirebaseAuth.getInstance().getCurrentUser().getUid()).child(FirebaseAuth.getInstance().getCurrentUser().getUid());//reach out to your photo file hierarchically as stored on firebase
storageRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
Log.e("URI", uri.toString());
Glide.with(SaveUserActivity.this).load(uri).into(profile_image);
url = uri.toString();
}
});
Consider using Firebase-UI Android library which gives you ability to load images from storage ref directly. In your case it would look something like this
I'm not sure if Picasso is supported but you can use Glide
for example:
mStorageRef = FirebaseStorage.getInstance().getReference();
Glide.with(this /* context */)
.using(new FirebaseImageLoader())
.load(mStorageRef + "/Photos/" + userId)
.error(R.drawable.default)
.into(imageView);
You should use getDownloadUrl() while fetching images from Firebase storage using Picasso OR glide etc.
I am creating a gallery application and I uploaded 200 images on my phone to test with. Some of them appear as blank thumbnails in my app and in the device's native gallery as well. They are regular JPG files and on my computer I can see them just fine.
How do I exclude these images that will not be rendered, when requesting media from MediaStore here?
ArrayList<String> mediaStoreColumns = new ArrayList<>();
if (cursorID == CURSOR_LOADER_THUMBS) {
mediaStoreColumns.add(MediaStore.Images.Media._ID);
mediaStoreColumns.add(MediaStore.Images.ImageColumns.DATE_TAKEN);
mediaStoreColumns.add(MediaStore.Images.Thumbnails.DATA);
}
return new CursorLoader(GalleryActivity.this,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
mediaStoreColumns.toArray(new String[mediaStoreColumns.size()]), null, null,
MediaStore.Images.ImageColumns.DATE_TAKEN + " DESC");
Here is one of the files:
Here is its information:
And this is an excerpt from the logs:
07-21 14:55:42.674 4469-5489/com.asd.android V/MediaStore: Create the thumbnail in memory: origId=10105, kind=1, isVideo=false
07-21 14:55:42.704 4469-5485/com.asd.android D/skia: --- decoder->decode returned false
07-21 14:55:42.714 4469-5489/com.asd.android D/skia: --- decoder->decode returned false
EDIT:
This is the code I use to obtain thumbnails:
thumbnailBitmap = MediaStore.Images.Thumbnails.getThumbnail(
getContentResolver(),
imageIdInMediaStore,
12345,
MediaStore.Images.Thumbnails.MINI_KIND,
null);
So basically I need to filter out images that do not have a Thumbnail in the media store - how do I do that?
I am not sure, but I think MediaStore.Images.Thumbnails.getThumbnail may be wrong.
It will be worth to try Picasso (or other image libraries).
like this:
int dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
String path = cursor.getString(dataColumn);
Picasso.with(context)
.load(path) // or .load(new File(path))
.resize(thumbnailWidth, thumbnailHeight)
.centerCrop()
.into(imageView);
Hope this helps.