2010-10-06 17 views
25

Posso riprodurre i video con precisione back to back implementando OnCompletionListener per impostare l'origine dati su un file diverso. Nessun problema lì. Chiamo reset() e prepare() bene.Android: MediaPlayer senza pause o senza interruzioni Riproduzione video

Quello che non sono stato in grado di capire, è come sbarazzarsi dello sfarfallio dello schermo gap di 1-2 secondi tra la modifica della sorgente dati e l'avvio del nuovo video. Il divario mostra uno schermo nero e non ho trovato alcun modo per aggirarlo.

Ho provato a impostare lo sfondo della vista genitore su un'immagine, ma riesce a ignorarlo. Anche se il SurfaceView è trasparente (che è l'impostazione predefinita). Ho anche provato a far riprodurre contemporaneamente più file video allo stesso tempo e a cambiare il display del mediaplayer quando uno finisce e l'altro dovrebbe iniziare.

L'ultima cosa che ho provato, era avere una seconda vista sullo sfondo che mostro temporaneamente mentre il video si sta "preparando" e rimuovendolo quando il video è pronto per essere avviato. Anche questo non era molto semplice.

C'è un modo per sbarazzarsi di tale lacuna. L'esecuzione di un video in loop funziona perfettamente e fa esattamente ciò che voglio, con l'eccezione che sta guardando attraverso lo stesso video invece di riprodurne uno diverso.

main.xml

<?xml version="1.0" encoding="utf-8"?> 
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="fill_parent" 
    android:background="@drawable/background" 
    android:layout_height="fill_parent"> 
    <SurfaceView 
     android:id="@+id/surface" 
     android:layout_width="fill_parent" 
     android:layout_height="fill_parent" 
     android:layout_gravity="center"> 
    </SurfaceView> 
</FrameLayout> 

Player.java

public class Player extends Activity implements 
     OnCompletionListener, MediaPlayer.OnPreparedListener, SurfaceHolder.Callback { 
     private MediaPlayer player; 
    private SurfaceView surface; 
    private SurfaceHolder holder; 

    public void onCreate(Bundle b) { 
     super.onCreate(b); 
     setContentView(R.layout.main); 
     surface = (SurfaceView)findViewById(R.id.surface); 
     holder = surface.getHolder(); 
     holder.addCallback(this); 
     holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);  
    } 

    public void onCompletion(MediaPlayer arg0) { 
     File clip = new File(Environment.getExternalStorageDirectory(),"file2.mp4"); 
     playVideo(clip.getAbsolutePath()); 
    } 
    public void onPrepared(MediaPlayer mediaplayer) { 
     holder.setFixedSize(player.getVideoWidth(), player.getVideoHeight()); 
     player.start(); 
    } 

    private void playVideo(String url) { 
     try { 
      File clip = new File(Environment.getExternalStorageDirectory(),"file1.mp4"); 

      if (player == null) { 
       player = new MediaPlayer(); 
       player.setScreenOnWhilePlaying(true); 
      } 
      else { 
       player.stop(); 
       player.reset(); 
      } 
      player.setDataSource(url); 
      player.setDisplay(holder); 
      player.setOnPreparedListener(this); 
      player.prepare(); 
      player.setOnCompletionListener(this); 
     } 
     catch (Throwable t) { 
      Log.e("ERROR", "Exception Error", t); 
     } 
    } 
+0

Anche se questo è stato pubblicato qualche tempo fa, sto affrontando lo stesso problema. Anche con l'utilizzo di videoview, ho ancora una lacuna quando si passa da un video all'altro. C'è un altro modo per risolvere questo? – dulys

risposta

2

dopo troppo tempo sprecato cercare di capire come giocare video consecutivi senza il "gap", i' Mi sto impegnando verso l'impossibile. a meno che, naturalmente, non sia possibile risalire al livello nativo e implementare il proprio lettore, il lettore multimediale di Android non supporta la riproduzione continua del momento.

+0

Ho raggiunto questo tramite un hack. Passare da 2 istanze di mediaplayer a un servizio. Ho una variabile int configurabile in modo tale che inizio a riprodurre l'asset multimediale B "N" prima che l'asset multimediale A termini. – Krafty

+0

è bello, ma per esperienza posso dirti che testare anche sullo stesso dispositivo, il tempo esatto è quasi impossibile da impostare, dato che un dispositivo a volte può esaurire la memoria, rendendo la transizione inesatta. – josephus

+0

@ user721448 in ogni caso, ti consiglio di postare il tuo codice qui come risposta e di testarlo. Sono andato avanti con altri progetti senza trovare una soluzione funzionante a questo problema, ma sono ancora curioso di conoscere la soluzione. – josephus

1

Non l'ho fatto con la riproduzione di video su un MediaPlayer ma ho fatto qualcosa di simile con i file audio quando uno streaming viene interrotto perché un utente è passato da 3G a Wifi.

