Come ridurre il ritardo di avvio di iOS AVPlayer


115

Nota, per la domanda seguente: tutte le risorse sono locali sul dispositivo: non è in corso lo streaming di rete. I video contengono tracce audio.

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

Quello che ho fatto per esaminare i ritardi di avvio effettivi è chiamare addBoundaryTimeObserverForTimesil lettore video, con un periodo di tempo di un millisecondo per vedere quando il video ha effettivamente iniziato a essere riprodotto, e prendo la differenza di quel timestamp con il primo posto in il codice che indica quale risorsa avviare la riproduzione.

Da quello che ho visto finora, ho scoperto che usare la combinazione di AVAssetcaricamento e quindi creare un AVPlayerItemda quello una volta che è pronto, e quindi aspettare AVPlayerStatusReadyToPlayprima di chiamare play, tende a impiegare da 1 a 3 secondi per avviare il clip.

Da allora sono passato a quello che penso sia più o meno equivalente: chiamare [AVPlayerItem playerItemWithURL:]e aspettare per AVPlayerItemStatusReadyToPlaygiocare. Più o meno la stessa prestazione.

Una cosa che sto osservando è che il caricamento del primo elemento di AVPlayer è più lento del resto. Sembra che un'idea sia pre-pilotare AVPlayer con una risorsa breve / vuota prima di provare a riprodurre il primo video potrebbe essere una buona pratica generale. [ Avvio lento per AVAudioPlayer la prima volta che viene riprodotto un suono

Mi piacerebbe ridurre il più possibile i tempi di inizio del video e avere alcune idee su cose con cui sperimentare, ma vorrei qualche consiglio da chiunque possa essere in grado di aiutare.

Aggiornamento: l'idea 7, di seguito, come implementata produce tempi di commutazione di circa 500 ms. Questo è un miglioramento, ma sarebbe bello farlo ancora più velocemente.

Idea 1: usa N AVPlayer (non funzionerà)

Usando ~ 10 AVPPlayeroggetti e avvia e metti in pausa tutti i ~ 10 clip, e una volta che sappiamo di quale abbiamo veramente bisogno, passa a, e rimuovi la pausa dal corretto AVPlayer, e ricomincia da capo per il ciclo successivo.

Non penso che funzioni, perché ho letto che c'è approssimativamente un limite di 4 attivi AVPlayer'sin iOS. Qualcuno ha chiesto informazioni su StackOverflow qui e ha scoperto il limite di 4 AVPlayer: commutazione rapida tra video utilizzando avfoundation

Idea 2: usa AVQueuePlayer (non funzionerà)

Non credo che spingere 10 AVPlayerItemsin un AVQueuePlayerli precarichi tutti per un avvio senza interruzioni. AVQueuePlayerè una coda e penso che in realtà renda solo il video successivo in coda pronto per la riproduzione immediata. Non so quale dei ~ 10 video vogliamo riprodurre, finché non è il momento di avviarlo. ios-AVPlayer-video-precaricamento

Idea 3: carica, riproduci e conserva AVPlayerItemsin background (non ancora sicuro al 100%, ma non ha un bell'aspetto)

Sto cercando di capire se c'è qualche vantaggio nel caricare e riprodurre il primo secondo di ogni clip video in background (sopprimere l'uscita video e audio) e mantenere un riferimento a ciascuno AVPlayerItem, e quando sappiamo quale elemento deve essere riprodotto per real, scambia quello e scambia lo sfondo AVPlayer con quello attivo. Risciacqua e ripeti.

La teoria sarebbe che i giochi riprodotti di recente AVPlayer/AVPlayerItempotrebbero ancora contenere alcune risorse preparate che renderebbero la riproduzione successiva più veloce. Finora, non ho visto benefici da questo, ma potrei non avere la AVPlayerLayerconfigurazione corretta per lo sfondo. Dubito che questo migliorerà davvero le cose da quello che ho visto.

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

Attualmente sto utilizzando il formato H.264 .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 la dimensione del file aumenta il tempo di ricerca, ma non ho trovato alcuna opzione che vada nella direzione opposta.

