MediaPlayer: 在不同控件之间实现视频的无缝切换的方法

最近使用MediaPlayer + TextureView 实现了一个视频播放器,并且实现了它的横竖屏切换的效果,唯一美中不足的是在横竖屏切换的时候画面会卡顿一下,虽然也不影响播放,但是怕测试会报Bug,到时候还得自己解决,所以就先把这个问题处理下,并记录之:

TextureView的监听方法有以下四个:

  @Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

    }

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {
        return true;
    }

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

    }

我们一般是在 onSurfaceTextureAvailable() 方法里面取得 SurfaceTexture 并包装成一个 Surface 再调用MediaPlayer的 setSurface 方法完成播放器的显示工作,然而在横竖屏切换的时候,由于当前TextureView所在的ViewGroup会把该TextureView remove掉,这里便触发了TextureView的 onSurfaceTextureDestroyed 方法,然后在横屏窗口中,由于需要重新添加TextureView以便于显示,所以这里又调用了 onSurfaceTextureAvailable 方法,我最开始的做法是这样的:

mSurface = new Surface(surfaceTexture);

然后传递给MediaPlayer, 由于在横竖屏切换时给MediaPlayer传递了两个不同的Surface,因此导致了这个问题,那么解决问题的方法也很简单,只要保存SurfaceTexture, 保证横竖屏切换时使用同一个Surface即可:

@Override
    public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
        if (mSurfaceTexture == null) {
            mSurfaceTexture = surfaceTexture;
            openMediaPlayer();
        } else {
            mTextureView.setSurfaceTexture(mSurfaceTexture);
        }
    }

这里将SurfaceTexture保存为一个成员变量,在使用前对其进行判断,保证使用的是同一个SurfaceTexture,也可以在

@Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
      Log.d(TAG, "onSurfaceTextureDestroyed: ");
      mSurfaceTexture = surface;
      return false;
    }

也可以在 onSurfaceTextureDestroyed 方法中保存,不过不管在哪个方法中保存这个SurfaceTexture, 都需要注意 onSurfaceTextureDestroyed 方法的返回值必须为false, 官方API的解释说明如下:

Invoked when the specified SurfaceTexture is about to be destroyed. If returns true, no rendering should happen inside the surface texture after this method is invoked. If returns false, the client needs to call release(). Most applications should return true.

大致的意思是如果返回ture,SurfaceTexture会自动销毁,如果返回false,SurfaceTexture不会销毁,需要用户手动调用release()进行销毁。
所以我们在销毁的时候返回false,并保存SurfaceTexture对象,然后在切换成全屏的时候在onSurfaceTextureAvailable()方法中,调用setSurfaceTexture(mSurfaceTexture)方法,这样就恢复之前的画面了。
另外,TextureView的生命周期为:
  • 切换至后台的时候会调用onSurfaceTextureDestroyed,从后台切换回来会调用onSurfaceTextureAvailable。
  • TextureView的ViewGroup remove TextureView的时候会调用onSurfaceTextureDestroyed方法。相同,TextureView的ViewGroup add TextureView的时候会调用onSurfaceTextureAvailable。这些都是建立在视图可见的基础上,如果视图不可见,add也不会调用onSurfaceTextureAvailable方法,remove也不会调用onSurfaceTextureDestroyed方法。
  • 当TextureView设置为Gone的时候,并不会调用onSurfaceTextureDestroyed方法法。
参考链接:
 
 
posted @ 2019-06-24 14:35  夜行过客  阅读(3537)  评论(0编辑  收藏  举报