您的位置:首页 > 产品设计 > UI/UE

AVFoundation Programming Guide - Using Assets

2016-12-28 11:06 381 查看
Using AssetsAssets can come from a file or from media in the user’s iPod library or Photo library. When you create an asset object all the information that you might want to retrieve for that item is not immediately available. Once youhave a movie asset, you can extract still images from it, transcode it to another format, or trim the contents.

Creating an Asset Object

To create an asset to represent any resource that you can identify using a URL, you use 
AVURLAsset
.The simplest case is creating an asset from a file:为了创建asset来表示任意确定使用URL的资源,我们可以使用
AVURLAsset
下面是最简单的例子从文件创建asset:
NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];

Options for Initializing an Asset

The 
AVURLAsset
 initialization methods take as their second argument an options dictionary. The only key used in the dictionary is 
AVURLAssetPreferPreciseDurationAndTimingKey
.The corresponding value is a Boolean (contained in an 
NSValue
 object) that indicates whether the asset should be prepared to indicate a precise duration and provideprecise random access by time.AVURLAsset初始化方法把第二个参数作为一个可选的字典,唯一的key能够被用于这个字典里的是AVURLAssetPreferPreciseDurationAndTimingKey,它的value是一个boolean类型(用NSValue包装的对象),这个值表示asset是否提供一个精确的duration并且随机按时间获取。Getting the exact duration of an asset may require significant processing overhead. Using an approximate duration is typically a cheaper operation and sufficient for playback. Thus:获取asset精确的duration需要过多的处理过程,而使用一个近似的duration是轻量级操作并且效率比较高,对播放来说已经足够。因此:If you only intend to play the asset, either pass 
nil
 instead of a dictionary, or pass a dictionary that contains the 
AVURLAssetPreferPreciseDurationAndTimingKey
 keyand a corresponding value of 
NO
(contained in an 
NSValue
 object).如果你只是想要播放asset,初始化方法传nil就行了,而不是一个dictionary,或者传一个以AVURLAssetPreferPreciseDurationAndTimingKey为key,值为NO的一个dictionary。If you want to add the asset to a composition (
AVMutableComposition
),you typically need precise random access. Pass a dictionary that contains the 
AVURLAssetPreferPreciseDurationAndTimingKey
 key and a corresponding value of 
YES
 (containedin an 
NSValue
 object—recall that 
NSNumber
 inheritsfrom 
NSValue
):如果你想把asset加到一个composition中,而且你需要一个精确的随机访问,这时你可以传一个dictionary,这个dictionary的一组键值对为AVURLAssetPreferPreciseDurationAndTimingKey和YES。
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

To access the assets managed by the iPod library or by the Photos application, you need to get a URL of the asset you want.为了访问由iPod library 和应用相册里asset,你需要获取你需要asset的URL。To access the iPod Library, you create an 
MPMediaQuery
 instanceto find the item you want, then get its URL using 
MPMediaItemPropertyAssetURL
.Formore about the Media Library, see Multimedia Programming Guide.To access the assets managed by the Photos application, you use 
ALAssetsLibrary
.为了访问iPod Library,我们可以创建MPMediaQuery对象来找到你想要对象,然后通过MPMediaItemPropertyAssetURL获取它的URL。要想获取更多关于MediaLibrary,查看 Multimedia Programming Guide.为了访问相册管理的assets,我们可以使用
ALAssetsLibrary
.The following example shows how you can get an asset to represent the first video in the Saved Photos Album.下面的例子用来获取相册里面的第一个视频
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];// Enumerate just the photos and videos group by using ALAssetsGroupSavedPhotos.[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {// Within the group enumeration block, filter to enumerate just videos.[group setAssetsFilter:[ALAssetsFilter allVideos]];// For this example, we're only interested in the first item.[group enumerateAssetsAtIndexes:[NSIndexSet indexSetWithIndex:0]options:0usingBlock:^(ALAsset *alAsset, NSUInteger index, BOOL *innerStop) {// The end of the enumeration is signaled by 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.}}];}failureBlock: ^(NSError *error) {// Typically you should handle an error more gracefully than this.NSLog(@"No groups");}];

Preparing an Asset for Use

