媒体时间处理的背景
AVPlayer 与AVPlayerItem都是基于时间的对象,但是在我们使用他们的功能之前,需要了解AVFoundation框架呈现时间的方式。
人们习惯于用日子、小时、分钟、秒来表示时间,而在开发人员中则把时间精确到毫秒、纳秒。所以用一个双精度浮点型数值来表示时间也算是合情合理。在 iOS 开发中,通常使用 NSTimeInterval 来表示一个时间,其实就是简单的对double进行了typedef定义。不过使用浮点型数据表示时间存在一些问题,因为浮点型数据在进行运算会导致结果不精确的情况。当进行时间的累加时这些不精确的情况就会非常严重,经常导致时间的明显偏移,是的媒体的多个数据流几乎无法实现同步。此外以浮点型数据呈现时间无法做到自我描述,这就导致在使用不同时间轴进行比较和运算时比较困难。AVFoundation 使用一种可靠性更高的方式来展示时间信息,这就是基于CMTime 的数据结构。
CMTime 的结构
AVFoundation 是基于 core Media 的高层封装,core Media 是基于 c的底层框架,提供了处理 MAC和iOS媒体栈的关键功能,这些功能大多都是在后台运行的不可见功能,不过我们经常能够接触到的部分就是他的数据结构CMTime。CMTime 为时间的正确表示给出了结构,即分数值的方式。
public struct CMTime {
public var value: CMTimeValue /*! @field value The value of the CMTime. value/timescale = seconds. */
/** @field value The value of the CMTime. value/timescale = seconds. */
public var timescale: CMTimeScale /*! @field timescale The timescale of the CMTime. value/timescale = seconds. */
/** @field timescale The timescale of the CMTime. value/timescale = seconds. */
public var flags: CMTimeFlags /*! @field flags The flags, eg. kCMTimeFlags_Valid, kCMTimeFlags_PositiveInfinity, etc. */
/** @field flags The flags, eg. kCMTimeFlags_Valid, kCMTimeFlags_PositiveInfinity, etc. */
public var epoch: CMTimeEpoch /*! @field epoch Differentiates between equal timestamps that are actually different because
of looping, multi-item sequencing, etc.
Will be used during comparison: greater epochs happen after lesser ones.
Additions/subtraction is only possible within a single epoch,
however, since epoch length may be unknown/variable. */
public init()
public init(value: CMTimeValue, timescale: CMTimeScale, flags: CMTimeFlags, epoch: CMTimeEpoch)
}
的最关键的两个变量value和 timescale。value 是一个 64位整数类型值,timescale 是一个32位整数类型值,在时间的呈现样式中分别充当分子和分母的作用。
public typealias CMTimeValue = Int64
public typealias CMTimeScale = Int32
建立以分数值来表示时间的方式刚开始会有些不太适应,当开发中不断使用之后,就慢慢开始顺手,开始习惯了。
CMTime 使用
下面使用swift来对CMTime 的基本操作进行个演示
创建
// 第一个参数为秒数4,第二个参数为时间刻度字段,最终可得出 time.value = 8,time.timescale = 2,
let time1 = CMTimeMakeWithSeconds(4, preferredTimescale: 2)
let seconds = CMTimeGetSeconds(time1)//4
print("seconds:\(seconds),time.value:\(time1.value), time.timescale\(time1.timescale)") // seconds:4,time.value:8,time.timescale:2
let time2 = CMTimeMake(value: 6, timescale: 3)
let seconds2 = CMTimeGetSeconds(time2)//2
print("seconds:\(seconds2),time.value:\(time2.value), time.timescale\(time2.timescale)") // seconds:2,time.value:6,time.timescale:3
比较
let time1 = CMTimeMakeWithSeconds(4, preferredTimescale: 2)
let time2 = CMTimeMake(value: 6, timescale: 3)
print(time1 > time2)//true
print(time1 <= time2)//false
print(time1 == time2)//false
print(time1 != time2)//true
运算
let time1 = CMTimeMakeWithSeconds(4, preferredTimescale: 2)
let time2 = CMTimeMake(value: 6, timescale: 3)
// 相加
let time3 = time1 + time2// time3 = 8/2 + 6/3 = 24/6 + 12/6 = 36/6
print("value:\(time3.value), timescale:\(time3.timescale)")// value:36, timescale:6
// 相减
let time4 = time1 - time2// time3 = 8/2 - 6/3 = 24/6 - 12/6 = 12/6
print("value:\(time4.value),timescale:\(time4.timescale)")
除了上面这些使用方法以外,CMTime 还提供了大量实用的函数存在于 CMTime.h文件中,本人也还在学习中。