iOS视频播放器之ZFPlayer剖析

这篇具有很好参考价值的文章主要介绍了iOS视频播放器之ZFPlayer剖析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1、引言


本文主要针对ZFPlayer的功能实现来剖析,以及总结一下大家遇到的问题和解决方案 首先ZFPlayer现在拥有的功能:

  • 支持横、竖屏切换,在全屏播放模式下还可以锁定屏幕方向

  • 支持本地视频、网络视频播放

  • 支持在TableviewCell播放视频

  • 左侧1/2位置上下滑动调节屏幕亮度(模拟器调不了亮度,请在真机调试)

  • 右侧1/2位置上下滑动调节音量(模拟器调不了音量,请在真机调试)

  • 左右滑动调节播放进度

  • 全屏状态下拖动slider控制进度,显示视频的预览图

  • 断点下载功能

  • 切换视频分辨率

ZFPlayer是对AVPlayer的封装,有人会问它支持什么格式的视频播放,问这个问题的可以自行搜索AVPlayer支持的格式。

跟AVPlayer联系密切的名词:

  • Asset:AVAsset是抽象类,不能直接使用,其子类AVURLAsset可以根据URL生成包含媒体信息的Asset对象。

  • AVPlayerItem:和媒体资源存在对应关系,管理媒体资源的信息和状态。

  • AVPlayerLayer: CALayer的subclass,它主要用来在iOS中播放视频内容

2、具体功能实现


2.1 通过一个网络链接播放视频

AVURLAsset *urlAsset = [AVURLAsset assetWithURL:videoURL];

// 初始化playerItem

AVPlayerItem *playerItem = [AVPlayerItem playerItemWithAsset:urlAsset];

// 也可以使用来初始化playerItem

// AVPlayerItem * playerItem = [AVPlayerItem playerItemWithURL:videoURL];

// 初始化Player

AVPlayer *player = [AVPlayer playerWithPlayerItem:self.playerItem];

// 初始化playerLayer

AVPlayerLayer *playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.player];

// 添加playerLayer到self.layer

[self.layer insertSublayer:self.playerLayer atIndex:0];

2.2 播放器的常用操作

  • 播放:

[player play];

需要注意的是初始化完player之后不一定会马上开始播放,需要等待player的状态变为ReadyToPlay才会进行播放。

  • 暂停:

[player pause];

2.3 播放多个items

这里我们有两种方式可以实现,一种是由你自行控制下一首歌曲的item,将其替换到当前播放的item

[player replaceCurrentItemWithPlayerItem:playerItem];

在iOS9后,AVPlayer的replaceCurrentItemWithPlayerItem方法在切换视频时底层会调用信号量等待然后导致当前线程卡顿,如果在UITableViewCell中切换视频播放使用这个方法,会导致当前线程冻结几秒钟。遇到这个坑还真不好在系统层面对它做什么,后来找到的解决方法是在每次需要切换视频时,需重新创建AVPlayer和AVPlayerItem。

另一种可以使用AVQueuePlayer播放多个items,AVQueuePlayer是AVPlayer的子类,可以用一个数组来初始化一个AVQueuePlayer对象。代码如下:

NSArray *items = <#An array of player items#>;

AVQueuePlayer *queuePlayer = [[AVQueuePlayer alloc] initWithItems:items];

和AVPlayer一样,直接调用play方法来播放,queue player顺序播放队列中的item,如果想要跳过一个item,播放下一个item,可以调用方法advanceToNextItem。

可以对队列进行插入和删除操作,调用方法insertItem:afterItem:, removeItem:, 和 removeAllItems。正常情况下当插入一个item之前,应该检查是否可以插入,通过使用canInsertItem:afterItem:方法,第二个参数传nil,代码如下:

AVPlayerItem *anItem = <#Get a player item#>;

if ([queuePlayer canInsertItem:anItem afterItem:nil]) {

[queuePlayer insertItem:anItem afterItem:nil];

}

2.4 seekToTime指定从某一秒开始播放

可以使用seekToTime:定位播放头到指定的时间,如下代码:

CMTime fiveSecondsIn = CMTimeMake(5, 1);

[player seekToTime:fiveSecondsIn];

seekTime:不能精确定位,如果需要精确定位,可以使用seekToTie:toleranceBefore:toleranceAfter:,代码如下:

