美文网首页iOS控件
iOS视频播放:预览播放视频前面N秒的设计

iOS视频播放:预览播放视频前面N秒的设计

作者: 双鱼子曰1987 | 来源:发表于2020-11-04 09:16 被阅读0次

    一、需求

    • 1、视频播放列表中,对于曝光的视频,需要播放视频前面N秒;
    • 2、如果同时曝光多个视频,则视频循环播放视频。如A、B、C三个视频同时都在屏幕内,那么依照曝光的先后顺序播放A-B-C;
    • 3、视频的显示格式有两种:一个Cell显示一个视频;一个Cell显示两个视频。
    • 4、只有当上一个cell的视频全部播放完成后,才会播放下一个Cell的视频。

    二、设计

    2.1、设计要求

    • 使用系统AVPlayer、AVPlayerLayer、AVPlayerItem来播放视频。
    • 多个视频,同时只有一个Player存在。
    • Cell的曝光控制逻辑。
    • 使用数据驱动渲染Cell(DataItem唯一,Cell复用)。
    • 通用组件设计标准,多个页面可以简单集成使用。

    2.2、类图

    短视频预览控制~.png

    2.3、设计说明

    • 采用数据驱动框架RETableViewManager,具体的搜索GitHub。
    • RETBL_ViewController 信息流列表,持有DataItemList,将其交给RETableViewManager渲染出cell;每个DataItem对应列表每一条数据,且唯一,但Cell复用,根据DataItem渲染页面。RETBL_ViewController 持有VideoPlayerController,功能如下。
    @interface RETBL_ViewController : NSObject
    @property (nonatomic, strong) VideoPlayerController *videoPlayerManager;
    @property (nonatomic, strong) RETableViewManager *tblViewManager;
    
    // 曝光的时候
    [self.videoPlayerManager addVideoIntoList:item];
    
    // cell 消失
    [self.videoPlayerManager removeVideoFromList:item];
    @end
    
    • ShortVideoPlayerViewDelegate 协议接口,VideoPlayerController 可以通过 id< ShortVideoPlayerViewDelegate> obj(本例是DataItem) 向外部获取VideoUrlVideoContainerView(AVPlayerLayer的播放容器View)。
    @protocol VideoPlayerPreviewDelegate <NSObject>
    @optional
    - (NSArray<NSString *> *)videoUrlList;
    - (NSArray<UIView *> *)videoContainerViewList;
    @end
    
    • 代理模式,CellDataItem 实现 ShortVideoPlayerViewDelegate接口,并且DataItem 有代理属性cDelegate 指向Cell。这样设计之后,针对信息流每一个Cell中,DataItem提供VideoUrl;又通过DataItem的代理向Cell获取VideoContainerView
    @interface VideosPreviewTableCell : RETableCell < ShortVideoPlayerViewDelegate >
    @end
    @implementation VideosPreviewTableCell
    #pragma mark - ZTHVideoPlayerPreviewDelegate
    - (NSArray<UIView *> *)videoContainerViewList {
        return viewList; // 一个cell可能有多个视频view
    }
    @end
    
    @interface VideosPreviewTableCellItem : RETableCellItem < ShortVideoPlayerViewDelegate >
    @property (nonatomic, weak) id< ShortVideoPlayerViewDelegate > cDelegate;
    @end
    @implementation VideosPreviewTableCellItem
    #pragma mark - ZTHVideoPlayerPreviewDelegate
    - (NSArray<NSString *> *)videoUrlList {
        return urlList;
    }
    
    - (NSArray<UIView *> *)videoContainerViewList {
        if (self.cDelegate && [self.cDelegate respondsToSelector:@selector(videoContainerViewList)]) {
            return [self.cDelegate videoContainerViewList];
        }
        
        return nil;
    }
    @end
    
    • VideoPlayerController
      用来管理哪些DataItem需要播放,当cell曝光%50以上,则加入播放队列;当Cell不可见从播放队列中移除。
    @interface VideoPlayerController ()
    /// 由于Player的ContentView,可能被复用的,如在Cell中使用。但是每个Id
    @property (nonatomic, strong) NSMutableArray<id< ShortVideoPlayerViewDelegate >> *videoItemList;
    @property (nonatomic, strong) ShortVideoPlayerCenter *currentPlayerCenter;
    @property (nonatomic, strong) GCDTimer *timer;
    @end
    
    @implementation VideoPlayerController
    // timer回调函数,播放videoItemList的控制
    - (void)videoPlayControlLoopHandler {
      ...
    }
    @end
    

    同时,内部设计一个定时器1s,定时器函数videoPlayControlLoopHandler主要代码是,检查VideoPlayer播放器状态是否可以加载下一个DataItem,可以则加载下一个,播放其对应视频。

    采用定时器的原因在于,将列表DataITem播放与否 和 视频播放逻辑剥离,彼此互不影响。类似RunLoop循环机制,将需要播放的DataItem放入队列中,内部定时循环是否启动播放。而不是来一个就马上播放一个,消失一个立即暂停,当列表快速滚动的时候,会频繁让播放器在播放和暂停不断切换,会影响性能。

    当然,后续的优化中,可以加入列表的ScrollRate,当滚动太快的时候,暂停播放逻辑提高性能。也可以考虑加入displaylink,当有空余能力的时候,才启动播放逻辑。

    • ShortVideoPlayerCenter 专门负责每个DataItem对应视频的播放。
      播放某个DataItem的时候,通过id< ShortVideoPlayerViewDelegate > obj(本例即DataItem自身),获取videoUrlList 和 viewList,保存在ShortVideoPlayerUnit实例中。
      VideoPlayer播放时候,取出videoUrl 和 对应的containerView(将PlayerLayer添加上去);播放N秒后,播放当前DataItem的下一个视频。如果全部播放结束,改变播放器状态允许加载下一个。
    @interface ShortVideoPlayerCenter ()
    /// 由于Player的ContentView,可能被复用的,如在Cell中使用。但是每个Id
    @property (nonatomic, strong) EasyVideoPlayer *videoPlayer;
    @property (nonatomic, strong) ShortVideoPlayerUnit *playerUnit;
    @end
    
    @implementation ShortVideoPlayerCenter
    // timer回调函数,播放videoItemList的控制
    - (void)videoPlayControlLoopHandler {
      ...
    }
    @end
    
    • ShortVideoPlayerUnit 存储DataItem 对应的 videoUrlListviewList;原则上一个url对应一个view。
      ShortVideoPlayerUnit 的设计主要考虑的是,播放逻辑中的可变和不可变剥离。VideoPlayerPlayerLayer 和 播放逻辑控制,是不变的部分;但播放数据是经常异动,且urlview都不同,因此封装起来,好管理这部分数据的创建和销毁。
    @interface ShortVideoPlayerUnit : NSObject
    @property (nonatomic, strong) NSArray<NSString *> *videoUrlList;
    @property (nonatomic, strong) NSArray<UIView *> *videoViewList;
    @end
    

    三、总结

    • 通用性能力,需要“视频预览”能力的列表,只需要让数据源和Cell实现ShortVideoPlayerViewDelegate,提供对应url和view,然后交给VideoPlayerController进行管理即可,然后在Cell曝光和消失的时候添加和移除数据源即可。
    • 由于考虑到NSTimer强引用性,需要手动是否timer否则会导致循环引用。因此这边使用GCDTimer
    • 使用Timer左右loop动力驱动,可以根据具体的需求切换为DisplayLink,然后加入scrollRate滚动速率等因此,进一步提高性能。

    其他

    • 上面类的命名已经非项目命名,叫法不甚合适,本篇旨在说明设计意图。

    相关文章

      网友评论

        本文标题:iOS视频播放:预览播放视频前面N秒的设计

        本文链接:https://www.haomeiwen.com/subject/hukivktx.html