關(guān)于封裝播放器相關(guān)

一:基礎(chǔ)功能的實(shí)現(xiàn):

? ? 1.基于AVFoundation/AVFoundation.h來實(shí)現(xiàn)功能.

1.1創(chuàng)建一個(gè)播放器,并且傳一個(gè)url過來就播放,是否考慮緩存

- (void)playWithURL:(NSURL*)url isCache:(BOOL)isCache;

播放需要2個(gè)類來輔助,AVURLAsset,AVPlayerItem.

AVURLAsset:用來處理資源的請(qǐng)求

AVPlayerItem:用來組織資源,? 當(dāng)資源的組織者, 告訴我們資源準(zhǔn)備好了之后, 我們?cè)俨シ?后續(xù)會(huì)在個(gè)里面做緩存相關(guān)).使用KVO監(jiān)聽他的兩個(gè)狀態(tài)? ,來做播放的相應(yīng)的操作.item 是他的實(shí)例對(duì)象.

//AVPlayerItemStatus statu

? ? [itemaddObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

? ? [itemaddObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];

這里給播放器設(shè)置資源組織者,讓他來管理資源.

? ? self.player = [AVPlayer playerWithPlayerItem:item];

#pragma mark - KVO

-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void*)context {

? ? if([keyPathisEqualToString:@"status"]) {

? ? ? ? AVPlayerItemStatus status = [change[NSKeyValueChangeNewKey] integerValue];

? ? ? ? if (status == AVPlayerItemStatusReadyToPlay) {

? ? ? ? ? ? NSLog(@"資源準(zhǔn)備好了, 這時(shí)候播放就沒有問題");

? ? ? ? ? ? [selfresume];

//? ? ? ? ? ? [self.player play];

? ? ? ? }else{

? ? ? ? ? ? NSLog(@"狀態(tài)未知");

? ? ? ? ? ? self.playState = MLRemotePlayerStateFailed;

? ? ? ? }

? ? }

? ? else if ([keyPath isEqualToString:@"playbackLikelyToKeepUp"]) {

? ? ? ? BOOLisKeepUp = [change[NSKeyValueChangeNewKey]boolValue];

? ? ? ? if(isKeepUp) {

? ? ? ? ? ? NSLog(@"當(dāng)前的資源, 準(zhǔn)備的已經(jīng)足夠播放了");

? ? ? ? ? ? if(!_isUserPause) {

? ? ? ? ? ? ? ? [selfresume];

? ? ? ? ? ? }

? ? ? ? }else{

? ? ? ? ? ? NSLog(@"資源還不夠, 正在加載過程當(dāng)中");

? ? ? ? ? ? self.playState = MLRemotePlayerStateLoading;

? ? ? ? }

? ? }

}

? ? 2.基礎(chǔ)功能包括播放,暫停,繼續(xù)播放,快進(jìn),進(jìn)度條拖動(dòng),倍速,靜音功能,

基礎(chǔ)的功能大部分都是都有直接調(diào)用的方法.直接自己封裝下就好了,幾個(gè)需要自己計(jì)算的功能.


方法聲明


要注意用戶的操作的優(yōu)先級(jí)要高,弄一個(gè)暫停的屬性來記錄用戶的暫停操作


幾個(gè)需要計(jì)算的方法,很簡(jiǎn)單,有些方法看名字就知道意思了


這個(gè)是加載的進(jìn)度,因?yàn)橐纛l是一段一段加載的所以取出最新的那一段/總時(shí)長(zhǎng)

二:狀態(tài)控制,播放事件

比較煩的狀態(tài)控制,需要不斷調(diào)試,寫一個(gè)枚舉來記錄.


狀態(tài)控制的枚舉

在播放,暫停,加載數(shù)據(jù)等時(shí)候去賦值就好,需要自己去看在哪里加合適.

播放事件就是上面說到的監(jiān)聽的兩個(gè)屬性,AVPlayerItemStatus status ,self.player.currentItem.playbackLikelyToKeepUp

status :來監(jiān)聽狀態(tài)是否資源準(zhǔn)備好了,好了就可以播放

playbackLikelyToKeepUp:這個(gè)也是用來準(zhǔn)備資源,看準(zhǔn)備的資源是否足夠這一段的播放,是一段一段的,所以寫一個(gè)if else.

注意:要注意用戶重復(fù)點(diǎn)擊播放按鈕,重復(fù)監(jiān)聽這兩個(gè)屬性,寫一個(gè)移除監(jiān)聽的方法,判斷當(dāng)前播放任務(wù)已經(jīng)存在并且是同一個(gè)url地址,是的話就繼續(xù)播放,還要判斷當(dāng)前self.palyer.currentItem是否存在 存在就移除,然重新去監(jiān)聽.


三:攔截播放請(qǐng)求,準(zhǔn)備動(dòng)態(tài)下載,緩存數(shù)據(jù)

播放請(qǐng)求其實(shí)走的是資源組織者對(duì)象的代理方法,?AVURLAsset *asset = [AVURLAsset assetWithURL:url]; 所以以這個(gè)為切入點(diǎn),來攔截他的請(qǐng)求.

