Chaque fois que je suspends mon activité (en fait Fragment) pour aller à une autre application, à mon retour avec onResume, j'essaie de reprendre la lecture de la vidéo mais la lecture ne se lit pas: je reçois un écran vide. Après enquête, je vois ce qui suit dans le 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
Voici le code que j'ai appelé à l'intérieur sur CV
player.seekTo(mVideoSeekPosition);
player.start();
FYI: J'ai essayé d'appliquer cette réponse à mon cas, mais je ne peux pas: Que puis-je faire lorsque la BufferQueue a été abandonnée?
UPDATE
J'ai eu du mal à y aller seul, mais je suis toujours en train de chuter. Donc, je poste le code entier pour l'aide
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();
}
J'ai eu le même problème lors de la commutation entre les activités et j'avais également MediaPlayer (1971): Erreur (100,0). Résolu en ajoutant ces lignes dans onSurfaceTextureDestroyed
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
if (mediaPlayer != null) {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer = null;
}
return true;
}
Il semble qu'il y ait un bogue dans votre code: dans SurfaceTextureDestroyed (), vous n'avez pas réinitialisé surface ni mediaPlayer. Lors de la reprise, ni mediaPlayer ni la surface ne sont nuls, c’est pourquoi, dans resumeVideoUponReturningFromAnotherActivity (), définissez la surface et le début de la lecture, mais cette surface est déjà invalide en raison de la présence de SurfaceTextureDestroyed. C'est pourquoi vous obtenez une erreur.
Pour résoudre ce problème, vous devez réinitialiser la surface dans callback SurfaceTextureDestroyed. Lorsque vous reprenez, reconstruisez la surface dans le rappel SurfaceTextureAvailable, configurez-le sur mediaPlayer et appelez start à jouer. Les codes vont comme ceci:
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;
}
Et vous n'avez pas du tout besoin de réinitialiser le lecteur multimédia. Si vous réinitialisez l'appareil, vous devez le ré-instancier et le remettre en mémoire tampon, ce qui provoque un délai, ce qui nuit à l'expérience de l'utilisateur car aucun délai de pause/reprise n'est plus souhaité.
Je trouve que setSurface(null)
est utile.
Si vous utilisez un TextureView pour afficher quelque chose, lorsque TextureView.SurfaceTextureListener
callback onSurfaceTextureDestroyed
est appelé, vous devez cesser d'utiliser SurfaceTexture/new Surface(SurfaceTexture)
lié par camera2
, MediaCodec
ou MediaPlayer
.
Comme ça
@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mediaPlayer.setDisplayer(null);
return false;//do not return true if you reuse it.
}