本文共 9827 字,大约阅读时间需要 32 分钟。
在使用 AVFoundation 框架处理多媒体资源时,通常会用到一些在 CoreMedia 框架中定义的结构体,
这里对其中描述时间的类型 CMTime 、CMTimeRange 、CMTimeMapping 进行简单的小结。CMTime 是一个结构体,其用来表示一个有理数,描述一个时刻或时段。在结构体中有4个成员,如下:
typedef struct{ CMTimeValue value; CMTimeScale timescale; CMTimeFlags flags; CMTimeEpoch epoch;} CMTime;
该结构体类型的变量表示的时刻或时段的值为 value/timescale ,单位是秒。
那么 1/timescale 表示一个单元占用了多长时间,这个时间小于 1 秒,而 value * (1/timescale) 即表示整个结构体变量所表示的时间长度。
flags 该标识可以表示当前变量表示的时刻或时段是否有效、是否是准确值等,可取的值如下:
kCMTimeFlags_Valid = 1UL<<0
该值必需设置,否则当前变量会被认为是无效的kCMTimeFlags_HasBeenRounded = 1UL<<1
表示当前变量是约数并不是原始的精确值,或者是由其他非精确的值生成的kCMTimeFlags_PositiveInfinity = 1UL<<2
表示当前变量为正无穷kCMTimeFlags_NegativeInfinity = 1UL<<3
表示当前变量为负无穷kCMTimeFlags_Indefinite = 1UL<<4
表示当前变量未定义kCMTimeFlags_ImpliedValueFlagsMask = kCMTimeFlags_PositiveInfinity | kCMTimeFlags_NegativeInfinity | kCMTimeFlags_Indefinite
表示正负无穷或未定义epoch 可以用来区分两个表示相同时间的变量,如循环递增的时间,这个值可以区分不同循环内的相同的时间的变量。
在 CoreMedia 框架中,提供了一些常量,用来表示特殊的 CMTime 值。
要判断已知的变量是否等于上述的变量时,不可以使用 “==” 进行判断,而是要使用框架中提供的宏,在这些宏定义中,都是对变量的成员 flags 值进行了判断。
CMTIME_IS_VALID(time)
判断已知的 CMTime 变量是否是有效的CMTIME_IS_INVALID(time)
判断已知的 CMTime 变量是否是无效的CMTIME_IS_POSITIVE_INFINITY(time)
判断已知的 CMTime 变量是否表示时间正无穷CMTIME_IS_NEGATIVE_INFINITY(time)
判断已知的 CMTime 变量是否表示时间负无穷CMTIME_IS_INDEFINITE(time)
判断已知的 CMTime 变量是否是未定义的CMTIME_IS_NUMERIC(time)
判断已知的 CMTime 变量是否是明确的时间,而不是正负无穷或未定义CMTIME_HAS_BEEN_ROUNDED(time)
判断已知的 CMTime 变量是否是约数CMTime CMTimeMake(int64_t value,int32_t timescale);
CMTime CMTimeMakeWithEpoch(int64_t value,int32_t timescale,int64_t epoch);
上面两个是生成 CMTime 变量的常见函数,通过指定相应的成员变量的值来生成相应的变量。
CMTime CMTimeMakeWithSeconds(Float64 seconds,int32_t preferredTimescale)
除了指定相应的成员变量来生成 CMTime 变量外,还可以通过指定时间和时间粒度来生成变量。返回的变量,其成员 epoch 被设置为 0 ,而 value 的值则是 seconds 与 preferredTimescale 的乘积,所以 value 的值可能会溢出。
当发生溢出时,会将 preferredTimescale 的值自动减半,直到 value 的值不再溢出,或者 preferredTimescale 减到 1 ,如果减到 1 后,value 仍然溢出,则这个变量表示无穷大。
由于提供的时间是浮点型,而计算得到的成员变量 value 是整型值,所以计算时,value 的值可能含有小数,如果有小数部分,便需要舍入。如此,使用成员变量再次计算得到的时间值与原来提供的时间值不相等,所以对于这种情况,返回值的成员变量 flags 中,kCMTimeFlags_HasBeenRounded 标识会被设置。
Float64 CMTimeGetSeconds(CMTime time);
CMTime CMTimeConvertScale(CMTime time,int32_t newTimescale,CMTimeRoundingMethod method);
该方法可以修改已知的 CMTime 类型变量的 timescale 成员变量的值,计算 value 的值时可能需要舍入小数部分,所以调用函数时要指定舍入方法。
CMTimeRoundingMethod 有以下可取值:
//转换后 time2 的 value 为 1CMTime time1 = CMTimeMake(1, 4);CMTime tiem2 = CMTimeConvertScale(time, 2, kCMTimeRoundingMethod_RoundHalfAwayFromZero);//转换后 time2 的 value 为 0CMTime time1 = CMTimeMake(1, 5);CMTime tiem2 = CMTimeConvertScale(time, 2, kCMTimeRoundingMethod_RoundHalfAwayFromZero);//转换后 time2 的 value 为 0CMTime time1 = CMTimeMake(1, 5);CMTime tiem2 = CMTimeConvertScale(time, 2, kCMTimeRoundingMethod_QuickTime);//转换后 time2 的 value 为 -1CMTime time1 = CMTimeMake(-1, 5);CMTime tiem2 = CMTimeConvertScale(time, 2, kCMTimeRoundingMethod_QuickTime);
CMTime CMTimeAdd( CMTime addend1,CMTime addend2);
CMTime CMTimeSubtract(CMTime minuend,CMTime subtrahend);
两个 CMTime 类型的变量之和或之差,得到的结果的 timescale 的值是两个变量的 timescale 的最小公倍数。如果这个公倍数大于 kCMTimeMaxTimescale 这个值,那么 timescale 就使用 kCMTimeMaxTimescale 这个值。在转换这个 timescale 的过程中,计算 value 的值时采用默认的舍入方法,如果 value 的值溢出,便减半 timescale 再进行计算,判断其是否溢出,若溢出,再次减半,直到其值为 1 ,如果仍然溢出,则返回的结果为无穷大。
CMTime CMTimeMultiply(CMTime time,int32_t multiplier);
CMTime CMTimeMultiplyByFloat64(CMTime time,Float64 multiplier);
扩大已知的 time 的倍数,value 的值扩大 multiplier 倍,如果溢出,持续减半 timescale 的值,直到不再溢出或为 1 ,如果为 1 时仍然溢出,返回的值表示无穷大。
CMTime CMTimeMultiplyByRatio(CMTime time,int32_t multiplier,int32_t divisor)
用已知的 time 的 value 值乘以 multiplier 再除以 divisor 得到新的 value 值,如果 value 的值发生溢出,那么 timescale 便会发生转变。
int32_t CMTimeCompare(CMTime time1,CMTime time2)
两个时间比较,遵循的规则:负无穷 < 具体时间 < 未定义 < 正无穷 < 无效时间
具体的两个时间比较大小时,其成员 epoch 也参与比较,epoch 较大的时间较大。
框架中提供了一个宏 CMTIME_COMPARE_INLINE(time1, comparator, time2) ,通过提供比较运算符(>、>=、=、<、=<)comparator 来获取 time1 与 time2 的大小关系。
CMTime CMTimeMinimum(CMTime time1,CMTime time2)
CMTime CMTimeMaximum(CMTime time1,CMTime time2)
CMTime CMTimeAbsoluteValue(CMTime time)
返回 time 的绝对值
CFDictionaryRef CM_NULLABLE CMTimeCopyAsDictionary(CMTime time,CFAllocatorRef CM_NULLABLE allocator)
CMTime CMTimeMakeFromDictionary(CFDictionaryRef CM_NULLABLE dict)
上面两个方法,可以将 CMTime 类型的变量转化为 CFDictionaryRef 类型的变量,或者从已经转化的变量中生成一个 CMTime 类型的变量。在 CFDictionary 中,它应包含键值:kCMTimeValueKey 、kCMTimeScaleKey 、kCMTimeEpochKey 、kCMTimeFlagsKey 分别对应 CMTime 的各个成员变量。
CFStringRef CM_NULLABLE CMTimeCopyDescription(CFAllocatorRef CM_NULLABLE allocator,CMTime time)
void CMTimeShow(CMTime time)
上面的两个方法,可以获取 CMTime 类型变量的字符串描述,或者直接将字符串描述打印出来。
CMTimeRange 是用来表示一个时间范围的结构体变量,它的两个成员变量都是 CMTime 类型的变量,分别表示时间范围的开始时刻和时间范围的持续时长,所以开始时刻与持续时长的和得到的时刻并不属于该类型表示的时间范围。
typedef struct{ CMTime start; CMTime duration;} CMTimeRange;
可以使用 kCMTimeRangeZero 、kCMTimeRangeInvalid 分别表示时间范围为 0 和无效的的 CMTimeRange 类型变量。
对于有效的 CMTimeRange 类型变量,它的两个 CMTime 成员变量都必须是有效的,并且 duration.epoch 必须是 0 ,duration.value 的值必须是非负的。可以直接使用框架中提供的宏定义,进行判断。
CMTimeRange CMTimeRangeMake(CMTime start,CMTime duration)
CMTimeRange CMTimeRangeGetUnion(CMTimeRange range1,CMTimeRange range2)
返回两个时间范围的最小并集
CMTimeRange CMTimeRangeGetIntersection(CMTimeRange range1,CMTimeRange range2)
返回两个时间范围的最大交集
Boolean CMTimeRangeEqual(CMTimeRange range1,CMTimeRange range2)
返回两个时间范围是否相等
Boolean CMTimeRangeContainsTime(CMTimeRange range,CMTime time)
返回指定的时间范围内是否包含指定的时间
Boolean CMTimeRangeContainsTimeRange(CMTimeRange range1,CMTimeRange range2)
返回指定的时间范围 range1 是否包含 指定的时间范围 range2
CMTime CMTimeRangeGetEnd(CMTimeRange range)
返回指定时间范围的结束时间,这个时间是不包含在时间范围内的,即
CMTimeRangeContainsTime(range, CMTimeRangeGetEnd(range))
的返回值总是 false 。
CMTime CMTimeMapTimeFromRangeToRange(CMTime t,CMTimeRange fromRange,CMTimeRange toRange )
将指定的时间 t 根据时间范围 fromRange 和 toRange 进行转换,如果 t 是 fromRange 的开始或者结束时间,那么转换后,其就是 toRange 的开始或结束时间。如果 t 是其他时间,那么按照公式
result = (t-fromRange.start)*(toRange.duration/fromRange.duration)+toRange.start
进行计算。CMTime CMTimeClampToRange(CMTime time,CMTimeRange range)
返回的是指定的时间范围内 range 中距离指定时间 time 最近的时间。如果 time 的时间小于 range 的开始时间,那么返回的就是 range 的开始时间,如果 time 在 range 范围内,那么返回其本身,如果 time 是 range 的结束时间或结束时间之后,那么返回的都是 range 的结束时间(即使该结束时间不属于 range 表示的时间范围之内)。
CMTime CMTimeMapDurationFromRangeToRange(CMTime dur,CMTimeRange fromRange,CMTimeRange toRange )
将指定的时间范围的持续时长根据时间范围 fromRange 和 toRange 进行转换,实际是对持续时长进行了缩小或放大,其计算公式为
result = dur*(toRange.duration/fromRange.duration)
CMTimeRange CMTimeRangeFromTimeToTime(CMTime start,CMTime end)
CFDictionaryRef CM_NULLABLE CMTimeRangeCopyAsDictionary(CMTimeRange range,CFAllocatorRef CM_NULLABLE allocator)
CMTimeRange CMTimeRangeMakeFromDictionary(CFDictionaryRef CM_NONNULL dict)
上面的方法实现了 CMTimeRange 类型变量与 CFDictionaryRef 变量的相互转换,CFDictionary 中的键 kCMTimeRangeStartKey 、kCMTimeRangeDurationKey 分别对应着 CMTimeRange 中的成员。
CFStringRef CM_NULLABLE CMTimeRangeCopyDescription(CFAllocatorRef CM_NULLABLE allocator,CMTimeRange range)
void CMTimeRangeShow(CMTimeRange range)
上面的两个方法,可以获取 CMTimeRange 类型变量的字符串描述,或者直接将字符串描述打印出来。
CMTimeMapping 是一个描述媒体资源时间线映射关系的结构体变量,其包含两个 CMTimeRange 类型的成员变量。
typedef struct { CMTimeRange source; CMTimeRange target;} CMTimeMapping;
在框架中,使用 kCMTimeMappingInvalid 来表示无效的 CMTimeMapping 类型变量,可以使用 CMTIMEMAPPING_IS_VALID(mapping)
、CMTIMEMAPPING_IS_INVALID(mapping)
来判断变量 mapping 是否有效(mapping.target 有效即可),或者使用 CMTIMEMAPPING_IS_EMPTY(mapping)
来判断 mapping 是否为空(mapping 有效且 mapping.source.start 为 kCMTimeInvalid)
CMTimeMapping CMTimeMappingMake(CMTimeRange source,CMTimeRange target)
创建一个映射关系变量,提供的 source 和 target 的 epoch 的值必需为 0 ,否则将返回一个无效值。
CMTimeMapping CMTimeMappingMakeEmpty(CMTimeRange target)
创建一个空的变量,提供的 target 的 epoch 必需时 0 ,否则将返回一个无效值。
CFDictionaryRef CM_NULLABLE CMTimeMappingCopyAsDictionary(CMTimeMapping mapping,CFAllocatorRef CM_NULLABLE allocator)
CMTimeMapping CMTimeMappingMakeFromDictionary(CFDictionaryRef CM_NONNULL dict)
上面的方法实现了 CMTimeMapping 类型变量与 CFDictionaryRef 变量的相互转换,CFDictionary 中的键 kCMTimeMappingSourceKey 、kCMTimeMappingTargetKey 分别对应着 CMTimeMapping 中的成员。
CFStringRef CM_NULLABLE CMTimeMappingCopyDescription(CFAllocatorRef CM_NULLABLE allocator,CMTimeMapping mapping)
void CMTimeMappingShow(CMTimeMapping mapping)
上面的两个方法,可以获取 CMTimeMapping 类型变量的字符串描述,或者直接将字符串描述打印出来。
转载地址:http://ixdws.baihongyu.com/