2012-06-23 13 views
99

Nota: per la domanda seguente: Tutte le risorse sono locali sul dispositivo, non è in corso lo streaming di rete. I video contengono tracce audio.Come ridurre il ritardo di avvio di AVPlayer per iOS

Sto lavorando a un'applicazione iOS che richiede la riproduzione di file video con un ritardo minimo per avviare il video clip in questione. Sfortunatamente non sappiamo quale clip video specifico è il prossimo finché non avremo effettivamente bisogno di avviarlo. Nello specifico: quando viene riprodotto un video, sapremo quale sarà il prossimo set di (circa) 10 video clip, ma non sappiamo quale sia esattamente, fino a quando non verrà il momento di riprodurre "immediatamente" la clip successiva.

Quello che ho fatto per vedere i ritardi di avvio effettivi è chiamare addBoundaryTimeObserverForTimes sul lettore video, con un periodo di tempo di un millisecondo per vedere quando il video ha effettivamente iniziato a suonare, e prendo la differenza di quel timestamp con il primo posto nel codice che indica quale risorsa iniziare a giocare.

Da quello che ho visto così-lontano, ho trovato che utilizzando la combinazione di AVAsset carico, e quindi la creazione di un AVPlayerItem da quella volta che è pronto, e quindi in attesa di AVPlayerStatusReadyToPlay prima di chiamare il gioco, tende a prendere tra le 1 e 3 secondi per avviare la clip.

Da allora sono passato a quello che penso sia grosso modo equivalente: chiamando [AVPlayerItem playerItemWithURL:] e aspettando il AVPlayerItemStatusReadyToPlay per giocare. Circa le stesse prestazioni.

Una cosa che sto osservando è che il primo caricamento di AVPlayer è più lento del resto. Sembra che l'idea di pre-flight di AVPlayer con un asset breve/vuoto prima di provare a riprodurre il primo video potrebbe essere una buona pratica generale. [Slow start for AVAudioPlayer the first time a sound is played

Mi piacerebbe avere il tempo di avvio del video il più possibile, e avere alcune idee su cose da sperimentare, ma vorrei qualche consiglio da parte di chiunque fosse in grado di aiutare.

Aggiornamento: idea 7, di seguito, i tempi di commutazione dei rendimenti implementati di circa 500 ms. Questo è un miglioramento, ma sarebbe bello farlo ancora più velocemente.

Idea 1: Utilizzare N AVPlayers (non funziona)

Utilizzando ~ 10 AVPPlayer oggetti e start-e-sospendere tutti ~ 10 clip, e una volta che sappiamo quale abbiamo veramente bisogno, interruttore per, e interrompere la corretta AVPlayer, e ricominciare tutto da capo per il ciclo successivo.

Non penso che funzioni, perché ho letto che c'è approssimativamente un limite di 4 AVPlayer's attivo in iOS. C'era qualcuno che chiedeva su questo su StackOverflow qui, e ha scoperto circa il limite 4 AVPlayer: fast-switching-between-videos-using-avfoundation

Idea 2: Utilizzare AVQueuePlayer (non funziona)

Non credo che spingendo 10 AVPlayerItems in un AVQueuePlayer li precaricherà tutti per un avvio senza interruzioni. AVQueuePlayer è una coda, e penso che in realtà rende solo il prossimo video in coda pronto per la riproduzione immediata. Non so quale dei 10 video che vogliamo riprodurre, finché non è il momento di avviarlo.ios-avplayer-video-preloading

Idea 3: carico, gioco, e mantenere AVPlayerItems in background (non al 100% ancora sicuro - ma non guardando bene)

sto guardando se c'è qualche beneficio per caricare e giocare il primo secondo di ogni clip video in background (sopprimere il video e l'uscita audio), e mantenere un riferimento a ogni AVPlayerItem, e quando sappiamo quale elemento deve essere riprodotto per davvero, scambiare quello in, e scambiare lo sfondo AVPlayer con quello attivo. Risciacqua e ripeti.

La teoria sarebbe che i dischi suonati di recente AVPlayer/AVPlayerItem possano ancora contenere risorse preparate che renderebbero più veloce la riproduzione successiva. Finora, non ho visto benefici da questo, ma potrei non avere l'installazione AVPlayerLayer correttamente per lo sfondo. Dubito che questo migliorerà davvero le cose da quello che ho visto.

