在UITableView中更改AVPlayer的playerItem [英] Changing playerItem of AVPlayer in UITableView

查看:559
本文介绍了在UITableView中更改AVPlayer的playerItem的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 UITableView 包含许多要在滚动时播放的视频。当tableView中的单元格被重用时,我只会为每一行实例化一个 AVPlayer 。当一个单元格被重用时,我通过调用 [self.player replaceCurrentItemWithPlayerItem:newItem]; 改变单元格播放器的 PlayerItem $ c>。这当前正在 tableView:cellForRowAtIndexPath 中间接调用。当向下滚动时,当重新使用发生时,存在明显的滞后。有一个消除过程,我得出结论,滞后是由 replaceCurrentItemWithPlayerItem 引起的,甚至开始播放之前。



我试图解决这个问题:

strong>



我有一个自定义 UITableViewCell 用于播放这些视频,使用来自对象的新信息进行初始化。 IE,在 cellForRowAtIndexPath: i call [cell initializeNewObject:newObject]; 执行以下方法:

  //在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;
}
} /*...*/
}

,我得到相同的结果,如果我完全删除了替换项目的调用显然,这个函数不能被线程
我不完全确定我的期望从这,我想象我需要一个清除 copy AVPlayer 为这个工作,但搜索一下后,我发现几个评论说, replaceCurrentItemWithPlayerItem:可以在单独的线程中调用,这对我来说没有意义。我知道UI元素永远不应该在其他线程而不是主/ UI线程处理,但我永远不会想象 replaceCurrentItemWithPlayerItem 属于这个类别。



我现在正在寻找一种方法来改变一个 AVPlayer 的项目没有滞后,但是找不到任何。我希望我已经理解这个函数的线程错了,有人会纠正我..



编辑:
我现在已经被告知这个调用是已经线程化,这不应该真的发生。但是,我看不到其他解释..下面是我的 cellForRowAtIndexPath:。它在一个自定义的 UITableView 中,代理设置为 self (因此 self == tableView

   - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{
CustomCell * cell = [self dequeueReusableCellWithIdentifier:kCellIdentifier];
if(!cell)
cell = [[[NSBundle mainBundle] loadNibNamed:@CustomCellowner:self options:nil] objectAtIndex:0];

//数组'data'包含要显示的所有对象。每个对象都有标题,url等等。
CustomVideoObject * currentObject = [data objectAtIndex:indexPath.row];
//当一个单元格稍后开始播放时,我存储一个指向该tableView中名为playing的单元格的指针
//快速滚动后,出列单元格可能是当前正在播放的单元格 - resetting
if(playing == cell)
playing = nil;
//这个调用会在自定义单元格
[cell initializeNewObject:currentObject]中插入新视频的正确URL,标题等;
return cell;
}

initializeNewObject 目前是工作,但是滞后(这在 CustomCell.m 中:

   - (void)initializeNewObject:(CustomObject *)o 
{
//如果此单元格正在出列/重新使用,其播放器可能仍在播放旧文件
[ self.player pause];
self.currentObject = o;
/ *
//设置文本变量的标题等删除此帖子,但通过在代码中注释,没有改进
* /

//替换单元格播放器中的旧playerItem
NSURL * url = [NSURL URLWithString:self.currentObject.url];
AVAsset * newAsset = [AVAsset assetWithURL:url];
AVPlayerItem * newItem = [AVPlayerItem playerItemWithAsset:newAsset];
[self.player replaceCurrentItemWithPlayerItem:newItem];

//最后一行,replaceCurrentItemWithPlayerItem :,是坏家伙
//当评论一个,所有滞后都消失了(当然,没有视频将播放)
//滞后即使我从来不调用[self.player play],这导致我
//相信没有什么后这个函数可以导致滞后

self.isPlaying = NO;
}

每次都会在完全相同的地方发生延迟。当快速滚动时,我们可以看到,当最底部单元格的顶部到达屏幕中心时,发生短暂的滞后。我想这不意味着什么,但是很明显,滞后发生在每一次完全相同的地方,即当一个新的单元格出队。更改 AVPlayer 的playerItem后,我会没有。我稍后才开始播放视频。 replaceCurrentItemWithPlayerItem: 造成这种明显的滞后。该文档声明它正在更改另一个线程中的项目,但该方法中的 正在阻止我的UI。



我被告知要使用时间分析器在仪器,以找出它是什么,但我不知道如何这样做。通过运行分析器并暂时滚动一次, 这是结果(图像) 。每个图组的峰值是我所说的滞后。一个单一的极端峰值(我想),当我已经滚动到底部,点击状态栏滚动到顶部。我不知道如何解释结果。我在堆栈中搜索 replace ,找到了混蛋。它在这里从主线程(在顶部),这是有道理的,与运行时间50ms,我不知道想到的。图的相关比例具有约1分半的时间跨度。
相比之下,当注释掉单行并再次运行Time Profiler时,图的峰值显着降低(最高峰为13%,与图像上的峰相比,可能约为60-70%)。 / p>

我不知道要查找什么。

解决方案



replaceCurrentItemWithPlayerItem:的文档c $ c>清楚地表明它异步执行,因此它不应该是您的主队列跳跃的来源。


异步发生;观察currentItem
属性以找出替换将何时/确实发生的时间。


此处的文档



如果你仍然不能弄清楚,发布更多的代码,特别是至少你的 cellForRowAtIndexPath 方法。



UPDATE



根据@ joey的评论,此答案的先前内容不再有效。 文档 a>不再声明该方法是异步的,因此可能不是。


I have a UITableView containing a number of videos to play when scrolling. As the cells in the tableView are being re-used, I only instantiate one AVPlayer for each row, ever. When a cell is re-used I simply change the PlayerItem of the cell's player by calling [self.player replaceCurrentItemWithPlayerItem:newItem];. This is currently being indirectly called inside tableView:cellForRowAtIndexPath. When scrolling down, there is a noticeable lag when the re-using occurs. With a process of elimination, I have concluded that the lag is caused by replaceCurrentItemWithPlayerItem, before it's even starting to play. When removing this single line of code (preventing the player from getting a new video) the lagging disappears.

What I've tried to fix it:

I have a custom UITableViewCell for playing these videos, and I've created a method inside these to initialize with the new information from an object. I.E, in cellForRowAtIndexPath: i call [cell initializeNewObject:newObject]; to perform the following method:

//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;
        }
    }/*...*/
}

