AVPlayerLayer慢实例化

时间:2016-06-29 09:58:25

标签: ios xamarin avplayer avplayerviewcontroller avplayerlayer

注意:我接受Xamarin.iOS,Objective-C或Swift中的任何答案。如果您需要帮助阅读Xamarin代码,我可以为您清除,但考虑到"复杂性"它应该很好。这里的代码。

我怀疑我的AVPlayerLayer会减慢我的进程。

我使用ViewDidLoad中的以下代码将视频/音频播放器嵌入我的控制器中:

    void SetupLayer()
    {
        _layer = AVPlayerLayer.FromPlayer(_player);
        _layer.Frame = PlayerViewContainer.Bounds;
        _layer.Player = _player;
        _layer.BackgroundColor = UIColor.Black.CGColor;
        _layer.VideoGravity = AVLayerVideoGravity.ResizeAspect;

        //This is a UIView
        PlayerViewContainer.Layer.InsertSublayer(_layer, 0);
    }

除此之外,在我自己的控制器(包含播放器)的构造函数中:

        public void SetUrls(string mediaUrl, string coverUrl = null)
        {
            CoverUrl = string.IsNullOrEmpty(coverUrl) ? string.Empty : coverUrl;
            MediaUrl = mediaUrl;

            AVUrlAsset asset = new AVUrlAsset(new NSUrl(MediaUrl));
            AVPlayerItem item = new AVPlayerItem(asset);

            _isVideo = item.Asset.Tracks.Length != 1;

            _player = new AVPlayer(item);
        }

这是ViewDidLoad和构造函数中唯一相关的代码。被删除的部分应该没有任何影响(设置文本,加载资产等等)。

现在我面临的问题是加载一个"大" (大,我不是指超过4小时的视频流。通常它们大约是4分钟。 )文件占用了很多时间。最多4秒。在构造函数(SetUrls函数)中为0.5-1.5,在ViewDidLoadSetupLayer函数中)为1.5-2.5之间。

我定时了,删除这些方法大大减少了滞后的程度(但我显然没有图像或不良结果)。

我使用以下代码与本机播放器进行了比较:

            _item = AVPlayerItem.FromUrl(url);
            _player = new AVPlayer(_item);

            _controller = new AVPlayerViewController();
            _controller.Player = _player;

            this.PresentViewController(_controller, true, _player.Play);

立即加载 。它甚至不是4秒的加载分布更均匀,它总共需要不到4秒。

考虑到它可能在动画期间加载,并且当显示播放器时屏幕仍然是黑色并且没有播放任何内容,我说原生控制器在大约1-2秒内完成工作(虽然其中一半可能是在动画期间)。

在动画制作/显示任何内容之前,我会做所有事情。关于这一点唯一的好处是视频尽快播放,没有黑屏。缺点是控制器的加载时间非常糟糕。

注意:在加载期间,我的UI完全被阻止。这让我相信它在UI线程上发生了,也许,它不应该。

我的问题是:

  • 我的瓶颈在哪里?我显然做错了什么。
  • 我应该做些什么?也许是我在自己的控制器中加载播放器的方式?
  • 如何异步加载这些组件以避免阻塞UI线程?是否足以减少加载时间?或者简单地说,它甚至被允许这样做吗?

2 个答案:

答案 0 :(得分:1)

Radin的回答帮助了我,我遇到了同样的问题。此链接提供了更多信息 - https://developer.apple.com/reference/avfoundation/avasynchronouskeyvalueloading/1387321-loadvaluesasynchronously

import UIKIT
import AVFoundation

typealias VideoDownloadResponse = (Bool, AVPlayerLayer?) -> Void

func loadVideoFromURL(urlString: String, onCompletion: @escaping VideoDownloadResponse) {

    if let url = URL(string: urlString) as URL? {
        let asset = AVURLAsset(url: url)
        // Load the asset's "playable" key
        asset.loadValuesAsynchronously(forKeys: ["playable"]) {
            var error: NSError? = nil
            let status = asset.statusOfValue(forKey: "playable", error: &error)
            switch status {

            case .loaded:
                // Sucessfully loaded, continue processing
                // Build the player
                let playerItem = AVPlayerItem(asset: asset)
                let player = AVPlayer(playerItem: playerItem)
                let layer = AVPlayerLayer(player: player)
                //send it back to be shown in the UI
                DispatchQueue.main.async(execute: {
                    onCompletion(true, layer)
                })

            case .failed:
                // Examine NSError pointer to determine failure
                DispatchQueue.main.async(execute: {
                    onCompletion(false, nil)
                })
            default:
                // Handle all other cases
                DispatchQueue.main.async(execute: {
                    onCompletion(false, nil)
                })
            }
        }
    }

}

答案 1 :(得分:0)

将您的方法转换为异步并在创建资产后立即调用await asset.LoadValuesTaskAsync(new string[] { @"playable" });。这将预加载视频不会阻止用户界面。