12

So I'm trying to do a screen shot of a VideoView. I figured the easiest way would be:

videoView.setDrawingCacheEnabled(true);

Then when I need to take a screenshot:

Bitmap screenshot = videoView.getDrawingCache();

But for some reason the bitmap I get back is just black every time. Anyone had any success with this? I also tried:

Bitmap bitmap = Bitmap.createBitmap(videoView.getWidth(), videoView.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
videoView.draw(canvas);

But once again, this returns me a black image. I can see that the VideoView is hardly even documented in the Android javadocs. Any help?

Brayden
  • 521
  • 1
  • 5
  • 17
  • 1
    This reminds me of the old days when I used to try and take screenshots of videos in WMP with Print screen and paint. I believe it is an issue where the surface view is just a transparent layer in the window and so cannot be snapshotted like you're attempting to do. – deed02392 Mar 19 '12 at 09:00

2 Answers2

13

From the docs for View#setDrawingCacheEnabled:

Enabling the drawing cache is similar to setting a layer when hardware acceleration is turned off. When hardware acceleration is turned on, enabling the drawing cache has no effect on rendering because the system uses a different mechanism for acceleration which ignores the flag. If you want to use a Bitmap for the view, even when hardware acceleration is enabled, see setLayerType(int, android.graphics.Paint) for information on how to enable software and hardware layers.

It's possible that the VideoView operates with hardware acceleration and is bypassing the caching mechanism. A good source dive might shed some light.

Edit - this post seems to clear some things up:

Sorry, by its nature a SurfaceView does not draw in the normal view hierarchy update system, so it won't be drawn in that.

(VideoView is a child of SurfaceView)

AlikElzin-kilaka
  • 34,335
  • 35
  • 194
  • 277
Matthew
  • 44,826
  • 10
  • 98
  • 87
  • 1
    Hm. I can see that a view has setLayerType in the javadocs, but my VideoView doesn't have a setLayerType nor does View show me the constants it uses (To set it to View.LAYER_TYPE_SOFTWARE). This is such a weird class. It also says in the javadocs that there is a resume() method for VideoView, but mine doesn't show one of those? I'll keep looking around and possibly dive into the source. – Brayden Mar 11 '11 at 22:22
  • You should probably think of SurfaceView as hardware magic. Your code apparently won't be able to touch the bits as they move to the screen. – Matthew Mar 11 '11 at 22:24
  • Yeah I'm realizing that. So basically. I can't take a screenshot from a VideoView? – Brayden Mar 11 '11 at 23:03
  • I don't think you can, unfortunately. – Matthew Mar 11 '11 at 23:18
  • 7
    SurfaceView is a "hole" inside the window, it therefore cannot be cached inside a bitmap. We are aware of this limitation and we'd like to get something better but there's nothing planned for now. – Romain Guy Mar 12 '11 at 04:17
  • did any one try http://www.droidnova.com/how-to-create-and-save-a-screenshot-from-a-surfaceview,880.html , here there are showing capture bitmap using surface view. – CoDe Aug 13 '12 at 07:18
  • @RomainGuy So what is the alternative way ? I am not directly using SurfaceView, but my webview has a html5 video player and not able to capture the screenshot – droidev May 15 '19 at 06:32
0

Since API 10, you can use MediaMetadataRetriever to retrieve a frame at given time (in micro seconds). Here is a sample code:

public Bitmap videoFrame(String uri, long msec) {       
    MediaMetadataRetriever retriever = new MediaMetadataRetriever();
    try {                       
        retriever.setDataSource(uri);            
        return retriever.getFrameAtTime(msec);
    } catch (IllegalArgumentException ex) {
        ex.printStackTrace();
    } catch (RuntimeException ex) {
        ex.printStackTrace();
    } finally {
        try {
            retriever.release();
        } catch (RuntimeException ex) {
        }
    }
    return null;
}
bachr
  • 5,780
  • 12
  • 57
  • 92
  • 2
    I haven't revisited this in a long time, but this is good to know, thank you. However, this wouldn't have helped in my instance as much of what I was wanting to screenshot was streaming video. – Brayden Feb 19 '13 at 21:53
  • @Arbi thanks, i was able to do this with a video stored locally on the phone. However, when the video is streamed in the VideoView, I can't seem to capture the video frame. Do you know how? – code Dec 12 '14 at 02:56
  • you need the get the uri of the streamed video – bachr Dec 12 '14 at 10:26
  • Hi @Arbi . I placed a sample "http://www.test.com/myVideo.mp4" into the uri parameter but it is not successful. It seems that the function videoFrame() above only works if the video is downloaded on the device – code Dec 13 '14 at 01:27
  • You're not providing the protocol (I wonder if you were able to play the video). Try with something like `new URL("you_full_url").toExternalForm()` to be sure you're giving a correct url otherwise you'll see an exception. – bachr Dec 14 '14 at 11:37
  • At this point in time (03/01/2017), the above code worked with an external (http) uri as long as I used [https://developer.android.com/reference/android/media/MediaMetadataRetriever.html#setDataSource(java.lang.String, java.util.Map)](this setDataSource call) – David Crawford Mar 21 '17 at 20:19