Android problems with MediaMetadataRetriever: return null value - android

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)

Related

Get rating metadata form a list of song (MP3) in android using android.media.Rating

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();
}

ExoPlayer: get songs metadata from HTTP stream

I use the following code to play a music stream through ExoPlayer:
exoPlayer = ExoPlayer.Factory.newInstance(numRenderers, minBufSize, maxBufSize);
String url = Helper.getPr().getString("url", "http://mp3.nashe.ru:80/ultra-128.mp3");
Uri uri = Uri.parse(url);
Log.i(TAG, "Going to open " + url);
Allocator allocator = new DefaultAllocator(BUFFER_SEGMENT_SIZE);
DataSource dataSource = new DefaultUriDataSource(getApplicationContext(), USER_AGENT);
ExtractorSampleSource sampleSource = new ExtractorSampleSource(uri, dataSource, allocator, BUFFER_SEGMENT_COUNT * BUFFER_SEGMENT_SIZE);
audioRenderer = new MediaCodecAudioTrackRenderer(sampleSource);
exoPlayer.addListener(this);
exoPlayer.sendMessage(audioRenderer, MediaCodecAudioTrackRenderer.MSG_SET_VOLUME, volume);
exoPlayer.prepare(audioRenderer);
exoPlayer.setPlayWhenReady(true);
I can't find any info on how to get metadata like artist and name of the current song. Is it possible to get the metadata and if yes, how?
Thanks a lot.
There are many types of metadata in many types of media, It's depending on your stream. But currently Exoplayer itself, only parse metadata from HLS streams (HTTP Live Streaming) they get ID3 data from the stream.
As you can see on there github repository issue,this is the current state of metadata in Exoplayer lib (August 2015):
https://github.com/google/ExoPlayer/issues/704
If it's your stream case, I will recommend you to download the Exoplayer demo on github (https://github.com/google/ExoPlayer/tree/release-v2/demos).
One of the examples in the demo display stream ID3 metadata on LogCat.
If it's not your case, nothing will help you in ExoPlayer lib right now.
But there is an alternative solution, which I have used for a radio stream application, and it work well:
IcyStreamMeta to get meta data from online stream radio :
Getting metadata from SHOUTcast using IcyStreamMeta
but not sure it will work with simple mp3 file.
I am late But with Exoplayer-2. You can use an extension created by #saschpe. https://github.com/sandeeprana011/android-exoplayer2-ext-icy
For example see this app: https://play.google.com/store/apps/details?id=com.zilideus.jukebox_new
gradle
implementation 'saschpe.android:exoplayer2-ext-icy:1.0.1'
So it includes an Extra Header "Icy-Metadata" with value 1
and on the response, it extracts the metadata from the stream data.
Usage:
IcyHttpDataSourceFactory factory = new IcyHttpDataSourceFactory.Builder(Util.getUserAgent(this, getResources().getString(R.string.app_name)))
.setIcyHeadersListener(this)
.setIcyMetadataChangeListener(this).build();
DefaultDataSourceFactory datasourceFactory = new DefaultDataSourceFactory(getApplicationContext(), null, factory);
ExtractorMediaSource mediaSource = new ExtractorMediaSource.Factory(datasourceFactory)
.setExtractorsFactory(new DefaultExtractorsFactory())
.createMediaSource(uri);
Exo.resetPlayer();
Exo.getPlayer(this).prepare(mediaSource);
In the case of Icy metadata, exoplayer has built in support as of version 2.10. see: https://stackoverflow.com/a/56333429/1898380
You probably should use MediaMetadataRetriever
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(getActivity(), uri);
String artist = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
You could use the follow code to do that(Maybe you should download the mp3 file first):
MediaMetadataRetriever metaRetriver = new MediaMetadataRetriever();
metaRetriver.setDataSource("LOCAL MP3 FILE PATH");
byte[] picArray = metaRetriver.getEmbeddedPicture();
Bitmap songImage = BitmapFactory .decodeByteArray(picArray, 0, picArray.length);
String albumName = metaRetriver .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
String artistName = metaRetriver .extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
String songGenre = metaRetriver .extractMetadata(MediaMetadataRetriever.METADATA_KEY_GENRE));
source:http://mrbool.com/how-to-extract-meta-data-from-media-file-in-android/28130#ixzz3s8PUd9E7

MediaMetadataRetriever returns null on S3

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());
}

Android check for valid video file

How to check a video file is valid or not without checking its extension(.mp3 or .3gp etc). Means how to check the video file on SD card is supported by device or not?
Is there any api to validate video file in android 4.0 and above?
My Scenario: I am playing video on VideoView after downloading it and play it from local SD card after download success. Next time when a request for same video, then checks in SD card, if found then start playing it(No download in this case). But sometimes network error or app kill interrupt the downloading(in this case the video file is not completely downloaded) so the downloaded file is corrupted and VideoView is unable to play this file. So how to detect this corrupted file.
Here is the code that worked for me:
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
retriever.setDataSource(context, Uri.fromFile(fileToTest));
String hasVideo = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO);
boolean isVideo = "yes".equals(hasVideo);
#Alex had given right answer but still some problems are there as like #Kirill mention in comment that setDataSource often throws java.lang.RuntimeException: setDataSource failed exception. So Here is the function check for valid video file
private boolean videoFileIsCorrupted(String path){
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
retriever.setDataSource(myContext, Uri.parse(path));
}catch (Exception e){
e.printStackTrace();
return false;
}
String hasVideo = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_VIDEO);
return "yes".equals(hasVideo);
}
I think this will be useful, The method is an older one that i used for other purpose just modified a bit for your use, Try it ,May work
private void checkAndLoadFile(
File currentFile) {
String path = currentFile.getAbsolutePath();
String extension = Utility.getExtension(path);
MimeTypeMap mimeMap = MimeTypeMap.getSingleton();
if(mimeMap.hasExtension(extension))
{
String mimeType = mimeMap.getMimeTypeFromExtension(extension);
Intent viewFile = new Intent(Intent.ACTION_VIEW);
viewFile.setDataAndType(Uri.fromFile(currentFile), mimeType);
PackageManager pm = getPackageManager();
List<ResolveInfo> apps =
pm.queryIntentActivities(viewFile, PackageManager.MATCH_DEFAULT_ONLY);
if (apps.size() > 0)
startActivity(viewFile); //This video is supported and there are apps installed in this device to open the video
else
showAsNotSupported();
} else
showAsNotSupported();
}

Is it possible to retrieve album art from remote mp3 file in Android?

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?

Categories

Resources