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
被调用时,你必须停止使用camera2
、MediaCodec
或MediaPlayer
绑定的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代替)