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

推荐阅读更多精彩内容