Idea 5: combinazione di formato video lossless + AVQueuePlayer

Se c'è un formato video che è veloce da caricare, ma forse dove la dimensione del file è folle, un'idea potrebbe essere quella di pre-preparare i primi 10 secondi di ogni clip video con una versione che è gonfia ma più veloce da caricare, ma indietro quello con una risorsa che è codificata in H.264. Utilizzare un AVQueuePlayer e aggiungere i primi 10 secondi nel formato di file non compresso, quindi seguirlo con uno in H.264 che ottiene fino a 10 secondi di tempo di preparazione / precaricamento. Quindi avrei "il meglio" di entrambi i mondi: tempi di avvio rapidi, ma anche vantaggi di un formato più compatto.

Idea 6: usa un AVPlayer non standard / scrivi il mio / usa quello di qualcun altro

Date le mie esigenze, forse non posso usare AVPlayer, ma devo ricorrere a AVAssetReader e decodificare i primi secondi (possibilmente scrivere file raw su disco), e quando si tratta di riproduzione, utilizzare il formato raw per riprodurlo indietro veloce. Mi sembra un progetto enorme, e se lo intraprendo in modo ingenuo, è poco chiaro / improbabile che funzioni anche meglio. Ogni fotogramma video decodificato e non compresso è di 2,25 MB. Ingenuamente parlando, se andiamo con ~ 30 fps per il video, finirei con ~ 60 MB / s di richiesta di lettura dal disco, il che è probabilmente impossibile / spingerlo. Ovviamente dovremmo fare un certo livello di compressione delle immagini (forse formati di compressione nativi openGL / es tramite PVRTC) ... ma è un po 'folle. Forse c'è una biblioteca là fuori che posso usare?

Idea 7: combina tutto in una singola risorsa film e seekToTime

Un'idea che potrebbe essere più semplice di alcune delle precedenti è combinare tutto in un unico film e utilizzare seekToTime. Il fatto è che salteremmo dappertutto. Accesso essenzialmente casuale al film. Penso che questo possa effettivamente funzionare bene: avplayer-movie-playing-lag-in-ios5

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


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 del codec, la risoluzione e la frequenza dei fotogrammi chiave hanno un impatto sui tempi di seekto?
Bernt Habermeier

È in ritardo per il gioco, ma potrebbe valere la pena cambiare video il più velocemente possibile (cioè immediatamente dopo che il nuovo inizia a giocare) e profilare l'app per vedere dove trascorre la maggior parte del tempo della CPU.
tc.

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

1
Sono andato con l'opzione 7 e sono arrivato da qualche parte tra 300 ms e 500 ms. Una cosa che ho scoperto è che più elaborate sono le opzioni del codec mp4, più lento è il seekTo. Esistono alcune opzioni di compressione video che consentono una migliore compressione e mantengono la qualità video, ma riducono il tempo di decodifica.
Bernt Habermeier

