如何在swift/ios的AVPlayer中播放DRM保护的视频?

2exbekwf  于 2023-05-30  发布在  iOS
关注(0)|答案(1)|浏览(114)

下面是我从后端API得到的响应。我如何在Swift AVPlayer中播放带有.mpd扩展名的视频,有widevine和没有widevine。
我的证书数据正在下载,但我无法获取streamingContentKeyRequestData。
我在看这篇文章。https://medium.com/@burak.oguz/ios-fairplay-drm-integration-with-different-use-cases-8aff3d4248dd

响应JSON

{
  "url": "https://z2cltd.akamaized.net/example-4671-mp4-cbcs.mpd",
  "fairPlayCertificateUrl": "https://mw.example.net/static/FairPlay.der",

   "drms": {
            "com.widevine.alpha": "https://mw.example.net/widevine_proxy",
            "com.apple.fps": "https://mw.example.net/ksm",
            "com.apple.fps.1_0": "https://mw.example.net/ksm"
        },
}

ViewController

class ViewController: UIViewController {
    
    var player: AVPlayer?
    var asset: AVURLAsset?

    override func viewDidLoad() {
        super.viewDidLoad()
       
        // Create the AVURLAsset and assign the delegate
              guard let url = URL(string: "htps://z2cltd.akamaized.net/mini01/vods/49/s1e1-andhera-ujala-ghani-chaon-copy-3395/64366c9ccc181-4606-mp4-cbcs.mpd") else {
                  return
              }

              asset = AVURLAsset(url: url)
              asset?.resourceLoader.setDelegate(self, queue: DispatchQueue.global(qos: .default))

              // Create an AVPlayerItem using the AVURLAsset
              let playerItem = AVPlayerItem(asset: asset!)
//
              // Create an AVPlayer using the AVPlayerItem
              player = AVPlayer(playerItem: playerItem)

              // Add the AVPlayerLayer to the mediaView
              let playerLayer = AVPlayerLayer(player: player)
              playerLayer.frame = view.bounds
              playerLayer.videoGravity = .resizeAspectFill
        playerLayer.addObserver(self, forKeyPath: "status", options: NSKeyValueObservingOptions(), context: nil)

            view.layer.addSublayer(playerLayer)

              // Play the content using the AVPlayer
              player?.play()
    }
    private func observePlayerItemProperties(for item: AVPlayerItem) {
        item.observe(\.status, changeHandler: self.onStatusObserverChanged)
        print(item.observe(\.status, changeHandler: self.onStatusObserverChanged))
    }

    private func onStatusObserverChanged(playerItem: AVPlayerItem, change: NSKeyValueObservedChange<AVPlayerItem.Status>) {
        guard playerItem.status != .failed else {
            if let error = playerItem.error as? Error {
                // DRM Errors handled here
                print("DRM errors:\(error)")

            }
            return
        }
    }



    let keyServerUrl: URL = URL(string: "https://mw.hivesys.net/")!

}

extension ViewController: AVAssetResourceLoaderDelegate {
    
    

    func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {

        
        let url =  URL(string: "https://z2cltd.akamaized.net/mini01/vods/49/s1e1-andhera-ujala-ghani-chaon-copy-3395/64366c9ccc181-4606-mp4-cbcs.mpd")
        
        // Get the content id. Content id will be stored in the host of the request url
        guard let contentId = url!.host, let contentIdData = contentId.data(using: String.Encoding.utf8) else {
            print("Unable to read the content id.")
         //   loadingRequest.finishLoading(with: DRMError.noContentIdFound)
            return false
        }
        
        // Request SPC data from OS
        var _spcData: Data?
        var certificateDataNeed: Data?

       // var _spcError: Error?
        let certificateUrl = URL(string: "https://mw.hivesys.net/static/FairPlay.der")!
        let certificateDataTask = URLSession.shared.dataTask(with: certificateUrl) { (data, response, error) in
                  if let certificateData = data {
                   //   let contentIdHeaderValue = "spc=\(contentIdBase64String ?? ""), cert=\(certificateData.base64EncodedString(options: []))"
                      certificateDataNeed = certificateData
                      // Use the obtained certificateData and contentIdHeaderValue as needed
                      // Handle the provided content key request and provide the necessary response
                      // This involves retrieving the license from the license server and providing it to the key request
                      print("Data :\(certificateData)")
                    //  print("contentIdHeaderValue :\(contentIdHeaderValue)")
                      do {
    // **This is where I'm getting stucked unable to get spcData**
                          _spcData = try loadingRequest.streamingContentKeyRequestData(forApp: certificateData, contentIdentifier: contentIdData, options: [AVAssetResourceLoadingRequestStreamingContentKeyRequestRequiresPersistentKey: true as AnyObject])
                          
                          
                          guard let spcData = _spcData, let dataRequest = loadingRequest.dataRequest else {
                             // loadingRequest.finishLoading(with: DRMError.noSPCFound(underlyingError: _spcError))
                              print("Unable to read the SPC data.")
                              return()
                          }
                          
                          let stringBody: String = "spc=\(spcData.base64EncodedString())&assetId=\(contentId)"
                          var ckcRequest = URLRequest(url: self.keyServerUrl)
                          ckcRequest.httpMethod = "POST"
                          ckcRequest.httpBody = stringBody.data(using: String.Encoding.utf8)
                          URLSession(configuration: URLSessionConfiguration.default).dataTask(with: ckcRequest) { data, _, error in
                              guard let data = data else {
                                  print("Error in response data in CKC request: \(error)")
                                 // loadingRequest.finishLoading(with: DRMError.unableToFetchKey(underlyingError: _spcError))
                                  return
                              }
                              // The CKC is correctly returned and is now send to the `AVPlayer` instance so we
                              // can continue to play the stream.
                              guard let ckcData = Data(base64Encoded: data) else {
                                  print("Can't create base64 encoded data")
                                  //loadingRequest.finishLoading(with: DRMError.cannotEncodeCKCData)
                                  return
                              }
                              // If we need non-persistent token, then complete loading
                              // dataRequest.respond(with: data)
                              // loadingRequest.finishLoading()
                          
                              // If we need persistent token, then it is time to add persistence option
                              var persistentKeyData: Data?
                              do {
                                  persistentKeyData = try loadingRequest.persistentContentKey(fromKeyVendorResponse: ckcData, options: nil)
                              } catch {
                                  print("Failed to get persistent key with error: \(error)")
                                 // loadingRequest.finishLoading(with: DRMError.unableToGeneratePersistentKey))
                                  return
                              }
                              // set type of the key
                              loadingRequest.contentInformationRequest?.contentType = AVStreamingKeyDeliveryPersistentContentKeyType
                              dataRequest.respond(with: persistentKeyData!)
                              loadingRequest.finishLoading()
                          
                          }.resume()

                          
                      } catch let error {
                       //   _spcError = error
                          print("Failed to get stream content key with error: \(error)")
                      }
                    
                  }
              }
              certificateDataTask.resume()
        return true
    }
}
vcudknz3

vcudknz31#

你可能会问,类似的问题这里https://futureminutes.com/ask-question我会推荐一个人。谢啦

相关问题