Initializing an asset (or track) does not necessarily mean that all the information that you might want to retrieve for that item is immediately available. It may require some time to calculate eventhe duration of an item (an MP3 file, for example, may not contain summary information). Rather than blocking the current thread while a value is being calculated, you should use the 
AVAsynchronousKeyValueLoading
 protocol toask for values and get an answer back later through a completion handler you define using a block. (
AVAsset
 and 
AVAssetTrack
 conformto the 
AVAsynchronousKeyValueLoading
 protocol.)初始化一个asset(或者track)并不表示你想从item中获取的信息都是立马可用的。它需要一些时间去计算,相当于item的播放时间(duration)(比如:没有摘要信息的mp3文件),你应该使用AVAsynchronousKeyValueLoading协议获取这些值,通过- loadValuesAsynchronouslyForKeys:completionHandler:在handler里面获取你要的值,而不应该在值被计算的时候阻塞当前线程。(AVAssetand AVAssetTrack 遵守了AVAsynchronousKeyValueLoading protocol)You test whether a value is loaded for a property using 
statusOfValueForKey:error:
.When an asset is first loaded, the value of most or all of its properties is 
AVKeyValueStatusUnknown
.To load a value for one or more properties, you invoke 
loadValuesAsynchronouslyForKeys:completionHandler:
.In the completion handler, you take whatever action is appropriate depending on the property’s status. You should always be prepared for loading to not complete successfully, either because it failed for some reason such as a network-based URL being inaccessible,or because the load was canceled.你可以用statusOfValueForKey:error:测试一个属性的value是否成功获取,当一个assert第一次被加载,大多数属性的值是AVKeyValueStatusUnknown状态,为了获取一个或多个属性的值,你要调用loadValuesAsynchronouslyForKeys:completionHandler:,在completion handler里面,你可以根据属性的状态做任何合适的处理。你要处理加载没有成功的情况,可能因为一些原因比如网络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;}}];
If you want to prepare an asset for playback, you should load its 
tracks
 property.For more about playing assets, see Playback.如果你想要播放asset,你应该加载它的tracks属性,更多学习看Playback

Getting Still Images From a Video

To get still images such as thumbnails from an asset for playback, you use an 
AVAssetImageGenerator
object.You initialize an image generator with your asset. Initialization may succeed, though, even if the asset possesses no visual tracks at the time of initialization, so if necessary you should test whether the asset has any tracks with the visual characteristicusing 
tracksWithMediaCharacteristic:
. 为了从asset中获取静态图片(比如说缩略图)用于播放,我们可以用AVAssetImageGenerator对象。可以用asset初始化一个AVAssetImageGenerator对象.即使asset在初始化的时候拥有不可见的track,初始化也可能成功。所以如果需要你应该检测asset是否有容易的tracks拥有着可视的特征,使用tracksWithMediaCharacteristic:
AVAsset anAsset = <#Get an asset#>;if ([[anAsset tracksWithMediaType:AVMediaTypeVideo] count] > 0) {AVAssetImageGenerator *imageGenerator =[AVAssetImageGenerator assetImageGeneratorWithAsset:anAsset];// Implementation continues...}
You can configure several aspects of the image generator, for example, you can specify the maximum dimensions for the images it generates and the aperture mode using 
maximumSize
 and 
apertureMode
respectively.Youcan then generate a single image at a given time, or a series of images. You must ensure that you keep a strong reference to the image generator until it has generated all the images.我们可以设置imagegenerator的一些方面,比如,我们可以使用属性maximumSizeapertureMode指定生成图片的最大尺寸和光圈模式,你可以指定时间生成一张图片,或者一系列图片。你必须确保一直持有generator的强引用,直到生成所有的图片。

Generating a Single Image

You use 
copyCGImageAtTime:actualTime:error:
 togenerate a single image at a specific time. AVFoundation may not be able to produce an image at exactly the time you request, so you can pass as the second argument a pointer to a CMTime that upon return contains the time at which the image was actually generated.我们可以使用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

To generate a series of images, you send the image generator a 
generateCGImagesAsynchronouslyForTimes:completionHandler:
 message.The first argument is an array of 
NSValue
 objects,each containing a 
