I am trying to get the image of mp3 file on my phone. I've been struggling a few days and now I know;
Firstly, I use a content provider with this code
` Uri allSongsUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String selection = MediaStore.Audio.Media.IS_MUSIC + " != 0";
String[] projection = {
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Media.DATA,
MediaStore.Audio.Media.DISPLAY_NAME,
MediaStore.Audio.Media.DURATION,
MediaStore.Audio.Media.ALBUM,
MediaStore.Audio.Media.ALBUM_ID,
MediaStore.Audio.Media.ALBUM_KEY,
MediaStore.Audio.Media.DATE_MODIFIED
};
String sortOrder = MediaStore.Video.Media.DATE_MODIFIED + " DESC";
And I create my cursor like this;
Cursor cursor = ctx.getContentResolver().query(allSongsUri, projection, null, null, sortOrder);
In there I have all my mp3 files. That's ok. Now I want to get their's cover image.
If I use MediaMetadataRetriver's getEmbeddedPicture method like this
mediaMetadataRetriever.setDataSource(localeMusic.getPath());
localeMusic.setImage(mediaMetadataRetriever.getEmbeddedPicture());
it took about 6-7 seconds with nearly 40-50 file. Because getEmbeddedPicture() is too slow!.
Also tried to get album_id and query another cursor to MediaStore.Audio.Albums and I saw all album id is the same because all of them is the same folder. I don't want to show their Album image. I want to show the file's cover image.
I tried this like here But in there, we are getting file's albums image. That is not I ask.
Where can I find the file's image path? Where can the MetadataRetriever class get it with getEmbeddedPicture? Where is that embedded picture?
Thanks. Best regards
mediaMetadataRetriever.getEmbeddedPicture() is a native method and every native method call has a price because JNI calls takes time. So, if you iterate such calls, you may lost a lot of time. You may try to call this method asynchronously on demand and cache the result. Try to combine with glide
This will solve two of your problem at the same time, glide calls is naturally asnyc, so you don't need to implement an AsyncTask class also it caches your images.
This is the basic glide usage:
Glide.with(context).load(mediaMetadataRetriever.getEmbeddedPicture());
I encourage you to read glide documents. It has lots of other features.
Hope this helps.
You can get the album art as mentioned here
https://stackoverflow.com/a/17574629/3825975
Basically,
Cursor cursor = getContentResolver().query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[] {MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID+ "=?",
new String[] {String.valueOf(albumId)},
null);
if (cursor.moveToFirst()) {
String path = cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM_ART));
// do whatever you need to do
}
But to get individual song art, this is how I remember doing it. Hope it helps.
float ht_px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics());
float wt_px = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics());
Bitmap artwork, bitmap2 = null;
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
byte[] rawArt;
BitmapFactory.Options bfo = new BitmapFactory.Options();
try {
mmr.setDataSource(songUri); //songUri is the uri of the song. You need to extract this from the song id
rawArt = mmr.getEmbeddedPicture();
if (rawArt != null)
bitmap2 = BitmapFactory.decodeByteArray(rawArt, 0, rawArt.length, bfo);
if (bitmap2 == null)
bitmap2 = BitmapFactory.decodeResource(getResources(), R.drawable.def_icon);
artwork = Bitmap.createScaledBitmap(bitmap2, (int) ht_px, (int) wt_px, true); //This is the bitmap you need
} catch (Exception e) {
//Exception handling
}
}
Related
I want to select a video from my Gallery. It's working fine. But now I want to display a Bitmap, as a thumbnail.I tried this code and it's not working, it always says: NullPointerException
Bitmap bitmap2 = ThumbnailUtils.createVideoThumbnail(uri.getPath, MediaStore.Video.Thumbnails.MICRO_KIND);
This is all in an onActivityResult().
How can I get the Bitmap from the video Uri??
Thanks for your help
In the latest API 24, you may face some issues if you stick with an approach in the accepted answer.
for example in this line int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); sometimes I got W/System.err: java.lang.IllegalArgumentException: column '_data' does not exist error message.
also in the latest API, you may get SecurityException if you deal with widgets or shared content. Keep that in mind.
As for the video thumbnail from Uri - I use an approach which utilizes MediaMetadataRetriever, thus you don't need to get String filePath:
MediaMetadataRetriever mMMR = new MediaMetadataRetriever();
mMMR.setDataSource(context, videoUri);
bmp = mMMR.getFrameAtTime();
Hope this helps
in onActivityResult
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
String picturePath = cursor.getString(columnIndex);
cursor.close();
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(picturePath, MediaStore.Video.Thumbnails.MICRO_KIND);
Edit
Kotlin version
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
val cursor = context.contentResolver.query(uri, filePathColumn, null, null, null)
cursor.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
val picturePath = cursor.getString(columnIndex)
cursor.close()
val bitmap = ThumbnailUtils.createVideoThumbnail(picturePath, MediaStore.Video.Thumbnails.MICRO_KIND)
Try this one:
Bitmap bitmap2 = ThumbnailUtils.createVideoThumbnail( uri.getPath() , MediaStore.Images.Thumbnails.MINI_KIND );
For API 27, for document URI (1000 is microseconds)
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource( context, doc_uri );
Bitmap bm = mmr.getScaledFrameAtTime( 1000, MediaMetadataRetriever.OPTION_NEXT_SYNC, 128, 128 );
This works for me:
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(filePath, Thumbnails.MINI_KIND);
Using ThumbnailUtils, you can create thumbnail of two types.
MediaStore.Images.Thumbnails.MICRO_KIND - type will generate thumbnail of size 96 x 96.
MediaStore.Images.Thumbnails.MINI_KIND - type will generate thumbnail of size 512 x 384.
createVideoThumbnail() needs the file path, not the content uri.
The file path requires external read permissions.
If you're getting null responses, it may be from using the content uri (though the assumption in ThumbnailsUtils.java is of a corrupt video file). When I fixed that, then I was getting permissions errors.
I was able to get the file path from the content uri using the video's ID like this:
val selection = MediaStore.Video.Media._ID + " = $id"
val cursor =
this.contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null,
selection, null, null)
And then continue on with the cursor as in the other answers in SO.
Docs for contentResolver.query()
Cursor c = MediaStore.Video.query(cr,uri, new String[]{
MediaStore.Video.VideoColumns._ID,
MediaStore.Video.VideoColumns.DATA});
if (c!=null){
c.moveToFirst();
int id = Integer.valueOf( c.getString(0) );
c.close();
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize = 1;
try {
return MediaStore.Video.Thumbnails.getThumbnail(cr, id, MediaStore.Video.Thumbnails.MINI_KIND, options);
}catch (java.lang.SecurityException ex){
ex.printStackTrace();
//TODO: add create ThumbnailUtils.createVideoThumbnail
return null;
}
}
CancellationSignal ca = new CancellationSignal();
var vthumb = ThumbnailUtils.createVideoThumbnail(new File(value),new Size(120,120), ca);
So I've been trying this for some time now. To get the album art for an mp3 file and displaying it on its respective ImageView and I am using the uri("content://media/external/audio/albumart")
This is my method for getting the album art
public Bitmap getAlbumArt(long idAlbum){
Bitmap bitmap = null;
try{
final Uri sArtworkUri = Uri.parse("content://media/external/audio/albumart");
Uri uri = ContentUris.withAppendedId(sArtworkUri, idAlbum);
ParcelFileDescriptor parcelFileDescriptor = getContext().getContentResolver().openFileDescriptor(uri,"r");
if (parcelFileDescriptor != null){
FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
bitmap = BitmapFactory.decodeFileDescriptor(fileDescriptor);
}
}catch (Exception e){
e.printStackTrace();
}
return bitmap;
}
and this method always returns
java.io.FileNotFoundException: No entry for content://media/external/audio/albumart/31726
where the 31726 is the album id.
Since I'm catching this exception and I set it to a default Album art if it returns null, every mp3 has its ImageView set to the default album art. I am using my Samsung Galaxy s3 to run the application and my device runs android 4.2.2 JellyBean. Please someone help me getting this right.
This is how I request the album id
Uri musicUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
String[] columns = {
MediaStore.Audio.Media.TITLE,
MediaStore.Audio.Media.ARTIST,
MediaStore.Audio.Albums._ID,
MediaStore.Audio.Media.DATA
};
String where = MediaStore.Audio.Media.IS_MUSIC + "=1";
Cursor musicCursor = usicResolver.query(musicUri,columns,where,null, null);
Then in an if loop with condition
if(musicCursor.moveToFirst()){
int albumId = musicCursor.getColumnIndex
(MediaStore.Audio.Albums._ID);
do{
long idAlbum = musicCursor.getLong(albumId);
//Then i send it to my above method getAlbumArt
Bitmap songAlbumArt = getAlbumArt(idAlbum);
}while(musicCursor.moveToNext());
}
This is how I query the cover art path from the album id:
private static String getCoverArtPath(long albumId, Context context) {
Cursor albumCursor = context.getContentResolver().query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Albums.ALBUM_ART},
MediaStore.Audio.Albums._ID + " = ?",
new String[]{Long.toString(albumId)},
null
);
boolean queryResult = albumCursor.moveToFirst();
String result = null;
if (queryResult) {
result = albumCursor.getString(0);
}
albumCursor.close();
return result;
}
You can get the Bitmap from the BitmapFactory using the path returned from the method above:
BitmapFactory.decodeFile(coverArtPath);
ImageLoader.getInstance().
displayImage( ContentUris.withAppendedId(Uri.parse("content://media/external/audio/albumart"), song_tag.albumId).toString(),
image,
new DisplayImageOptions.Builder().cacheInMemory(true).showImageOnFail(R.drawable.stock6).resetViewBeforeLoading(true).build());
image is the object of ImageView
song_tag.albumid is the album id which you have to send to get the image
stock6 is the default image
EDIT:
It seems that ALBUM_ART was deprecated on API 29:
https://developer.android.com/reference/android/provider/MediaStore.Audio.AlbumColumns#ALBUM_ART
Instead, they suggest using ContentResolver#loadThumbnail:
https://developer.android.com/reference/android/content/ContentResolver#loadThumbnail(android.net.Uri,%20android.util.Size,%20android.os.CancellationSignal)
--
ORIGINAL:
Querying the album art field from content://media/external/audio/albums would do it for me some time ago, but I noticed it stopped working since a few Android versions ago, for some reason.
Now I querying the albums table gets me a null album art field:
adb shell content query --uri content://media/external/audio/albums
Row: 0 numsongs=1, artist=My Artist, numsongs_by_artist=1, _id=8821305607184940112, album=My Album, album_art=NULL, album_key=4c3a3434044e5052303a4604342a3e32044248194e, artist_id=7053871990187004266, artist_key=484c465046503832464c2a04422a402a563a32444e3a4e, maxyear=NULL, minyear=NULL, album_id=8821305607184940112
Querying the album art route directly, also gives me no results...
adb shell content query --uri content://media/external/audio/albumart
No result found.
It seems that the MediaStore on the platform side... stopped trying to parse album art from music files, and add them to its db?
I am populating a gridview with MICRO_KIND thumbnails using the following:
/* Find images of interest */
imagecursor = getActivity().getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CON TENT_URI,
columns,
MediaStore.Images.Media.DATA + " like ? ",
new String[]{"%/houseTab" + currentHouseNumber + "/%"},
null);
/* Retrieve MICRO_KIND Thumbnails */
int id = imagecursor.getInt(image_column_index);
thumbnails[i] = MediaStore.Images.Thumbnails.getThumbnail(
getActivity().getApplicationContext().getContentResolver(), id,
MediaStore.Images.Thumbnails.MICRO_KIND, null);
The retrieve process works perfectly; the issue happen when I delete the actual image files I can not delete the MICRO_KIND Thumbnails. This is what I am using right now and the files images gets deleted but the MICRO_KIND does not get deleted and still visible in the gridview even after a refresh. To get rid of the thumbnail I have to turn off the device or do a unmount/mount of the sdcard.
int count = imagecursor.getCount();
int image_column_index = imagecursor.getColumnIndex(MediaStore.Images.Media._ID);
ContentResolver cr = getActivity().getApplicationContext().getContentResolver();
for (int i = 0; i < count; i++) {
new File(arrPath[i]).delete(); // Delete the actual image file
imagecursor.moveToPosition(i);
long id = imagecursor.getInt(image_column_index);
/* Delete the thumbnails ???? Not working */
cr.delete(MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI, MediaStore.Images.Thumbnails.IMAGE_ID +
"= ?",new String[]{"" + id});
By the way arrPath is retrieve from the mediastore using the following:
int dataColumnIndex = imagecursor.getColumnIndex(MediaStore.Images.Media.DATA);
arrPath[i] = imagecursor.getString(dataColumnIndex);
I also try to following to delete the thumbnails but also without any success.
MediaScannerConnection.scanFile(
getActivity().getApplicationContext(),
new String[]{arrPath[i]},
null,
new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
refreshImages();
}
});
So how do I remove this entry from the database so the when the imagecursor is refreshed after the file deletion the imagecursor is empty and no MICRO_KIND or any data for that matter is returned???
Any help would be appreciated.
Hopefully this will help others. I manage to delete the entry from the mediastore hence the MICRO_KIND thumbnails using the following:
Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
id);
cr.delete(uri,null,null);
I'm having this same problem, I couldn't find any way to delete the MICRO_KIND thumbnails no matter what I did, so I peeked through the MediaStore source code and saw that there were references to the /sdcard/DCIM/.thumbnails/.thumbdata3--##### file, and it looks like thats where the MICRO_KIND thumbnails are stored.
The MediaStore database holds records that point to the thumbnail files in the /sdcard/DCIM/.thumbnails folder, so when you delete a thumbnail from MediaStore, it also deletes the file under that folder (which appear to be the MINI_KIND thumbnails since they are considerably larger than MICRO_KIND).
When I deleted the /sdcard/DCIM/.thumbnails/.thumbdata--BLAHBLAH file through ADB, it fixed my problem, the correct thumbnails loaded and I noticed the file instantly was recreated.
I also noticed when I deleted the file throught he ContentResolver like you did, and then queried the MINI_KIND thumbnails, they always loaded correctly.
So my answer (which seems more like a workaround than an answer) was to query the MINI_KIND thumbnails from the MediaStore, and extract a thumbnail from that:
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 3;
Bitmap out = MediaStore.Images.Thumbnails.getThumbnail(contentResolver, imageId, MediaStore.Images.Thumbnails.MINI_KIND, opts);
out = ThumbnailUtils.extractThumbnail(out, 96, 96);
And delete the thumbnail using user2553585's answer
Hope this helps
I'm trying to provide an in-app Activity which displays thumbnails of photos in the
device's media store, and allow the user to select one. After the user makes a
selection, the application reads the original full-size image and does things with it.
I'm using the following code to create a Cursor over all the images on the external
storage:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView( R.layout.image_select );
mGridView = (GridView) findViewById( R.id.image_select_grid );
// Query for all images on external storage
String[] projection = { MediaStore.Images.Media._ID };
String selection = "";
String [] selectionArgs = null;
mImageCursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
// Initialize an adapter to display images in grid
if ( mImageCursor != null ) {
mImageCursor.moveToFirst();
mAdapter = new LazyCursorAdapter(this, mImageCursor, R.drawable.image_select_default);
mGridView.setAdapter( mAdapter );
} else {
Log.i(TAG, "System media store is empty.");
}
}
And the following code to load the thumbnail image (Android 2.x code is shown):
// ...
// Build URI to the main image from the cursor
int imageID = cursor.getInt( cursor.getColumnIndex(MediaStore.Images.Media._ID) );
Uri uri = Uri.withAppendedPath( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
Integer.toString(imageID) );
loadThumbnailImage( uri.toString() );
// ...
protected Bitmap loadThumbnailImage( String url ) {
// Get original image ID
int originalImageId = Integer.parseInt(url.substring(url.lastIndexOf("/") + 1, url.length()));
// Get (or create upon demand) the micro thumbnail for the original image.
return MediaStore.Images.Thumbnails.getThumbnail(mContext.getContentResolver(),
originalImageId, MediaStore.Images.Thumbnails.MICRO_KIND, null);
}
And the following code to load the original image from the URL once the user makes a selection:
public Bitmap loadFullImage( Context context, Uri photoUri ) {
Cursor photoCursor = null;
try {
// Attempt to fetch asset filename for image
String[] projection = { MediaStore.Images.Media.DATA };
photoCursor = context.getContentResolver().query( photoUri,
projection, null, null, null );
if ( photoCursor != null && photoCursor.getCount() == 1 ) {
photoCursor.moveToFirst();
String photoFilePath = photoCursor.getString(
photoCursor.getColumnIndex(MediaStore.Images.Media.DATA) );
// Load image from path
return BitmapFactory.decodeFile( photoFilePath, null );
}
} finally {
if ( photoCursor != null ) {
photoCursor.close();
}
}
return null;
}
The problem I'm seeing on some Android devices, including my own personal phone, is that the
cursor I get from the query in onCreate() contains a few entries for which the actual full-sized image file (JPG or PNG) is missing. (In the case of my phone, the images had been imported and subsequently erased by iPhoto).
The orphaned entries may or may not have thumbnails, depending upon whether thumbnails where generated before the actual media file when AWOL. The end result is that the app displays thumbnails for images that don't actually exist.
I have a few questions:
Is there a query I can make to the MediaStore content provider that will filter out
images with missing media in the returned Cursor?
Is there a means, or an API to force the MediaStore to rescan, and eliminate the orphan entries? On my phone, I USB-mounted then unmounted the external media, which is supposed to trigger a rescan. But the orphan entries remain.
Or is there something fundamentally wrong with my approach that's causing this problem?
Thanks.
Okay, I've found the problem with this code sample.
In the onCreate() method, I had this line:
mImageCursor = managedQuery( MediaStore.Images.Thumbnails.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
The problem here is that it's querying for the thumbnails, rather than the actual images. The camera app on HTC devices does not create thumbnails by default, and so this query will fail to return images that do not already have thumbnails calculated.
Instead, query for the actual images themselves:
mImageCursor = managedQuery( MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
projection, selection, selectionArgs, null );
This will return a cursor containing all the full-sized images on the system. You can then call:
Bitmap bm = MediaStore.Images.Thumbnails.getThumbnail(context.getContentResolver(),
imageId, MediaStore.Images.Thumbnails.MINI_KIND, null);
which will return the medium-sized thumbnail for the associated full-size image, generating it if necessary. To get the micro-sized thumbnail, just use MediaStore.Images.Thumbnails.MICRO_KIND instead.
This also solved the problem of finding thumbnails that have dangling references to the original full-sized images.
Please note that things will be changing soon, managedQuery method is deprecated. Use CursorLoader instead(since api level 11).
I tried to create a video thumbnail as described here.
I also read the reference here.
In my app I first let the user choose a video with:
startActivityForResult(new Intent(Intent.ACTION_GET_CONTENT).setType("video/*"), ACTIVITY_PICKVIDEO);
Then I determine the video ID with:
fileID = Integer.parseInt(contentUri.getLastPathSegment());
So, the video content://media/external/video/media/5 would have the ID 5.
Then I try to get the thumbnail bitmap with:
ContentResolver crThumb = getContentResolver();
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
Bitmap curThumb = MediaStore.Video.Thumbnails.getThumbnail(crThumb, fileID, MediaStore.Video.Thumbnails.MICRO_KIND, options);
There's no exception thrown but the bitmap has a width and height of -1.
I'm not sure if the ID needed in getThubnail() is actually the ID that I determined above.
Does anyone know of a working example how to get the thumbnail bitmap if you have the content Uri?
Interestingly (maybe so) I get null when trying with MediaStore.Video.Thumbnails.MINI_KIND as thumbnail size and an IllegalArgumentException ("Unsupported kind: 2") when I try FULL_SCREEN_KIND.
I'm using a Motorola Milestone with Android 2.1.
EDIT:
I also tried getting the ID with querying for the BaseColumns._ID but it turns out to be the same as in the Uri (in the given example the _ID is 5).
for getting video id try this
String[] proj = {
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DATA
};
Cursor cursor = managedQuery(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
proj, MediaStore.Video.Media.DISPLAY_NAME+"=?",new String[] {"name.mp4"}, null);
cursor.moveToFirst()
fileid = cursor.getLong(cursor.getColumnIndex(MediaStore.Video.Media._ID));
for getting thumbnail :
ContentResolver crThumb = getContentResolver();
Bitmap curThumb = MediaStore.Video.Thumbnails.getThumbnail(crThumb,fileid, MediaStore.Video.Thumbnails.MICRO_KIND, options);
iv2.setImageBitmap(curThumb);
here iv2 is imageview and name.mp4 will represent your file name