Idea 4: utilizzare un formato file diverso, forse uno più veloce da caricare?

Attualmente sto usando il formato H.264 di .m4v (video-MPEG4). H.264 ha molte diverse opzioni di codec, quindi è possibile che alcune opzioni siano più veloci da cercare rispetto ad altre. Ho scoperto che l'utilizzo di impostazioni più avanzate che riducono le dimensioni del file aumentano il tempo di ricerca, ma non hanno trovato alcuna opzione che vada diversamente.

Idea 5: Combinazione di formato video senza perdita di dati + AVQueuePlayer

Se v'è un formato video che è veloce da caricare, ma forse in cui la dimensione del file è folle, un'idea potrebbe essere quella di pre-preparare il i primi 10 secondi di ciascun video clip con una versione che è gonfia ma più veloce da caricare, ma a cui si aggiunge un asset codificato in H.264. Usa un AVQueuePlayer e aggiungi i primi 10 secondi nel formato di file non compresso, quindi segui uno di quelli in H.264 che richiede fino a 10 secondi di tempo di preparazione/preload. Quindi otterrei il "meglio" di entrambi i mondi: tempi di avvio rapidi, ma anche i vantaggi di un formato più compatto.

Idea 6: Utilizzare una non-standard AVPlayer/scrivere il mio/usare qualcun altro

Data la mia necessità, forse non posso usare AVPlayer, ma necessario ricorrere a AVAssetReader, e decodificare il primo pochi secondi (possibilmente scrivere file raw su disco) e, quando si tratta di riproduzione, utilizzare il formato raw per riprodurlo velocemente. Sembra un grande progetto per me, e se lo faccio in modo ingenuo, non è chiaro/improbabile che funzioni meglio. Ogni frame video decodificato e non compresso è 2,25 MB. In parole povere - se andiamo con ~ 30 fps per il video, finirei con un requisito di lettura da disco di ~ 60 MB/s, che è probabilmente impossibile/spingendolo. Ovviamente dovremmo fare un po 'di compressione delle immagini (magari i formati di compressione openGL/es nativi tramite PVRTC) ... ma è un po' strano. Forse c'è una biblioteca là fuori che posso usare?

Idea 7: unire il tutto in un singolo asset di film, e seekToTime

Un'idea che potrebbe essere più facile di quanto alcuni di quanto sopra, è quello di unire il tutto in un unico filmato, e utilizzare seekToTime. Il fatto è che salteremmo dappertutto. Accesso essenzialmente casuale al film. Penso che questo possa effettivamente funzionare a dovere: avplayer-movie-playing-lag-in-ios5

Quale approccio pensi sarebbe meglio? Finora, non ho fatto molti progressi in termini di riduzione del ritardo.

+0

Per quello che vale, vado con Idea 7. È ancora lento, ma non così imprevedibilmente lento come le altre opzioni. La prossima domanda che ho è: le opzioni di codec, la risoluzione e la frequenza dei fotogrammi chiave hanno un impatto sulla ricerca del tempo? –

+0

In ritardo, ma potrebbe valere la pena di cambiare video il più velocemente possibile (ad esempio immediatamente dopo che il nuovo inizia a suonare) e profilare l'app per vedere dove trascorre la maggior parte del tempo della CPU. –

+1

Quasi un anno dopo, cosa hai mai scoperto con questo? – lnafziger

risposta

0

Senza aver fatto nulla del genere in passato, basandomi sui vostri pensieri ed esperienze, provavo una combinazione di 7 e 1: precaricare un AVPlayer con i primi due secondi dei 10 video di follow-up. Quindi saltare sarà molto più veloce e più affidabile a causa della riduzione dei dati. Mentre stai suonando il brano selezionato, hai tempo sufficiente per preparare l'AVPlayer per il resto del video di follow-up selezionato in background. Quando l'inizio è finito, si passa all'AVPlayer preparato. Quindi, in totale, in qualsiasi momento hai caricato un massimo di 2 AVPlayer.

Ovviamente non so se la commutazione può essere eseguita in modo così semplice da non disturbare la riproduzione.

(avrebbe aggiunto questo come un commento, se potessi.)

migliore, Peter

+0

