11

I have created a media player which plays video on the surface view. After completion of video the last frame of the video remains on the surface. I want to remove the video frame from the surface because after some delay another video starts.

The flow of the video is:

NOW: Video on surface -> last video frame on surface -> another video on surface.

But the required flow is:

REQUIRED: Video on surface -> clear surface (black) -> another video on surface.

can anyone help to solve this problem.

Thanks Ishan jain

ishan jain
  • 681
  • 3
  • 10
  • 27

7 Answers7

10

Building on Fadden's answer, and Andreimarinescu's question, here is a version for API 16 and below:

private void clearSurface(Surface surface) {
    EGL10 egl = (EGL10) EGLContext.getEGL();
    EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
    egl.eglInitialize(display, null);

    int[] attribList = {
            EGL10.EGL_RED_SIZE, 8,
            EGL10.EGL_GREEN_SIZE, 8,
            EGL10.EGL_BLUE_SIZE, 8,
            EGL10.EGL_ALPHA_SIZE, 8,
            EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
            EGL10.EGL_NONE, 0,      // placeholder for recordable [@-3]
            EGL10.EGL_NONE
    };
    EGLConfig[] configs = new EGLConfig[1];
    int[] numConfigs = new int[1];
    egl.eglChooseConfig(display, attribList, configs, configs.length, numConfigs);
    EGLConfig config = configs[0];
    EGLContext context = egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, new int[]{
            EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
            EGL10.EGL_NONE
    });
    EGLSurface eglSurface = egl.eglCreateWindowSurface(display, config, surface,
            new int[]{
                    EGL14.EGL_NONE
            });

    egl.eglMakeCurrent(display, eglSurface, eglSurface, context);
    GLES20.glClearColor(0, 0, 0, 1);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    egl.eglSwapBuffers(display, eglSurface);
    egl.eglDestroySurface(display, eglSurface);
    egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, 
            EGL10.EGL_NO_CONTEXT);
    egl.eglDestroyContext(display, context);
    egl.eglTerminate(display);
}

Pretty crude, lacks error checking, but it works for me.

nmr
  • 16,625
  • 10
  • 53
  • 67
  • `EGL14.EGL_OPENGL_ES2_BIT` should be replaced with `EGL10.EGL_WINDOW_BIT` - `EGL14.EGL_NONE` should be replace with `EGL10.EGL_NONE` - No idea how to replace `EGL14.EGL_CONTEXT_CLIENT_VERSION`. Currently your solution require API 17... But it works great on API 17. – Hugo Gresse May 28 '15 at 09:16
  • 1
    I've made it compatible with API 16 : https://gist.github.com/HugoGresse/5ca05821444353a823bb – Hugo Gresse May 28 '15 at 09:58
  • Oh, interesting. Thanks for the update. I think if you compile with SDK 17 you can still run this (I think) on API 16 because the constants will be folded in at compile time. Not 100% sure though. – nmr May 29 '15 at 21:49
  • When runing on API 16 I have some warning or error depends – Hugo Gresse May 30 '15 at 09:39
5

You can clear it with GLES. You can't clear it with Canvas draw commands because that will prevent you from playing movies on that surface again.

An example can be found in Grafika's PlayMovieSurfaceActivity class. The clearSurface() method does this:

    EglCore eglCore = new EglCore();
    WindowSurface win = new WindowSurface(eglCore, surface, false);
    win.makeCurrent();
    GLES20.glClearColor(0, 0, 0, 0);
    GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
    win.swapBuffers();
    win.release();
    eglCore.release();

The EglCore and WindowSurface classes are part of Grafika. The key thing is that it attaches to the surface, does the clear, and then detaches from the surface. Make sure the video player has released the surface before doing this, or GLES won't be able to attach.

If you want to understand why the attach / detach stuff is necessary, see the system-level graphics architecture doc.

fadden
  • 51,356
  • 5
  • 116
  • 166
  • 1
    Any chance this could work with API level 15+? I've tried to port over the EglCore class from Grafika, and it seems bound to API level 17. – andreimarinescu Dec 12 '14 at 15:54
  • Grafika uses some features introduced with EGL 1.4, which was added in API 17. I think the above is trivial enough that it should be doable with EGL 1.0, but you'd want to pull out just the necessary bits from the Grafika gles code. If you're not sure what the EGL 1.0 / 1.4 API differences are, http://bigflake.com/mediacodec/#ExtractMpegFramesTest was written twice, for API 16 and 17, which makes it easy to do a side-by-side comparison. – fadden Dec 12 '14 at 16:01
  • This is great, thanks for the pointers, @fadden! It's a good learning excercise for me as well:) – andreimarinescu Dec 12 '14 at 20:18
