I have the problem that MediaMetadataRetriever always returns null for the title, but only on stock S3. It's working with CyanogenMod on S3 but not with Samsungs stock rom. Also, on my OnePlus is everything working fine.
The Code is very simple:
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
String titlename = fields[count].getName();
final Uri uri = Uri.parse("android.resource://" + getPackageName() + "/raw/" + titlename);
mmr.setDataSource(MainActivity.this, uri);
final String name = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
[...]
tv.setText(name + " ");
The TextView will show null on Samsung stock ROM, but not on other ROMs.
This is a bit strange, does someone here have an idea? If not, I'll try a third-party library for ID3 tags.
I noticed the same issue on ICS (On Galaxy SII and Galaxy Tab II both running ICS 4.0.3). This seems to impact only mp3.
I guess one of the solutions would be to use an external library but I also prefer to use what android offers rather then external libraries.
I have tried two solutions:
MediaMetadataRetriever mmdr = new MediaMetadataRetriever();
mmdr.setDataSource(path);
String title = mmdr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
And
File file = new File(path);
FileInputStream inputStream;
inputStream = new FileInputStream(file);
mmdr = new MediaMetadataRetriever();
mmdr.setDataSource(inputStream.getFD());
inputStream.close();
String title = mmdr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
But the problem persists:
MediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE) always retuns null.
A solution that I thought of apart from using an external library would be to query the MediaStore on the file's path:
Cursor c = mContext.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, new String[] {MediaStore.MediaColumns.TITLE},
MediaStore.MediaColumns.DATA + "=?",
new String[] { path }, null);
String title;
if(c!=null && c.moveToFirst())
title = c.getString(c.getColumnIndex(MediaStore.MediaColumns.TITLE))
}
If the MediaScanner scanned it (it should have), the info should be there. This should also work for API levels before 10.
Basically, what to do is the following: If SDK version is < 10 or the file's extension is mp3 and SDK version is 15, I query the MediaStore, otherwise I use MediaMetaDataRetriever.
Also you can try this
if (Build.VERSION.SDK_INT >= 14) {
mmr = new MediaMetadataRetriever();
mmr.setDataSource(audio.url, new HashMap<String, String>());
} else {
mmr = new MediaMetadataRetriever();
mmr.setDataSource(audio.url);
}
This is what I have tried so far to solve the issue. But I can't guarantee if it is going to work for you.
Hope I helped.
EDIT: You need to pass path or file descriptor as an argument to setDataSource. Try this code:
AssetFileDescriptor afd = getResources().openRawResourceFd(R.raw.music);
if (afd != null) {
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(afd.getFileDescriptor());
}
Related
I need to retrieve the rating from a list of all the songs in a phone.
Currently I have them on a File List. Some metadata can be listed with MediaMetadataRetriever but the ratings saved in the song by BlackPlayer EX can't, so I need to extract them with another method.
I've found "android.media.Rating" but with no luck.
My code so far:
String musicPath = Environment.getExternalStorageDirectory().toString() + "/Music";
textView.setText(musicPath);
File directory = new File(musicPath);
textView.setText("On it");
MP3FileFilter fileFilter = new MP3FileFilter();
List songsFiles = listFiles(directory, fileFilter, true);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
for(int i = 0; i<songsFiles.size(); i++){
String song = songsFiles.get(i).toString();
mmr.setDataSource(song);
((Rating) songsFiles.get(i)).getStarRating();
}
textView.setText("Done");
The error displaying is pretty obvious but I can't find a way to solve it:
java.io.File cannot be cast to android.media.Rating
Thanks in advance.
Got it working with JAudioTagger jar and this code:
MP3File musicFile = (MP3File) AudioFileIO.read((File) songsFiles.get(i));
if (musicFile != null && musicFile.hasID3v2Tag()) {
ID3v23Frame frame = (ID3v23Frame)
musicFile.getID3v2Tag().getFrame(ID3v24Frames.FRAME_ID_POPULARIMETER);
FrameBodyPOPM body = (FrameBodyPOPM) frame.getBody();
Long irating = body.getRating();
}
I'm using Drive Android API to sync a file between devices and to hold the latest version on Drive. Since some time ago it started behaving really strange.
To see that a file exists and get it's latest version, I do a Query search by that file name and sorting by modified date descending. It returns the correct datetime when the file was updated:
final SortOrder sortOrder = new SortOrder.Builder()
.addSortDescending(SortableField.MODIFIED_DATE)
.build();
final Query query = new Query.Builder()
.addFilter(Filters.eq(SearchableField.TITLE, "fileName"))
.addFilter(Filters.eq(SearchableField.TRASHED, false))
.setSortOrder(sortOrder)
.build();
Drive.DriveApi.query(apiClient, query)
.setResultCallback(lastModifiedCallback);
But when I query the file contents, it returns some older version of it. I couldn't understand what causes it.
I read the file as follows:
driveId.asDriveFile()
.open(apiClient, DriveFile.MODE_READ_ONLY, null)
.setResultCallback(fileContentsCallback);
The drive contents I read as follows:
final DriveContents driveContents = result.getDriveContents();
final InputStream inputStream = driveContents.getInputStream();
final File newFile = new File("fileName");
final FileOutputStream dest = new FileOutputStream(newFile);
ByteStreams.copy(inputStream, dest);
driveContents.commit(apiClient, null);
Any ideas why it's happening and how to fix it?
I know that the version returned is old, because if I use the Drive application on my device, it returns the correct, latest version of the same file.
Trying to retrieve mp3 informations (Albumname,...) with MediaMetadataRetriever.
In the emulator it worked fine. On my device most methods returns null.
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(songPath);
String albumName = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
String mp3Title = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
String mimekey = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_MIMETYPE);
The mp3 has definitly these informtion because in the emulator these information (the same file!) are shown. The file path is ok the mimekey is set and I got no exception.
I'm using SdkVersion=14.
I've checked
How to get songs from album/Artist in android,using MediametadataRetriever? and
Android MediaMetadataRetriever returns null values from most keys
but it didn't help. Can't debug the MediaMetadataRetriever.extractMetadata because its native code.
Any ideas?
Have you tried FFmpegMediaMetadataRetriever?:
FFmpegMediaMetadataRetriever retriever = new FFmpegMediaMetadataRetriever();
retriever.setDataSource(songPath);
String albumName = retriever.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_ALBUM);
String mp3Title = retriever.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_TITLE);
retriever.release();
I was having the same issue with video GPS_LOCATION. In some of the devices it was working, while in some devices it was not working.
The fix was minor, instead of
setDataSource(context, uri)
I used
setDataSource(absoluteFilePath)
I'm currently writing a UPnP remote control app which is used to connect a remote MediaServer to a remote MediaRenderer. Since the actual MP3 files aren't sent to the Android device, I'd like to be able to get the album art of the currently playing file without having to download the entire MP3 file to my phone.
I've read that MediaMetadataRetriever is useful for this kind of thing, but I haven't been able to get it to work. Each way I try it, I keep getting an IllegalArgumentException by the call to MediaMetadataRetriever#setDataSource, which indicates that my file handle or URI is invalid.
MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
The following works since it's a direct file path on the device itself:
metaRetriever.setDataSource("/sdcard/Music/Daft_Punk/Homework/01 - Daftendirekt.mp3");
However, any of the following fail with the same error:
metaRetriever.setDataSource(appCtx, Uri.parse("http://192.168.1.144:49153/content/media/object_id/94785/res_id/1/rct/aa"));
metaRetriever.setDataSource(appCtx, Uri.parse("http://192.168.1.144:49153/content/media/object_id/94785/res_id/0/ext/file.mp3"));
metaRetriever.setDataSource("http://192.168.1.144:49153/content/media/object_id/94785/res_id/0/ext/file.mp3");
The first one is the albumArtURI pulled from the UPnP metadata (no *.mp3 extension, but the file will download if pasted into a web browser).
The second and third attempts are using the "res" value from the UPnP metadata, which points to the actual file on the server.
I'm hoping I'm just parsing the URI incorrectly, but I'm out of ideas.
Any suggestions? Also, is there a better way to do this entirely when pulling from a UPnP server? FWIW, I'm using the Cling UPnP library.
== SOLUTION ==
I started looking into william-seemann's answer and it led me to this: MediaMetadataRetriever.setDataSource(String path) no longer accepts URLs
Comment #2 on this post mentions using a different version of setDataSource() that still accepts remote URLs.
Here's what I ended up doing and it's working great:
private Bitmap downloadBitmap(final String url) {
final MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
metaRetriever.setDataSource(url, new HashMap<String, String>());
try {
final byte[] art = metaRetriever.getEmbeddedPicture();
return BitmapFactory.decodeByteArray(art, 0, art.length);
} catch (Exception e) {
Logger.e(LOGTAG, "Couldn't create album art: " + e.getMessage());
return BitmapFactory.decodeResource(getResources(), R.drawable.album_art_missing);
}
}
FFmpegMediaMetadataRetriever will extract metadata from a remote file (Disclosure: I created it). I has the same interface as MediaMetadataRetriever but it uses FFmpeg as it's backend. Here is an example:
FFmpegMediaMetadataRetriever mmr = new FFmpegMediaMetadataRetriever();
mmr.setDataSource(mUri);
String album = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_ALBUM);
String artist = mmr.extractMetadata(FFmpegMediaMetadataRetriever.METADATA_KEY_ARTIST);
byte [] artwork = mmr.getEmbeddedPicture();
mmr.release();
Looking at the source code for MediaMetadataRetriever (not from the official Android repo, but it should still be similar, if not equivalent) showed me this:
if (uri == null) {
throw new IllegalArgumentException();
}
And this:
ContentResolver resolver = context.getContentResolver();
try {
fd = resolver.openAssetFileDescriptor(uri, "r");
} catch(FileNotFoundException e) {
throw new IllegalArgumentException();
}
if (fd == null) {
throw new IllegalArgumentException();
}
FileDescriptor descriptor = fd.getFileDescriptor();
if (!descriptor.valid()) {
throw new IllegalArgumentException();
}
Your exception is coming from one of those blocks.
From looking at the MediaMetadataRetriever documentation and source code, it seems to me that the file has to be on the device. You can use a Uri, but I think it has to be something like "file:///android_asset/mysound.mp3". I could be wrong though; are you sure that MediaMetadataRetriever can be used to resolve files over a network?
I've got file name of mp3 file. How can I extract metadata like artist, album, album image,... from this mp3 file?
try this for API level 10 or greater
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(filePath);
String albumName = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM));
and so on...
for more help
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(songsList.get(songIndex).get("songPath"));
byte[] artBytes = mmr.getEmbeddedPicture();
if(artBytes!=null)
{
// InputStream is = new ByteArrayInputStream(mmr.getEmbeddedPicture());
Bitmap bm = BitmapFactory.decodeByteArray(artBytes, 0, artBytes.length);
bSongImage.setImageBitmap(bm);
}
else
{
bSongImage.setImageDrawable(getResources().getDrawable(R.drawable.cmp));
}
else for not having embedded image in audio file
MetaDataRetriever m_metaRetriever = new MetaDataRetriever();
m_metaRetriever.setDataSource(MainActivity.this,uriSound);
The input parameter of the setDataSource method should include the context also.Else it throws illigalArgument Exception.