2013-04-09 12 views
5

mio problema sembra accadere solo su Android 4.2.2Android mediaplyer seekTo all'interno onPrepared

vado in questo modo stato di inattività -> inizializzata Stato -> prepareAsync() -> e in onPrepared il seekTo si chiama, ma su questa versione di Android il mediaplayer ritorna

"Tentativo di cercare di oltre la fine del file: richiesta = {int> 0}, durationMs = 0"

e iniziare a giocare dall'inizio, in quanto non v'è alcun punto in cui ho potrebbe prendere questo, né alcun ascoltatore, basta scrivere questo messaggio al log, non posso davvero reagire su questo.

Che cosa è ancora più strano è che se io chiamo mediaPlayer.getDuration() in onPrepared() restituisce il giusto valore e non 0.

Pensi che sia un bug mediaplayer o c'è un posto migliore dove chiamata seek To? o forse un modo come sapere la ricerca Per fallire? Vorrei evitare di controllare periodicamente la posizione corrente se è più piccola della posizione desiderata e provare a chiamare cerca perché questo approccio ha molti problemi diversi.

si tratta di un liscio di contenuti video in streaming

risposta

5

Attualmente sto cercando di trovare una soluzione allo stesso problema. Il meglio che ho escogitato finora è il seguente.

Su 4.2 Ho notato che le seguenti chiamata spalle vengono ricevuti:

1) onVideoSizeChanged() - in cui l'altezza e la larghezza = 0
2) onPrepared()
3) onVideoSizeChanged() - corretto altezze e larghezze

Non è possibile chiamare seekTo in (1) poiché il lettore non è ancora pronto.

Come si è preso nota, se si chiama seekTo in (2) il lettore multimediale genera l'avvertimento "Tentativo di cercare di oltre la fine del file"

È ricevere solo (3) se MediaPlayer.start() è stato chiamato, ma a questo punto è possibile chiamare seekTo() correttamente.

MediaPlayer mMediaPlayer = new MediaPlayer(); // + some initialisation code 
boolean mVideoSizeIsSet = false; 
boolean mMediaPlayerIsPrepared = false; 

public void onPrepared(MediaPlayer mediaplayer) { 
    Log.d(TAG, "onPrepared called"); 
    mMediaPlayerIsPrepared = true; 

    if (mVideoSizeIsSet) { 
     mMediaPlayer.seekTo(); 
    } 

    mMediaPlayer.start() 
} 


public void onVideoSizeChanged(MediaPlayer mp, int width, int height) { 
    Log.d(TAG, "onVideoSizeChanged called"); 

    if (width == 0 || height == 0) { 
     Log.d(TAG, "invalid video width(" + width + ") or height(" + height + ")"); 
    } else { 

     mVideoSizeIsSet = true; 

     if (mMediaPlayerIsPrepared) { 
      mMediaPlayer.seekTo(); 
     } 
    } 
} 

(io personalmente non mi piace l'uso delle guardie booleane, ma se si guarda il campione lettore multimediale fornito con l'SDK, si fa qualcosa di simile).

Test su una gamma di dispositivi/versioni del sistema operativo, questo fornisce una soluzione generica. Tuttavia, c'è un bug con 4.2. La chiamata a mMediaPlayer.start() sembra causare la riproduzione dei primi fotogrammi del video prima che si verifichi seekTo(), questo è appena visibile per la mia situazione, ma potrebbe essere più visibile per te. Attualmente sto cercando di nascondere la mia vista di superficie in qualche modo fino a quando non ricevo l'evento onSeekComplete(), ma questo non è l'ideale.

Se qualcuno ha una soluzione migliore che funzioni su tutte le versioni del sistema operativo, mi piacerebbe sentirla.

+0

In seguito alla risposta di Robin, ho provato a rintracciare il codice sorgente del lettore multimediale dove viene impostato il valore di durata. Ho finito per guardare la classe StageFrightPlayer, che ha una struttura AwesomePlayer, che sembra mantenere il valore nel suo membro mDurationUs. Questo sembra essere impostato quando viene effettuata una chiamata a initAudioDecoder o initVideoDecoder. Immagino che la soluzione ideale possa far richiamare una di queste due funzioni senza bisogno di chiamare la funzione java MediaPlayer.start()? – Simon

+0

Ho appena aggiunto queste informazioni come commento su Android [numero 54112] (http://code.google.com/p/android/issues/detail?id=54112). – Simon

+0

questo è lavoro per me, grazie! – Eric

0

Ecco il codice sorgente:

418 status_t MediaPlayer::seekTo_l(int msec) 
419 { 
420  ALOGV("seekTo %d", msec); 
421  if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED | MEDIA_PLAYER_PLAYBACK_COMPLETE))) { 
422   if (msec < 0) { 
423    ALOGW("Attempt to seek to invalid position: %d", msec); 
424    msec = 0; 
425   } else if ((mDuration > 0) && (msec > mDuration)) { 
426    ALOGW("Attempt to seek to past end of file: request = %d, EOF = %d", msec, mDuration); 
427    msec = mDuration; 
428   } 
429   // cache duration 
430   mCurrentPosition = msec; 
431   if (mSeekPosition < 0) { 
432    getDuration_l(NULL); 
433    mSeekPosition = msec; 
434    return mPlayer->seekTo(msec); 
435   } 
436   else { 
437    ALOGV("Seek in progress - queue up seekTo[%d]", msec); 
438    return NO_ERROR; 
439   } 
440  } 
441  ALOGE("Attempt to perform seekTo in wrong state: mPlayer=%p, mCurrentState=%u", mPlayer.get(), mCurrentState); 
442  return INVALID_OPERATION; 
443 } 

suggerisco di chiamare getDuration() primi a lasciare l'istanza mediaplayer per forzare inizializzare il campo di durata. Altrimenti, prova a chiamare anche start() prima seekTo() o chiama anche seekTo() qualche volta dopo start().

+1

grazie per la risposta, sfortunatamente chiamare getDuration() prima di cercarePer non aiuta, start() prima seekTo() non aiuta pure, e chiamare seekTo con un ritardo non è una soluzione affidabile. –

2

Questo è un problema con l'implementazione NuPlayer. NuPlayer non ha una corretta implementazione dello stato di preparazione, diversamente dalla riproduzione locale con AwesomePlayer. La connessione di rete viene stabilita solo quando viene chiamato start(), dopo di che la durata è nota. Il problema può essere risolto aggirando il controllo della durata se la durata è 0, l'ho provato prima.

Problemi correlati