与AVPlayer多部影片(Multiple videos with AVPlayer)

2019-07-19 02:53发布

我正在开发适用于iPad的iOS应用程序需要在屏幕上的某些部分,以播放视频。 我有几个视频文件,需要在没有在编译时发出的命令后,对方播放。 它必须看起来好像只是一个视频播放。 这是好的,从一个视频的时候去到下一个就是一些延迟,其中的两个视频的最后一个或第一帧被显示,但不应该有闪烁或白色屏幕,没有内容。 该视频不包含音频。 把内存使用情况考虑是非常重要的。 该影片有一个非常高的分辨率和几个不同的视频序列可以在同一时间下一个要播放给对方。

为了获得这个我已经尝试了一些解决方案为止。 他们列举如下:

1. AVPlayer与AVComposition与它的所有视频

在这个解决方案我已经使用含放在彼此相邻的所有视频的AVComposition上AVPlayerItem提出,将只使用一个AVPlayer。 当去特定的影片,我试图在组合物的时间,其中该解决方案的下一个视频start.The问题是寻求播放器时,很快就会显示出一些,它是通过寻找帧,这是不能接受的。 这似乎是没有办法直接跳转到该组合物中的具体时间。 我试图通过在刚刚完成视频的最后一帧的图像解决这一点,那么表明在AVPLayer之前,而寻求,终于求做之后将其删除。 我正在使用AVAssetImageGenerator图像,但由于某种原因,图像的质量是不一样的视频,因此在显示和在视频隐藏图像时存在显着的变化。 另一个问题是,AVPlayer使用了大量的内存,因为单个AVPlayerItem持有的所有视频。

2. AVPlayer具有多个AVPlayerItems

该解决方案采用了AVPlayerItem每个视频和替代切换到新的视频的时候AVPlayer的项目。 这样做的问题是,切换AVPlayer的项目时,它会显示一个白色的屏幕很短的时间,同时加载新的项目。 若要将图像在前面用最后一帧与问题解决此问题的解决方案,同时加载可以使用,但仍然是图像和视频的质量是不同的,显着的。

3.两个相互回吐的顶部AVPlayers轮番上场AVPlayerItem

接下来的解决方案,我试过了对方,将轮流上场AVPlayerItems的顶部有两个AVPlayer。 所以当玩家完成打它将停留在视频的最后一帧。 其他AVPlayer将被带到前面(与它的项目设置为nil,所以它是透明的),并且下一个AVPlayerItem将在AVPlayer插入。 一旦它被装载它会开始播放和两个视频之间平滑交易的假象将是完整的。 这种解决方案的问题是内存使用情况。 在某些情况下,我需要打的屏幕在同一时间,这将导致4个AVPlayers与在同一时间加载AVPlayerItem两个视频。 这简直是​​太多的内存,因为视频可以在一个非常高的分辨率。


有没有人有一些想法,建议,意见或事关全局的问题的东西,上面贴了尝试的解决方案。

Answer 1:

因此,该项目现在住在App Store,现在是时候回来这个线程和分享我的发现和揭示了什么我落得这样做。

什么没有奏效

在这里我对大AVComposition使用中的所有影片的第一个选项是不够好,因为没有办法跳转到组成一个特定的时间,而不具有小擦洗毛刺。 另外我有一个问题,因为API不能为暂停提供框架保证在组合物刚好两个视频之间暂停视频。

具有两个AVPlayers,让他们轮流第三个在实践中很好工作。 Exspecially在iPad 4和iPhone 5设备的RAM的低量是个问题,但由于在消耗了太多的内存,同时在内存中的几部影片。 尤其是因为我不得不处理非常高的分辨率的视频。

我落得这样做

好了,剩下的就是选择号码2时所需的视频创建AVPlayerItem并将其进料的AVPlayer。 关于这个解决方案的好处是内存消耗。 由懒创建AVPlayerItems并扔掉他们不再需要在能保持内存消耗降到最低,这是为了支持RAM有限的旧设备非常重要的时刻。 这种解决方案的问题是,从一个视频会在未来出现黑屏在快速的时刻,而未来视频被加载到内存中。 我解决这个的想法是把图像的AVPlayer当玩家被缓冲,将显示后面。 我知道我需要我们准确像素到像素的完美与视频图像,所以我拍摄的那名的影片的最后和第一帧的精确副本图像。 该解决方案在实践中摸索很大。

这种解决方案的问题

我有问题,虽然该内部的UIImageView图像的位置是不一样的AVPlayer内的视频的位置,如果视频/图像并不是它的天然大小或一个模块4缩放。 说换句话说,我曾与像素如何一半一个UIImageView和AVPlayer进行处理的问题。 它似乎没有相同的方式。

我怎么固定它

