这可能是最详细的CMTime教程

最近在做视频开发,避不开就是会用到CMTime。根据网上之前的教程,CMTime的用法其实挺简单的,例如:

    Float64 seconds = 5; 
    int32_t preferredTimeScale = 600;
    CMTime inTime = CMTimeMakeWithSeconds(seconds, preferredTimeScale);
    CMTimeShow(inTime);

然后告诉你seconds是时长,preferredTimeScale是帧率。

int64_t value = 10000;
int32_t preferredTimeScale = 600;
CMTime inTime = CMTimeMake(value, preferredTimeScale);
CMTimeShow(inTime);

这里value表示视频的帧数,preferredTimeScale表示每秒的帧数。所以这里seconds是 10000/600 = 16.667

OK,以上其实理解起来没问题,但是当我们在处理视频的时候,常常要把后面的timeScale写成600:

let sTime = CMTime(seconds: starSeconds, preferredTimescale: 600)

那么这里就有个问题:如果timeScale表示的帧率,这里的意思是视频每秒的帧率是600帧么??
我们知道人眼可识别的帧率24帧就够了,iPhone手机拍摄帧率为60fps,部分安卓手机的帧率甚至只有30fps。那么这里为什么要设置为600呢?
重新去查Apple的文档,看到里面这么解释:

CMTime
is a C structure that represents time as a rational number, with a numerator (an int64_t
value), and a denominator (an int32_t
timescale). Conceptually, the timescale specifies the fraction of a second each unit in the numerator occupies. Thus if the timescale is 4, each unit represents a quarter of a second; if the timescale is 10, each unit represents a tenth of a second, and so on. You frequently use a timescale of 600, because this is a multiple of several commonly used frame rates: 24 fps for film, 30 fps for NTSC (used for TV in North America and Japan), and 25 fps for PAL (used for TV in Europe). Using a timescale of 600, you can exactly represent any number of frames in these systems.

这里的意思是使用600帧,可以兼容各种视频帧率(24fps, 30fps, 25fps等),是这些帧率的最小公倍数。不过这并不能解释之前的困惑,设置成600以后,视频的帧率真的达到600fps了么?这样子GPU在处理照片的时候不会出现问题吗?

那么我们再来重新认识下这个CMTime吧!

假设我们需要在视频文件中精确地指定一个时刻,比如35:06。通常的方法是把时间表示为一个双精度的浮点数据,比如:NSTimeInterval t = 2106.0; 那这个方法在大多数情况下是没有问题的,但是当我们把非常长的时间段划分成非常小的切片时,就会出现问题。不直接进行浮点类型的运算,而是把一个double类型可以容纳大约16位有效数字(十进制)的8个字节的内存空间(在其他通用平台上,sizeof(NSTimeInterval) == sizeof(Float64) == sizeof(double) == 8)。 再次普及double浮点型数据的换算过程和推算原理

浮点数存在一个大问题:重复操作(加法,乘法等)导致不精确的积累,于是在视频时长很长的时候这个差异会被无限放大,从而在同步多个媒体流时可能导致错误。

这里举个栗子。一百万个0.000001相加,结果约为1.0000000000079181。该错误是由于1e-6不能以我们使用的double类型精确的表示,所以我们改为使用二进制近似位,它的低有效位不同。这并不是一个大问题,但是当你在运行一个HTTP流服务器的时候,那么你可能会无限期的每秒去积累这种不精确度。

这就促使我们去找到一种更精确表达时间的方式,通过消除double类型和他们固有的不精确性(不说他们的硬编码舍入行为)。

CMTime

虽然Apple已经有很多数据结构来表示Mac和iOS平台上的时间,但是在iOS4和Mac OS X 10.7 推出的时候,加上了CMTime和CMTimeRange。CMTime的类型定义如下:

  typedef struct
  {
     CMTimeValue    value;        
     CMTimeScale    timescale;    
     CMTimeFlags    flags;        
     CMTimeEpoch    epoch;        
   } CMTime;
  public typealias CMTimeValue = Int64
  public typealias CMTimeScale = Int32

显然,CMTime定义是一个C语言的结构体,CMTime是以分数的形式表示时间,value表示分子,timescale表示分母,flags是位掩码,表示时间的指定状态。

这里value,timescale是分别以64位32位整数来存储的,我们从上文已经知道,这样可以避免double类型带来的精度丢失。另外,通过用64位整数来表示分子,我们可以为每个timescale表示90亿个不同的正值,最多19位唯一的十进制数字。

timescale

那么timescale又是什么? 它表示每秒分割的“切片”数。CMTime的整体精度就是受到这个限制的。比如:
如果timescale为1,则不能有对象表示小于1秒的时间戳,并且时间戳以1秒为增量。类似的,如果timescale是1000,则每秒被分割成1000个,并且该value表示我们要显示的毫秒数。

所以当你试图表示0.5秒的时候,你千万不能这么写:

CMTime interval = CMTimeMakeWithSeconds(0.5, 1);

这里interval实际上是0 而不是0.5。
所以为了能让你选择合理的时间尺度确保不被截断,Apple建议我们使用600。如果你需要对音频文件进行更精确的所以,你可以把timescale设为60,000或更高。这里64位 value的好处就是,你仍然可以用这种方式来明确的表示580万年的增量,即1/60,000秒。

所以,这里可以得出结论:

timescale只是为了保证时间精度而设置的帧率,并不一定是视频最后实际的播放帧率。

相关资料:
Understanding CMTime

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,098评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,213评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,960评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,519评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,512评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,533评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,914评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,804评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,563评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,644评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,350评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,933评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,908评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,146评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,847评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,361评论 2 342

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,849评论 6 13
  • 最近看到一篇关于CMTime的文章,感觉讲得通俗易懂,就想着翻译一下,我尽量在语义正确的情况下按照原著来翻译,原文...
    鐵甲陳小寶阅读 6,124评论 3 7
  • 教程一:视频截图(Tutorial 01: Making Screencaps) 首先我们需要了解视频文件的一些基...
    90后的思维阅读 4,648评论 0 3
  • 江梅梅找出放在玫瑰中的卡片,上边写着:“祝梅梅天天开心”,落款是YH,她无奈的笑了笑,这是马一鸿送来的,心中却有一...
    默默幽幽阅读 256评论 0 0
  • 今天的太阳, 像瘫痪的卡车, 在遍布沙粒的荒野, 扯着喉咙不能唱歌。 阴郁盗取了灵魂, 树叶挤出欢乐。 许多昏暗重...
    暮雨激潭阅读 280评论 0 6