互联网不可用时无法播放下载的 HLS 内容

Posted

技术标签:

【中文标题】互联网不可用时无法播放下载的 HLS 内容【英文标题】:Unable to play downloaded HLS content while internet is not available 【发布时间】:2020-03-10 01:30:30 【问题描述】:

我正在下载和播放 HLS 内容,要下载 HLS,我正在使用以下代码

func downloadTask() 

let videoUrl =  URL(string: "https://bitdash-a.akamaihd.net/content/MI201109210084_1/m3u8s/f08e80da-bf1d-4e3d-8899-f0f6155f6efa.m3u8")!

    configuration = URLSessionConfiguration.background(withIdentifier: downloadIdentifier)
    downloadSession = AVAssetDownloadURLSession(configuration: configuration!, assetDownloadDelegate: self, delegateQueue: OperationQueue.main)

    let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    destinationUrl = documentsDirectoryURL.appendingPathComponent(videoUrl.lastPathComponent)


    var urlComponents = URLComponents(
        url: videoUrl,
        resolvingAgainstBaseURL: false
        )!
    urlComponents.scheme = "https"
    do 
        let asset = try AVURLAsset(url: urlComponents.url!)
        asset.resourceLoader.setDelegate(self, queue: DispatchQueue(label: "com.example.AssetResourceLoaderDelegateQueue"))

        if #available(ios 10.0, *) 
            assetDownloadTask = downloadSession!
                .makeAssetDownloadTask(
                    asset: asset,
                    assetTitle: "RG-TVVideo",
                    assetArtworkData: nil,
                    options: nil
            )
            APP_DELEGATE.isProgressRunning = true
            assetDownloadTask?.resume()
         else 
            // Fallback on earlier versions
        
     catch  print("Erorr while parsing the URL.") 

下载完成

 func urlSession(_ session: URLSession, assetDownloadTask: AVAssetDownloadTask, didFinishDownloadingTo location: URL) 

    if #available(iOS 11.0, *) 
        let storageManager = AVAssetDownloadStorageManager.shared()
        let newPolicy = AVMutableAssetDownloadStorageManagementPolicy()
        newPolicy.expirationDate = Date()
        newPolicy.priority = .important
        let baseURL = URL(fileURLWithPath: NSHomeDirectory())
        let assetURL = baseURL.appendingPathComponent(location.relativePath)
        storageManager.setStorageManagementPolicy(newPolicy, for: assetURL)

        UserDefaults.standard.set(location.relativePath, forKey: "videoPath")
        strDownloadStatus = "5"
        let dictVideoInfo = ["strDownloadStatus" : "5","VideoID":self.strID]

// Here I am Storing Downloaded location in to database 
            DBManager.shared.updateVideoStatus(strVideoID: APP_DELEGATE.arrTempVideoIds.object(at: 0) as! String, strStatus: "5", strSavePath: location.relativePath)  (status) in 

        DispatchQueue.main.async 
            NotificationCenter.default.post(name: NSNotification.Name.init("UpdateProgress"), object: self.percentageComplete, userInfo: dictVideoInfo)
        

    

现在我正在尝试从存储在数据库中的位置获取视频路径并尝试使用以下代码离线播放(没有互联网)

  func setLocalPlayer(strDownloadPath: String) 

    let strDownloadPath = “”

    //Getting path from database
    DBManager.shared.getDownloadedPath(videoID:  VideoID)  (strPath) in
        strDownloadPath = strPath
    

    activityIndicator.isHidden = false

    let baseURL = URL(fileURLWithPath: NSHomeDirectory())
    let assetURL = baseURL.appendingPathComponent(strDownloadPath)
    let asset = AVURLAsset(url: assetURL)

    //        if let cache = asset.assetCache, cache.isPlayableOffline 
    //            let videoAsset = AVURLAsset(url: assetURL)
    asset.resourceLoader.preloadsEligibleContentKeys = true

    asset.resourceLoader.setDelegate(self, queue: DispatchQueue(label: "com.example.AssetResourceLoaderDelegateQueue"))
    let playerItem = AVPlayerItem(asset: asset)
    avPlayer = AVPlayer(playerItem: playerItem)
    avPlayerLayer = AVPlayerLayer()
    avPlayerLayer.frame = CGRect(x: 0, y: 0, width: playerContainer.frame.width, height: playerContainer.frame.height)
    avPlayerLayer.videoGravity = .resize

    avPlayerLayer.player = avPlayer

    playerContainer.layer.addSublayer(avPlayerLayer)

    let interval = CMTime(seconds: 0.01, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
    timeObserver = avPlayer?.addPeriodicTimeObserver(forInterval: interval, queue: DispatchQueue.main, using:  elapsedTime in
        self.updateVideoPlayerState()

        if self.avPlayer != nil 
            self.bufferState()
        
    )

    self.slider.setThumbImage(UIImage(named: "slider_dot"), for: UIControl.State.normal)
    resetTimer()

    avPlayer.play()
    isPlaying = true
    //        

注意:此代码在互联网开启时工作正常

我参考了以下链接

https://developer.apple.com/library/archive/documentation/AudioVideo/Conceptual/MediaPlaybackGuide/Contents/Resources/en.lproj/HTTPLiveStreaming/HTTPLiveStreaming.html

https://assist-software.net/snippets/how-play-encrypted-http-live-streams-offline-avfoundation-ios-using-swift-4

Downloading and playing offline HLS Content - iOS 10

请指导我做错了什么。

谢谢

【问题讨论】:

嗨@Khush,我知道我迟到了,但你有哪个错误?您可以使用命令检查 AVPlayer 错误:po avPlayer.currentItem?.errorLog() 【参考方案1】:

好吧,我不知道这是否是你的错误,但为了进一步阅读:

不要这样做newPolicy.expirationDate = Date() 这是一个错误。根据Advances in HTTP Live Streaming 2017 WWDC session,它将尽快删除您的文件。

在播放离线播放之前,您可以在“设置”->“常规”->“存储”->“我的应用”中检查它是否仍在您的设备上

到期日期属性存在,以防您的资产在某个时候 不再有资格被播放。例如,您可能会发现 您可能处于某个特定节目可能要离开的情况 您的目录,您不再有权流式传输它。

如果是这种情况,您可以设置到期日期,它会有所增加 在删除队列中。所以,使用它是相当简单的。

【讨论】:

以上是关于互联网不可用时无法播放下载的 HLS 内容的主要内容,如果未能解决你的问题,请参考以下文章

EasyNVR播hls格式视频无法全屏自适应播放如何调节?

歌曲不可用时的警报视图

FFmpeg基于HLS实现大视频分片下载播放[视频直播二]

FFmpeg基于HLS实现大视频分片下载播放[视频直播二]

android 中判断WiFi是否可用的可靠方法 ,android 是否联网

如何在 VLC 中播放 HLS 流