我尝试了很多东西,因为我在我的应用程序是使用互动方式的视频中以不同的尺寸显示。 我试着改变了magnificationfilter和AVPlayerLayer和的CALayer minificationFilter使用相同的算法,但并没有真正改变任何东西。 最后,我结束了创建iPad应用程序,可以自动可以采取的视频截图在我需要的所有尺寸,然后用正确的图像时,视频量化为一定规模。 这给了那名像素完美的在所有的大小,我表示特定的视频图像。 不是一个完美的工具链,但结果却是完美的。

最后的反思

最主要的原因,这个位置的问题是很明显的,我(并因此解决非常重要),是因为视频内容我的应用程序正在播放绘制动画,其中很多内容是在一个固定的位置,并且只的一部分画面移动。 如果所有的内容只是移动一个像素就给人一种很明显的和丑陋的毛刺。 在WWDC今年我用苹果电脑的工程师是在AVFoundation专家讨论这个问题。 当我介绍了这个问题给他他的建议基本上是去与选项3,但我向他解释说,这是不可能的,因为内存消耗,而且我已经尝试过,解掉。 有鉴于此,他说,我选择了正确的解决方案,并问我什么时候视频进行缩放以发送错误报告的的UIImage / AVPlayer定位。



Answer 2:

你可能已经看过这个了,但你检查出AVQueuePlayer 文档

它是专为打AVPlayerItems在排队,并且是AVPlayer的直接子类,所以只用它以同样的方式。 您可以设置它像如下:

AVPlayerItem *firstItem = [AVPlayerItem playerItemWithURL: firstItemURL];
AVPlayerItem *secondItem = [AVPlayerItem playerItemWithURL: secondItemURL];

AVQueuePlayer *player = [AVQueuePlayer queuePlayerWithItems:[NSArray arrayWithObjects:firstItem, secondItem, nil]];

[player play];

如果要添加新项目在运行时,排队只是用这个方法:

[player insertItem:thirdPlayerItem afterItem:firstPlayerItem];

我没有测试,看看这降低了你所提到的闪烁问题,但似乎这将是一段路要走。



Answer 3:

更新- https://youtu.be/7QlaO7WxjGg

下面是一个使用集合视图作为一个例子,这将同时播放8你的答案(注意,没有任何形式的内存管理是必要的;你可以使用ARC):

    - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    UICollectionViewCell *cell = (UICollectionViewCell *)[collectionView dequeueReusableCellWithReuseIdentifier:kCellIdentifier forIndexPath:indexPath];

    // Enumerate array of visible cells' indexPaths to find a match
    if ([self.collectionView.indexPathsForVisibleItems
         indexOfObjectPassingTest:^BOOL(NSIndexPath * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
             return (obj.item == indexPath.item);
         }]) dispatch_async(dispatch_get_main_queue(), ^{
             [self drawLayerForPlayerForCell:cell atIndexPath:indexPath];
         });


    return cell;
}

- (void)drawPosterFrameForCell:(UICollectionViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    [self.imageManager requestImageForAsset:AppDelegate.sharedAppDelegate.assetsFetchResults[indexPath.item]
                                                          targetSize:AssetGridThumbnailSize
                                                         contentMode:PHImageContentModeAspectFill
                                                             options:nil
                                                       resultHandler:^(UIImage *result, NSDictionary *info) {
                                                           cell.contentView.layer.contents = (__bridge id)result.CGImage;
                                                       }];
}

- (void)drawLayerForPlayerForCell:(UICollectionViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    cell.contentView.layer.sublayers = nil;
    [self.imageManager requestPlayerItemForVideo:(PHAsset *)self.assetsFetchResults[indexPath.item] options:nil resultHandler:^(AVPlayerItem * _Nullable playerItem, NSDictionary * _Nullable info) {
        dispatch_sync(dispatch_get_main_queue(), ^{
            if([[info objectForKey:PHImageResultIsInCloudKey] boolValue]) {
                [self drawPosterFrameForCell:cell atIndexPath:indexPath];
            } else {
                AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:[AVPlayer playerWithPlayerItem:playerItem]];
                [playerLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
                [playerLayer setBorderColor:[UIColor whiteColor].CGColor];
                [playerLayer setBorderWidth:1.0f];
                [playerLayer setFrame:cell.contentView.layer.bounds];
                [cell.contentView.layer addSublayer:playerLayer];
                [playerLayer.player play];
            }
        });
    }];
}

该方法drawPosterFrameForCell地方,因为它是存储在iCloud上,而不是装置的视频无法播放的图像。

无论如何,这是起点; 一旦你理解它是如何工作的,你可以做所有你想要的东西,没有任何毛刺的,内存是聪明的,你描述。



文章来源: Multiple videos with AVPlayer