博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
分享一个功能很全的视频播放器
阅读量:5816 次
发布时间:2019-06-18

本文共 9998 字,大约阅读时间需要 33 分钟。

基于AVPlayer.

极速初始化, 不阻塞主线程.

这个应该是目前基于AVPlayer的播放器中, 功能最全的一个吧.


使用

pod 'SJVideoPlayer' 复制代码

功能

  1. 支持
  2. 支持
  3. 支持
  4. 支持
  5. 支持
  6. 支持
  7. 支持
  8. 支持
  9. 支持
  10. 本地化处理.
  11. 可以

只需pod到项目中即可带全屏手势

为啥自定义手势?

在使用原生手势返回时, 当前播放的视频会出现卡帧的问题. 原因我不太清楚. 我查看了腾讯视频和爱奇艺等App均为自己实现的手势返回.

当时使用了一个全屏返回的三方库. 是截屏返回的, 发现存在两个问题: 一是截屏耗时, 二是视频部分截取不了(黑色的) 由于我们起步8.0, 我便使用了新的APIsnapshotViewAfterScreenUpdates:(这个接口其实7.0就有了)来替换截屏的方式, 直接使用视图快照, 这个接口一举两得, 不仅速度快, 而且视频播放也可以截取到. 但是快照是一个view, 并不是image, 原来的三方库截屏方式无法使用, 于是我重新撸了一个全屏手势.

手势使用

pod 'SJFullscreenPopGesture'复制代码

手势功能介绍

// default is `SJFullscreenPopGestureType_EdgeLeft`.typedef NS_ENUM(NSUInteger, SJFullscreenPopGestureType) {    SJFullscreenPopGestureType_EdgeLeft,    // 默认, 屏幕左边缘触发手势    SJFullscreenPopGestureType_Full,        // 全屏触发手势};复制代码
  1. 目前有两种:

/// 将要拖拽@property (nonatomic, copy, readwrite, nullable) void(^sj_viewWillBeginDragging)(__kindof UIViewController *vc);/// 拖拽中@property (nonatomic, copy, readwrite, nullable) void(^sj_viewDidDrag)(__kindof UIViewController *vc);/// 结束拖拽@property (nonatomic, copy, readwrite, nullable) void(^sj_viewDidEndDragging)(__kindof UIViewController *vc);复制代码
  1. 等 ...

网络状态切换提示

网络状态提示就是当网络状态变更时, 播放器显示一行字或者图片等, 提示用户网络变更了.

对于默认提示的内容(可自定义), 我做了本地化处理, 根据 localLanguage 自动选择一种语言提示(中文/繁体/英文), 如下:

关于旋转我想吐槽一下: 大部分三方库的旋转是直接把播放器添加到window的中心, 再做一个transform动画.. . 旋转过程中, 界面会闪一下, 这个体验几次眼就会累... 为了解决这个问题, 我又写了一个在添加之前, 我做了相应的坐标转换, 使播放器添加到window上时, 还处于原始位置. 然后去做transform动画并更新bounds和center.

播放器除了自动旋转之外, 您可以随意的控制旋转. 支持的方向如下:

/// 竖屏 || (左右)横屏/// Auto rotate supported orientationtypedef NS_ENUM(NSUInteger, SJAutoRotateSupportedOrientation) {    SJAutoRotateSupportedOrientation_All,    SJAutoRotateSupportedOrientation_Portrait = 1 << 0,    SJAutoRotateSupportedOrientation_LandscapeLeft = 1 << 1,  // UIDeviceOrientationLandscapeLeft    SJAutoRotateSupportedOrientation_LandscapeRight = 1 << 2, // UIDeviceOrientationLandscapeRight};复制代码

关于旋转的一些方法:

/** Autorotation. Animated. */- (void)rotate;/** Rotate to the specified orientation.  @param orientation     Any value of SJOrientation. @param animated        Whether or not animation. */- (void)rotate:(SJOrientation)orientation animated:(BOOL)animated;/** Rotate to the specified orientation.  @param orientation     Any value of SJOrientation. @param animated        Whether or not animation. @param block           The block invoked when player rotated. */- (void)rotate:(SJOrientation)orientation animated:(BOOL)animated completion:(void (^ _Nullable)(__kindof SJBaseVideoPlayer *player))block;复制代码

旋转的一些设置

/** The block invoked When player will rotate.  readwrite. */@property (nonatomic, copy, nullable) void(^willRotateScreen)(__kindof SJBaseVideoPlayer *player, BOOL isFullScreen);/** The block invoked when player rotated.  readwrite. */@property (nonatomic, copy, nullable) void(^rotatedScreen)(__kindof SJBaseVideoPlayer *player, BOOL isFullScreen);复制代码

