[AVFoundation]時(shí)間和媒體表示

原文:AVFoundation Programming Guide

基于時(shí)間的視聽數(shù)據(jù),例如電影文件或視頻流在AV Foundation框架中使用AVAsset表示篡殷。AV Foundation用來表示時(shí)間和媒體的幾個(gè)低級(jí)數(shù)據(jù)結(jié)構(gòu)鸠澈,例如樣本緩沖區(qū)來自Core Media框架歇父。

資源表示

AVAsset是AV Foundation框架的核心類。 它提供了基于時(shí)間的視聽數(shù)據(jù)的格式無關(guān)抽象,例如電影文件或視頻流赘方。 主要關(guān)系如圖6-1所示。 在許多情況下弱左,您使用其中一個(gè)子類:使用composition子類創(chuàng)建新資源(請(qǐng)參閱Editing)窄陡,使用AVURLAsset從給定URL創(chuàng)建新的資源實(shí)例(包括MPMedia框架或Asset Library框架的資源 - 請(qǐng)參閱Using Assets)。

Figure 6-1 AVAsset provides an abstraction of time-based audiovisual data

資源包含在一起呈現(xiàn)或處理的軌道的集合拆火,每個(gè)軌道的媒體類型跳夭,包括(但不限于)音頻涂圆,視頻,文本币叹,隱藏字幕和字幕润歉。 資源對(duì)象提供關(guān)于整個(gè)資源的信息,例如其持續(xù)時(shí)間或標(biāo)題颈抚,以及呈現(xiàn)的提示踩衩,例如其自然大小。 資源還可以具有由AVMetadataItem的實(shí)例表示的元數(shù)據(jù)贩汉。

軌道由AVAssetTrack的實(shí)例表示驱富,如圖6-2所示。 在通常的簡(jiǎn)單情況下雾鬼,一個(gè)軌道表示音頻萌朱,另一個(gè)表示視頻; 在復(fù)雜的組合中,可能存在多個(gè)重疊的音頻和視頻軌道策菜。

Figure 6-2 AVAssetTrack

軌道具有許多屬性晶疼,例如其類型(視頻或音頻),視覺和/或聽覺特征又憨,元數(shù)據(jù)和時(shí)間軸翠霍。 軌道還具有一系列格式描述。 該數(shù)組包含CMFormatDescription對(duì)象(請(qǐng)參閱CMFormatDescriptionRef)蠢莺,每個(gè)對(duì)象描述該軌道引用的媒體樣本的格式寒匙。 一個(gè)軌道如果包含統(tǒng)一的媒體(例如,全部使用相同設(shè)置編碼)那么這個(gè)數(shù)組的計(jì)數(shù)為1躏将。

軌道本身可以分為段锄弱,由AVAssetTrackSegment的實(shí)例表示。 段是從源到資源軌道時(shí)間線的時(shí)間映射祸憋。

時(shí)間表示

AV Foundation中的時(shí)間由Core Media框架的原始結(jié)構(gòu)表示会宪。

CMTime代表一段時(shí)間

CMTime是一個(gè)C結(jié)構(gòu),它將時(shí)間表示為有理數(shù)蚯窥,分子(一個(gè)int64_t的值)和分母(一個(gè)int32_t時(shí)間標(biāo)度)掸鹅。 在概念上,時(shí)間標(biāo)度指在每一秒中所占有的比例拦赠。 因此巍沙,如果時(shí)間標(biāo)度是4,每個(gè)單位代表四分之一秒; 如果時(shí)間刻度為10荷鼠,則每個(gè)單位表示十分之一秒句携,依此類推。 您經(jīng)常使用600的時(shí)間尺度允乐,因?yàn)檫@是幾種常用的幀速率的倍數(shù):24 fps的電影务甥,30 fps的NTSC(用于北美和日本的電視)和25 fps的PAL(用于電視 歐洲)牡辽。 使用600的時(shí)間刻度,您可以準(zhǔn)確地表示這些系統(tǒng)中的任意數(shù)量的幀敞临。

除了簡(jiǎn)單的時(shí)間值之外,CMTime結(jié)構(gòu)可以表示非數(shù)值值:+無窮大麸澜,-infinity和無限期挺尿。 它也可以指示時(shí)間是否在某一點(diǎn)被舍入,并且它保持一個(gè)epoch(紀(jì)元)數(shù)字炊邦。

使用CMTime

