那些年,追逐過的小視頻

最近公司快不行了,又有空閒的時間了😳,對以前作的一些功能作一些總結,微信小視頻,曾經熱火朝天的功能,許多社交類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元素比較簡單,但也能比較不一樣方式的性能差別,視頻播放其實並不難實現,主要是注意性能,利用線程的特性,處理好視頻播放。視頻播放確定還有其餘實現方式。

相關文章
相關標籤/搜索