首页 > 解决方案 > 互联网不可用时无法播放下载的 HLS 内容

问题描述

我正在下载和播放 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

下载和播放离线 HLS 内容 - iOS 10

请指导我做错了什么。

谢谢

标签: swiftavplayerofflinehttp-live-streamingplayback

解决方案


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

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

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

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

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


推荐阅读