《AVFoundation》官方文檔08--時間和媒體表示

基于時間的視聽數據,例如電影文件或視頻流,在AV Foundation框架中被表示AVAsset。其結構決定了大部分的框架作品。AV Foundation用來表示時間和媒體的幾個低級數據結構,如樣本緩沖區來自Core Media框架。

Asset表示

AVAsset是AVFoundation框架的核心課程。它提供了基于時間的視聽數據的格式無關抽象,例如電影文件或視頻流。主要關系如圖6-1所示。在許多情況下,您可以使用其子類之一:創建新資源時使用組合子類(請參閱編輯),并且您可以使用AVURLAsset從給定URL(包括MPMedia框架的Asset或從MPMedia框架的Asset)創建新的Asset實例Asset庫框架 - 請參閱使用Asset)。

圖6-1 AVAsset提供了基于時間的視聽數據的抽象

Asset包含旨在一起顯示或處理的每個軌道的集合,每個軌道均包含(但不限于)音頻,視頻,文本,隱藏式字幕和字幕。Asset對象提供有關整個資源的信息,例如其持續時間或標題,以及呈現的提示,如自然大小。Asset也可能具有由實例表示的元數據AVMetadataItem

軌道由一個實例AVAssetTrack表示,如圖6-2所示。在典型的簡單情況下,一個音軌表示音頻分量,另一個表示視頻分量; 在復雜的組合中,可能存在多個重疊的音頻和視頻軌道。

圖6-2 AVAssetTrack

軌道具有許多屬性,例如其類型(視頻或音頻),視覺和/或聽覺特征(酌情),元數據和時間軸(以其父Asset的方式表示)。軌道還具有一系列格式描述。數組包含CMFormatDescription對象(參見CMFormatDescriptionRef),每個對象描述了軌道引用的媒體樣本的格式。包含統一媒體(例如,使用相同設置編碼的曲目)的曲目將提供一個計數為1的數組。

軌道本身可以分為段,由實例表示AVAssetTrackSegment。段是從源到Asset軌道時間線的時間映射。

時間的表示

AVFoundation的時間由Core Media框架的原始結構表示。

CMTime表示時間長度

CMTime
是一個表示時間為有理數字的C結構,分子(int64_t值)和分母(int32_t
時間刻度)。在概念上,時間刻度指定分子占據的每個單位的分數。
因此,如果時間刻度是4,每個單位代表四分之一秒; 如果時間尺度為10,則每個單位表示十分之一秒,依此類推。您經常使用600的時間刻度,因為這是幾種常用的幀速率的倍數:24 fps的電影,30 fps的NTSC(用于北美和日本的電視)和25 fps的PAL(用于歐洲電視)。使用600的時間刻度,您可以準確地表示這些系統中的任何數量的幀。

除了簡單的時間值之外,CMTime結構可以表示非數值值:+無窮大,-infinity和無限期。它也可以指示時間是否在某點被舍入,并且它保持一個時代數字。

使用CMTime

您創建一個時間使用CMTimeMake或其中一個相關的功能,如CMTimeMakeWithSeconds(允許您使用浮點數創建一個時間并指定首選時間表)。有幾種基于時間的算術和比較時間的功能,如下例所示:

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");
}

有關所有可用功能的列表,請參閱CMTime參考

CMTime的特殊價值

核心媒體提供了特殊值的常量:kCMTimeZero,kCMTimeInvalid,kCMTimePositiveInfinity,和kCMTimeNegativeInfinity。CMTime例如,結構可以有許多方式表示無效的時間。為了測試是否CMTime是有效的,或者非數字的值,你應該使用合適的微距,例如CMTIME_IS_INVALIDCMTIME_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.
}

你不應該比較任意CMTime結構的值kCMTimeInvalid。

將CMTime表示為對象

如果需要CMTime在注釋或Core Foundation容器中使用結構,則可以分別使用和函數將CMTime結構轉換為CFDictionary不透明類型(參見CFDictionaryRef)。您還可以使用該函數獲取結構的字符串表示形式。CMTimeCopyAsDictionaryCMTimeMakeFromDictionaryCMTimeCMTimeCopyDescription

Epochs

CMTime結構的時代號通常設置為0,但您可以使用它來區分不相關的時間軸。例如,可以使用呈現循環在每個循環中遞增歷元,以區分N循環0中的時間N和循環1中的時間。

CMTimeRange表示時間范圍