CMTime fiveSecondsIn = CMTimeMake(5, 1);

[player seekToTime:fiveSecondsIn toleranceBefore:kCMTimeZero toleranceAfter:kCMTimeZero];

当tolerance=0的时候,framework需要进行大量解码工作,比较耗性能,所以,只有当你必须使用的时候才用这个方法,比如开发一个复杂的多媒体编辑应用,这需要精确的控制。

关于重播什么的就不用我多说了吧,点击重播seekToTime:kCMTimeZero。还有关于下次播放的时候从上次离开的那个时间开始播放,大家都有思路啦吧,当离开当前视频时候记录播放到哪一秒了,下次点开直接seekToTime到那一秒开始播放就好了嘛。

2.5 监听播放进度

使用addPeriodicTimeObserverForInterval:queue:usingBlock:来监听播放器的进度 (1)方法传入一个CMTime结构体,每到一定时间都会回调一次,包括开始和结束播放 (2)如果block里面的操作耗时太长,下次不一定会收到回调,所以尽量减少block的操作耗时 (3)方法会返回一个观察者对象,当播放完毕时需要移除这个观察者 添加观察者:

id timeObserve = [player addPeriodicTimeObserverForInterval:CMTimeMake(1.0, 1.0) queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {

float current = CMTimeGetSeconds(time);

float total = CMTimeGetSeconds(songItem.duration);

if (current) {

weakSelf.progress = current / total;

weakSelf.playTime = [NSString stringWithFormat:@"%.f",current];

weakSelf.playDuration = [NSString stringWithFormat:@"%.2f",total];

}

}];

移除观察者:

if (timeObserve) {

[player removeTimeObserver:_timeObserve];

timeObserve = nil;

}

2.6 监听改播放器状态

[playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];

播放器的三种状态,当playerItem的状态变为AVPlayerItemStatusReadyToPlay才会进行播放。

typedef NS_ENUM(NSInteger, AVPlayerItemStatus) {

AVPlayerItemStatusUnknown,

AVPlayerItemStatusReadyToPlay,

AVPlayerItemStatusFailed

};

播放完了需要移除观察者

[playerItem removeObserver:self forKeyPath:@"status"];

2.7 监听缓冲进度

[playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];

播放完了需要移除观察者

[playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];

2.8 监听网络缓冲状态

// 缓冲区空了,需要等待数据

[playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];

// 缓冲区有足够数据可以播放了

[playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];

播放完了需要移除观察者

[playerItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];

[playerItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];

2.9 监听AVPlayer播放完成通知

监听通知AVPlayerItemDidPlayToEndTimeNotification,来处理一些播放完的事情

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerItemDidReachEnd:) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];

2.10 系统音量相关

/**

* 获取系统音量

*/

- (void)configureVolume

{

MPVolumeView *volumeView = [[MPVolumeView alloc] init];

_volumeViewSlider = nil;

for (UIView *view in [volumeView subviews]){

if ([view.class.description isEqualToString:@"MPVolumeSlider"]){

_volumeViewSlider = (UISlider *)view;

break;

}

}

// 使用这个category的应用不会随着手机静音键打开而静音,可在手机静音下播放声音

NSError *setCategoryError = nil;

BOOL success = [[AVAudioSession sharedInstance]

setCategory: AVAudioSessionCategoryPlayback

error: &setCategoryError];

if (!success) { /* handle the error in setCategoryError */ }

// 监听耳机插入和拔掉通知

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:nil];

}

/**

* 耳机插入、拔出事件

*/

- (void)audioRouteChangeListenerCallback:(NSNotification*)notification

{

NSDictionary *interuptionDict = notification.userInfo;

NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];

switch (routeChangeReason) {

case AVAudioSessionRouteChangeReasonNewDeviceAvailable:

// 耳机插入

break;

case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:

{

// 耳机拔掉

// 拔掉耳机继续播放

[self play];

}

break;

case AVAudioSessionRouteChangeReasonCategoryChange:

// called at start - also when other audio wants to play

NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");

break;

}

}

设置系统音量

// 0 ... 1.0的数值, 1.0是最大的声音.

self.volumeViewSlider.value = ...

2.11 屏幕亮度相关

// 0 ... 1.0的数值, 1.0是最大的亮度.

[UIScreen mainScreen].brightness = ...

2.12 屏幕旋转相关

