2013-04-09 10 views
5

mein Problem nur auf Android 4.2.2android mediaplyer seekTo onPrepared innerhalb

zu passieren scheint, dass ich gehen auf diese Weise Ruhezustand -> initialisierten Zustand -> prepareAsync() -> und in onPrepared die seekTo genannt wird, sondern auf diese android-Version der Mediaplayer gibt

„der Versuch, über das Ende der Datei zu suchen: request = {int> 0}, durationMs = 0“

und beginnen zu spielen von Anfang an, da es keinen Punkt, wo ich Könnte das fangen, noch irgendeinen Zuhörer, es schreibe einfach diese Nachricht in das Protokoll, ich kann nicht wirklich darauf reagieren.

Was noch seltsamer ist, dass, wenn ich mediaPlayer.getDuration() in onPrepared() aufrufen, es richtige Wert zurückgibt und nicht 0

Glauben Sie, es ist ein Mediaplayer Fehler oder gibt es einen besseren Ort, wo man Anruf seekTo? oder vielleicht ein Weg, wie man die Suche nach fehlgeschlagen? Ich möchte vermeiden, die aktuelle Position regelmäßig zu überprüfen, wenn sie kleiner als die gewünschte Position ist, und versuchen, versuchen zu suchen, da dieser Ansatz viele verschiedene Probleme hat.

es ist eine glatte Streaming-Video-Inhalt

Antwort

5

Ich versuche derzeit, eine Lösung für das gleiche Problem zu finden. Das Beste, was mir bisher eingefallen ist, ist folgendes.

auf 4.2 Ich habe bemerkt, dass die folgenden Rückrufe empfangen werden:

1) onVideoSizeChanged() -, wobei Höhe und Breite = 0
2) onPrepared()
3) onVideoSizeChanged() - ordnungsgemäße Höhen und Breiten

Sie können seekTo nicht in (1) aufrufen, da der Player noch nicht vorbereitet ist.

Wie Sie bemerkt, wenn Sie seekTo in (2) der Media Player erzeugt die Warnung als „Versuch, über das Ende der Datei zu suchen“

Sie nur (3) erhalten, wenn MediaPlayer.start() gab aufgerufen, aber an dieser Stelle können Sie seekTo() erfolgreich aufrufen.

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(); 
     } 
    } 
} 

(Ich persönlich mag es nicht, die Verwendung der Booleschen Wachen, aber wenn Sie den Media Player Probe mit dem sdk vorgesehen sehen, tut es so ähnlich).

Testen über eine Reihe von Geräten/Betriebssystemversionen bietet dies eine generische Lösung. Es gibt jedoch einen Fehler mit 4.2. Der Aufruf von mMediaPlayer.start() scheint dazu zu führen, dass die ersten paar Frames des Videos abgespielt werden, bevor seekTo() auftritt. Dies ist für meine Situation kaum sichtbar, kann aber für Sie besser sichtbar sein. Ich versuche derzeit, meine Oberflächenansicht irgendwie zu verstecken, bis ich das onSeekComplete() -Ereignis erhalte, aber das ist nicht ideal.

Wenn jemand eine bessere Lösung hat, die über alle Betriebssystemversionen funktioniert, würde ich es gerne hören.

+0

Im Anschluss an Robins Antwort versuchte ich, den Quellcode des Media Players auf die Stelle zu ziehen, an der der Wert für die Dauer letztendlich festgelegt wird. Am Ende habe ich mir die StageFrightPlayer-Klasse angeschaut, die eine AwesomePlayer-Struktur hat, die den Wert in ihrem mDurationUs-Member zu halten scheint. Dies scheint bei einem Aufruf von initAudioDecoder oder initVideoDecoder eingestellt zu werden. Ich denke, die ideale Lösung würde dazu führen, dass eine dieser beiden Funktionen aufgerufen wird, ohne die java MediaPlayer.start() - Funktion aufrufen zu müssen. – Simon

+0

Ich habe diese Informationen auch als Kommentar zu Android [Ausgabe 54112] (http://code.google.com/p/android/issues/detail?id=54112) hinzugefügt. – Simon

+0

das ist Arbeit für mich, danke! – Eric

0

Hier ist der Quellcode:

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 } 

Ich schlage vor, Sie getDuration() aufrufen, zuerst die Mediaplayer-Instanz zu lassen, die Dauer Feld zu zwingen, initialisieren. Ansonsten versuchen Sie bitte, start() vor seekTo() aufzurufen, oder rufen Sie seekTo() einige Zeit nach start() auf.

+1

Vielen Dank für die Antwort, leider rufen Sie getDuration() vor seekTo nicht helfen, start() vor seekTo() hilft auch nicht, und rufen Sie seekTo mit einer Verzögerung ist keine zuverlässige Lösung. –

2

Dies ist ein Problem bei der Implementierung von NuPlayer. NuPlayer verfügt im Gegensatz zur lokalen Wiedergabe mit AwesomePlayer nicht über eine ordnungsgemäße Bereitstellung des Vorbereitungsstatus. Die Netzwerkverbindung wird nur hergestellt, wenn start() aufgerufen wird. Danach ist die Dauer bekannt. Das Problem kann gelöst werden, indem die Dauerprüfung umgangen wird, wenn die Dauer 0 ist. Ich habe es vorher versucht.