7

I need to get a frame of a video file (it may be on sdcard, cache dir or app dir). I have package android.media in my application and inside I have class MediaMetadataRetriever. To get first frame into a bitmap, I use code:

public static Bitmap getVideoFrame(Context context, Uri videoUri) {
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
        retriever.setDataSource(context, videoUri);
        return retriever.captureFrame();
    } catch (IllegalArgumentException ex) {
        throw new RuntimeException();
    } catch (RuntimeException ex) {
        throw new RuntimeException();
    } finally {
        retriever.release();
    }
}

But this it's not working. It throws an exception (java.lang.RuntimeException: setDataSource failed: status = 0x80000000) when I set data source. Do you know how to make this code to work? Or Do you have any similar (simple) solution without using ffmpeg or other external libraries? videoUri is a valid uri (media player can play video from that URI)

Buda Gavril
  • 21,409
  • 40
  • 127
  • 196
  • can you provide a sample for your question, i tried a lot for this kind of sample, finally had to ask you. – ManishSB Apr 18 '15 at 11:11

8 Answers8

13

The following works for me:

public static Bitmap getVideoFrame(FileDescriptor FD) {
        MediaMetadataRetriever retriever = new MediaMetadataRetriever();
        try {
            retriever.setDataSource(FD);
            return retriever.getFrameAtTime();
        } catch (IllegalArgumentException ex) {
            ex.printStackTrace();
        } catch (RuntimeException ex) {
            ex.printStackTrace();
        } finally {
            try {
                retriever.release();
            } catch (RuntimeException ex) {
            }
        }
        return null;
    }

Also works if you use a path instead of a filedescriptor.

Rab Ross
  • 2,098
  • 22
  • 28
  • what value should be pass as FileDescripter argument. Real thinks is that,in my application, there are video url only , and want to get the list of frames of that video file... – Ashish Dwivedi Apr 10 '12 at 04:31
  • To get a FileDescriptor object do - openFileInput(myVideoFileName).getFD(). To do this the video must be in your applications private directory. You can also change to public static Bitmap getVideoFrame(String FD) and pass your videos path. – Rab Ross Apr 16 '12 at 09:26
  • In one second a video have 25 to 30 frames. R u able to get all frames. Because by this technique i got 3-4 repeated frames every time .and some frames are missing. – Akanksha Rathore Apr 25 '14 at 05:19
  • 1
    @Rab Ross kindly give detail code. how you do this . I am unable to make it working . What must be the extention and vice versa – Zar E Ahmer Jun 19 '14 at 07:56
  • @Nepster This was a while ago and I do not have access to the detailed code anymore. My apologies. – Rab Ross Jun 19 '14 at 10:25
6

Try this, I've used it and its working

public static Bitmap getVideoFrame(Context context, Uri uri) {
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        retriever.setDataSource(uri.toString(),new HashMap<String, String>());
        return retriever.getFrameAtTime();
    } catch (IllegalArgumentException ex) {
        ex.printStackTrace();
    } catch (RuntimeException ex) {
        ex.printStackTrace();
    } finally {
        try {
            retriever.release();
        } catch (RuntimeException ex) {
        }
    }
    return null;
}

In place of uri you can directly pass your url .

Prashant
  • 1,046
  • 14
  • 21
1

I used this code and that is working for me. you can try this one.

if (Build.VERSION.SDK_INT >= 14) {
                ffmpegMetaDataRetriever.setDataSource(
                        videoFile.getAbsolutePath(),
                        new HashMap<String, String>());
            } else {
                ffmpegMetaDataRetriever.setDataSource(videoFile
                        .getAbsolutePath());
            }
0

I was getting the same error using the ThumbnailUtils class http://developer.android.com/reference/android/media/ThumbnailUtils.html
It uses MediaMetadataRetriever under the hood and most of the time you can send it a filepath using this method with no problem:

public static Bitmap createVideoThumbnail (String filePath, int kind)  

However, on Android 4.0.4, I kept getting the same error @gabi was seeing. Using a file descriptor instead solved the problem and still works for non-4.0.4 devices. I actually ended up subclassing ThumbnailUtils. Here is my subclass method:

 public static Bitmap createVideoThumbnail(FileDescriptor fDescriptor, int kind) 
 {
    Bitmap bitmap = null;
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {
        retriever.setDataSource(fDescriptor);
        bitmap = retriever.getFrameAtTime(-1);
    } 
    catch (IllegalArgumentException ex) {
        // Assume this is a corrupt video file
        Log.e(LOG_TAG, "Failed to create video thumbnail for file description: " + fDescriptor.toString());
    }
    catch (RuntimeException ex) {
        // Assume this is a corrupt video file.
        Log.e(LOG_TAG, "Failed to create video thumbnail for file description: " + fDescriptor.toString());
    } finally {
        try {
            retriever.release();
        } catch (RuntimeException ex) {
            // Ignore failures while cleaning up.
        }
    }

    if (bitmap == null) return null;

    if (kind == Images.Thumbnails.MINI_KIND) {
        // Scale down the bitmap if it's too large.
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int max = Math.max(width, height);
        if (max > 512) {
            float scale = 512f / max;
            int w = Math.round(scale * width);
            int h = Math.round(scale * height);
            bitmap = Bitmap.createScaledBitmap(bitmap, w, h, true);
        }
    } else if (kind == Images.Thumbnails.MICRO_KIND) {
        bitmap = extractThumbnail(bitmap,
                TARGET_SIZE_MICRO_THUMBNAIL,
                TARGET_SIZE_MICRO_THUMBNAIL,
                OPTIONS_RECYCLE_INPUT);
    }
    return bitmap;
}
n8tr
  • 5,018
  • 2
  • 32
  • 33
0

The exception is thrown also when the File doesn't exist. So before calling setDataSource() you'd better check if new File(url).exists().

Alessandro Roaro
  • 4,665
  • 6
  • 29
  • 48
0

I have the same mistake on my application. I saw on this site that

this is an unofficial way of doing it and it will only work in cupcake (and maybe later version). The Android team does not guarantee that libmedia_jni.so, which the java file uses, will be included or have the same interface in future versions.

http://osdir.com/ml/AndroidDevelopers/2009-06/msg02442.html

I have updated my phone to GingerBread and it doesn't work anymore.

0

Uri's are not very specific. Sometimes they refer to something in a bundle. They often need to be translated to an absolute path form. The other instance in which you used the Uri, it probably was smart enough to check what kind of Uri it was. This case that you have shown appears to be not looking very hard.

droideka-coder
  • 259
  • 1
  • 2
  • 5
-2

so is there a specific way to get the frame from video as

 File sdcard = Environment.getExternalStorageDirectory();
 File file = new File(sdcard, "myvideo.mp4");
Paresh Mayani
  • 127,700
  • 71
  • 241
  • 295
Dhiraj Tayade
  • 407
  • 3
  • 10
  • 22
  • it was giving errors... now its working... i guess there is some problem with my eclipse editor. Thanks anyway – Dhiraj Tayade Mar 20 '12 at 14:17
  • My comment was to ask you that "This 2 line code is your answer or a question with your problem?" – Paresh Mayani Mar 20 '12 at 14:18
  • It was a question ... The above code was not working initially... but its correct its working now – Dhiraj Tayade Mar 20 '12 at 17:06
  • @PareshMayani, how to get the list of frames of video file to show in gallery view, please have a look at [my question](http://stackoverflow.com/questions/10071408/how-to-get-frames-of-video-file-in-android) – Ashish Dwivedi Apr 09 '12 at 10:16