系統播放器(AVPlayer)不支援快取,比較依賴網路,這段時間重新研究了下,為了以後方便學習和研究寫了份demo。功能:支援視訊的離線快取、邊下邊播、快進、斷網重連、資料自動儲存到本地、當下次重新播放時會優先使用本地資料等,專案 TTPlayerCache 支援了CocoaPods,用起來比較方便。
1、用法:
pod `TTPlayerCache`
#import <TTPlayerCache.h>
...
//把視訊播放地址轉成系統不能識別的URL
NSString *videoUrl = @"http://....";
videoUrl = TTResourceUrlFromOrigianllUrl(videoUrl);
...
...
//設定AVPlayer播放
//初始化代理
self.resourceLoaderDelegate = [TTResourceLoaderDelegate new];
self.urlAsset = [AVURLAsset assetWithURL:self.videoURL];
[self.urlAsset.resourceLoader setDelegate:self.resourceLoaderDelegate queue:TT_resourceLoader_delegate_queue()];
...
複製程式碼
2、視訊播放過程
通過對系統播放器抓包分析:
(只測試了MP4視訊格式)
- AVPlayer每次播放時第一次都會先請求bytes=0-2的資料,獲得到視訊的總位元組數、視訊型別等資訊
- 第二次請求全部資料bytes=x-,當資料響應填充後可能會有不同的反應,請求全部資料是requestsAllDataToEndOfResource == YES。
- 當視訊快進時,會取消先前的下載任務,如果快進區域沒有緩衝也會呼叫**resourceLoader: shouldWaitForLoadingOfRequestedResource:方法,這是會出現requestsAllDataToEndOfResource == NO/YES的loadingRequest ,然後繼續重複。
…
當視訊快取到一定程度時系統會呼叫resourceLoader: didCancelLoadingRequest:**取消下載任務。
3、程式碼分析:
程式碼比較少,主要是TTResourceLoaderDelegate和TTResourceLoaderData這兩個類
- TTResourceLoaderDelegate 實現AVAssetResourceLoaderDelegate的兩個代理方法。
- (BOOL)resourceLoader:(AVAssetResourceLoader *)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest *)loadingRequest {
//對loadingRequest進行處理,資料回填
...
return YES;
}
- (void)resourceLoader:(AVAssetResourceLoader *)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {
//取消請求處理
...
}
複製程式碼
- TTResourceLoaderData實現對loadingRequest響應資料、快取、判斷是否繼續請求資料(還是使用本地資料)、請求任務取消等操作。
- TTResourceLoaderData對下載資料的處理類。
- TTResourceLoaderCache對本地快取資料的處理,可以獲取總快取大小、清空全部快取和刪除某個快取。
- TTPlayerCacheMacro定義了TTPlayerCache的Scheme等常量、URL轉換方法。
- TTReachability 是對Reachability原始碼加了字首方便使用,管理視訊播放過程中斷網處理。
- (void)handleAssetResourceLoadingRequest:(AVAssetResourceLoadingRequest *)loadingRequest {...}
實現對loadingRequest的處理,根據loadingRequest.dataRequest.requestsAllDataToEndOfResource == YES與否分別處理(是否等待請求全部資料),封裝不同的NSURLRequest,判斷是否使用本地資料。requestsAllDataToEndOfResource 為YES的下載任務只有一個,在開始之前取消上一個等等。
- 下載任務收到響應時
- (void)TT_downloadTaskDataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response
,先初始化一個TTResourceLoaderData儲存下視訊的總位元組數和型別,TTResourceLoaderData會建立一個和視訊位元組數一樣長度的NSMutableData用於填充資料。 - 下載任務收到資料時
- (void)TT_downloadTaskDataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
->呼叫TTResourceLoaderData- (void)appendData:(NSData *)data taskId:(NSUInteger)taskIdentifier
方法對資料進行處理:
把data放到_data
的正確位置、調整_receivedDataPointArray
(儲存已經下載的資料的位置)、loadingRequest.dataReqeust
響應資料 ,具體看程式碼。 - 下載任務完成或出錯
- (void)TT_downloadTaskTask:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
->呼叫TTResourceLoaderData- (void)taskCompleteWithError:(NSError *)error taskId:(NSUInteger)taskIdentifier
對下載任務是否取消、網路錯誤、正常完成分別處理。 - 網路恢復時呼叫
- (void)reloadLoadingRequestWhenHasNetError
重新整理播放器。
對下載資料的處理都在TTResourceLoaderData類裡完成。
重點:
loadingRequest.dataRequest.requestsAllDataToEndOfResource == YES or NO
的處理
TTResourceLoaderData
物件對視訊資料實際位置的表示…
第一次寫,寫的比較簡陋,不對、不好的地方歡迎指正,謝謝!