轉載自:chenjiang3的技術博客html
爲了建立一個由URL標識的表明任何資源的assert對象,可使用AVURLAssert,最簡單的是從文件裏建立一個assert對象:ios
NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>; AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
AVURLAsset初始化方法的第二個參數使用一個dictionary,這個dictionary裏的惟一一個key是 AVURLAssetPreferPreciseDurationAndTimingKey,它的value是一個boolean類型(用NSValue包裝的對象),這個值表示asset是否提供一個精確的duration。
獲取asset精確的duration須要不少處理時間,使用一個預估的duration效率比較高而且對播放來講足夠。所以:
· 若是你想要播放asset,初始化方法傳nil就好了,而不是一個dictionry,或者傳一個以AVURLAssetPreferPreciseDurationAndTimingKeydictionary爲key,值爲NO的一個dictionary。
· 若是你想把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];
爲了訪問 iPod library 和相冊裏asset,你須要獲取asset的URL。
· 爲了訪問ipod Library,須要建立MPMediaQuery對象來找到你想要對象,而後經過MPMediaItemPropertyAssetURL獲取它的URL。要想獲取更多關於Media Library,查看Multimedia Programming Guide.
· 爲了訪問相冊,可使用ALAssetsLibrary.
下面的例子用來獲取相冊裏面的第一個視頻:
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:0 usingBlock:^(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"); }];
初始化一個asset(或者track)並非表示asset裏面全部的信息都是立刻可用的。它須要一些時間去計算,即便是durtation(好比沒有摘要信息的mp3文件),你應該使用AVAsynchronousKeyValueLoading協議獲取這些值,經過- loadValuesAsynchronouslyForKeys:completionHandler:在handler裏面獲取你要的值。
你能夠用statusOfValueForKey:error:測試一個屬性的value是否成功獲取,當一個assert第一次被加載,大多數屬性的值是AVKeyValueStatusUnknown狀態,爲了獲取一個或多個屬性的值,你要調用loadValuesAsynchronouslyForKeys:completionHandler:,在comletiton handler裏面,你能夠根據屬性的狀態作任何合適的處理。你要處理加載沒有成功的狀況,可能由於一些緣由好比網絡不可鏈接,又或者loading被取消。session
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; } }];
若是你想要播放asset,你應該加載他的tracks屬性。app
從asset中獲取靜態圖片(好比說縮略圖),你能夠用AVAssetImageGenerator對象。能夠用asset初始化一個AVAssetImageGenerator對象.即便asset在初始化的時候沒有可見的track也能成功,因此你應該檢測asset是否有track,使用tracksWithMediaCharacteristic:異步
AVAsset anAsset = <#Get an asset#>; if ([[anAsset tracksWithMediaType:AVMediaTypeVideo] count] > 0) { AVAssetImageGenerator *imageGenerator = [AVAssetImageGenerator assetImageGeneratorWithAsset:anAsset]; // Implementation continues... }
你還能夠設置imagegenerator的其餘屬性,好比,你能夠指定生成圖片的最大的分辨率,你能夠生成指定時間的一張圖片,或者一系列圖片。你必須一直持有generator的引用,直到生成全部的圖片。ide
你可使用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); }
爲了生成一系列圖片,你能夠調用generateCGImagesAsynchronouslyForTimes:completionHandler:,第一個參數是一個包含NSValue類型的數組,數組裏每個對象都是CMTime結構體,表示你想要生成的圖片在視頻中的時間點,第二個參數是一個block,每生成一張圖片都會回調這個block,這個block提供一個result的參數告訴你圖片是否成功生成或者圖片生成操做是否取消。ui
在你的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: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"); } }];
你也能夠取消生成圖片的操做,經過想generator發送cancelAllCGImageGeneration的消息。
你能夠對視頻進行轉碼、裁剪,經過使用AVAssetExportSession對象。這個流程以下圖所示,
一個export session是一個控制對象,能夠異步的生成一個asset。能夠用你須要生成的asset和presetName來初始化一個session,presetName指明你要生成的asset的屬性。接下來你能夠配置export session,好比能夠指定輸出的URL和文件類型,以及其餘的設置,好比metadata等等。
你能夠先檢測設置的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. }
你能夠配置session的輸出的url(這個url必須是文件url),AVAssetExportSession能夠推斷經過url的擴展名出輸出文件的類型。固然,你能夠直接設置文件類型,使用outputFileType。你還能夠指定其餘屬性,好比time range,輸出文件的長度等等,下面是列子:
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;
生成一個新的asset,能夠調用exportAsynchronouslyWithCompletionHandler:,當生成操做結束後會回調block,在這個block中你須要經過檢查session的status來判斷是否成功,以下:
[exportSession exportAsynchronouslyWithCompletionHandler:^{ switch ([exportSession status]) { case AVAssetExportSessionStatusFailed: NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]); break; case AVAssetExportSessionStatusCancelled: NSLog(@"Export canceled"); break; default: break; } }];
你能夠取消這個生成操做,經過給session發送 cancelExport 消息。
若是導出的文件存在,或者導出的url在沙盒以外,這個導出操做會失敗。還有兩種狀況也可能致使失敗:
· 來了一個電話
· 你的程序在後臺運行而且其餘的應用開始播放。
這種狀況下,你應該通知用戶export失敗,而且從新export。