自己實(shí)現(xiàn)一個(gè)代理的類MLRemoteResourceLoaderDelegate,并且設(shè)置asset的代理為 這個(gè)類的實(shí)例.? ? [asset.resourceLoader setDelegate:self.resourceLoaderDelegate queue:dispatch_get_main_queue()];

實(shí)現(xiàn)這兩個(gè)代理:

/**當(dāng)外界, 需要播放一段音頻資源是, 會(huì)跑一個(gè)請(qǐng)求, 給這個(gè)對(duì)象

?? 這個(gè)對(duì)象, 到時(shí)候, 只需要根據(jù)請(qǐng)求信息, 拋數(shù)據(jù)給外界

在這個(gè)里面做3件事情

?*/

- (BOOL)resourceLoader:(AVAssetResourceLoader*)resourceLoader shouldWaitForLoadingOfRequestedResource:(AVAssetResourceLoadingRequest*)loadingRequest{
? ? // 1. 填充相應(yīng)的信息頭信息

? ? // 計(jì)算總大小

? ? NSURL*url = loadingRequest.request.URL;

? ? long long totalSize = [XMGRemoteAudioFile cacheFileSize:url];

? ? loadingRequest.contentInformationRequest.contentLength = totalSize;

? ? NSString *contentType = [XMGRemoteAudioFile contentType:url];

? ? loadingRequest.contentInformationRequest.contentType = contentType;

? ? loadingRequest.contentInformationRequest.byteRangeAccessSupported = YES;


? ? // 2. 相應(yīng)數(shù)據(jù)給外界

? ? NSData *data = [NSData dataWithContentsOfFile:[XMGRemoteAudioFile cacheFilePath:url] options:NSDataReadingMappedIfSafe error:nil];


? ? longlongrequestOffset = loadingRequest.dataRequest.requestedOffset;

? ? NSIntegerrequestLength = loadingRequest.dataRequest.requestedLength;


? ? NSData*subData = [datasubdataWithRange:NSMakeRange(requestOffset, requestLength)];


? ? [loadingRequest.dataRequestrespondWithData:subData];


? ? // 3. 完成本次請(qǐng)求(一旦,所有的數(shù)據(jù)都給完了, 才能調(diào)用完成請(qǐng)求方法)

? ? [loadingRequestfinishLoading];

}

/** 取消請(qǐng)求*/

- (void)resourceLoader:(AVAssetResourceLoader*)resourceLoader didCancelLoadingRequest:(AVAssetResourceLoadingRequest*)loadingRequest


四:動(dòng)態(tài)下載,緩存數(shù)據(jù)

4.1創(chuàng)建一個(gè)管理文件的類,方便文件的操作,要先把下載中的文件放在temp文件夾,當(dāng)他的下載大小和響應(yīng)頭中返回給我們的資源總大小一致的時(shí)候我們要把他移動(dòng)到cache文件夾下保存.


用來執(zhí)行一些文件夾的操作.


就這寫相關(guān)操作吧.

文件夾操作實(shí)現(xiàn)就不寫了

4.2創(chuàng)建下載的類,主要用于下載文件,并且將文件以輸出流的方式輸出到指定目錄下,寫一個(gè)代理,將告訴外界已經(jīng)在下載了,然后由資源的代理在下載代理的視線中開始處理音頻播放的相關(guān)操作.從而實(shí)現(xiàn)了下載和播放的操作,自己要弄一個(gè)可變數(shù)組來存儲(chǔ)不斷返回來的loadingRequest,因?yàn)閘oadingRequest是一段一段的數(shù)據(jù)流.


MLAudioDownLoader的一些屬性和方法.

1>創(chuàng)建session對(duì)象

session

2>實(shí)現(xiàn)-(void)downloadWithUrl:(NSURL*)url offset:(longlong)offset方法

下載方法,下載的是一段數(shù)據(jù).

3>實(shí)現(xiàn)session的3個(gè)代理方法


需要自己創(chuàng)建一個(gè)輸出流


? ?在MLRemoteResourceLoaderDelegate中創(chuàng)建一個(gè)下載器downloader,delegate = self.實(shí)現(xiàn)代理方法,在代理方法中調(diào)用處理資源handeAllLoading的方法.

? 拿到資源的URL地址?

? NSURL*url = [loadingRequest.request.URLHTTPUrl];

請(qǐng)求的偏移量和當(dāng)前偏移量

1>在資源返回的代理方法中判斷是否有本地?cái)?shù)據(jù);

判斷本地是否存在

2>判斷是否有正在下載的數(shù)據(jù)

requestOffset是從哪里開始下載

3>判斷當(dāng)前的資源是否需要重新下載

3.1>當(dāng)資源請(qǐng)求, 開始點(diǎn) < 下載的開始點(diǎn)

3.2>?當(dāng)資源的請(qǐng)求, 開始點(diǎn) > 下載的開始點(diǎn) + 下載的長(zhǎng)度 + 一個(gè)你自己想要的緩存值


4>開始處理資源請(qǐng)求 (在下載過程當(dāng)中, 也要不斷的判斷)

處理請(qǐng)求的方法.

4.3注意事項(xiàng):假如在創(chuàng)建player的時(shí)候需要緩存,?NSURLComponents *components 的scheme需要修改成sreaming的流模式.自己寫一個(gè)URL分類,修改一下.

?著作權(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)容