6

I wanted to know if it is possible to extract frames from a running Video in Android? I need to extract frames at regular intervals and send them for further processing.

Would someone be able to find an answer for me?

Thanks,

Abhi

Cœur
  • 37,241
  • 25
  • 195
  • 267
Abhishek Sharma
  • 61
  • 1
  • 1
  • 2
  • 1
    Duplicate: http://stackoverflow.com/questions/1893072/getting-frames-from-video-image-in-android – Alexander Stolz Jan 26 '10 at 21:58
  • 2
    I've marked that *possible* duplicate, but the other question seems more camera oriented than playback oriented (this question). They may be very different... Also - the other question doesn't have a lot of detail in the answers. – Marc Gravell Jan 27 '10 at 06:49
  • By running do you mean "while being recorded" or "while being played back"? – rogerdpack Sep 07 '18 at 16:50

4 Answers4

14

You can use MediaMetadataRetriever:

I'm currently using it, by calling:

mediaMetadataRetriever.getFrameAtTime(timeUs,MediaMetadataRetriever.OPTION_CLOSEST);

I get the frame's bitmap.

Note that it's only supported since: API Level 10.

Zain Aftab
  • 703
  • 7
  • 21
Oren Bengigi
  • 994
  • 9
  • 17
5

You can use the code below:

String SrcPath="/sdcard/Pictures/Video Task/";

MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever();

mediaMetadataRetriever.setDataSource(SrcPath);
String METADATA_KEY_DURATION = mediaMetadataRetriever
        .extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION);

Bitmap bmpOriginal = mediaMetadataRetriever.getFrameAtTime(0);
int bmpVideoHeight = bmpOriginal.getHeight();
int bmpVideoWidth = bmpOriginal.getWidth();

Log.d("LOGTAG", "bmpVideoWidth:'" + bmpVideoWidth + "'  bmpVideoHeight:'" + bmpVideoHeight + "'");

byte [] lastSavedByteArray = new byte[0];

float factor = 0.20f;
int scaleWidth = (int) ( (float) bmpVideoWidth * factor );
int scaleHeight = (int) ( (float) bmpVideoHeight * factor );
int max = (int) Long.parseLong(METADATA_KEY_DURATION);
for ( int index = 0 ; index < max ; index++ )
{
    bmpOriginal = mediaMetadataRetriever.getFrameAtTime(index * 1000, MediaMetadataRetriever.OPTION_CLOSEST);
    bmpVideoHeight = bmpOriginal == null ? -1 : bmpOriginal.getHeight();
    bmpVideoWidth = bmpOriginal == null ? -1 : bmpOriginal.getWidth();
    int byteCount = bmpOriginal.getWidth() * bmpOriginal.getHeight() * 4;
    ByteBuffer tmpByteBuffer = ByteBuffer.allocate(byteCount);
    bmpOriginal.copyPixelsToBuffer(tmpByteBuffer);
    byte [] tmpByteArray = tmpByteBuffer.array();

    if ( !Arrays.equals(tmpByteArray, lastSavedByteArray))
    {
        int quality = 100;
        String mediaStorageDir="/sdcard/Pictures/Video Task/";
        File outputFile = new File(mediaStorageDir , "IMG_" + ( index + 1 )
                + "_" + max + "_quality_" + quality + "_w" + scaleWidth + "_h" + scaleHeight + ".png");
        Log.e("Output Files::>>",""+outputFile);
        OutputStream outputStream = null;
        try {
            outputStream = new FileOutputStream(outputFile);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        Bitmap bmpScaledSize = Bitmap.createScaledBitmap(bmpOriginal, scaleWidth, scaleHeight, false);

        bmpScaledSize.compress(Bitmap.CompressFormat.PNG, quality, outputStream);

        try {
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        lastSavedByteArray = tmpByteArray;
    }
}
capturedImageView.setImageBitmap(bmpOriginal);
mediaMetadataRetriever.release();
Pang
  • 9,564
  • 146
  • 81
  • 122
  • Just an FYI, METADATA_KEY_DURATION appears to return the video length in millisecs. That for loop could run for a while. – RudyF Oct 29 '20 at 06:29
0

Assuming you are using the MediaPlayer, I believe it is not possible to extract video (or audio) frames. The mediaplayer runs it's own process [mediaplayerservice]. And, only this process has access to these frames. It is considered a security violation if the raw frames are accessible by other processes. Say for example you are playing some content that is copyright protected, then providing access to these frames should not be allowed.

user287989
  • 19
  • 1
0

If you just want to extract a limited number of frames. You can try "getFrameAtIndex()" function from the MediaMetadataRetriever class.

Here's how you can use it:

// Create a MediaMetadataRetriever instance
MediaMetadataRetriever retriever = new MediaMetadataRetriever();

// Set the data source to your video file
retriever.setDataSource(yourVideoFilePath);

// Get a frame at a specific time index (in microseconds)
long timeUs = desiredTimeInMillis * 1000; // Convert milliseconds to microseconds
Bitmap frame = retriever.getFrameAtIndex(timeUs, MediaMetadataRetriever.OPTION_CLOSEST_SYNC);

// Release the MediaMetadataRetriever
retriever.release();

If you want to extract all frames from a video with high performance. You might find this repository useful: https://github.com/duckyngo/Fast-Video-Frame-Extraction.

Kenny
  • 11
  • 1