苹果手机除iPhone 4s(320*480)屏幕宽高比不是16:9外,其他都为16:9,所以横竖屏可以这样实现,这里必须使用autolayout,这里提供两种方法实现:

  • 使用Xib或者Storyboard的话,必须把播放器view的宽高比设置成16:9,4s的话可以单独适配加约束(使用sizeClasses)

  • 使用masonry,具体代码如下:

[self.playerView mas_makeConstraints:^(MASConstraintMaker *make) {

make.top.equalTo(self.view).offset(20);

make.left.right.equalTo(self.view);

// 注意此处,宽高比16:9优先级比1000低就行,在因为iPhone 4S宽高比不是16:9

make.height.equalTo(self.playerView.mas_width).multipliedBy(9.0f/16.0f).with.priority(750);

}];

关于屏幕旋转可以这样强制让屏幕转屏,有人会问了,在我demo中为啥能转屏,而集成到自己项目中不能转屏,我可以明确的告诉你,是你们项目的横屏给禁止掉了,你可以看一下这里是否打钩啦:

zfplayer使用,音视频开发,ios,swift,音视频,Powered by 金山文档

设备方向

有人又会问了,我们想实现这么个需求,只有在播放器页面支持横屏,其他页面不支持横屏。好了,那下边我来告诉怎么实现,首先上图中的横屏必须勾选,其次在你需要转屏的ViewController中来实现三个方法:

// 是否支持自动转屏

- (BOOL)shouldAutorotate

{

// 调用ZFPlayerSingleton单例记录播放状态是否锁定屏幕方向

return !ZFPlayerShared.isLockScreen;

}

// 支持哪些转屏方向

- (UIInterfaceOrientationMask)supportedInterfaceOrientations

{

return UIInterfaceOrientationMaskAllButUpsideDown;

}

// 页面展示的时候默认屏幕方向(当前ViewController必须是通过模态ViewController(模态带导航的无效)方式展现出来的,才会调用这个方法)

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation

{

return UIInterfaceOrientationPortrait;

}

ZFPlayer内部已经实现屏幕旋转的分类(UITabBarController+ZFPlayerRotation.h UINavigationController+ZFPlayerRotation UIViewController+ZFPlayerRotation),不管你项目的rootViewController的是UINavigationController还是UITabBarController,则只需要在支持除竖屏以外的控制器实现上边三个方法就行。

下边来说说强制屏幕旋转,即使用户的手机锁定了屏幕方法,调用这个方法照样可以旋转:

/**

* 强制屏幕转屏

*

* @param orientation 屏幕方向

*/

- (void)interfaceOrientation:(UIInterfaceOrientation)orientation

{

// arc下

if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {

SEL selector = NSSelectorFromString(@"setOrientation:");

NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];

[invocation setSelector:selector];

[invocation setTarget:[UIDevice currentDevice]];

int val = orientation;

// 从2开始是因为0 1 两个参数已经被selector和target占用

[invocation setArgument:&val atIndex:2];

[invocation invoke];

}

/*

// 非arc下

if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) {

[[UIDevice currentDevice] performSelector:@selector(setOrientation:)

withObject:@(orientation)];

}

// 直接调用这个方法通不过apple上架审核

[[UIDevice currentDevice] setValue:[NSNumber numberWithInteger:UIInterfaceOrientationLandscapeRight] forKey:@"orientation"];

*/

}

监听设备旋转通知,来处理一些UI显示问题

[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];

[[NSNotificationCenter defaultCenter] addObserver:self

selector:@selector(onDeviceOrientationChange)

name:UIDeviceOrientationDidChangeNotification

object:nil

];

原文链接:https://www.jianshu.com/p/5566077bb

★文末名片可以免费领取音视频开发学习资料,内容包括(FFmpeg ,webRTC ,rtmp ,hls ,rtsp ,ffplay ,srs)以及音视频学习路线图等等。

见下方!↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓文章来源地址https://www.toymoban.com/news/detail-664704.html