CMTimeRange是具有開始時間和持續時間的C結構,都表示為CMTime
結構。時間范圍不包括開始時間加上持續時間的時間。

您使用CMTimeRangeMake或創建時間范圍CMTimeRangeFromTimeToTime。對CMTime時代的價值有一些限制:

  • CMTimeRange 結構不能跨越不同的時代。
  • CMTime表示時間戳的結構中的時期可能不為零,但您只能CMTimeRangeGetUnion對起始字段具有相同歷元的范圍執行范圍操作(例如)。
  • CMTime表示持續時間的結構中的時期應始終為0,該值必須為非負數。
使用時間范圍

核心媒體提供了可用于確定時間范圍是否包含給定的時間或其他時間范圍的功能,確定兩個時間段是否相等,并計算工會和時間范圍的交叉點,例如CMTimeRangeContainsTimeCMTimeRangeEqualCMTimeRangeContainsTimeRange,和CMTimeRangeGetUnion

鑒于時間范圍不包括開始時間加上持續時間的時間,以下表達式總是計算為false:

CMTimeRangeContainsTime(range,CMTimeRangeGetEnd(range))

有關所有可用函數的列表,請參閱CMTimeRange參考

CMTimeRange的特殊值

核心媒體提供常數零長度范圍和無效范圍,kCMTimeRangeZerokCMTimeRangeInvalid分別。有許多方法,盡管CMTimeRange
結構可能是無效的,或者是零或不確定的(如果其中一個CMTime結構是無限的)如果你需要測試CMTimeRange
結構是有效的,零的還是不確定的,你應該使用適當的宏:CMTIMERANGE_IS_VALIDCMTIMERANGE_IS_INVALIDCMTIMERANGE_IS_EMPTY,或CMTIMERANGE_IS_EMPTY

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

你不應該比較任意CMTimeRange結構的值kCMTimeRangeInvalid。

將CMTimeRange結構表示為對象

如果需要CMTimeRange在注釋或Core Foundation容器中使用結構,則可以分別使用和/ 或將透明類型(見)轉換CMTimeRange為CFDictionary不透明類型的結構。您還可以使用該函數獲取結構的字符串表示形式。CFDictionaryRefCMTimeRangeCopyAsDictionaryCMTimeRangeMakeFromDictionaryCMTimeCMTimeRangeCopyDescription

媒體表示

視頻數據及其關聯的元數據在AV Foundation中由Core Media框架的不透明對象表示。Core Media代表使用CMSampleBuffer(見CMSampleBufferRef)的視頻數據。CMSampleBuffer是一種核心基礎風格的不透明型; 一個實例包含視頻數據幀作為核心視頻像素緩沖區的樣本緩沖區(參見CVPixelBufferRef)。您可以使用CMSampleBufferGetImageBuffer以下方式從樣本緩沖區訪問像素緩沖區

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

從像素緩沖區,您可以訪問實際的視頻數據。有關示例,請參閱將CMSampleBuffer轉換為UIImage對象

除了視頻數據外,您還可以檢索視頻幀的其他方面:

  • 時序信息。你得到兩個原始演示文稿的時間和使用解碼時間準確時間戳CMSampleBufferGetPresentationTimeStampCMSampleBufferGetDecodeTimeStamp分別。

  • 格式化信息。格式信息封裝在CMFormatDescription對象中(參見CMFormatDescriptionRef)。從格式的描述,您可以使用獲得例如像素型和視頻的尺寸CMVideoFormatDescriptionGetCodecType和CMVideoFormatDescriptionGetDimensions分別。

  • 元數據。元數據作為附件存儲在字典中。你CMGetAttachment用來檢索字典:

      CMSampleBufferRef sampleBuffer = <#獲取一個樣本緩沖區#>;
    
    CFDictionaryRef metadataDictionary =
    
    CMGetAttachment(sampleBuffer,CFSTR(“MetadataDictionary”,NULL);
    
    if(metadataDictionary){
    
    //用元數據做某事
    
    }
    

將CMSampleBuffer轉換為UIImage對象

以下代碼顯示了如何將a轉換CMSampleBuffer為UIImage對象。使用前請仔細考慮您的要求。執行轉換是相對昂貴的操作。例如,從每秒鐘拍攝的視頻數據幀中創建靜止圖像是適當的。您不應該使用它來實時地操縱來自捕獲設備的每一幀視頻。

// 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);
}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容