那些年,追逐过的小视频

最近公司快不行了,又有空闲的时间了😳,对以前作的一些功能作一些总结,微信小视频,曾经热火朝天的功能,许多社交类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元素比较简单,但也能比较不一样方式的性能差别,视频播放其实并不难实现,主要是注意性能,利用线程的特性,处理好视频播放。视频播放确定还有其余实现方式。

相关文章
相关标签/搜索