BufferQueue 已被废弃:使用 TextureView 播放视频时

Posted

技术标签:

【中文标题】BufferQueue 已被废弃:使用 TextureView 播放视频时【英文标题】:BufferQueue has been abandoned: When playing video with TextureView 【发布时间】:2016-01-22 03:52:33 【问题描述】:

每次我暂停我的活动(实际上是片段)以转到另一个应用程序时,在使用 onResume 返回时,我尝试恢复视频播放,但它不播放:我得到一个空白屏幕。经调查,我在 Logcat 中看到以下内容

E/BufferQueueProducer: [unnamed-23827-0] queueBuffer: BufferQueue has been abandoned
E/MediaPlayer: error (1, -38)
E/MediaPlayer: error (1, -38)
E/MediaPlayer: error (1, -38)
E/MediaPlayer: error (1, -38)
E/BufferQueueProducer: [unnamed-23827-0] connect(P): BufferQueue has been abandoned

这是我在简历中调用的代码

player.seekTo(mVideoSeekPosition);
player.start();

仅供参考:我一直在尝试将此答案应用于我的案例,但我不能:What can I do when the BufferQueue has been abandoned?

更新

我努力一个人去,但我还是崩溃了。所以我发布了整个代码以寻求帮助

private void setupVideoPlayingSystem(View root) 
  textureView = (TextureView) root.findViewById(R.id.textureView);
    
  textureView.setSurfaceTextureListener(this);

    
    
    

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) 
  Log.d(TAG, "onSurfaceTextureAvailable");
  if (null == surface) 
    Log.d(TAG, "new surface");
    surface = new Surface(surfaceTexture);
    mediaPlayer = new MediaPlayer();
    mediaPlayer.setSurface(surface);
    mediaPlayer.setLooping(false);
  
    
  /*
    
  outstandingVideoRequest is IOU for orentation change (verifed: onResume before onSurfaceTextureAvailable)
  but for cold startup, must check mVideoUrl
  */
    
  if (outstandingVideoRequest && null != mVideoUrl) 
    
    outstandingVideoRequest = false;

        playNewVideo(mVideoUrl);
  
    

    
    

@Override
    
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) 
    
  Log.d(TAG, "onSurfaceTextureSizeChanged");

    
    
    

@Override

    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) 
    
  Log.d(TAG, "onSurfaceTextureDestroyed");
  return false;//leave destruction for onDestroy
    


@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) 
        
    

    private void playNewVideo(String url) 
        
      if (null == mediaPlayer || null == surface) 
        
        Log.d(TAG, "playNewVideo not ready");
    
            synchronized (outstandingVideoRequest) 
    
              Log.d(TAG, "playNewVideo outstandingVideoRequest");
    
               outstandingVideoRequest = true;
        
         
       else 
        
        try 
        
          mediaPlayer.reset();
        
          mediaPlayer.setDataSource(getContext(), Uri.parse(url));
        
          mediaPlayer.setLooping(false);
        
          mediaPlayer.prepareAsync();
         
          mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() 

            @Override
        
            public void onPrepared(MediaPlayer player) 
        
              Log.d(TAG, "onPrepared changeMediaPlayerDatasource");
        
              onReadyToPlay(player);
            
        
          );
        
        catch (Exception e) //IOException && IllegalStateException
        
         Log.d(TAG, "textureview playNewVideo ERORR");
        
         e.printStackTrace();
        
       
        
        
     
        
    

  private void resumeVideoUponReturningFromAnotherActivity() 

            if (null == mediaPlayer || null == surface) 

                Log.d(TAG, "resumeVideoUponReturningFromAnotherActivity outstandingVideoRequest");

                outstandingVideoRequest = true;
    
         else 
    
