【iOS音视频】CMTime的使用

638 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第6天,点击查看活动详情

AVFoundation 是Apple iOS和OS X系统中用于处理基于时间的媒体数据的高级框架,通过开发所需的工具提供了强大的功能集,让开发者能够基于苹果平台创建当下最先进的媒体应用程序,其针对64位处理器设计,充分利用了多核硬件优势,会自动提供硬件加速操作,确保大部分设备能以最佳性能运行,是iOS开发接触音视频开发必学的框架之一

参与掘金日新计划,持续记录AVFoundation学习,Demo学习地址,里面封装了一些工具类,可以直接使用,这篇文章主要讲述CMTime的使用,其他类的相关用法可查看我的其他文章。

CMTime

苹果平台表示时间一般用NSTimeInterval,它是一个简单的双精度类型,其天然的不精确性导致双精度类型无法应用于更多的高级时基媒体的开发中。比如,一个单一舍入错误就会导致丢帧或音频丢失。所以在更准确的场景中应使用Core Media框架定义的CMTime数据类型作为时间格式。 CMTime定义如下:

        /**
            @typedef    CMTime
            @abstract    Rational time value represented as int64/int32.
        */
        @available(iOS 4.0, *)
        public struct CMTime {

            public init()

            public init(value: CMTimeValue, timescale: CMTimeScale, flags: CMTimeFlags, epoch: CMTimeEpoch)

            
            /**< The value of the CMTime. value/timescale = seconds */
            public var value: CMTimeValue

            /**< The timescale of the CMTime. value/timescale = seconds. */
            public var timescale: CMTimeScale

            /**< The flags, eg. kCMTimeFlags_Valid, kCMTimeFlags_PositiveInfinity, etc. */
            public var flags: CMTimeFlags

            /**< 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 var epoch: CMTimeEpoch
        }

  • CMtime是一个分数,value/timeScale 表示一个时间
  • value是分子,CMTimeValue即Int64
  • timescale分母,CMTimeScale即Int32
  • CMTimeFlags是一个位掩码用于表示时间的指定状态,比如判断数据是否有效、不确定或是否出现舍入值等

CMTime创建

  • 通过value和timeScale创建
  • 在处理视频内容时常见的时问刻度为600,这是大部分常用视频帧率 24FPS、25FPS 和30FPS 的公倍数。音频数据常见的时问刻度就是采样率,比如44 100(44. IKHIz)或 48 000(48k112)。
        let time1 = CMTime(value: 1800, timescale: 600)
        let time2 = CMTimeMake(value: 3000, timescale: 1000)
        // 打印CMTime
        CMTimeShow(time1) //{1800/600 = 3.000}
        CMTimeShow(time2) //{3000/1000 = 3.000}
  • 通过时间和timeScale创建
  • 例如5秒,timeScale600,则value为3000
        let time3 = CMTimeMakeWithSeconds(5, preferredTimescale: 600)
        let time4 = CMTime(seconds: 5, preferredTimescale: 600)
        CMTimeShow(time3) //{3000/600 = 5.000}得到的是5.000

CMTime计算

  • 相加,OC时经常使用CMTimeAdd,Swift通过扩展定义了+-><等使用
        let addTime1 = CMTimeAdd(time1, time2)
        let addTime2 = time1 + time2
        CMTimeShow(addTime2) //{18000/3000 = 6.000}
  • 相减
        let subTime1 = CMTimeSubtract(time3, time2)
        let subTime2 = time3 - time2
        CMTimeShow(subTime2) //{6000/3000 = 2.000}
  • 相乘
        let mulTime1 = CMTimeMultiply(time1, multiplier: 2) //乘以2
        let mulTime2 = CMTimeMultiplyByFloat64(time1, multiplier: 1.5) // 乘以1.5
        let mulTime3 = CMTimeMultiplyByRatio(time1, multiplier: 2, divisor: 3) // 乘以(2/3)
        CMTimeShow(mulTime1) //{3600/600 = 6.000}
        CMTimeShow(mulTime2) //{4500000000/1000000000 = 4.500}
        CMTimeShow(mulTime3) //{3600/1800 = 2.000}

CMTime比较

  • 直接使用 == > < >= <= 即可
        //CMTimeCompare(time1, time2) time1小于time2返回-1,等于返回0,大于返回1,
        let comResult1 = CMTimeCompare(time1, time2)
        let comResult2 = time1 == time2
        let comResult3 = time1 > time2
        let comResult4 = time1 <= time2
        print(comResult1, comResult2, comResult3, comResult4)
        let minTime = CMTimeMinimum(time1, time2)
        let maxTime = CMTimeMaximum(time1, time2)
        CMTimeShow(minTime) //{3000/1000 = 3.000}
        CMTimeShow(maxTime) //{1800/600 = 3.000}

CMTimeRange

Core Media框架还为时间范围提供了一个数据类型,称为CMTimeRange,CMTimeRange由两个CMTime值组成,第一个值定义时间范围的起点,第二个值定义时问范围的持续时间。

    public struct CMTimeRange {

    public init()

    public init(start: CMTime, duration: CMTime)

    
    /**< The start time of the time range. */
    public var start: CMTime

    /**< The duration of the time range. */
    public var duration: CMTime
}
  • 两种创建方式,一种是起点和终点
  • 一种是起点和时长
        let timeRange1 = CMTimeRange(start: time1, end: time1)
        let timeRange2 = CMTimeRange(start: time1, duration: time1)
        CMTimeRangeShow(timeRange1) //{{1800/600 = 3.000}, {0/600 = 0.000}}
        CMTimeRangeShow(timeRange2) // {{1800/600 = 3.000}, {1800/600 = 3.000}}
  • 时间范围交集并集
        let intersectionRange = CMTimeRangeGetIntersection(timeRange1, otherRange: timeRange2)
        CMTimeRangeShow(intersectionRange)//{{0/1 = 0.000}, {0/1 = 0.000}}
        let unionRange = CMTimeRangeGetUnion(timeRange1, otherRange: timeRange2)
        CMTimeRangeShow(unionRange)//{{1800/600 = 3.000}, {1800/600 = 3.000}}
        let endTime = CMTimeRangeGetEnd(timeRange2)
        CMTimeShow(endTime)//{3600/600 = 6.000}