Using Assets
资源可以来自用户的iPod库或照片库中的文件或媒体。当您创建资产对象时,您可能想要为该项目检索的所有信息不会立即可用。拥有电影资源后,您可以从中提取静态图片,将其转码为其他格式或修剪内容。
Creating an Asset Object(创建资源对象)
要创建资源来表示可以使用URL标识的任何资源,请使用AVURLAsset。最简单的情况是从文件创建资产:
NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;标识视听资源(例如电影文件)的URL
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil]
Options for Initializing an Asset(初始化资源的选项)
AVURLAsset初始化方法将第二个参数作为选项字典。字典中唯一使用的密钥是AVURLAssetPreferPreciseDurationAndTimingKey。相应的值是一个布尔值(包含在NSValue对象中),用于指示资源是否应准备好指示精确的持续时间并提供按时间进行的精确随机访问。获取资源的确切持续时间可能需要大量的处理开销。使用大致的持续时间通常是更便宜的操作并且足够播放。从而:
1>.如果您只打算播放资源,则传递nil而不是字典,或传递包含AVURLAssetPreferPreciseDurationAndTimingKey键和NO(包含在NSValue对象中)的相应值的字典。
2>.如果要将资产添加到合成(AVMutableComposition),通常需要精确的随机访问。传递一个包含AVURLAssetPreferPreciseDurationAndTimingKey键和相应值YES的字典 (包含在NSValue对象中 - 回想NSNumber从NSValue继承):
NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;
NSDictionary *options = @{ AVURLAssetPreferPreciseDurationAndTimingKey : @YES };
AVURLAsset *anAssetToUseInAComposition = [[AVURLAsset alloc] initWithURL:url options:options];
Accessing the User’s Assets(访问用户资源)
要访问由iPod库或Photos应用程序管理的资产,您需要获取所需资产的URL。
1>.要访问iPod库,您需要创建一个MPMediaQuery实例来查找所需的项目,然后使用MPMediaItemPropertyAssetURL获取其URL。
2>.有关媒体库的更多信息,请参阅多媒体编程指南。
3>.要访问Photos应用程序管理的资产,请使用ALAssetsLibrary。
以下示例显示如何获取资源以表示“已保存的照片相册”中的第一个视频。
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.通过使用ALAssetsGroupSavedPhotos来枚举照片和视频组。
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
//在组枚举block中,筛选仅列举视频
[group setAssetsFilter:[ALAssetsFilter allVideos]];
// 举个例子,我们只对第一个item感兴趣
[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:0]
options:0
usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {
//枚举的结尾由asset == nil表示
if (alAsset) {
ALAssetRepresentation *representation = [alAsset defaultRepresentation];
NSURL *url = [representation url];
AVAsset *avAsset = [AVURLAsset URLAssetWithURL:url options:nil];
// Do something interesting with the AV asset 对AV资产做一些有趣的事情
}
}];
}
failureBlock: ^(NSError *error) {
// Typically you should handle an error more gracefully than this.
NSLog(@"No groups");
}];
Preparing an Asset for Use (准备资源以供使用)
初始化资源(或轨道)并不一定意味着您可能想要为该item检索的所有信息都立即可用。可能需要一些时间来计算一个item的持续时间(例如,MP3文件可能不包含摘要信息)。在计算值时,不应阻塞当前线程,而应使用AVAsynchronousKeyValueLoading协议来请求值,并稍后通过您使用block定义的完成处理程序返回答案。(AVAsset和AVAssetTrack符合AVAsynchronousKeyValueLoading协议)。
您测试是否为使用statusOfValueForKey:error :的属性加载了一个值.首次加载资源时,其大部分或全部属性的值为AVKeyValueStatusUnknown。要为一个或多个属性加载值,可以调用loadValuesAsynchronouslyForKeys:completionHandler :.在完成处理程序中,根据属性的状态采取适当的操作。您应该始终准备好加载时 未成功完成加载,要么是因为某些原因(例如基于网络的URL无法访问),要么因为加载被取消而失败。
NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
NSArray *keys = @[@"duration"];
[asset loadValuesAsynchronouslyForKeys:keys completionHandler:^() {
NSError *error = nil;
AVKeyValueStatus tracksStatus = [asset statusOfValueForKey:@"duration" error:&error];
switch (tracksStatus) {
case AVKeyValueStatusLoaded:
[self updateUserInterfaceForDuration];
break;
case AVKeyValueStatusFailed:
[self reportError:error forAsset:asset];
break;
case AVKeyValueStatusCancelled:
// Do whatever is appropriate for cancelation.
break;
}
}];
如果您想准备资源进行播放,则应加载其轨道属性。有关播放资源的更多信息,请参阅Playback.。
Getting Still Images From a Video(从视频获取静止图像)
从资源中获取静止图像(例如缩略图)用于播放。请使用AVAssetImageGenerator对象。您使用您的资源初始化图像生成器。虽然初始化可能会成功,即使资源在初始化时没有 视觉轨迹,所以如果有必要,您应该使用trackWithMediaCharacteristic:来测试资源是否具有视觉特征的任何轨迹。
AVAsset anAsset = <#Get an asset#>;
if ([[anAsset tracksWithMediaType:AVMediaTypeVideo] count] > 0) {
AVAssetImageGenerator *imageGenerator =
[AVAssetImageGenerator assetImageGeneratorWithAsset:anAsset];
// Implementation continues...继续执行..
}
您可以配置图像生成器的几个方面,例如,您可以分别指定它生成的图像的最大尺寸和使用maximumSize和apertureMode的光圈模式。然后,您可以在给定时间或一系列图像上生成单个图像。您必须确保您保留对图像生成器的强烈参考,直至其生成所有图像。
Generating a Single Image(生成单个图像)
您使用copyCGImageAtTime:actualTime:error:在特定时间生成单个图像。AVFoundation可能无法在您请求的确切时间生成图像,因此您可以将第二个参数作为一个指向CMTime的指针,该指针在返回时包含图像实际生成的时间。
AVAsset *myAsset = <#An asset#>];
AVAssetImageGenerator *imageGenerator = [[AVAssetImageGenerator alloc] initWithAsset:myAsset];
Float64 durationSeconds = CMTimeGetSeconds([myAsset duration]);
CMTime midpoint = CMTimeMakeWithSeconds(durationSeconds/2.0, 600);
NSError *error;
CMTime actualTime;
CGImageRef halfWayImage = [imageGenerator copyCGImageAtTime:midpoint actualTime:&actualTime error:&error];
if (halfWayImage != NULL) {
NSString *actualTimeString = (NSString *)CMTimeCopyDescription(NULL, actualTime);
NSString *requestedTimeString = (NSString *)CMTimeCopyDescription(NULL, midpoint);
NSLog(@"Got halfWayImage: Asked for %@, got %@", requestedTimeString, actualTimeString);
// Do something interesting with the image.对图像做一些有趣的事情。
CGImageRelease(halfWayImage);
}
Generating a Sequence of Images(生成一系列图像)
为生成一系列的图像,你要发送图像发生器generateCGImagesAsynchronouslyForTimes:completionHandler:消息。第一个参数是NSValue对象的数组,每个对象包含一个CMTime结构,指定为其生成图像的资源时间。第二个参数是一个block,用于为 每个生成的图像 调用 一个回调。block参数提供一个结果常量,它告诉您图像是否成功创建,或者是否取消了操作,并且视情况而定:
1>.图像 2>.您请求图片的时间以及图片生成的实际时间 3>.描述原因生成失败的错误对象。
在您的block的实现中,检查结果常量,以确定是否创建了图像。此外,确保您对图像生成器有很强的引用,直到它完成了图像的创建。
AVAsset *myAsset = <#An asset#>];
// Assume: @property (strong) AVAssetImageGenerator *imageGenerator;
self.imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:myAsset];
Float64 durationSeconds = CMTimeGetSeconds([myAsset duration]);
CMTime firstThird = CMTimeMakeWithSeconds(durationSeconds/3.0, 600);
CMTime secondThird = CMTimeMakeWithSeconds(durationSeconds*2.0/3.0, 600);
CMTime end = CMTimeMakeWithSeconds(durationSeconds, 600);
NSArray *times = @[NSValue valueWithCMTime:kCMTimeZero],
[NSValue valueWithCMTime:firstThird], [NSValue valueWithCMTime:secondThird],
[NSValue valueWithCMTime:end]];
[imageGenerator generateCGImagesAsynchronouslyForTimes:times
completionHandler:^(CMTime requestedTime, CGImageRef image, CMTime actualTime,
AVAssetImageGeneratorResult result, NSError *error) {
NSString *requestedTimeString = (NSString *)
CFBridgingRelease(CMTimeCopyDescription(NULL, requestedTime));
NSString *actualTimeString = (NSString *)
CFBridgingRelease(CMTimeCopyDescription(NULL, actualTime));
NSLog(@"Requested: %@; actual %@", requestedTimeString, actualTimeString);
if (result == AVAssetImageGeneratorSucceeded) {
// Do something interesting with the image.
}
if (result == AVAssetImageGeneratorFailed) {
NSLog(@"Failed with error: %@", [error localizedDescription]);
}
if (result == AVAssetImageGeneratorCancelled) {
NSLog(@"Canceled");
}
}];
您可以通过发送图像生成器cancelAllCGImageGeneration消息来取消生成图像序列。
Trimming and Transcoding a Movie(修剪和转码电影)
您可以使用AVAssetExportSession对象将电影从一种格式转换为另一种格式,并修剪电影。工作流程如图1-1所示。导出会话 是管理资源异步导出的 控制器对象。您可以使用你想要 导出的资源 初始化会话,并使用 导出 预设的名称 来表示要应用的 导出选项(请参阅allExportPresets)。然后,您可以配置 导出会话 以 指定输出URL 和 文件类型,以及可选的其他设置,例如元数据以及输出是否应针对网络使用进行优化。Figure 1-1 The export session workflow(导出会话的工作流程)
您可以 检查是否 可以使用 exportPresetsCompatibleWithAsset方法 和使用给定预设 然后导出 给定资产:如本例所示:
AVAsset *anAsset = <#Get an asset#>;
NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:anAsset];
if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {
AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
initWithAsset:anAsset presetName:AVAssetExportPresetLowQuality];//Export 输出,出口,ExportSession 导出会话
// Implementation continues.
}
exportSession.outputURL = <#A file URL#>;
exportSession.outputFileType = AVFileTypeQuickTimeMovie;
CMTime start = CMTimeMakeWithSeconds(1.0, 600);
CMTime duration = CMTimeMakeWithSeconds(3.0, 600);
CMTimeRange range = CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
要创建新文件,请调用exportAsynchronouslyWithCompletionHandler :. 当导出操作完成时,调用完成处理程序block;在执行处理程序时,你应检查会话的状态值以确定导出是成功,失败还是被取消:
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
break;
}
}];
您可以通过发送 cancelExport 消息 来取消导出。如果您尝试覆盖现有文件或在应用程序沙箱外写入文件,导出操作将失败。 在以下情况下它也可能失败:
1>. 有一个来电 2>.您的应用程序在后台,另一个应用程序开始播放。
在这些情况下,通常应该通知用户导出失败,然后允许用户重新启动 。