0

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

Harsha pps
  • 2,012
  • 2
  • 25
  • 35

2 Answers2

1

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.

Sinan Ceylan
  • 1,043
  • 1
  • 10
  • 14
  • Thanks for your help Sinan. I tried your suggestion but now I have all same image. I think we must use first cursor's some field and use it second album_art cursor. Because second cursor doesn't know which songs album to get? I tried with album id but that didn't worked because the songs which are locate same folder, have same image – Tayfun Cesur Oct 13 '18 at 19:14
  • Dear Sinan, I think you are iterating the albums cursor. But I don't want albums. I need to get individual cover art of file. – Tayfun Cesur Oct 13 '18 at 19:55
  • @TayfunCesur I understand. Do you use AsyncTask? – Sinan Ceylan Oct 13 '18 at 21:04
  • Yes. But AsyncTask doesn't help in this case. Because the process takes too much time. – Tayfun Cesur Oct 13 '18 at 21:06
  • mediaMetadataRetriever.getEmbeddedPicture() is a native method and every native method call has a price because JNI calls takes time. You may try to combine your async process with glide. https://github.com/bumptech/glide – Sinan Ceylan Oct 13 '18 at 21:16
  • That is exactly brilliant Sinan! I've combined glide and metadataretiever like this, Glide.with(context).load(mediaMetadataRetriever.getEmbeddedPicture()) and now it works so faster! You are awesome!. I think you should edit your answer like this and I'll mark your answer. Adamsınn :) – Tayfun Cesur Oct 13 '18 at 21:26
  • I'm happy to see that it works for you. Thank you for your compliments and adamsın :). By the way I edited my answer. – Sinan Ceylan Oct 13 '18 at 22:03
  • Yes glide is a great library, if you have time look its source. But, glide is not the only one, there are Picasso and Volley. – Sinan Ceylan Oct 13 '18 at 22:46
  • I think glide is the best of them. Google suggests it also – Tayfun Cesur Oct 14 '18 at 00:48
  • If you are using a `RecyclerView` don't forget to override `onViewRecycled` and call `Glide.with(context).clear(holder.imgThumbnail);` this will also speed up the recyclerView – Pierre Nov 14 '19 at 05:57
0

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
        }
    }
varunkr
  • 5,364
  • 11
  • 50
  • 99
  • Thank you for your suggestion. I need to get individual song art, and I've already tried MediaMetadataRetriever. I said that in my question above. This is too slow way – Tayfun Cesur Oct 13 '18 at 19:21
  • Really? You might have been fetching a larger image. See I have restricted the height and width. I created a music player and this worked well. I am sure this should work for your case. – varunkr Oct 13 '18 at 19:24
  • The thing is mmr.getEmbeddedPicture() and decoding this byre array. After this there is no problem about scaling – Tayfun Cesur Oct 13 '18 at 19:43
  • @TayfunCesur OK, I see. If I remember correctly, this process might be a long one as you said. You need to load the images in a background service the first time and then cache them so that you don't need to load them again. So you will have to do this only once. After that, you can just reuse them. The first time you can do it in the splash screen or show the user some loader etc. – varunkr Oct 13 '18 at 19:53
  • 1
    Sounds good. I didn't understand how android os doing this too fast. Now I think they are doing this in that way :D Thank you. I'll try this – Tayfun Cesur Oct 13 '18 at 20:00