注意:我接受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,在ViewDidLoad
(SetupLayer
函数中)为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线程上发生了,也许,它不应该。
答案 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" });
。这将预加载视频不会阻止用户界面。