這可能是最詳細(xì)的CMTime教程

最近在做視頻開發(fā),避不開就是會(huì)用到CMTime。根據(jù)網(wǎng)上之前的教程,CMTime的用法其實(shí)挺簡單的,例如:

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

然后告訴你seconds是時(shí)長,preferredTimeScale是幀率。

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

這里value表示視頻的幀數(shù),preferredTimeScale表示每秒的幀數(shù)。所以這里seconds是 10000/600 = 16.667

OK,以上其實(shí)理解起來沒問題,但是當(dāng)我們?cè)谔幚硪曨l的時(shí)候,常常要把后面的timeScale寫成600:

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

那么這里就有個(gè)問題:如果timeScale表示的幀率,這里的意思是視頻每秒的幀率是600幀么??
我們知道人眼可識(shí)別的幀率24幀就夠了,iPhone手機(jī)拍攝幀率為60fps,部分安卓手機(jī)的幀率甚至只有30fps。那么這里為什么要設(shè)置為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等),是這些幀率的最小公倍數(shù)。不過這并不能解釋之前的困惑,設(shè)置成600以后,視頻的幀率真的達(dá)到600fps了么?這樣子GPU在處理照片的時(shí)候不會(huì)出現(xiàn)問題嗎?

那么我們?cè)賮碇匦抡J(rèn)識(shí)下這個(gè)CMTime吧!

假設(shè)我們需要在視頻文件中精確地指定一個(gè)時(shí)刻,比如35:06。通常的方法是把時(shí)間表示為一個(gè)雙精度的浮點(diǎn)數(shù)據(jù),比如:NSTimeInterval t = 2106.0; 那這個(gè)方法在大多數(shù)情況下是沒有問題的,但是當(dāng)我們把非常長的時(shí)間段劃分成非常小的切片時(shí),就會(huì)出現(xiàn)問題。不直接進(jìn)行浮點(diǎn)類型的運(yùn)算,而是把一個(gè)double類型可以容納大約16位有效數(shù)字(十進(jìn)制)的8個(gè)字節(jié)的內(nèi)存空間(在其他通用平臺(tái)上,sizeof(NSTimeInterval) == sizeof(Float64) == sizeof(double) == 8)。 再次普及double浮點(diǎn)型數(shù)據(jù)的換算過程和推算原理

浮點(diǎn)數(shù)存在一個(gè)大問題:重復(fù)操作(加法,乘法等)導(dǎo)致不精確的積累,于是在視頻時(shí)長很長的時(shí)候這個(gè)差異會(huì)被無限放大,從而在同步多個(gè)媒體流時(shí)可能導(dǎo)致錯(cuò)誤。

這里舉個(gè)栗子。一百萬個(gè)0.000001相加,結(jié)果約為1.0000000000079181。該錯(cuò)誤是由于1e-6不能以我們使用的double類型精確的表示,所以我們改為使用二進(jìn)制近似位,它的低有效位不同。這并不是一個(gè)大問題,但是當(dāng)你在運(yùn)行一個(gè)HTTP流服務(wù)器的時(shí)候,那么你可能會(huì)無限期的每秒去積累這種不精確度。

這就促使我們?nèi)フ业揭环N更精確表達(dá)時(shí)間的方式,通過消除double類型和他們固有的不精確性(不說他們的硬編碼舍入行為)。

CMTime

雖然Apple已經(jīng)有很多數(shù)據(jù)結(jié)構(gòu)來表示Mac和iOS平臺(tái)上的時(shí)間,但是在iOS4和Mac OS X 10.7 推出的時(shí)候,加上了CMTime和CMTimeRange。CMTime的類型定義如下:

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

顯然,CMTime定義是一個(gè)C語言的結(jié)構(gòu)體,CMTime是以分?jǐn)?shù)的形式表示時(shí)間,value表示分子,timescale表示分母,flags是位掩碼,表示時(shí)間的指定狀態(tài)。

這里value,timescale是分別以64位32位整數(shù)來存儲(chǔ)的,我們從上文已經(jīng)知道,這樣可以避免double類型帶來的精度丟失。另外,通過用64位整數(shù)來表示分子,我們可以為每個(gè)timescale表示90億個(gè)不同的正值,最多19位唯一的十進(jìn)制數(shù)字。

timescale

那么timescale又是什么? 它表示每秒分割的“切片”數(shù)。CMTime的整體精度就是受到這個(gè)限制的。比如:
如果timescale為1,則不能有對(duì)象表示小于1秒的時(shí)間戳,并且時(shí)間戳以1秒為增量。類似的,如果timescale是1000,則每秒被分割成1000個(gè),并且該value表示我們要顯示的毫秒數(shù)。

所以當(dāng)你試圖表示0.5秒的時(shí)候,你千萬不能這么寫:

CMTime interval = CMTimeMakeWithSeconds(0.5, 1);

這里interval實(shí)際上是0 而不是0.5。
所以為了能讓你選擇合理的時(shí)間尺度確保不被截?cái)啵珹pple建議我們使用600。如果你需要對(duì)音頻文件進(jìn)行更精確的所以,你可以把timescale設(shè)為60,000或更高。這里64位 value的好處就是,你仍然可以用這種方式來明確的表示580萬年的增量,即1/60,000秒。

所以,這里可以得出結(jié)論:

timescale只是為了保證時(shí)間精度而設(shè)置的幀率,并不一定是視頻最后實(shí)際的播放幀率。

相關(guān)資料:
Understanding CMTime

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報(bào)批稿:20170802 前言: 排版 ...
    庭說閱讀 12,530評(píng)論 6 13
  • 最近看到一篇關(guān)于CMTime的文章,感覺講得通俗易懂,就想著翻譯一下,我盡量在語義正確的情況下按照原著來翻譯,原文...
    鐵甲陳小寶閱讀 6,296評(píng)論 3 7
  • 教程一:視頻截圖(Tutorial 01: Making Screencaps) 首先我們需要了解視頻文件的一些基...
    90后的思維閱讀 4,991評(píng)論 0 3
  • 江梅梅找出放在玫瑰中的卡片,上邊寫著:“祝梅梅天天開心”,落款是YH,她無奈的笑了笑,這是馬一鴻送來的,心中卻有一...
    默默幽幽閱讀 324評(píng)論 0 0
  • 今天的太陽, 像癱瘓的卡車, 在遍布沙粒的荒野, 扯著喉嚨不能唱歌。 陰郁盜取了靈魂, 樹葉擠出歡樂。 許多昏暗重...
    暮雨激潭閱讀 349評(píng)論 0 6

友情鏈接更多精彩內(nèi)容