Search code examples
androidandroid-mediaplayervideo-captureandroid-bitmaptextureview

Why MediaPlayer.seekTo() and onSurfaceTextureUpdated() not working inside loop?


I'm trying to get screenshots(bitmaps) of each 100ms frame from MediaPlayer video on textureview and the bitmap's color config should be ARGB_8888

I thought that onSurfaceTextureUpdated is called everytime I call mediaplayer.seekTo(timeframe), and I can get bitmaps in there.

So I created a button in the activity where textureview and applied on click method in the activity like this:

public void onViewClicked() {

    float begin = starttimeframe;  // starting point of analysis in timeframe
    float end = endtimeframe;      // ending point of analysis in timeframe

    int f = round(begin);
    status = 2;
    while (f < round(end)) {
        mediaplayer.seekTo(f);
        currenttimeframe = f;
        f += 100;  // forward to next frame (100ms interval)
    }

    Toast.makeText(Extractor2Activity.this, "Done!", Toast.LENGTH_SHORT).show();
}

And added code for capturing textureview when surfacetexture updated like this:

    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
            Bitmap bitmap = Bitmap.createBitmap(tvWidth, tvHeight, Bitmap.Config.ARGB_8888);
            textureView.getBitmap(bitmap);

            File file = new File(Environment.getExternalStorageDirectory().toString(), "capture" + current timeframe + ".jpg");

            OutputStream fout = null;
            try {
                fout = new FileOutputStream(file);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout);
                fout.flush();
                fout.close();
                MediaStore.Images.Media.insertImage(this.getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
            } catch (IOException e) {
                e.printStackTrace();
            }
    }

The problem is, video on textureview not changing and onSurfaceTextureUpdated not gets called during the iteration.

onSurfaceTextureUpdated() gets called only after the Toast message shown, just once.

I guess there must be a solution but I'm not good at android programming and don't know how to resolve this.

How to make seekTo and onSurfaceTextureUpdated works properly while looping?

What I tried:

Using MediaMetadataRetriever.getFrameAtTime , it's possible to capture desired frames inside loops but acquired bitmap's color config is RGB565 by default and don't know how to get a image of ARGB_8888 config from getFrameAtTime.


Solution

  • A little recursive solution will be handy in this situation. You could call seek wait for the call back get your bitmap and seek further. until you reach the end of stream.

    public void onViewClicked() {
    
        viewClicked = true;
    
        seekTo(round(starttimeframe));
    }
    
    public void seekTo(int time) {
        if (time < round(endtimeframe)) {
            mediaplayer.seekTo(time);
            currenttimeframe = time;
        }
        else {
            viewClicked = false;
        }
    }
    
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
       if (viewClicked) {
            Bitmap bitmap = Bitmap.createBitmap(tvWidth, tvHeight, Bitmap.Config.ARGB_8888);
            textureView.getBitmap(bitmap);
    
            File file = new File(Environment.getExternalStorageDirectory().toString(), "capture" + current timeframe + ".jpg");
    
            OutputStream fout = null;
            try {
                fout = new FileOutputStream(file);
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout);
                fout.flush();
                fout.close();
                MediaStore.Images.Media.insertImage(this.getContentResolver(), file.getAbsolutePath(), file.getName(), file.getName());
            } catch (IOException e) {
                e.printStackTrace();
            }
            seekTo(mediaPlayer.getCurrentPosition() + 100);
       }
    }