这几个功能都已封装在默认的控制层中, 并且相应的提示文本也做了本地化处理

方法如下:

- (UIImage * __nullable)screenshot;- (void)screenshotWithTime:(NSTimeInterval)time                completion:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, UIImage * __nullable image, NSError *__nullable error))block;- (void)screenshotWithTime:(NSTimeInterval)time                      size:(CGSize)size                completion:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, UIImage * __nullable image, NSError *__nullable error))block;/** export session.  @param beginTime           unit is sec. @param endTime             unit is sec. @param presetName 	        default is `AVAssetExportPresetMediumQuality`. @param progressBlock       progressBlock @param completion 	        completion @param failure 	        failure */- (void)exportWithBeginTime:(NSTimeInterval)beginTime                    endTime:(NSTimeInterval)endTime                 presetName:(nullable NSString *)presetName                   progress:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, float progress))progressBlock                 completion:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, NSURL *fileURL, UIImage *thumbnailImage))completion                    failure:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, NSError *error))failure;- (void)cancelExportOperation;- (void)generateGIFWithBeginTime:(NSTimeInterval)beginTime                        duration:(NSTimeInterval)duration                        progress:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, float progress))progressBlock                      completion:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, UIImage *imageGIF, UIImage *thumbnailImage, NSURL *filePath))completion                         failure:(void(^)(__kindof SJBaseVideoPlayer *videoPlayer, NSError *error))failure;- (void)cancelGenerateGIFOperation;复制代码

目前提示文本支持 NSString(可自定义字体) 以及 NSAttributedString. 正如前面看到的网路状态提示, 就是使用的这些方法, 方法如下:

/** The middle of the player view shows the specified title. duration default is 1.0. @param title       prompt. */- (void)showTitle:(NSString *)title;/** The middle of the view shows the specified title. @param title       prompt. @param duration    prompt duration. duration if value set -1, prompt will always show. */- (void)showTitle:(NSString *)title duration:(NSTimeInterval)duration;- (void)showTitle:(NSString *)title duration:(NSTimeInterval)duration hiddenExeBlock:(void(^__nullable)(__kindof SJBaseVideoPlayer *player))hiddenExeBlock;- (void)showAttributedString:(NSAttributedString *)attributedString duration:(NSTimeInterval)duration;- (void)showAttributedString:(NSAttributedString *)attributedString duration:(NSTimeInterval)duration hiddenExeBlock:(void(^__nullable)(__kindof SJBaseVideoPlayer *player))hiddenExeBlock;/** Hidden Prompt. */- (void)hiddenTitle;复制代码

播放器的手势介绍

  • 默认会存在四种手势: Single Tap, double Tap, Pan, Pinch.
  1. SingleTap 单击手势 当用户单击播放器时, 播放器会调用显示或隐藏控制层的相关代理方法. 见 controlLayerDelegate

  2. DoubleTap 双击手势 双击会触发暂停或播放的操作

  3. Pan 移动手势 当用户水平滑动时, 会触发控制层相应的代理方法. 见 controlLayerDelegate 当用户垂直滑动时, 如果在屏幕左边, 则会触发调整亮度的操作, 并显示亮度提示视图. 如果在屏幕右边, 则会触发调整声音的操作, 并显示系统音量提示视图

  4. Pinch 捏合手势 当用户做放大或收缩触发该手势时, 会设置播放器显示模式AspectAspectFill.


关于自定义控制层的相关协议

下面介绍如何自定义一个控制层, 相关的方法后面, 我都会跟上一个相应实现.

数据源介绍

@protocol SJVideoPlayerControlLayerDataSource 
@required- (UIView *)controlView;- (BOOL)controlLayerDisappearCondition;- (BOOL)triggerGesturesCondition:(CGPoint)location;@optional- (void)installedControlViewToVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer;@end复制代码
  • - (UIView *)controlView;
  • - (BOOL)controlLayerDisappearCondition;
  • - (BOOL)triggerGesturesCondition:(CGPoint)location;

代理介绍

控制层的显示与隐藏
@required/**Objective-C This method will be called when the control layer needs to be appear. You should do some appear work here. */- (void)controlLayerNeedAppear:(__kindof SJBaseVideoPlayer *)videoPlayer;/** This method will be called when the control layer needs to be disappear. You should do some disappear work here. */- (void)controlLayerNeedDisappear:(__kindof SJBaseVideoPlayer *)videoPlayer;复制代码

播放器会接管控制层的显示与隐藏, 也就是当SingleTap时播放器会调用controlLayerNeedAppear: 播放器会在一段时间后调用隐藏controlLayerNeedDisappear:.

  • controlLayerNeedAppear:
  • controlLayerNeedDisappear:
在UITableView或者CollectionView中播放时的代理回调
- (void)videoPlayerWillAppearInScrollView:(__kindof SJBaseVideoPlayer *)videoPlayer;- (void)videoPlayerWillDisappearInScrollView:(__kindof SJBaseVideoPlayer *)videoPlayer;复制代码
  • videoPlayerWillAppearInScrollView:

  • videoPlayerWillDisappearInScrollView:

准备播放一个资源时以及播放状态/播放进度的回调
- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer prepareToPlay:(SJVideoPlayerURLAsset *)asset;- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer stateChanged:(SJVideoPlayerPlayState)state;- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer        currentTime:(NSTimeInterval)currentTime currentTimeStr:(NSString *)currentTimeStr          totalTime:(NSTimeInterval)totalTime totalTimeStr:(NSString *)totalTimeStr;复制代码
  • videoPlayer:prepareToPlay:
  • videoPlayer:stateChanged:
  • 第三个方法
缓存的状态回调
- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer loadedTimeProgress:(float)progress;- (void)startLoading:(__kindof SJBaseVideoPlayer *)videoPlayer;- (void)cancelLoading:(__kindof SJBaseVideoPlayer *)videoPlayer;- (void)loadCompletion:(__kindof SJBaseVideoPlayer *)videoPlayer;复制代码
  • videoPlayer:loadedTimeProgress:
  • startLoading:
  • cancelLoading:
  • loadCompletion:
锁屏的回调以及一个只有在锁屏状态下才触发的单击手势
- (void)lockedVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer;- (void)unlockedVideoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer;- (void)tappedPlayerOnTheLockedState:(__kindof SJBaseVideoPlayer *)videoPlayer;复制代码
  • lockedVideoPlayer:
  • unlockedVideoPlayer:
  • tappedPlayerOnTheLockedState:
屏幕旋转的回调
- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer willRotateView:(BOOL)isFull;- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer didEndRotation:(BOOL)isFull;复制代码
  • videoPlayer:willRotateView:
  • videoPlayer:didEndRotation:
静音 / 音量 / 亮度 / 调速的回调
- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer muteChanged:(BOOL)mute;- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer volumeChanged:(float)volume;- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer brightnessChanged:(float)brightness;- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer rateChanged:(float)rate;复制代码
  • videoPlayer:muteChanged:
  • videoPlayer:volumeChanged:
  • videoPlayer:brightnessChanged:
  • videoPlayer:rateChanged:
水平方向手势触发的回调
/// 水平方向开始拖动.- (void)horizontalDirectionWillBeginDragging:(__kindof SJBaseVideoPlayer *)videoPlayer;/** @param progress drag progress */- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer horizontalDirectionDidMove:(CGFloat)progress;/// 水平方向拖动结束.- (void)horizontalDirectionDidEndDragging:(__kindof SJBaseVideoPlayer *)videoPlayer;复制代码
  • horizontalDirectionWillBeginDragging:
  • videoPlayer:horizontalDirectionDidMove:
  • horizontalDirectionDidEndDragging:
Network
/// 网络状态变更- (void)videoPlayer:(__kindof SJBaseVideoPlayer *)videoPlayer reachabilityChanged:(SJNetworkStatus)status;复制代码
  • videoPlayer:reachabilityChanged:

Demo

项目地址: https://github.com/changsanjiang/SJVideoPlayer

我的邮箱: changsanjiang@gmail.com

如果您有什么建议, 望请联系我!

转载地址:http://ifhbx.baihongyu.com/

你可能感兴趣的文章
network
查看>>
SettingsNotePad++
查看>>
centos7安装cacti-1.0
查看>>
3个概念,入门 Vue 组件开发
查看>>
没有JS的前端:体积更小、速度更快!
查看>>
数据指标/表现度量系统(Performance Measurement System)综述
查看>>
GitHub宣布推出Electron 1.0和Devtron,并将提供无限制的私有代码库
查看>>
论模式在领域驱动设计中的重要性
查看>>
Spring Web Services 3.0.4.RELEASE和2.4.3.RELEASE发布
查看>>
有关GitHub仓库分支的几个问题
查看>>
云原生的浪潮下,为什么运维人员适合学习Go语言?
查看>>
EAServer 6.1 .NET Client Support
查看>>
锐捷交换机密码恢复(1)
查看>>
Kali linux virtualbox rc=1908 错误解决办法
查看>>
linux软件包管理之三(源代码安装)
查看>>
数据库三范式是什么?
查看>>
[转载]设置Ubuntu自动连接无线,无须再输入密钥环和无线密码
查看>>
Apache配置
查看>>
Ext gridPanel 单元格数据的渲染
查看>>
Android SDK 的下载代理
查看>>