CMTime
 structure, specifying the asset times for which you want images to be generated. The second argument is a block thatserves as a callback invoked for each image that is generated. The block arguments provide a result constant that tells you whether the image was created successfully or if the operation was canceled, and, as appropriate:为了生成一系列图片,我们可以调用image generator的generateCGImagesAsynchronouslyForTimes:completionHandler:方法,第一个参数是一个包含NSValue类型的数组,数组里每一个对象都是CMTime结构体,表示你想要生成的图片在视频中的时间点,第二个参数是一个block,每生成一张图片都会回调这个block,这个block提供一个result的参数告诉你图片是否成功生成或者图片生成操作是否取消。The image 生成的图片The time for which you requested the image and the actual time for which the image was generated 图片生成的实际时间An error object that describes the reason generation failed 错误的原因In your implementation of the block, check the result constant to determine whether the image was created. In addition, ensure that you keep a strong reference to the image generator untilit has finished creating the images.在你的block实现中,需要检查result,判断image是否成功生成,另外,确保你强引用有image generator直到生成图片的操作结束。
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:timescompletionHandler:^(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");}}];
You can cancel the generation of the image sequence by sending the image generator a 
cancelAllCGImageGeneration
 message.你也可以取消生成图片的操作,通过向generator发送cancelAllCGImageGeneration的消息。

Trimming and Transcoding a Movie

You can transcode a movie from one format to another, and trim a movie, using an 
AVAssetExportSession
 object.The workflow is shown in Figure 1-1. An export session is a controller object that manages asynchronous export of an asset. You initialize the session using the asset you want to export and the name of a export presetthat indicates the export options you want to apply (see 
allExportPresets
).You then configure the export session to specify the output URL and file type, and optionally other settings such as the metadata and whether the output should be optimized for network use.你可以对视频进行转码、裁剪,通过使用AVAssetExportSession对象。这个流程如下图所示:一个export session是一个控制对象,可以异步的生成一个asset。可以用你需要生成的asset和预置的export name来初始化一个session,该export preset指明你想要使用的export options(可以看allExportPresets)。我们可以配置exportsession,比如可以指定输出的URL和文件类型,以及其他的设置,比如metadata、是否输出应该使用最优网络等等。Figure 1-1  Theexport session workflowYou can check whether you can export a given asset using a given preset using 
exportPresetsCompatibleWithAsset:
 asillustrated in this example:我们可以先检测是否export使用了给定的preset,通过使用exportPresetsCompatibleWithAsset:方法,下面是具体代码解释:
AVAsset *anAsset = <#Get an asset#>;NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:anAsset];if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) {AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:anAsset presetName:AVAssetExportPresetLowQuality];// Implementation continues.}
You complete the configuration of the session by providing the output URL (The URL must be a file URL.) 
AVAssetExportSession
 caninfer the output file type from the URL’s path extension; typically, however, you set it directly using 
outputFileType
.You can also specify additional properties such as the time range, a limit for the output file length, whether the exported file should be optimized for network use, and a video composition. The following example illustrates how to use the 
timeRange
 propertyto trim the movie:你可以提供URL(URL必须是文件URL)来完成配置session,AVAssetExportSession可以推断通过url的扩展名出输出文件的类型。当然,你可以直接设置输出文件类型,使用
outputFileType
.。也可以指定其他属性,比如timerange,限制输出文件的长度等等,是否输出文件应该在最优网络下使用,video组成部分,下面列子解释了怎样使用 
timeRange
 剪裁video:
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;
To create the new file, you invoke 
exportAsynchronouslyWithCompletionHandler:
.The completion handler block is called when the export operation finishes; in your implementation of the handler, you should check the session’s 
status
 valueto determine whether the export was successful, failed, or was canceled:为了创建新的文件,我们能够调用
exportAsynchronouslyWithCompletionHandler:
,当输出操作完成block被调用,在handler中,我们应该检查session的status来判断是成功、失败、还是取消,如下:
[exportSession exportAsynchronouslyWithCompletionHandler:^{switch ([exportSession status]) {case AVAssetExportSessionStatusFailed:NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);break;case AVAssetExportSessionStatusCancelled:NSLog(@"Export canceled");break;default:break;}}];
You can cancel the export by sending the session a 
cancelExport
 message.你可以取消这个生成(export)操作,通过给session发送 cancelExport 消息。The export will fail if you try to overwrite an existing file, or write a file outside of the application’s sandbox. It may also fail if:如果我们尝试重写存在的文件,或者在应用沙盒之外写文件,那么导出将失败,下面情况也可能会失败:There is an incoming phone call  来了一个电话Your application is in the background and another application starts playback你的程序在后台运行并且其他的应用开始播放In these situations, you should typically inform the user that the export failed, then allow the user to restart the export.这种情况下,你应该通知用户export失败,并且重新export
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: