Ändern playerItem der AVPlayer in UITableView
Ich habe eine UITableView
mit einer Anzahl von videos und spielen beim scrollen. Da die Zellen in der tableView werden wieder verwendet, ich habe nur Instanzierung einer AVPlayer
für jede Zeile, immer. Wenn eine Zelle wieder verwendet, die ich ändern Sie einfach die PlayerItem
von der Zelle player durch den Aufruf [self.player replaceCurrentItemWithPlayerItem:newItem];
. Dies wird derzeit indirekt aufgerufen, in tableView:cellForRowAtIndexPath
. Wenn Sie nach unten scrollen, es gibt eine merkliche Verzögerung, wenn die re-Nutzung Auftritt. Mit einen Prozess der Beseitigung, habe ich festgestellt, dass die lags verursacht durch replaceCurrentItemWithPlayerItem
, bevor es auch nur angefangen zu spielen. Beim entfernen dieser Zeile code (verhindern, dass der Spieler immer eine neue video -) die Gummierung verschwindet.
, Was ich versucht habe um es zu beheben:
Habe ich eine benutzerdefinierte UITableViewCell
für die Wiedergabe dieser videos, und ich habe eine Methode in diesen zu initialisieren, mit den neuen Informationen aus einem Objekt. I. E, in cellForRowAtIndexPath:
ich nenne [cell initializeNewObject:newObject];
zum ausführen der folgenden Methode:
//In CustomCell.m
-(void)initializeNewObject:(CustomObject*)newObject
{ /*...*/
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
AVPlayerItem *xPlayerItem = [[AVPlayerItem alloc] initWithURL:[NSURL URLWithString:newObject.url]];
AVPlayer *dummy = self.player;
[dummy replaceCurrentItemWithPlayerItem:xPlayerItem];
dispatch_async(dispatch_get_main_queue(), ^{
self.player = dummy;
playerItem = xPlayerItem;
}
}/*...*/
}
Beim laufen, bekomme ich das gleiche Ergebnis wie wenn ich komplett entfernt werden, der Aufruf für den Austausch der Sache. Offenbar, diese Funktion kann nicht eingefädelt werden.
Ich bin mir nicht ganz sicher, was ich erwartete von dieser. Ich könnte mir vorstellen, ich brauche eine saubere copy
des AVPlayer
für diese zu arbeiten, aber nach der Suche noch ein bisschen, ich fand einige Kommentare, die besagt, dass replaceCurrentItemWithPlayerItem:
können nicht aufgerufen werden, in einem separaten thread, das macht für mich keinen Sinn. Ich weiß, dass UI-Elemente sollten niemals behandelt werden, die in anderen threads als Haupt - /UI-thread, aber ich hätte mir nie vorstellen replaceCurrentItemWithPlayerItem
fallen unter diese Kategorie.
Ich bin jetzt auf der Suche nach einer Möglichkeit, ändern Sie das Element von einer AVPlayer
ohne lag, aber finde keine. Ich hoffe, ich habe verstanden das einfädeln diese Funktion falsch ist, und dass jemand korrigieren würde.. mich
EDIT:
Ich habe mich jetzt schon informiert, dass dieser Anruf ist bereits Gewinde, und dass dies nicht wirklich passieren. Allerdings sehe ich keine andere Erklärung.. Unten ist meine cellForRowAtIndexPath:
. Es ist in einem speziell UITableView
mit den Delegierten festgelegt self
(so self == tableView
)
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
CustomCell *cell = [self dequeueReusableCellWithIdentifier:kCellIdentifier];
if(!cell)
cell = [[[NSBundle mainBundle] loadNibNamed:@"CustomCell" owner:self options:nil] objectAtIndex:0];
//Array 'data' contains all objects to be shown. The objects each have titles, url's etc.
CustomVideoObject *currentObject = [data objectAtIndex:indexPath.row];
//When a cell later starts playing, I store a pointer to the cell in this tableView named 'playing'
//After a quick scroll, the dequeueing cell might be the cell currently playing - resetting
if(playing == cell)
playing = nil;
//This call will insert the correct URL, title, etc for the new video, in the custom cell
[cell initializeNewObject:currentObject];
return cell;
}
Den initializeNewObject
aktuell "arbeiten", jedoch hinken (dies ist innerhalb CustomCell.m
:
-(void)initializeNewObject:(CustomObject*)o
{
//If this cell is being dequeued/re-used, its player might still be playing the old file
[self.player pause];
self.currentObject = o;
/*
//Setting text-variables for title etc. Removed from this post, but by commenting them out in the code, nothing improves.
*/
//Replace the old playerItem in the cell's player
NSURL *url = [NSURL URLWithString:self.currentObject.url];
AVAsset *newAsset = [AVAsset assetWithURL:url];
AVPlayerItem *newItem = [AVPlayerItem playerItemWithAsset:newAsset];
[self.player replaceCurrentItemWithPlayerItem:newItem];
//The last line above, replaceCurrentItemWithPlayerItem:, is the 'bad guy'.
//When commenting that one out, all lag is gone (of course, no videos will be playing either)
//The lag still occurs even if I never call [self.player play], which leads me
//to believe that nothing after this function can cause the lag
self.isPlaying = NO;
}
Dem lag passiert an der exakt gleichen Stelle jeder Zeit. Beim scrollen schnell nach unten, können wir sehen, dass die kurze Verzögerung geschieht, wenn der Obere Teil der unteren Zelle, erreicht die Mitte des Bildschirms. Ich denke, das bedeutet nichts zu Ihnen, aber es ist klar, dass die Verzögerung geschieht an der exakt gleichen Stelle jedes mal, und zwar dann, wenn eine neue Zelle dequeueing. Nach dem ändern der playerItem der AVPlayer
ich tun nichts. Ich nicht anfangen zu spielen das video erst später. replaceCurrentItemWithPlayerItem:
ist dies verursacht merkliche Verzögerung. Die Dokumentation besagt, dass es ändert sich das Element in einem anderen thread, aber etwas in dieser Methode hält sich meine UI.
Wurde mir gesagt, ich nutze Mal Profiler in Instrumenten, um herauszufinden, was es ist, aber ich habe keine Ahnung, wie das geht. Durch ausführen der profiler, und scrollen Sie einmal in eine Weile, dies ist das Ergebnis(Bild). Die peaks der einzelnen graph-Gruppe ist die lag-ich spreche. Die einzigen extremen peak ist (denke ich), wenn ich musste Bildlauf nach unten und tippte auf die Statusleiste, um einen Bildlauf nach oben. Ich weiß nicht, wie das Ergebnis zu interpretieren ist. Ich suchte den Stapel für replace
, und fand den bastard. Es heißt hier innerhalb Main Thread
(an der Spitze), was Sinn macht, mit einer "Laufzeit" von 50ms, das ich keine Ahnung habe, zu denken. Der relevante Teil des Graphen ist von einer Zeitspanne von ungefähr 1 minute und eine Hälfte.
Im Vergleich, wenn das auskommentieren der einzelnen Zeile und Laufzeit-Profiler wieder, die Grafik der Gipfel sind deutlich niedriger (Höchster peak bei 13%, im Vergleich zu dem, was auf dem Bild, das ist wahrscheinlich rund 60-70%).
Ich weiß nicht, was Sie suchen..
- Ich habe das gleiche Problem. Haben Sie es fest irgendwie?
- Nein.. :/ ich beschloss, nur starten Sie die Wiedergabe, wenn der Bildlauf gestoppt hatte, statt. So kann ich scrollen, vorbei an vielen videos (mit richtigen thumbnails), ohne das video überhaupt geladen werden, und nur lädt, wenn das scrollen Stoppt über es. Nicht wirklich, was ich wollte, aber besser als der lag. Lassen Sie mich wissen, wenn Sie etwas herausfinden!
- wie kommen Sie und setzen Sie das video-thumbnail?
- Nicht sicher, dass replaceCurrentItemWithPlayerItem selbst ist das Problem. Ich habe versucht unter Beibehaltung aller AVPlayers (1 pro Zelle) und einfach tauschen AVPlayerLayer die Spieler für jede Zelle. Also nie ruft replaceCurrentItemWithPlayerItem wie jedes AVPlayer ist nur eine AVPlayerItem. Die lag ist immer noch da und tritt auch beim Austausch der AVPlayerLayer die Spieler auf eine bereits bestehende AVPlayer.
- Hast du irgendeine Lösung dafür? Ich bin auch stecken geblieben mit dem gleichen problem. Können Sie helfen.
- Fand ich nie heraus. Wie ich schon in dem Kommentar oben, landete ich jedes video, wenn das scrollen Stoppt.
- Haben Sie versucht, mit mehreren Spielern, so können Sie Vorspannung videos einfach? Und vielleicht habe ich verpasst, was ist die Größe der Zelle, ist es in den Vollbildmodus?
- Soweit ich weiß
replaceCurrentItemWithPlayerItem
ist bereits die Decodierung der video-und zeigt das erste Bild an, auch wenn du nicht spielst das item. Dies scheint zu passieren, auf dem Haupt-thread. Mein Ansatz dafür war nur mit einem einzigen AVPlayer und Befestigung seiner Leistung an den Zellen playerLayers, wenn auch dafür die Tabelle/collectionview super performant (Rastern, keine Ecke, radius -, minimal-offscreen-rendering). Einige Dinge in der UIKit Welt nur passieren, auf dem Haupt-thread, so dass Sie haben, um zu versuchen, um zu halten es frei (am Ende wechselte ich auf ASDK) - Wie sind Sie ur reuseIdentifier für die Zelle??? Sie versuchen, es zu bekommen, indem reuseidentifier aber nicht die Einstellung hier?
- Wie viele Zeilen auf einem Bildschirm für Ihren Fall???weil für jede Zeile intialliase-Methode aufgerufen werden, Können, wenn Sie einen Bildlauf durchführen, wird diese Methode aufgerufen, für mehr als ein Reihen, und das anhalten und das Auswechseln geschieht mehrere Male.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Wenn Sie tun, einige grundlegende Ebene des "profiling", ich denke, Sie können das problem einzugrenzen. Für mich, ich hatte ein ähnliches Problem, wo
replaceCurrentItemWithPlayerItem
war die Blockierung der UI-thread. Ich beschloss, dass ich es durch die Prüfung meiner code, um herauszufinden, welche Linie wurde sich Zeit nehmen. Für mich ist die AVAsset laden war die Zeit nehmen. So habe ich dasloadValuesAsynchronouslyForKeys
Methode der AVAsset zu lösen mein Problem.Daher können Sie Folgendes versuchen:
In Ihrem CustomCell.m Sie verwenden sollten, thumbnails, um ein Bild anzuzeigen, das für die spezifische Zelle, video, fügen Sie die Miniaturansicht, um eine Taste im inneren der Zelle sind, dann erstellen Sie einen benutzerdefinierten Delegaten in CustomCell.h, die aufgerufen wird, wenn Sie Tippen Sie auf die neu erstellte Schaltfläche, so etwas wie:
auch in Ihr .h fügen Sie die Aktion für die Schaltfläche:
auch in "didTappedPlayVideo" Sie tun das nächste:
Methode:
settupVideoWithURL
wird verwendet, um die init-du-playerund die Methode:
removeVideoAndShowPlaceholderImage
Stoppt das video und stellen Sie die AVPlayerItem und AVPlayer null.Nun, wenn der Benutzer tippt auf eine Zelle, die Sie senden den Anruf wieder auf das UIViewController, wo Sie den tableView und in der delegate-Methode, die Sie tun sollten, die nächste:
P. S.:
Auf älteren Geräten(fast alle von Ihnen, bis das neue iPad Pro) ist nicht angegeben, um mehrere Instanzen von
AVPlayer
.Hoffe auch, dass diese Brocken von code kann guide oder Ihnen bei Ihrer Suche helfen 🙂
Sollten Sie das Profil der app über die Zeit-profiler, um zu sehen, wo die hinterher tatsächlich passiert.
Die Dokumentation fürreplaceCurrentItemWithPlayerItem:
klar, dass es asynchron ausgeführt, so sollte es nicht sein, die Quelle der wichtigsten Warteschlange schreckhaftigkeit.Dokumentation hier
, Wenn Sie noch können ' T es herausfinden, poste mehr code, und insbesondere mindestens IhrecellForRowAtIndexPath
- Methode.UPDATE
Als pro @Joeys Kommentar, der Vorherige Inhalt dieser Antwort ist nicht mehr gültig. Die Dokumentation nicht mehr Staaten, dass die Methode ist asynchron, daher kann es nicht sein.
replaceCurrentItemWithPlayerItem
ist die einzige logische Erklärung für mein lag für mich.. ich kann nicht scheinen, um es zu finden. Siehe aktualisierte Frage nach mehr! (mit link zu Bild)Invert Call Tree
auf der linken Seite und loszuwerden, die filter, die Sie auf das Wort "ersetzen".objc_msgSend
. Durch den weiteren ausbau der[AVPlayerItem..]
-line-in, bekomme ich zurück zu den Haupt-Thread durch die gleiche Weise wie in der ursprünglichen Bild. Alle 1ms/1.1%..