您可以使用CMTimeMake或相關(guān)函數(shù)如CMTimeMakeWithSeconds(允許您使用float值創(chuàng)建一個(gè)時(shí)間并指定首選的時(shí)間標(biāo)度)來創(chuàng)建一個(gè)時(shí)間编矾。 有一些基于時(shí)間的算法和比較時(shí)間的方法,如以下示例所示:

CMTime time1 = CMTimeMake(200, 2); // 200 half-seconds
CMTime time2 = CMTimeMake(400, 4); // 400 quarter-seconds

// time1 and time2 both represent 100 seconds, but using different timescales.
if (CMTimeCompare(time1, time2) == 0) {
    NSLog(@"time1 and time2 are the same");
}

Float64 float64Seconds = 200.0 / 3;

CMTime time3 = CMTimeMakeWithSeconds(float64Seconds , 3); // 66.66... third-seconds

time3 = CMTimeMultiply(time3, 3);

// time3 now represents 200 seconds; next subtract time1 (100 seconds).
time3 = CMTimeSubtract(time3, time1);

CMTimeShow(time3);

if (CMTIME_COMPARE_INLINE(time2, ==, time3)) {
    NSLog(@"time2 and time3 are the same");
}

可用函數(shù)的列表可以參閱 CMTime Reference.

CMTime的特殊值

Core Media提供了一些常量:
kCMTimeZero馁害,kCMTimeInvalid窄俏,kCMTimePositiveInfinity和kCMTimeNegativeInfinity。 CMTime結(jié)構(gòu)可以有多種方式碘菜,例如凹蜈,表示無效的時(shí)間。 要測(cè)試CMTime是否有效或非數(shù)值忍啸,您應(yīng)該使用適當(dāng)?shù)暮暄鎏梗?a target="_blank" rel="nofollow">CMTIME_IS_INVALID,CMTIME_IS_POSITIVE_INFINITYCMTIME_IS_INDEFINITE计雌。

CMTime myTime = <#Get a CMTime#>;
if (CMTIME_IS_INVALID(myTime)) {
    // Perhaps treat this as an error; display a suitable alert to the user.
}

您不應(yīng)該將任意CMTime結(jié)構(gòu)的值與kCMTimeInvalid進(jìn)行比較悄晃。

將CMTime表示為對(duì)象

如果需要在Core Foundation容器中使用CMTime結(jié)構(gòu),則可以分別使用CMTimeCopyAsDictionaryCMTimeMakeFromDictionary函數(shù)將CMTime結(jié)構(gòu)轉(zhuǎn)換為CFDictionary opaque類型(參見CFDictionaryRef)凿滤。 您還可以使用CMTimeCopyDescription函數(shù)獲取CMTime結(jié)構(gòu)的字符串表示形式妈橄。

Epochs(紀(jì)元)

CMTime結(jié)構(gòu)的epoch通常設(shè)置為0,但您可以使用它來區(qū)分不相關(guān)的時(shí)間軸翁脆。 例如眷蚓,可以在循環(huán)時(shí)通過每個(gè)周期遞增epoch,以區(qū)分循環(huán)0中的時(shí)間N和循環(huán)1中的時(shí)間N.

CMTimeRange表示時(shí)間范圍

CMTimeRange是一個(gè)具有開始時(shí)間和持續(xù)時(shí)間的C結(jié)構(gòu)鹃祖,均表示為CMTime結(jié)構(gòu)溪椎。 時(shí)間范圍不包括開始時(shí)間加上持續(xù)時(shí)間的時(shí)間。

您使用CMTimeRangeMakeCMTimeRangeFromTimeToTime創(chuàng)建一個(gè)時(shí)間范圍恬口。 對(duì)CMTime的epochs有一些約束:

  • CMTimeRange結(jié)構(gòu)不能跨越不同的epochs校读。
  • 表示時(shí)間戳的CMTime結(jié)構(gòu)中的epoch可能不為零,但您只能在起始字段具有相同epoch的范圍上執(zhí)行范圍操作(例如CMTimeRangeGetUnion)祖能。
  • 表示持續(xù)時(shí)間的CMTime結(jié)構(gòu)中的epoch應(yīng)始終為0歉秫,并且該值必須為非負(fù)數(shù)。
使用時(shí)間范圍

Core Media提供了一些函數(shù)养铸,可以用于確定時(shí)間范圍是否包含給定時(shí)間或其他時(shí)間范圍雁芙,確定兩個(gè)時(shí)間范圍是否相等轧膘,計(jì)算時(shí)間范圍的聯(lián)合和交集,如CMTimeRangeContainsTime兔甘,CMTimeRangeEqual谎碍,CMTimeRangeContainsTimeRangeCMTimeRangeGetUnion

鑒于時(shí)間范圍不包括開始時(shí)間加上持續(xù)時(shí)間的時(shí)間洞焙,以下表達(dá)式總是為false:

CMTimeRangeContainsTime(range, CMTimeRangeGetEnd(range))

其他的一些可用函數(shù), 參閱 CMTimeRange Reference.

CMTimeRange的特殊值

Core Media分別為零長(zhǎng)度范圍和無效范圍提供了常量kCMTimeRangeZerokCMTimeRangeInvalid蟆淀。 有許多方式可以使CMTimeRange結(jié)構(gòu)無效,為零或不定式(如果其中一個(gè)CMTime結(jié)構(gòu)是不確定的)澡匪。如果您需要測(cè)試CMTimeRange結(jié)構(gòu)是否有效熔任,零或不確定,您應(yīng)該使用 一個(gè)適當(dāng)?shù)暮?: CMTIMERANGE_IS_VALID ,CMTIMERANGE_IS_INVALID ,CMTIMERANGE_IS_EMPTY , 或CMTIMERANGE_IS_EMPTY唁情。

CMTimeRange myTimeRange = <#Get a CMTimeRange#>;
if (CMTIMERANGE_IS_EMPTY(myTimeRange)) {
    // The time range is zero.
}

您不應(yīng)將任意CMTimeRange結(jié)構(gòu)的值與kCMTimeRangeInvalid進(jìn)行比較疑苔。

將CMTimeRange結(jié)構(gòu)表示為對(duì)象

如果需要在Core Foundation容器中使用CMTimeRange結(jié)構(gòu),則可以分別使用CMTimeRangeCopyAsDictionaryCMTimeRangeMakeFromDictionary將CMTimeRange結(jié)構(gòu)轉(zhuǎn)換為CFDictionary opaque類型(請(qǐng)參閱CFDictionaryRef)甸鸟。 您還可以使用CMTimeRangeCopyDescription函數(shù)獲取CMTime結(jié)構(gòu)的字符串表示形式惦费。

媒體表示

視頻數(shù)據(jù)及其關(guān)聯(lián)的元數(shù)據(jù)在AV Foundation中由Core Media框架中的不透明對(duì)象表示。 Core Media使用CMSampleBuffer表示視頻數(shù)據(jù)(請(qǐng)參閱CMSampleBufferRef)哀墓。 CMSampleBuffer是一個(gè)Core Foundation風(fēng)格的不透明類型; 一個(gè)實(shí)例包含視頻數(shù)據(jù)幀作為核心視頻像素緩沖區(qū)的樣本緩沖區(qū)(參見CVPixelBufferRef)趁餐。 您可以使用CMSampleBufferGetImageBuffer從樣本緩沖區(qū)訪問像素緩沖區(qū):

CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(<#A CMSampleBuffer#>);

從像素緩沖區(qū),您可以訪問實(shí)際的視頻數(shù)據(jù)篮绰。 有關(guān)示例后雷,請(qǐng)參閱 Converting CMSampleBuffer to a UIImage Object

除了視頻數(shù)據(jù)之外吠各,您還可以獲取視頻幀的其他方面:

CMSampleBufferRef sampleBuffer = <#Get a sample buffer#>;
CFDictionaryRef metadataDictionary =
    CMGetAttachment(sampleBuffer, CFSTR("MetadataDictionary", NULL);
if (metadataDictionary) {
    // Do something with the metadata.
}
將CMSampleBuffer轉(zhuǎn)換為UIImage對(duì)象

以下代碼顯示如何將CMSampleBuffer轉(zhuǎn)換為UIImage對(duì)象。 使用前伍掀,您應(yīng)仔細(xì)考慮您的要求掰茶。 執(zhí)行轉(zhuǎn)換是比較昂貴的操作。 例如蜜笤,從每秒鐘拍攝的視頻數(shù)據(jù)幀中創(chuàng)建靜止圖像是適當(dāng)?shù)摹?您不應(yīng)該使用它作為一種手段來實(shí)時(shí)地處理來自捕獲設(shè)備的每一幀視頻濒蒋。

// Create a UIImage from sample buffer data

- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer
{
    // Get a CMSampleBuffer's Core Video image buffer for the media data
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

    // Lock the base address of the pixel buffer
    CVPixelBufferLockBaseAddress(imageBuffer, 0);

    // Get the number of bytes per row for the pixel buffer
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);

    // Get the number of bytes per row for the pixel buffer
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);

    // Get the pixel buffer width and height
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);

    // Create a device-dependent RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // Create a bitmap graphics context with the sample buffer data
    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,
      bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);

    // Create a Quartz image from the pixel data in the bitmap graphics context
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);

    // Unlock the pixel buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    // Free up the context and color space
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    // Create an image object from the Quartz image
    UIImage *image = [UIImage imageWithCGImage:quartzImage];

    // Release the Quartz image
    CGImageRelease(quartzImage);

    return (image);
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子沪伙,更是在濱河造成了極大的恐慌瓮顽,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評(píng)論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件围橡,死亡現(xiàn)場(chǎng)離奇詭異暖混,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)某饰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門儒恋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人黔漂,你說我怎么就攤上這事≠鹘矗” “怎么了炬守?”我有些...
    開封第一講書人閱讀 163,912評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)剂跟。 經(jīng)常有香客問我减途,道長(zhǎng),這世上最難降的妖魔是什么曹洽? 我笑而不...
    開封第一講書人閱讀 58,449評(píng)論 1 293
  • 正文 為了忘掉前任鳍置,我火速辦了婚禮,結(jié)果婚禮上送淆,老公的妹妹穿的比我還像新娘税产。我一直安慰自己,他們只是感情好偷崩,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評(píng)論 6 392
  • 文/花漫 我一把揭開白布辟拷。 她就那樣靜靜地躺著,像睡著了一般阐斜。 火紅的嫁衣襯著肌膚如雪衫冻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評(píng)論 1 302
  • 那天谒出,我揣著相機(jī)與錄音隅俘,去河邊找鬼。 笑死笤喳,一個(gè)胖子當(dāng)著我的面吹牛为居,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播莉测,決...
    沈念sama閱讀 40,193評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颜骤,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了捣卤?” 一聲冷哼從身側(cè)響起忍抽,我...
    開封第一講書人閱讀 39,074評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤八孝,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后鸠项,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體干跛,經(jīng)...
    沈念sama閱讀 45,505評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評(píng)論 3 335
  • 正文 我和宋清朗相戀三年祟绊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了楼入。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡牧抽,死狀恐怖嘉熊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扬舒,我是刑警寧澤阐肤,帶...
    沈念sama閱讀 35,569評(píng)論 5 345
  • 正文 年R本政府宣布,位于F島的核電站讲坎,受9級(jí)特大地震影響孕惜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晨炕,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評(píng)論 3 328
  • 文/蒙蒙 一衫画、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧瓮栗,春花似錦削罩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至货邓,卻和暖如春秆撮,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背换况。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工职辨, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人戈二。 一個(gè)月前我還...
    沈念sama閱讀 47,962評(píng)論 2 370
  • 正文 我出身青樓舒裤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親觉吭。 傳聞我的和親對(duì)象是個(gè)殘疾皇子腾供,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 基于時(shí)間的視聽數(shù)據(jù),例如電影文件或視頻流,在AV Foundation框架中被表示AVAsset伴鳖。其結(jié)構(gòu)決定了大部...
    張芳濤閱讀 852評(píng)論 0 4
  • 本文轉(zhuǎn)自:AVAudioFoundation(6):時(shí)間和媒體表示 | www.samirchen.com 本文主...
    SamirChen閱讀 725評(píng)論 0 4
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理节值,服務(wù)發(fā)現(xiàn),斷路器榜聂,智...
    卡卡羅2017閱讀 134,656評(píng)論 18 139
  • ⒉案情梳理 蘇籬落從警局安然出來了搞疗。 她走在大街上,感覺有點(diǎn)冷须肆,才發(fā)現(xiàn)天已經(jīng)黑了匿乃。 不知不覺她被帶到警局做筆錄,到...
    葉凌凡閱讀 414評(píng)論 0 4
  • 一個(gè)陽(yáng)光正好豌汇、心情正好的時(shí)候幢炸,我正坐在辦公室里碼字,突然接到朋友的電話拒贱,要我?guī)兔φ匋c(diǎn)事兒阳懂。我關(guān)上電腦匆忙往外跑,見...
    恰逢閱讀 367評(píng)論 0 1