Non ho trovato alcun vantaggio nel caricare 10 risorse in serie su un AVPlayer. Inoltre, non capisco il tuo suggerimento, poiché vedo l'opzione (1) e (7) mutuamente esclusivi. L'opzione 7 unisce tutte le risorse video in un singolo asset, quindi esiste un solo asset per il periodo di caricamento. Questo è quello che sto facendo oggi, e per quello che vale ho un ritardo di circa 500 ms sui tempi di avvio/riproduzione effettivi. Vale la pena notare che il SeekTo si completa più velocemente rispetto al primo frame effettivo, quindi per i veri tempi di avvio, misuro quando il primo fotogramma viene effettivamente riprodotto tramite un callback temporizzato. –

+0

Solo per chiarire la mia idea: la mia idea era quella di suddividere una risorsa in due parti: i primi pochi secondi e il resto. Ora hai creato due risorse su una. I 10 inizi a cui ti unisci e usa il salto e, mentre giochi all'inizio, carichi il resto. Questo comprende quindi il suggerimento 8 che aggiunge alla tua lista. – ilmiacs

+0

Ma come ho capito dal tuo ultimo commento, nel frattempo hai spinto ulteriormente la ricerca che è buona, e la soluzione 7 non funziona. Sembra che AV rimanga fondamentalmente sulla tua strada e l'unico modo per te di andare probabilmente è usare la tecnologia sottostante, ovvero Core Media, per avere più controllo sulle tue risorse. Peter. – ilmiacs

1

l'attività possa non è pronto, una volta lo si crea, può non calcoli, come la durata del film, essere sicuri di contiene tutti i metadati del film nel file.

1

Dovresti provare prima l'opzione # 7, solo per vedere se riesci a farlo funzionare. Ho il sospetto che non funzionerà in realtà per le tue esigenze poiché il tempo di ricerca probabilmente non sarà abbastanza veloce da darti passaggio senza interruzioni tra i clip. Se ci provi e fallisce, ti suggerisco di fare l'opzione 4/6 e dare un'occhiata alla mia libreria iOS progettata appositamente per questo scopo, fai una rapida ricerca su google su AVAnimator per saperne di più. La mia libreria rende possibile implementare loop continui e passare da una clip all'altra, è molto veloce perché il video deve essere decodificato in un file prima della mano. Nel tuo caso, tutti i 10 video clip verranno decodificati in file prima di iniziare, ma il passaggio da uno all'altro sarebbe rapido.

+0

E la parte audio del video? Ho bisogno di video e audio per essere sincronizzati. –

+0

Sì, l'audio è già gestito con una sincronizzazione molto stretta tra la traccia audio e il video. Vedi i progetti xcode di esempio. È già tutto implementato, devi solo scaricarlo e provarlo. – MoDJ

+0

Esiste la possibilità di riprodurre video di rete usando AVAnimator? –

-1

Qui ci sono diverse proprietà e metodi forniti dalla classe AVAsset che possono aiutare:

- (void)_pu_setCachedDuration:(id)arg1; 
- (id)pu_cachedDuration; 
- (struct 
{ 
    long long x1; 
    int x2; 
    unsigned int x3; 
    long long x4; 
})pu_duration; 
- (void)pu_loadDurationWithCompletionHandler:(id /* block */)arg1; 
0

Se ho capito il problema in modo corretto, sembra che si dispone di un video continua a cui è necessario caricare la traccia audio per un attimo.

Se è il caso, suggerisco di esaminare BASS. BASS è una libreria audio simile a AVPlayer che ti dà (relativamente) un facile accesso alle API di basso livello del framework AudioUnits in iOS. Che cosa significa per te? Significa che con un po 'di manipolazione del buffer (potresti anche non averne bisogno, dipende da quanto piccolo vuoi il ritardo) puoi iniziare a riprodurre musica all'istante.

Le limitazioni si estendono al video, come ho detto, è una libreria audio quindi qualsiasi manipolazione video dovrà ancora essere eseguita con AVPlayer. Tuttavia utilizzando -seekToTime:toleranfeBefore:toleranceAfter: dovresti essere in grado di ottenere una ricerca rapida all'interno del video fintanto che esegui il preroll con tutte le opzioni necessarie.

Se si sta eseguendo la sincronizzazione tra più dispositivi (che la propria applicazione potrebbe suggerire) basta lasciare un commento e sarei felice di modificare la mia risposta.

PS: BASS può sembrare inizialmente scoraggiante perché è simile al formato C, ma è davvero molto facile da usare per quello che è.

Problemi correlati