Penso che il ritardo che si sta vedendo sia mentre il lettore multimediale sta memorizzando il file di input. Quindi forse puoi definire entrambi i giocatori all'inizio? Dovresti definire l'origine dati e preparare entrambi i giocatori, ma solo avviarne uno.

Quindi su onCompletionListener è possibile capovolgerli anziché reimpostare quello esistente e impostare una nuova origine dati.

player.release(); 
    player = flipPlayer; 
    flipPlayer = null; 
    player.start(); 

Ovviamente avresti bisogno usare sia ad un onPreparedListener diverso per flipPlayer o prendere il Player.start() dal onPrepare. (Dal momento che lo chiami in modo sincrono, non avrei pensato che si trattasse di un problema).

+0

hmm. vale un tentativo. anche se non rilasciare() in realtà lascia uno schermo vuoto proprio lì? – josephus

0

hai cercato di avere pronta (aperto/preparato) 2 VideoView, con uno visibile, l'altro invisibile e fermato, e l'asino che presto otterrà il callback di OnCompletionListener, renderò visibile il secondo, avviarlo e nasconderne il primo. Nel frattempo, mentre si gioca la seconda, è possibile chiamare open/prepare su 1st VideoView per aprire/preparare un altro file.

+0

L'onCompletionListener verrà chiamato subito dopo la fine della riproduzione del primo video. Gap partirà da lì e finirà dopo aver iniziato a suonare il secondo (ovviamente dopo aver cambiato visibilità). Non funzionerà. – josephus

4

anch'io ho lo stesso problema, come indicato dal collegamento sotto

VideoView Disappears for a second when video is changed

Ma questo problema solito si verifica se si tenta con Android 4.0+ (ICS). Ho iniziato a portare VideoView.java e MediaPlayer.java dalla 4.0 alla mia app, ma questo sembra complesso e senza fortuna fino ad ora. Fondamentalmente sembra un bug nel codice nativo delle versioni precedenti.

0

@ user1263019 - sei riuscito a portare Android 4.0 MediaPlayer nella tua app? Sto affrontando lo stesso problema e sto cercando una soluzione piacevole. Il mio caso è di avere un'immagine sul SurfaceView che dovrebbe essere nascosta per mostrare la riproduzione del video, ma c'è una lacuna tra la chiamata start() e l'inizio effettivo del video. L'unica soluzione finora è di avviare una discussione che verifica se getCurrentPosition() è> 0.

Sull'argomento - Penso che non sia possibile avere una riproduzione senza pause, sebbene Winamp sostenga di avere tali capacità. Uno scribacchino è quello di preparare il secondo giocatore diversi secondi prima della fine della riproduzione del primo giocatore e quindi chiamare start() del secondo lettore 100-200 ms prima della fine della riproduzione.

0

Nell'implementazione exoplayer (o MediaPlayer) utilizzare un gestore ripetutamente inviare un eseguibile, durante il gioco, che ottiene il tempo di monitoraggio corrente e lo passa ad una richiamata:

public interface MediaAction { 
    public void onTrackingChanged(long currentPosition); 
} 

public class ExoPlayerImplementation implements Exoplayer { 

    .. 

    private MediaAction mediaActionCallback; 
    public void setMediaActionCallback(MediaAction ma) { 
    mediaActionCallback = ma; 
    } 
    public void releaseMediaAction() { mediaActionCallback = null; } 

    private Handler trackingCallback = new Handler(Looper.getMainLooper()); 

    Runnable trackingTask; 
    private Runnable getTrackingTask() { 
    Runnable r = new Runnable { 
     @Override public void run() { 
     long currentPosition = getCurrentPosition(); 
     if (mediaActionCallback != null) { 
      mediaActionCallback.onTrackingChanged(currentPosition); 
     } 
     // 60hz is 16 ms frame delay... 
     trackingCallback.postDelayed(getTrackingTask(), 15); 
     } 
    }; 
    trackingTask = r; 
    return r; 
    } 

    public void play() { 
    // exoplayer start code 
    trackingCallback.post(getTrackingTask()); 
    } 

    public void pause/stop() { 
    trackingCallback.removeCallbacks(trackingTask); 
    } 

    .. 

} 

E ora si può tenere traccia di quando la posizione corrente in realtà è cambiata - se è cambiata, allora puoi mostrare la tua vista di output video/viste di scambio/rimuovere l'anteprima (ad esempio, utilizzare MediaExtractor per afferrare i fotogrammi iniziali, sovrapporre come anteprima in un ImageView e nascondere quando la posizione corrente sta aumentando). Puoi rendere questo codice più completo combinandolo con il listener dello stato: quindi sai se stai eseguendo il buffering (controlla la posizione del buffer rispetto alla posizione corrente), effettivamente stai riproducendo, in pausa o fermato con i callback appropriati (in MediaAction). È possibile applicare questo metodo a entrambe le classi MediaPlayer ed ExoPlayer (poiché è solo un'interfaccia e un gestore).

Spero che questo aiuti!

Problemi correlati