AVPlayer HLS 直播 IOS

Posted

技术标签:

【中文标题】AVPlayer HLS 直播 IOS【英文标题】:AVPlayer HLS live stream IOS 【发布时间】:2018-04-25 11:09:51 【问题描述】:

我正在尝试使用 HLS 进行直播,但出现错误:

错误:可选(“操作无法完成”),错误: 可选(错误域=AVFoundationErrorDomain 代码=-11800 "媒体 格式 - 样本描述无效(例如,尺寸无效)” UserInfo=NSUnderlyingError=0x60000005b510 错误 域=NSOSStatusErrorDomain 代码=-12714 "(null)", NSLocalizedFailureReason=发生未知错误 (-12714), NSDebugDescription=媒体格式 - 示例描述无效(例如 大小无效),NSLocalizedDescription=该操作无法进行 完成) 2018-04-25 12:14:51.608117+0200 morethen2[11681:374192] 任务 . 以错误结束 - 代码:-999

我无法共享流的链接,它是私人的。

代码如下:

class ViewController: UIViewController 

var player = AVPlayer()

override func viewDidLoad() 
    super.viewDidLoad()
    let url = URL(string: "https:can-t-share-it/LIVE-008900021A-LIP-0-channelNo2_360p/manifest.m3u8")!

    let asset = AVURLAsset(url: url)

    let playerItem = AVPlayerItem(asset: asset)

    player = AVPlayer(url: url)
    let layer = AVPlayerLayer(player: player)
    layer.frame = view.layer.frame
    view.layer.addSublayer(layer)


    self.player.addObserver(self, forKeyPath: #keyPath(AVPlayer.status), options: [.new, .initial], context: nil)
    self.player.addObserver(self, forKeyPath: #keyPath(AVPlayer.currentItem.status), options:[.new, .initial], context: nil)

    // Watch notifications
    let center = NotificationCenter.default
    center.addObserver(self, selector:"newErrorLogEntry:", name: .AVPlayerItemNewErrorLogEntry, object: player.currentItem)
    center.addObserver(self, selector:"failedToPlayToEndTime:", name: .AVPlayerItemFailedToPlayToEndTime, object: player.currentItem)


    player.play()

    // Do any additional setup after loading the view, typically from a nib.


override func didReceiveMemoryWarning() 
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.


@IBAction func dismiss(_ sender: Any) 
    UIApplication.shared.keyWindow?.rootViewController?.dismiss(animated: true, completion: nil)



// Observe If AVPlayerItem.status Changed to Fail
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) 
    if let player = object as? AVPlayer, keyPath == #keyPath(AVPlayer.currentItem.status) 
        let newStatus: AVPlayerItemStatus
        if let newStatusAsNumber = change?[NSKeyValueChangeKey.newKey] as? NSNumber 
            newStatus = AVPlayerItemStatus(rawValue: newStatusAsNumber.intValue)!
         else 
            newStatus = .unknown
        
        if newStatus == .failed 
            NSLog("Error: \(String(describing: player.currentItem?.error?.localizedDescription)), error: \(String(describing: player.currentItem?.error))")
        
    


// Getting error from Notification payload
func newErrorLogEntry(_ notification: Notification) 
    guard let object = notification.object, let playerItem = object as? AVPlayerItem else 
        return
    
    guard let errorLog: AVPlayerItemErrorLog = playerItem.errorLog() else 
        return
    
    NSLog("Error: \(errorLog)")


func failedToPlayToEndTime(_ notification: Notification) 
    let error = notification.userInfo!["AVPlayerItemFailedToPlayToEndTimeErrorKey"]
    NSLog("error: \(error)")
 

以下是视频详情:

同样的流也适用于 android 应用和网络

【问题讨论】:

这是服务器问题检查这个答案***.com/questions/49663296/… 【参考方案1】:

我在这里留下我的答案,以防其他人需要它。经过研究,尝试错误,我终于找到了让 AVPlayer 与 nginx rtmp hls 一起工作的方法。

发生这种情况的主要原因是服务器上的视频片段元数据错误。我们必须想办法解决这个问题。

这是我从我的 macbook 上传视频的命令,这是典型的:

ffmpeg -f avfoundation -framerate 30  -i "0:0" -f flv -s 360x240 -vcodec libx264 -c:a aac -async 1 -vsync 1 -preset slower rtmp://127.0.0.1/live/xyz

在服务器端,我在 Ubuntu 18.10 上配置了一个基本的 Nginx RTMP HLS,可以通过谷歌搜索找到它。请注意,我使用 fdk_aac 重新编译了最新的 ffmpeg。

RTMP 有两种应用:一种用于接收上游,另一种用于转码 HLS,这也是典型的。

为了解决元数据问题,我调整了带有基线配置文件的 ffmpeg 转码命令,添加了:-profile:v baseline -level 3.0。这会因为颜色格式错误而导致错误,所以我也加了:-vf "scale=480:trunc(ow/a/2)*2,format=yuv420p"

最后,我的 nginx 配置有效: https://gist.github.com/chung-nguyen/d88e73e3cc8788878f5ffb8c232b4729

还有我在 swift 中的 AVPlayer 代码:

    let videoURL = URL(string: "http://blogchange.live/hls/xyz_low/index.m3u8")

    let playerItem = AVPlayerItem(url: videoURL!)
    let adID = AVMetadataItem.identifier(forKey: "X-TITLE", keySpace: .hlsDateRange)
    let metadataCollector = AVPlayerItemMetadataCollector(identifiers: [adID!.rawValue], classifyingLabels: nil)
    metadataCollector.setDelegate(self, queue: DispatchQueue.main)
    playerItem.add(metadataCollector)


    let player = AVPlayer(playerItem: playerItem)
    let playerLayer = AVPlayerLayer(player: player)
    playerLayer.frame = self.view.bounds
    self.view.layer.addSublayer(playerLayer)
    self.player = player
    player.play()

【讨论】:

以上是关于AVPlayer HLS 直播 IOS的主要内容,如果未能解决你的问题,请参考以下文章

AVPlayer HLS 直播电平表(显示 FFT 数据)

AVPlayer 不播放 HLS 流

Hls 流 url 不会在 AVPlayer 中播放

在 iOS SDK - AVPlayer 中手动选择视频质量的 HLS 流?

是否可以使用 AVPlayer 缓存 HLS 段?

iOS AVPlayer 未加载大多数 HLS 流