//            playNewVideo(mVideoUrl);

                Log.d(TAG, "resumeVideoUponReturningFromAnotherActivity go NOW");

                mediaPlayer.setSurface(surface);
    
            onReadyToPlay(mediaPlayer);

            
    
    
    
    
    

    private void onReadyToPlay(MediaPlayer player) 
    
        //play video
    
        mProgressCircle.setVisibility(View.GONE);

            showVideoOverlayChildren();
    
        if (0 == mVideoSeekPosition) 
    
            Log.d(TAG, "onReadyToPlay start");

                player.start();

             else 
    
            Log.d(TAG, "onReadyToPlay seek");

                player.seekTo(mVideoSeekPosition);
     
           player.start();

            
    
        mHandler.postDelayed(new Runnable() 

                @Override

                public void run() 

                    Log.d(TAG, "postDelayed resumeVideo");
    
                hideVideoOverlayChildren();

                
    
        , Constant.BEFORE_VIDEO_OVERLAY_DISAPPEAR);

        


    
        private void destroyMediaPlayer() 

            if (null != mediaPlayer) //move to video todo
    
            mediaPlayer.stop();

                mediaPlayer.release();
    
            mediaPlayer = null;

            
    
        if (null != surface) 

                surface.release();

                surface = null;
    
        
    
    
    
    

    private void pauseVideo() 

            if (null != mediaPlayer) 

                Log.d(TAG, "pause");
    
            mediaPlayer.pause();

                mVideoSeekPosition = mediaPlayer.getCurrentPosition();

            
    
    


    
        private void stopVideo()
    
        if (null != mediaPlayer) 

                Log.d(TAG, "stop video");

                mediaPlayer.pause();

                mVideoSeekPosition = mediaPlayer.getCurrentPosition();

                mediaPlayer.stop();

            
    
    

@Override
    public void onResume() 

        super.onResume();

        Log.d(TAG, "onResume");
    
    mLocalBroadcastManager.registerReceiver(mVideoSelectionReceiver, mVideoSelectedIntentFilter);
    
    resumeVideoUponReturningFromAnotherActivity();

    
    

【问题讨论】:

如果在切换活动时显示表面消失了,那么您需要使用新的表面调用 setDisplay() / setSurface()。 我想不通。我把mediaPlayer.setSurface(surface); 放在搜索部分之前它仍然不起作用。另外,我还尝试了其他一些东西。 您是否从新的 TextureView 向其传递了新的 Surface? 【参考方案1】:

在活动之间切换时我遇到了同样的问题,并且还有 MediaPlayer(1971): Error (100,0)。通过在 onSurfaceTextureDestroyed 中添加这些行来解决它

    @Override
    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) 
        if (mediaPlayer != null) 
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        
        return true;
    

【讨论】:

【参考方案2】:

我发现setSurface(null) 很有用。

如果你使用TextureView来显示一些东西,当TextureView.SurfaceTextureListener回调onSurfaceTextureDestroyed被调用时,你必须停止使用camera2MediaCodecMediaPlayer绑定的SurfaceTexture/new Surface(SurfaceTexture)

像这样

@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) 
   mediaPlayer.setDisplayer(null);
   return false;//do not return true if you reuse it.

【讨论】:

【参考方案3】:

您的代码中似乎存在错误: 在 SurfaceTextureDestroyed() 中,您没有重置 Surface 或 mediaPlayer。 resume时,mediaPlayer和surface都不为null,所以在resumeVideoUponReturningFromAnotherActivity()中设置surface并调用start播放,但是由于之前的SurfaceTextureDestroyed,surface已经失效。这就是你得到错误的原因。

要修复它,您应该在回调 SurfaceTextureDestroyed 中重置表面。恢复时,在回调 SurfaceTextureAvailable 中重建表面,将其设置为 mediaPlayer 并调用 start 播放。代码如下:

public void onResume() 
   if (mSurface == null) 
      mResumeRequested = true;
      return;
   
   mMediaPlayer.start();


@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) 
   mSurface = new Surface(surface);
   if (mMediaPlayer != null) 
      mMediaPlayer.setSurface(mSurface);
      if (mResumeRequested) 
         mMediaPlayer.start();
         mResumeRequested = false;
      
   


@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) 
   mSurface = null;
   return false;

而且您根本不需要重置媒体播放器。如果重置,则必须重新实例化它并重新缓冲,这会导致延迟,这会损害用户体验,因为不希望延迟暂停/恢复。

【讨论】:

以上是关于BufferQueue 已被废弃:使用 TextureView 播放视频时的主要内容,如果未能解决你的问题,请参考以下文章

21.hash_map(已被废弃不再使用 被unordered_map代替)

Android Surfaceflinger服务 ----- BufferQueue分析

关于[废弃]

Swing 数据绑定框架

for each ……in

for each。。。。in