When running this, I get the same result as if I completely removed the call for replacing the item. Apparently, this function can't be threaded. I'm not completely sure what I expected from this. I would imagine I need a clean copy of the AVPlayer for this to work, but after searching a bit, I found several comments stating that replaceCurrentItemWithPlayerItem: can not be called in a separate thread, which makes no sense to me. I know that UI-elements should never be handled in other threads than main/UI-thread, but I would never imagine replaceCurrentItemWithPlayerItem to fall under this category.

I'm now looking for a way to change the item of an AVPlayer without the lag, but can't find any. I'm hoping I've understood the threading of this function wrong, and that someone would correct me..

EDIT: I've now been informed that this call is already threaded, and that this shouldn't really happen. However, I see no other explanation.. Below is my cellForRowAtIndexPath:. It is inside a custom UITableView with delegates set to 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;
}

The initializeNewObject that is currently "working", however lagging (this is inside 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;
}

The lag is happening at the exact same place each time. When scrolling fast down we can see that the short lag happens when the top part of the bottom-most cell reaches the center of the screen. I guess this doesn't mean anything to you, but it is clear that the lag is happening at the exact same place every time, namely when a new cell is dequeueing. After changing the playerItem of the AVPlayer, I do nothing. I do not start to play the video until later. replaceCurrentItemWithPlayerItem: is causing this noticeable lag. The documentation states that it's changing the item in another thread, but something in that method is holding up my UI.

I was told to use Time Profiler in Instruments to find out what it is, but I have no idea how to do that. By running the profiler, and scrolling once in a while, this is the result(image). The peaks of each graph-group is the lag I am talking about. The one single extreme peak is (I think) when I had scrolled to the bottom and tapped the status bar to scroll to the top. I do not know how to interpret the result. I searched the stack for replace, and found the bastard. It's called here from within Main Thread (at the top), which makes sense, with a "running time" of 50ms, which I have no idea to think of. The relevant proportion of the graph is of a timespan of about 1 minute and a half. In comparison, when commenting out that single line and running Time Profiler again, the graph's peaks are significantly lower (Highest peak at 13%, compared to what's on the image, which is probably around 60-70%).

I don't know what to look for..

解决方案

You should profile your app using the time profiler to see where the lagging is actually occurring.

The documentation for replaceCurrentItemWithPlayerItem: clearly states that it executes asynchronously, so it shouldn't be the source of your main queue jumpiness.

The item replacement occurs asynchronously; observe the currentItem property to find out when the replacement will/did occur.

Documentation here

If you still can't figure it out, post more code, and in particular at least your cellForRowAtIndexPath method.

UPDATE

As per @joey's comment below, the previous content of this answer is no longer valid. The documentation no longer states that the method is asynchronous, so it may not be.

这篇关于在UITableView中更改AVPlayer的playerItem的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