到了这里,关于iOS视频播放器之ZFPlayer剖析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Flutter视频播放器在iOS端和Android端都能实现全屏播放

    Flutter开发过程中,对于视频播放的三方组件有很多,在Android端适配都挺好,但是在适配iPhone手机的时候,如果设置了 UIInterfaceOrientationLandscapeLeft 和 UIInterfaceOrientationLandscapeRight 都为false的情况下,无法做到全屏播放,因为FLutter的 SystemChrome.setPreferredOrientations 方法不适配iOS端

    2024年02月05日
    浏览(47)
  • ffplay播放器剖析(1)----数据结构剖析

    ffplay是FFmpeg源码提供的一个播放器,它是由FFmpeg和SDL的API实现的播放器,对后续播放器的二次开发有着借鉴意义,比如哔哩哔哔哩的ijkplayer. 根据代码可以看出struct MyAVPacketList是一个AVPacket的一个节点,而PacketQueue是用管理这群节点的队列 接下来看一下操作这个队列的一些函数 3

    2024年02月16日
    浏览(45)
  • ffplay播放器剖析(2)----读取线程刨析

    avformat_alloc_context创建上下文 ic-interupt_callback.callback=decode_interrupt_cb 绑定回调函数 avformat_open_input 打开媒体文件 avformat_find_stream_info 读取媒体文件的包获取更多的stream信息 检测指定播放起始时间,如果seek到指定位置就使用avformat_seek_file 检查查找AVStream,将对应的index值记录到st

    2024年02月16日
    浏览(71)
  • 【Unity】代码控制视频的播放(视频播放器-更新)

     结果如上图,之前写过一个使用代码控制视频播放器的Demo,但是好多小伙伴说我附带的链接没法下载,这次我直接做一个完整版的,不用下载,照着一步一步做就能做出来。 之前写了如何设置RawImage进行自动播放,大家可以看一下基础操作这篇文章:,大佬勿怪。 【Unity】

    2024年02月09日
    浏览(59)
  • 【Xgplayer】xgplayer基本使用 | xgplayer使用 | 超好的前端视频播放器 | xgplayer前端最好视频播放器

    开发团队——字节跳动,字节跳动出品,必属精品。 xgplayer是一个超级牛逼的前端视频播放器,以下几个观点足以证明它的强大 大厂出品——稳 简洁 实用 优雅 文档清晰明了 支持弹幕 对移动端非常友好 自定义插件方便且强大 强就是了 xgplayer官网-点我进入 备用地址 https:

    2024年02月06日
    浏览(77)
  • 阿里云视频播放器

    阿里云的视频播放器类比 HTML5视频播放标签video和音频播放标签audio标签 只是阿里云视频播放器是针对阿里云上传的视频进行多功能配置和操作。 最终:阿里云视频播放器就是基于阿里云视频的前端播放标签 阿里云播放器 SDK ( ApsaraVideo Player SDK)是阿里视频服务的重要一环

    2023年04月09日
    浏览(62)
  • 学习笔记(1)——粤嵌gec6818实现电子相册,音乐播放器,视频播放器。

    (1)设计一个初始界面,并且设置电子相册,音乐播放器,视频播放器三个触摸按键。 (2)电子相册——能够实现相册的幻灯片功能,实现相册左右滑动切换相片。 (3)音乐播放器实现——切歌,播放和暂停功能。 (4)视频播放器实现——播放、暂停、音量大小、快进倒

    2024年02月11日
    浏览(61)
  • 电脑自带播放器怎么倍速播放视频

    1.选择视频文件,鼠标右击在打开方式中选择Windows Media Player播放器打开视频 2. 在Windows Media Player视频播放器中鼠标右击选择“播放速度设置”,再选择增强功能即可调整播放速度了。    

    2024年02月11日
    浏览(50)
  • 【Vue】播放flv格式视频(flv.js视频播放器)

     图片来源:HTTP-FLV直播初探   github地址:GitHub - bilibili/flv.js: HTML5 FLV Player npm install flv.js --save 封装一个组件flvVideo hasAudio设置为true就不展示。。。不知道为啥~ home.vue 参考:Vue 中使用flv.js视频播放器

    2024年02月14日
    浏览(78)
  • IOS开发之——音乐播放器-资源和Model(02)

    音乐播放器资源文件 资源文件转换为对应的Model类 2.1 图片资源 Images.xcassets(启动图标/播放按钮/默认背景等) 2.2 Resources(歌曲资源) Images(音乐大图) Lrcs(音乐歌词文件) MP3s(本地歌曲文件) Musics.plist(所有歌词信息,转换为HMMusic Model) 2.3 查看Copy Bundle Resources Targets——Build Phases——

    2023年04月12日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包