从AVPlayer的AVPeriodicTimebaseObse
一、崩溃包裹
分析Bugly奔溃日志,发现以下一个错误:
*** -[AVPeriodicTimebaseObserver initWithTimebase:interval:queue:block:] invalid parameter not satisfying: ((Boolean)(CMTimeCompare(interval, kCMTimeZero) > 0))
错误堆栈如下:
CoreFoundation ___exceptionPreprocess + 216
1 libobjc.A.dylib objc_exception_throw + 56
2 AVFCore ___68-[AVPeriodicTimebaseObserver initWithTimebase:interval:queue:block:]_block_invoke
3 AVFCore -[AVPlayer addPeriodicTimeObserverForInterval:queue:usingBlock:] + 132
...
由上可知,错误是在监听AVPlayer
播放进度 addPeriodicTimeObserverForInterval:queue:usingBlock:
的时候,非法入参引起的。
二、AVPlayer
播放进度的监听
iOS播放视频常常使用系统的AVPlayer
类,视频的进度是通过注册监听获得的。方法如下- (id)addPeriodicTimeObserverForInterval:(CMTime)interval queue:(nullable dispatch_queue_t)queue usingBlock:(void (^)(CMTime time))block;
。
该方法需要指定一个queue,然后在时间间隔interval内通过block回调回来。
-
注意:必须使用
- (void)removeTimeObserver:(id)observer;
移除监听。
不移除并不会倒是crash,但是这个queue的线程是不会释放的,会占用你大量的内存资源。如果很多AVPlayer都没有得到移除的话,结果是灾难性的。苹果的官方文档标注如下:
An object conforming to the NSObject protocol. You must retain this returned value as long as you want the time observer to be invoked by the player.Pass this object to -removeTimeObserver: to cancel time observation.
-
当
CMTime. timescale <= 0
的时候,就会引起上面的崩溃。
三、说说CMTime
3.1、CMTime的基本概念
- 打印一个CMTime变量如下
po CMTimeMakeWithSeconds(60, 600);
(CMTime) time = 36000 600ths of a second {
value = 36000 60*600
timescale = 600
flags = kCMTimeFlags_Valid
epoch = 0
}
- iOS系统中,将CMTime被定义为一个结构体如下,表示
typedef struct
{
CMTimeValue value;
CMTimeScale timescale;
CMTimeFlags flags; //flags 为一个位枚举
CMTimeEpoch epoch;
} CMTime;
typedef int64_t CMTimeValue;
typedef int32_t CMTimeScale;
typedef int64_t CMTimeEpoch;
我们一般关心 value
和 timescale
的赋值。
- CMTime被用来表示时间与帧数之间的关系,关系为
value/timescale = seconds
。
3.2、CMTime常用操作方法
-
通过宏
CMTIME_IS_VALID
判断CMTime是否有效值,宏定义如下:
#define CMTIME_IS_VALID(time) ((Boolean)(((time).flags & kCMTimeFlags_Valid) != 0))
-
创建CMTime变量,一般通过以下两个方法
CMTime CMTimeMake(int64_t value, int32_t timescale)
其中,value当前第几帧,timescale每秒多少帧。当前播放时间:seconds =value/timescaleCMTime CMTimeMakeWithSeconds(Float64 seconds, int32_t preferredTimescale)
seconds当前时间,preferredTimescale每秒多少帧。此时Value = seconds * preferredTimescale
文档指出,当preferredTimescale is <= 0
,CMTime是一个非法的值,会导致crash,错误如上。 -
表示零秒
kCMTimeZero
,其对应的结构体如下
(CMTime) time1 = 0 seconds {
value = 0
timescale = 1
flags = kCMTimeFlags_Valid
epoch = 0
}
-
将CMTime转化为秒,方法如下
Float64 CMTimeGetSeconds(CMTime time)
-
比较两个CMTime的大小,方法如下
int32_t CMTimeCompare(CMTime time1, CMTime time2)
time1 < time2,-1;time1 > time2,1;time1 == time2,0CMTime CMTimeMinimum(CMTime time1,CMTime time2)
返回 time1 与 time2 中较小的值CMTime CMTimeMaximum(CMTime time1,CMTime time2)
返回 time1 与 time2 中较大的值 -
CMTime CMTimeAbsoluteValue(CMTime time)
返回 time 的绝对值
其他
视频合成中CMTime的理解,以及利用CMTime实现过渡效果
CGTime CMTimeRange CMTimeMapping 小结