iOS HLS視頻播放

采用系統(tǒng)AVPlayer組件來(lái)播放,對(duì)于需要手動(dòng)處理加密的hls視頻,通過(guò)AVAssetResourceLoader攔截代理方法來(lái)手動(dòng)代理系統(tǒng)的m3u8文件下載、解密key下載等。
蘋果的hls有自己的標(biāo)準(zhǔn),注意參考標(biāo)準(zhǔn)來(lái)實(shí)現(xiàn),否則可能播不出來(lái),而且很難排查原因,參考文檔:https://developer.apple.com/documentation/http-live-streaming/hls-authoring-specification-for-apple-devices?language=objc

我們?nèi)绾稳ブ鲃?dòng)控制播放過(guò)程中m3u8文件下載、解密key下載等邏輯呢?

  1. 通常情況下,只要你設(shè)置了正確的播放url,AVAssetResourceLoader怎么都不會(huì)調(diào)用下面的代理方法,即使url報(bào)錯(cuò)也不會(huì),無(wú)法訪問(wèn)也不會(huì)。不知道為什么這么設(shè)計(jì)??
    想要觸發(fā)下面的代理調(diào)用,只有把設(shè)置進(jìn)去的url改成非url的形式才行,比如去掉url前面http/https,這樣系統(tǒng)就會(huì)調(diào)用下面代理方法了,就有操作空間了
func resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool
  1. 通過(guò)let url = loadingRequest.request.url?.absoluteString拿到系統(tǒng)當(dāng)前要執(zhí)行的url,判斷url的后綴來(lái)實(shí)現(xiàn)邏輯扭轉(zhuǎn)。
  2. 判斷如果是播放url
    // 自己下載m3u8文件,
    下載完成block里面的代碼: {
      // 下載完成后塞給系統(tǒng)
      loadingRequest.dataRequest?.respond(with: newData!)
      // 通知系統(tǒng)請(qǐng)求結(jié)束
      loadingRequest.finishLoading()
    }
    // 通知系統(tǒng)等待
    return true
  1. 如果你的hls視頻加密是自定義的,比如秘鑰下載完是加密的,那就要在m3u8文件里面#EXT-X-KEY:METHOD:后面的URI給改成非url,這樣系統(tǒng)就會(huì)調(diào)用這個(gè)代理,你自己去處理秘鑰下載然后解密的邏輯,自己下載完以上面同樣方式塞給系統(tǒng)。

  2. 視頻切片文件下載的邏輯不能用上面方式來(lái)實(shí)現(xiàn),采用同樣方式,塞Data給系統(tǒng),系統(tǒng)也不會(huì)播放,原因未知。系統(tǒng)只接受url重定向。
    因此碰到因?yàn)橐粢曨l編碼問(wèn)題,直接播放視頻切片文件播放不了的時(shí)候,目前我采用的是本地服務(wù)器的形式實(shí)現(xiàn),即把切片的url給改成非url,然后采用上面同樣的方式,手動(dòng)把視頻下載下來(lái),如果加密了還需要解密,然后使用ffmpeg轉(zhuǎn)碼,轉(zhuǎn)碼完成后,如果m3u8包含加密的,還需要再加密回去,(因?yàn)锳VAssetResourceLoader解密邏輯是內(nèi)部進(jìn)行的),然后啟動(dòng)本地服務(wù)器,把url重定向到本地視頻切片文件url

    // 下載切片文件完成回調(diào): {
      let localUrl = "http://localhost:port/" + fileName
      if let u = URL(string: localUrl) {
        let redirect = URLRequest(url: u)
        loadingRequest.redirect = redirect
        //設(shè)置需要重定向
        loadingRequest.response = HTTPURLResponse(url: u, statusCode: 301, httpVersion: nil, headerFields: nil)
        loadingRequest.finishLoading()
       }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容