最近公司快不行了,又有空閒的時間了😳,對以前作的一些功能作一些總結,微信小視頻,曾經熱火朝天的功能,許多社交類app都想着模仿。下面就來解析下小視頻功能特色。 1.小視頻沒有聲音 2.小視頻在cell中無限循環播放 3.性能要求,滑動須要順暢(線程設計)。ios
最先接觸iOS,我只知道播放視頻一般有兩種方式,一種是 AVPlayer,另外一種是MPMoviePlayerController 。如今 ios9以後蘋果已推薦播放視頻使用 AVPlayer。git
下面介紹下簡單的說下 AVPlayer 視頻播放器使用時的相關知識,具體的參見官方文檔github
//建立一個AVPlayer播放類 @property(nonatomic,strong) AVPlayer *player; //AVPlayerItem(多媒體資源) @property(nonatomic,strong) AVPlayerItem *playerItem; //AVAsset(音視頻當中單個資源,例如聲道,影片) @property (nonatomic, strong) AVAsset
AVPlayer功能很強大,音視頻均可以播放,但像小視頻功能咱們只須要他的視頻功能, 音頻功能不須要,若是小視頻功能用AVPlayer來實現,系統開銷可能就有點浪費了,由於AVPlayer實現了Video+Audio ,並且AVPlayer的音頻對AudioSession也有影響,若是app其餘地方有使用到聲音的,須要注意它的使用了。服務器
後來追求性能,發現了AVAssetReader類 AVAssetReader用於從AVAsset資源中讀取媒體樣本,能夠讀取出視頻和音頻微信
//從媒體中獲得聲音軌道 AVMediaTypeVideo 視頻 AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeAudio] firstObject];
AVAssetReaderOutput
輸出資源並經過copyNextSampleBuffer方法將咱們須要的數據給弄一份出來。注意讀取的過程是分幀(音頻是分塊)讀取,並非一次性將將全部數據讀取去完畢。結束時,AVAssetReader的status
屬性 會變成AVAssetReaderStatusCompleted
,經過此屬性來判斷是否讀取完畢。app
//從媒體中獲得視頻軌道 AVMediaTypeAudio 音頻 AVAssetTrack *track = [[self.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; //讀取配置 NSDictionary *setting = @{ (id)kCVPixelBufferPixelFormatTypeKey:@(kCVPixelFormatType_32BGRA), (id)kCVPixelBufferWidthKey:@(self.size.width), (id)kCVPixelBufferHeightKey:@(self.size.height), }; //讀取輸出,在相應的軌道和輸出對應格式的數據 self.assetReaderOutput = [[AVAssetReaderTrackOutput alloc] initWithTrack:track outputSettings:setting]; //賦給讀取並開啓讀取 if ([self.assetReader canAddOutput:self.assetReaderOutput]) { [self.assetReader addOutput:self.assetReaderOutput]; } [self.assetReader startReading];//開始讀取
小視頻功能能夠經過AVPlayer和AVAssetReader 兩種途徑實現, 我寫了個簡單的demo,但裏面仍是有不少學問的。下面簡述下demo中的3中實現方式:ide
實現方式1:用過AVPlayer的 可能都遇到過這麼一個現象:黑屏。黑屏的緣由是app最多支持16個AVPlayerLayer同時存在,等到17個的時候就會出現黑屏,解決這個問題須要及時釋放AVPlayer相關資源。 若是一屏須要展現的播放個數大於16,那麼AVPlayer就不適合用來實現小視頻,固然實際過程當中1屏幕就最多6,7我的視頻同時播放了。oop
實現方式2:利用AVAssetReader 中的獲取到的CGImageRef 將每一幀都放到layer.contents中展現性能
self.videoImageView.layer.contents = (__bridge id)(imageRef);
實現方式3:實際開發中 gif圖 你能夠是服務器下載下來的,也能夠是經過AVAssetReader 獲取到所須要的UIImages,製做成gif,而後保存展現。atom
以上3中方式,1的性能較差。2,3各有優勢。
這3種方式都有一個最大的特色,cell滑動過程當中不作視頻的加載,這樣作爲了滑動更流暢,結束的時候再加載當前屏幕中的cell視頻。對於gif和customPlayerLayer若是想要修改爲滑動時播放,須要修改timer的runloop的model。
//cell 不在可視區域內 能夠暫停播放 釋放資源 - (BOOL)currentCellIsNotShowedInScreen { UITableView *table; for (UIView* next = [self superview]; next; next = next.superview) { UIResponder* nextResponder = [next nextResponder]; if ([nextResponder isKindOfClass:[UITableView class]]) { table = (UITableView *)nextResponder; break; } } if (table) { CGRect cellR = [table rectForRowAtIndexPath:self.currentIndexPath]; if ((table.contentOffset.y + table.frame.size.height) < CGRectGetMinY(cellR) || table.contentOffset.y > CGRectGetMaxY(cellR)) { return true; } } return false; }
demo 總結:demo中cell元素比較簡單,但也能比較不一樣方式的性能差別,視頻播放其實並不難實現,主要是注意性能,利用線程的特性,處理好視頻播放。視頻播放確定還有其餘實現方式。