提问人:zaid afzal 提问时间:5/4/2023 最后编辑:zaid afzal 更新时间:5/31/2023 访问量:703
如何在 swift/ios 的 AVPlayer 中播放受 DRM 保护的视频?
How to play DRM protected videos in AVPlayer in swift/ios?
问:
这是我从后端 api 获得的响应下方。
如何在带有 widevine 和没有 widevine 的 swift AVPlayer 中播放扩展名为 .mpd 的视频。
我的证书数据现在正在下载中,但我无法获取 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
}
}
答:
0赞
Abdelrahman
5/31/2023
#1
AVPlayer 不支持 DASH (.mpd) 和 WideVine。AVPlayer 支持 HLS 流,并且仅支持 Apple FairPlay DRM 系统用于受保护的流。
请参阅 Apple 设备的 Apple 规格文稿。
评论