MediaMetadataRetriever.setDataSource(Native Method

2019-08-18 00:59发布

问题:

I'm building a media player using ReactNative. In order to accomplish such app I had to export a module I built for retrieving music metadata like album, artist, etc as well as file path.

The code above was working perfectly using jdk1.8.0_112, but since I updated to jdk1.8.0_144 It stopped working.

In this example, I'm not checking for not null, not empty, length > 0, etc, But I really do in the original one.

try {
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    mmr.setDataSource("Path to the file"); // /storage/337C-1C15/Music/Edguy/Speedhoven.mp3
} catch (RuntimeException ex) {
    // java.lang.RuntimeException: setDataSource failed: status = 0xFFFFFFEA
}

I'm facing two problems. On one hand, I'm not a great Android dev so getting some clues is such hard task. On the other hand, the error does provide a good description.

Just in case some of you had a better way to accomplish what I tried, I left here the whole code:

@ReactMethod
public void getAll(Callback errorCallback, Callback successCallback){

    ContentResolver musicResolver = this.getCurrentActivity().getContentResolver();
    Uri musicUri = android.provider.MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
    Cursor musicCursor = musicResolver.query(musicUri, null, null, null, null);

    if (musicCursor != null && musicCursor.moveToFirst()) {

        WritableArray jsonArray = new WritableNativeArray();
        MediaMetadataRetriever mmr = new MediaMetadataRetriever();
        WritableMap items = new WritableNativeMap();

        int titleColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.TITLE);
        int idColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media._ID);
        int artistColumn = musicCursor.getColumnIndex(android.provider.MediaStore.Audio.Media.ARTIST);

        try {
            do {
                items = new WritableNativeMap();
                byte[] art;

                long thisId = musicCursor.getLong(idColumn);
                String thisPath = musicCursor.getString(musicCursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA));
                String thisTitle = musicCursor.getString(titleColumn);
                String thisArtist = musicCursor.getString(artistColumn);
                String duration = musicCursor.getString(musicCursor.getColumnIndex(MediaStore.Audio.Media.DURATION));


                if(thisPath != null && thisPath != "" && thisPath.endsWith(".mp3")) {

                    mmr.setDataSource(thisPath);

                    String album = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
                    String artist = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
                    String title = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
                    String genre = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE);
                    String encoded = "";
                    String encodedImage = "";
                    art = mmr.getEmbeddedPicture();

                    if (album == null) {
                        album = thisArtist;
                    }

                    if (artist == null) {
                        artist = thisArtist;
                    }

                    if (title == null) {
                        title = thisTitle;
                    }

                    if (art != null) {
                        Bitmap songImage = BitmapFactory.decodeByteArray(art, 0, art.length);
                        if(songImage != null){
                            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                            songImage.compress(Bitmap.CompressFormat.JPEG, 60, byteArrayOutputStream);
                            byte[] byteArray = byteArrayOutputStream.toByteArray();
                            encodedImage = Base64.encodeToString(byteArray, Base64.DEFAULT);
                            String pathtoImg = "";
                            byte[] imageByte = Base64.decode(encodedImage, Base64.DEFAULT);
                            try {
                                pathtoImg = Environment.getExternalStorageDirectory() + "/" + thisId + ".jpg";
                                File filePath = new File(pathtoImg);
                                FileOutputStream fos = new FileOutputStream(filePath, true);
                                encoded = pathtoImg;
                                fos.write(imageByte);
                                fos.flush();
                                fos.close();
                            } catch (FileNotFoundException fnfe) {
                                errorCallback.invoke(fnfe.getMessage());
                            } catch (IOException ioe) {
                                errorCallback.invoke(ioe.getMessage());
                            }
                        }
                    }

                    String str = String.valueOf(thisId);
                    items.putString("id", str);
                    items.putString("album", album);
                    items.putString("artist", artist);
                    items.putString("title", title);
                    items.putString("genre", genre);

                    if (encoded == "") {
                        items.putString("cover", "");
                    } else {
                        items.putString("cover", "file://" + encoded);
                    }

                    items.putString("duration", duration);
                    items.putString("path", thisPath);
                    jsonArray.pushMap(items);
                }
            } while (musicCursor.moveToNext());

            successCallback.invoke(jsonArray);
            mmr.release();
        } catch (RuntimeException e) {
            errorCallback.invoke(e.toString());
            mmr.release();
        } catch (Exception e) {
            errorCallback.invoke(e.getMessage());
            mmr.release();
        }
    }
}

Of course, I've already taken a look at:

  • This post
  • This post
  • This post

回答1:

After debugging and researching a lot I found the problem.

It seems that mmr.setDataSource("path") returns a RuntimeException when something is wrong with the file. This is particularly important since even when the file exists its metadata cannot be retrieved.

The solution was to use the MediaMetadataRetriever into a try/catch like this:

while(cursor.moveNext()){
  try {
    MediaMetadataRetriever mmr = new MediaMetadataRetriever();
    mmr.setDataSource("Path to the file"); // /storage/337C 1C15/Music/Edguy/Speedhoven.mp3
  } catch (RuntimeException ex) {
    // something went wrong with the file, ignore it and continue
  }
}