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();
}
Related
Inside of a fragment in my android application, I take a video using an intent and then save it to my external storage:
private void dispatchTakeVideoIntent() {
Intent takeVideoIntent = new Intent(MediaStore.ACTION_VIDEO_CAPTURE);
if (takeVideoIntent.resolveActivity(getActivity().getPackageManager()) != null) {
startActivityForResult(takeVideoIntent, REQUEST_VIDEO_CAPTURE);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, #Nullable Intent intent) {
if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == Activity.RESULT_OK) {
takenVideoUri = intent.getData();
String ext = ".mp4";
String filename = new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss.SSS")
.format(System.currentTimeMillis()) + ext;
File root = getContext().getExternalFilesDir(Environment.DIRECTORY_MOVIES);
File file = new File(root, filename);
try(
InputStream is = getContext().getContentResolver().openInputStream(takenVideoUri);
FileOutputStream fos = new FileOutputStream(file)
) {
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] buf = new byte[1024];
while(is.read(buf)!=-1) {
bos.write(buf);
}
bos.close();
fos.close();
videoUri = Uri.fromFile(file);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Then, inside of another fragment, I have a VideoView to which I want to pass the Uri of the saved video for it to play it.
Uri videoUri = /* gotten from the other fragment */
videoView.setVideoURI(videoUri);
However, when I open that fragment, I get the errors:
2022-04-28 18:53:59.273 23764-23821/my.app E/MediaPlayerNative: error (1, -2147483648)
2022-04-28 18:53:59.305 23764-23764/my.app E/MediaPlayer: Error (1,-2147483648)
I understand those are generic errors, which makes it worse because I have no clue as to where the error is.
My manifest file does include permission for both reading and writing external storage. I have tried saving the video to internal storage too, but nothing changed.
What am I doing wrong?
It seems to me the file is incomplete/empty. You could check its size using file.length() before trying to play it. Copying the file might be unnecessary as you could simply call takeVideoIntent.putExtra(EXTRA_OUTPUT, uri) to the intent to specify the path(uri) the captured video's location.
What usually happens with camera capture outputs is that onActivityResult is called before the file contents were properly written to storage (bytes flushed and file closed) especially with slower storages (sd cards) so what you get is an incomplete file (often times even empty).
You can delay video playing after onActivityResult while checking if the video file's size and last modified time (file.lastModified()) have increased to see if writing/flushing has actually finished and you can play it. If it's a long video (more than a few seconds) and depending on the enconding used you may start playing it before its fully written to storage but if the video player reaches the end before the recording app has finished writing the playing will end abruptly and you'll probably need to reload the video in the player.
It's a big problem of linux with the slow writing on (ex/V)FAT partitions which are used on portable storage for interoperability with other OSs (Windows) especially over USB. It's always a long wait to copy a few GB of data on a USB stick.
I'm using this piece of code to try and open a .mp4 video:
VideoView videoView=(VideoView)findViewById(R.id.videoView1);
MediaController mediaController=new MediaController(this);
mediaController.setAnchorView(videoView) ;
videoView.setVideoPath("R.raw.videoname");
videoView.setMediaController(mediaController) ;
videoView.start();
However, whenever I try to run the app, I get a message saying "Can't play this video". I am using a new Nexus 7 tablet if that means anything.
Also, when I try to open the same file that I have stored in with my movies, the video runs perfectly normally when I use Gallery or Video Player to open it.
Any help is much appreciated.
File file = new File(getFilePath());//file path of your video
MimeTypeMap map = MimeTypeMap.getSingleton();
String ext = MimeTypeMap.getFileExtensionFromUrl(file.getName());
String type = map.getMimeTypeFromExtension(ext);
if (type == null)
type = "*/*";
Uri uri = Uri.parse("www.google.com");
Intent type_intent = new Intent(Intent.ACTION_VIEW, uri);
Uri data = Uri.fromFile(file);
type_intent.setDataAndType(data, type);
startActivity(type_intent);
Make sure there will be no space in video name, otherwise it will not
be played by android VideoView.
If not solved then let me know.
I am having a weird issue reading the length/duration of a video file recorded with a device's camera by using MediaRecorder. The file is recorded into the application's private storage directory, which is set like so:
mMediaRecorder.setOutputFile(context.getFilesDir() + "/recordings/webcam.3gpp");
After recording is complete, I attempt to read the length of the video with these methods:
Method 1:
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource(context.getFilesDir() + "/recordings/webcam.3gpp");
String time = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
return Long.parseLong(time);
Method 2:
MediaPlayer mp = MediaPlayer.create(context, Uri.parse(context.getFilesDir() + "/recordings/webcam.3gpp"));
long duration = mp.getDuration();
mp.release();
return duration;
None of the methods work. mediaMetadataRetriever.extractMetadata returns null and MediaPlayer.create fails with an IOException. I have verified that the file exists.
Important note: This issue DOES NOT happen if I save the recording to "/sdcard/recordings/webcam.3gpp". For some reason, I just cannot read the duration when the file is in the private files directory that belongs to the application. Also, this issue ONLY happens on my Samsung Droid Charge, which runs Android 2.3. It DOES NOT happen on a Samsung Galaxy S4, which runs Android 4.2, and Asus Nexus 7, which runs Android 4.3.
Edit:
If I take the same file and copy it to the sdcard, then read the length of it there, everything works. What gives?
copy(new File(context.getFilesDir() + "/recordings/webcam.3gpp"), new File("/sdcard/wtfisthiscrap.3gpp"));
MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();
mediaMetadataRetriever.setDataSource("/sdcard/wtfisthiscrap.3gpp");
String time = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);
return Long.parseLong(time); // works!
What can I do to solve this issue?
I was able to solve my issue by setting a FileInputStream as the data source of MediaPlayer.
MediaPlayer mp = new MediaPlayer();
FileInputStream stream = new FileInputStream(context.getFilesDir() + "/recordings/webcam.3gpp");
mp.setDataSource(stream.getFD());
stream.close();
mp.prepare();
long duration = mp.getDuration();
mp.release();
return duration;
The source of my answer comes from https://stackoverflow.com/a/6383655/379245
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?
First I make a call to
get_fullPathToAudio();
to determine the path of where an audio file was downloaded.
public File get_fullPathToAudioAsFile()
{
File storageFile = this.getExternalFilesDir(null);
if (storageFile == null)
{
// no external storage so store on private path
storageFile = this.getFilesDir();
}
return storageFile;
}
public String get_fullPathToAudio() {
return get_fullPathToAudioAsFile() + File.separator + this.get_currentArticleAudioFileName();
}
String filePath = this.myApp.get_fullPathToAudio();
mediaPlayer.setDataSource(filePath);
mediaPlayer.prepare();
mediaPlayer.start();
All works well if I have an SD drive on my emulator but when I don't have an emulator the function
get_fullPathToAudioAsFile();
uses
getFilesDir();
instead of
getExternalFilesDir(null);
which returns a path to my private drive where my app is installed. I can see the file in
data/data/com.myapp/files/myfile.m4a
for example. Is there a different way to play an audio file if it's not on the SD drive?
The error messsage I get is
error(-1, -2147483648)
Could not open file null for playback
I solved it this way
FileInputStream fileInputStream = new FileInputStream(mFile);
mPlayer.setDataSource(fileInputStream.getFD());
mPlayer.prepare();
MediaPlayer error -2147483648 when playing file on internal storage