2
Questa è una richiesta ragionevole, ma per implementare l'opzione 7, ci sono troppe sfaccettature nell'implementazione da pubblicare. Considera: (a) Crea una catena di strumenti per unire risorse video, (b) assicurati di tenere traccia degli offset dei segmenti video, (c) degli offset di ricerca quando arriva una richiesta per riprodurre un clip specifico, (d) usa addPeriodicTimeObserverForInterval per controllare se scappi da un video clip e reagisci di conseguenza (usa questo metodo contro un addBoundaryTimeObserverForTimes a scatto singolo perché ho scoperto che quest'ultimo a volte non si attiva ... nel complesso, questo non si presta a incollare il codice.
Bernt Habermeier

Risposte:


4

Per iOS 10.xe versioni successive per ridurre il ritardo di avvio di AVPlayer ho impostato: avplayer.automaticallyWaitsToMinimizeStalling = false; e questo sembrava risolverlo per me. Questo potrebbe avere altre conseguenze, ma non le ho ancora raggiunte.

Ho avuto l'idea da: https://stackoverflow.com/a/50598525/9620547


Ho ottenuto 6-7 secondi di riduzione del ritardo. Ma ho una domanda qui, avrà un impatto sulle prestazioni dell'app?
kalpa

@kalpa Abbiamo utilizzato questo codice in un'app di produzione per oltre un anno senza effetti negativi percepibili. Riproduciamo principalmente file audio di 20-60 minuti per gli ascoltatori negli Stati Uniti, dove la copertura dei dati mobili è generalmente veloce. Il tuo caso d'uso potrebbe essere diverso però.
grizzb

Grazie per le informazioni. @grizzb
kalpa

1

La risorsa potrebbe non essere pronta una volta creata, potrebbe eseguire calcoli come la durata del film, assicurati di contenere tutti i metadati del film nel file.


1

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


E la parte audio del video? Ho bisogno di sincronizzare video e audio.
Bernt Habermeier

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

Esiste la possibilità di riprodurre video di rete utilizzando AVAnimator?
Richard Topchii

No, funziona su file locali, lo streaming di video di rete è una cosa completamente diversa.
MoDJ

0

Senza aver fatto nulla di simile in passato, in base ai tuoi pensieri ed esperienze proverei una combinazione di 7 e 1: precarica un AVPlayer con i primi due secondi dei 10 video di follow-up. Quindi saltare molto probabilmente sarà più veloce e più affidabile a causa di meno dati. Mentre stai riproducendo il brano selezionato, hai abbastanza tempo per preparare AVPlayer per il resto del video di follow-up selezionato in background. Quando l'inizio è finito, passi 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ì fluido da non disturbare la riproduzione.

(Avrei aggiunto questo come commento se potessi.)

Meglio, Peter


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) che si escludono a vicenda. L'opzione 7 unisce tutte le risorse video in una singola risorsa, quindi c'è solo una singola risorsa per il periodo di caricamento. Questo è quello che sto facendo oggi, e per quel che vale, ricevo circa 500 ms di ritardo sui tempi di inizio / riproduzione effettivi. Vale la pena notare che SeekTo viene completato più velocemente del primo fotogramma effettivo viene riprodotto, quindi per i veri tempi di inizio, misuro quando il primo fotogramma viene effettivamente riprodotto tramite richiamata temporizzata.
Bernt Habermeier

Giusto per chiarire la mia idea: la mia idea era di dividere una risorsa in due parti: i primi secondi e il resto. Ora hai ricavato due risorse da una. I 10 inizi a cui ti unisci e che usi salta e mentre giochi all'inizio carichi il resto. Questo comprende quindi il suggerimento 8 che si aggiunge alla tua lista.
ilmiacs

Ma come ho capito dal tuo ultimo commento, nel frattempo hai spinto oltre la ricerca, il che è positivo, e neanche la soluzione 7 funziona. Sembra che l'AV rimanga fondamentalmente sulla tua strada e l'unico modo per te di farlo è probabilmente utilizzare la tecnologia sottostante, ovvero Core Media, per ottenere un maggiore controllo sulle tue risorse. Peter.
ilmiacs

Oh, capisco meglio la tua idea ora. Grazie. Sarebbe interessante verificare se si ottengono tempi di ricerca rapidi per brevi video clip. Non l'ho ancora provato, ma varrebbe la pena prendere in considerazione. Per quanto riguarda l'uso dei supporti di base, non ho trovato alcun buon materiale di riferimento su quell'API. Hai una buona risorsa a cui indicarmi?
Bernt Habermeier

No scusa. Come ho detto, non sono un esperto di AV o Core Media. Ho appena letto la tua domanda e avevo alcune idee su come avrei proceduto personalmente e volevo condividerle. Peter
ilmiacs

0

Se ho capito correttamente il tuo problema, sembra che tu abbia un video continuo a cui devi caricare la traccia audio per un momento.

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

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

Se esegui la sincronizzazione su più dispositivi (come potrebbe suggerire la tua applicazione) lascia un commento e sarei felice di modificare la mia risposta.

PS: BASS può sembrare scoraggiante all'inizio a causa del suo formato simile al C, ma è davvero molto facile da usare per quello che è.


-2

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;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.