在视频完成时从surfaceview清除视频帧

问题描述 投票:10回答:7

我创建了一个在表面视图上播放视频的媒体播放器。完成视频后,视频的最后一帧仍然在表面上。我想从表面删除视频帧,因为一段时间后,另一个视频开始播放。

视频流程如下:

现在:表面上的视频 - >表面上的最后一个视频帧 - >表面上的另一个视频。

但所需的流程是:

要求:表面上的视频 - >清晰的表面(黑色) - >表面上的另一个视频。

任何人都可以帮助解决这个问题。

谢谢和平耆那教

android video media-player surfaceview
7个回答
9
投票

基于Fadden的回答和Andreimarinescu的问题,这里是API 16及以下版本:

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);
}

非常粗糙,缺乏错误检查,但它适用于我。


5
投票

您可以使用GLES清除它。您无法使用Canvas绘制命令清除它,因为这会阻止您再次在该表面上播放电影。

一个例子可以在GrafikaPlayMovieSurfaceActivity类中找到。 clearSurface()方法这样做:

    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();

EglCoreWindowSurface课程是Grafika的一部分。关键是它附着在表面上,清晰,然后从表面脱离。在执行此操作之前,请确保视频播放器已释放曲面,否则GLES将无法附加。

如果您想了解为什么需要附加/分离内容,请参阅system-level graphics architecture doc。


3
投票

我有一个类似的问题。在我的情况下,我正在显示一个完全覆盖视频视图的标题卡,然后是视频本身。随后的第一张标题卡和视频播放得很好。但是,当隐藏任何后续标题卡时,上一个视频的最后一帧将在下一个视频开始之前闪烁。我在我的VideoView中添加了一个信息监听器,以便在隐藏标题卡之前监听第一帧渲染。这将覆盖视频,直到呈现第一个正确的帧。我希望这有帮助!

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;
    }
});

2
投票

我有一个示例问题,我在播放器发布后使用这两行来修复它。

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


1
投票

我也有同样的问题。也许帮助别人。我在这里找到了解决方案https://stackoverflow.com/a/18906637

我有玩家服务,片段我有onComplete回调和视频完成后:

videoHolder.setFormat(PixelFormat.TRANSPARENT);
videoHolder.setFormat(PixelFormat.OPAQUE);
videoService.setVideoDisplay(videoHolder);

0
投票

我用非常简单的方法解决了这个问题 - 只需将Surface设置为隐形,直到准备好视频。如果要黑屏,可以添加黑屏视图(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;
    }
    ...
}

-1
投票

完成视频播放后清除表面(MediaPlayer onCompletion回调):

    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);

另一种选择(但我现在还不清楚)是在onComplition()回调调用时调用MediaPlayer类函数之一:

MediaPlayer.stop();

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

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

其中一个导致清晰的表面视图。在release()之后你必须再次创建另一个MediaPlayer实例。

© www.soinside.com 2019 - 2024. All rights reserved.