4

I had a similar issue. In my case, I was showing a title card that completely covered the video view followed by the video itself. The first title card and video that followed played fine. However, when any subsequent title card was hidden, the last frame of the previous video would flash before the next video started. I added an info listener to my VideoView to listen for the first frame render before hiding the title card. This covers up the video until the first correct frame has rendered. I hope this helps!

mVideoView.setOnInfoListener(new MediaPlayer.OnInfoListener() 
{
    @Override
    public boolean onInfo(final MediaPlayer mp, final int what, final int extra) 
    {
        if (what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) 
        {
            mTitleCardView.setVisibility(View.GONE);

            return true;
        }

        return false;
    }
});
Stephen
  • 1,373
  • 1
  • 12
  • 13
3

I have a sample problem and i fixed it by using these two lines after player release.

surfaceViewHolder.setFormat(PixelFormat.TRANSPARENT); surfaceViewHolder.setFormat(PixelFormat.OPAQUE);

Zia
  • 270
  • 2
  • 7
1

I have the same problem. Maybe help someone. I found solution here https://stackoverflow.com/a/18906637

I have player in Service, in Fragment I have onComplete callback and after video finished:

videoHolder.setFormat(PixelFormat.TRANSPARENT);
videoHolder.setFormat(PixelFormat.OPAQUE);
videoService.setVideoDisplay(videoHolder);
Community
  • 1
  • 1
K. Maksym
  • 31
  • 3
0

I solved the problem with very simple way - just set Surface invisible until video is prepared. If you want to black screen, you can add a black screen view(curtainView).

public void play(String path) {
    try {
        status =  STATUS_PREPARING;
        mSurface.setVisibility(View.INVISIBLE);
        mCurtainView.setVisibility(View.VISIBLE);  // simple black view
        mPlayer = new MediaPlayer();
        if(mSurfaceHolder!=null) mPlayer.setDisplay(mSurfaceHolder);
        mPlayer.setDataSource(path);
        mPlayer.prepareAsync();
        mPlayer.setOnPreparedListener(this);
    } catch (Exception e) {
        return;
    }
}

...

@Override
public void onPrepared(MediaPlayer mp) {
    mSurface.setVisibility(View.VISIBLE);
    if(mSurfaceHolder != null){     
        mPlayer.start();
        mCurtainView.setVisibility(View.GONE);
        status = STATUS_PLAYING;
    } else {
        status = STATUS_DATA_PREPARED;
    }
}

private final class SurfaceCallback implements Callback {
    public void surfaceCreated(SurfaceHolder holder) {
        mSurfaceHolder = holder;
        mPlayer.setDisplay(holder);
        if(status==STATUS_DATA_PREPARED){
            mPlayer.start();
            mCurtainView.setVisibility(View.GONE);
            status = STATUS_PLAYING;
        }
    }

    public void surfaceDestroyed(SurfaceHolder holder) {
        mSurfaceHolder = null;
    }
    ...
}
Springwalk
  • 19
  • 3
-1

Clear surface when playback of video is completed (MediaPlayer onCompletion callback):

    Canvas canvas = surfaceView.getHolder().lockCanvas();

    // Clear surface by drawing on it
    canvas.drawColor(Color.BLACK, PorterDuff.Mode.CLEAR); 

   // option
   // canvas.drawColor(Color.BLACK);

   surfaceView.getHolder().unlockCanvasAndPost(canvas);

Another option (but I don't remember clearly right now) is call one of MediaPlayer class function when onComplition() callback called:

MediaPlayer.stop();

// reset to clear ready to reuse state.
MediaPlayer.reset();

// release all releted objects and memory
MediaPlayer.release()

One of them cause clear surface view. After release() you have to create another MediaPlayer instance again.

dasar
  • 5,321
  • 4
  • 24
  • 36
  • I already have tried and getting the following exception: **09-04 20:28:34.164: A/libc(545): Fatal signal 11 (SIGSEGV) at 0x5cd14000 (code=1), thread 545 ()** and application crashes. – ishan jain Sep 04 '14 at 14:58
  • Post whole stack trace and logs from logcat. Also try to call MediaPlayer.stop() and MediaPlayer.reset() / MediaPlayer.release() as I remember one of that func cause clear black screen. I'm sure. – dasar Sep 04 '14 at 18:49
  • No. none of them worked in my case. I tried playing video on Android 4.3 device. – Yeung Nov 07 '14 at 10:03
  • Nop, we can't use a Canvas to clean a Surface used to display video : " The trouble is that there is no way to detach a software-based (Canvas) buffer producer." so the next use will fail. See http://stackoverflow.com/a/24914966/1377145 – Hugo Gresse May 28 '15 at 08:59