本文是本人自己辛苦翻譯的,請轉(zhuǎn)載的朋友注明谢揪,翻譯于Z.MJun的簡書 删顶,感謝!<翻譯不容易啊>
翻譯于2016年9月6日
Assets可以從用戶的IPod's庫或者圖片庫的一個文件或者媒體來闭专。當(dāng)你創(chuàng)建一個Assets對象奴潘,所有的信息,你想檢索的是不可以立即可用的影钉。例如你有一個電影的Assets画髓,你可以提取它的圖片,轉(zhuǎn)成其他格式平委,或者修建內(nèi)容奈虾。
創(chuàng)建一個Assets
創(chuàng)建Assets來代表任何資源,你可以使用一個URL廉赔,使用AVURLAsset以下是一個極簡單的例子肉微。
NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
Asset初始化設(shè)置
AVURLAsset
初始方法的第二參數(shù)位選項字典。使用在字典里面的唯一一個關(guān)鍵詞為[AVURLAssetPreferPreciseDurationAndTimingKey](https://developer.apple.com/reference/avfoundation/avurlassetpreferprecisedurationandtimingkey)蜡塌。相對應(yīng)的值是布爾值(包含一個
NSValue`對象)碉纳。這表明,Asset是否應(yīng)該準(zhǔn)備好表示一個精確的持續(xù)時間和提供精確隨機(jī)存取時間馏艾。
獲取Asset的精確時間劳曹,可能需要明顯的性能開銷。但是使用一個相對的持續(xù)時間通忱拍Γ可以大大減少開銷和足夠的回放厚者。
- 如果你只是打算播放Asset,可以使用
nil
替換這個字典迫吐,或者使用一個字典AVURLAssetPreferPreciseDurationAndTimingKey
和值為NO
库菲。 - 如果你想增加Asset到組件里面AVMutableComposition,你通常需要精確地隨機(jī)存取志膀。使用一個字典
AVURLAssetPreferPreciseDurationAndTimingKey
key熙宇,和對應(yīng)值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];
訪問用戶的Assets
訪問iPod庫或者圖片應(yīng)用管理的Assets,你需要獲取Assets的URL烫止。
- 訪問IPod庫蒋荚,創(chuàng)建MPMediaQuery實例來需找你想要的內(nèi)容,獲取URL使用MPMediaItemPropertyAssetURL
有個更多關(guān)于媒體庫的馆蠕,請看Multimedia Programming Guide期升。 - 訪問圖片應(yīng)用,請看ALAssetsLibrary
根據(jù)這個例子互躬,你可以獲得一個asset來表示存放在相片冊里面的第一個視頻播赁。
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");
}];
準(zhǔn)備使用Asset
初始化一個Asset(或者軌道)不代表所有的信息你馬上能使用。他可能要求一些時間來計算吼渡,如總時長(一個MP3文件容为,例如,可能沒有包含所有信息)寺酪。而不是阻塞一個當(dāng)前線程直到這個值倍計算出來坎背,你應(yīng)該使用AVAsynchronousKeyValueLoading協(xié)議來請求這個值,和只用一個block來獲取這個數(shù)據(jù)寄雀。AVAsset
和AVAssetTrack
符合AVAsynchronousKeyValueLoading
協(xié)議得滤。
測試是有有一個是加載是為一個屬性服務(wù)statusOfValueForKey:error:。當(dāng)一個asset第一加載盒犹,大多數(shù)情況下是AVKeyValueStatusUnknown
懂更。位一個或多個屬性加載一個值,可以借助loadValuesAsynchronouslyForKeys:completionHandler:
阿趁。在完成的處理程序中膜蛔,你采取任何適當(dāng)?shù)男袆佣际侨Q于屬性的狀態(tài)坛猪。你應(yīng)該總是為加載失敗準(zhǔn)備,因為失敗有很多原因命黔,如網(wǎng)絡(luò)無法訪問就斤,或者請求被取消悍募。
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;
}
}];
如果你想為回放準(zhǔn)備一個asset,你需要請求tracks
屬性洋机,關(guān)于更多的播放中的asset,請看Playback喜鼓。
從Video獲取一個靜態(tài)圖片
從asset獲取靜態(tài)圖片副砍,如略縮圖,你可以使用 AVAssetImageGenerator對象庄岖。使用你的asset初始化圖片generator豁翎。初始化可能成功隅忿,不過,即使asset在初始化的時候沒有視覺跟蹤优烧,但是牢撼,如果有需要可以使用trackswithmediacharacteristic
來檢測asset任何具有視覺特性的軌道。
AVAsset anAsset = <#Get an asset#>;
if ([[anAsset tracksWithMediaType:AVMediaTypeVideo] count] > 0) {
AVAssetImageGenerator *imageGenerator =
[AVAssetImageGenerator assetImageGeneratorWithAsset:anAsset];
// Implementation continues...
}
你可以配置一些特性是關(guān)于圖片generator熏版。例如撼短,你可以指定圖像的最大尺寸和分別使用maximumSize生成最大光圈模式和apertureMode。你也可以在一個是指定的時間生成單張圖片或者一系列圖片曲横。你需要保證,圖片generator保持強(qiáng)引用灾杰,直到所有圖片生成熙参。
生成單張圖片
你可以使用copyCGImageAtTime:actualTime:error:在特定時間生成單張圖片。AVFoundation有可能不能生成你想要的一個精確時間的圖片昭娩。所以你可以通過第二參數(shù)指向CMTime
黍匾,這個時間包含了你想生成圖片的時間,從而達(dá)到圖片真正的生成了磕诊。
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);
}
生成序列圖片
生成一系列圖片,你可以發(fā)送圖片generator一個enerateCGImagesAsynchronouslyForTimes:completionHandler:消息融痛。第一個參數(shù)是一個NSValue
的數(shù)組神僵,每個都包含CMTime
結(jié)構(gòu),指定了你想要的那張圖片的時間保礼。第二參數(shù)是一個Block,來確定每張圖片是否生成炮障。
block包含參數(shù):
- 圖片
- 時間胁赢,這個時間是你想要生成圖片的時間
- 錯誤提示,描述生成失敗的原因
當(dāng)你執(zhí)行你的block智末,檢查結(jié)果是否生成了圖片。另外送漠,你需要保證由蘑,圖片generator保持強(qiáng)引用,直到所有圖片生成爷狈。
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取消圖片generator涎永。
電影微調(diào)和轉(zhuǎn)碼
你可以使用AVAssetExportSession把電影從這個格式轉(zhuǎn)換到另一個格式句惯,和微調(diào)電影支救。工作流如下圖各墨。一個輸出會話是一個控制器隊形管理異步的Asset輸出。初始化會話使用你想導(dǎo)出的Asset,和一個輸出設(shè)定名稱结洼,表明你想申請的輸出選項叉跛。(看allExportPresets)。你可以配置輸出會話來制定輸出的URL和文件格式鸣峭,和選項其他設(shè)置酥艳。例如元數(shù)據(jù)和是否網(wǎng)絡(luò)優(yōu)先使用。
你可以檢測你是否可以導(dǎo)出指定的asset莫换。使用 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.
}
你根據(jù)給定的輸出URL完成了會話配置(URL必須是文件URL)AVAssetExportSession
通扯枧溃可以推斷輸出文件類型來自URL的路徑擴(kuò)展。但是补鼻,你可以直接設(shè)置outputFileType风范。你也可以指定額外屬性,如時間區(qū)間硼婿,最小輸出文件長度。輸出的文件是否應(yīng)該網(wǎng)絡(luò)有限使用刊殉,和視頻組件州胳。根據(jù)這個例子說明,怎么使用timeRange這個屬性來微調(diào)電影遍膜。
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;
創(chuàng)建一個新的文件,你可以借助exportAsynchronouslyWithCompletionHandler:這個方法恩尾。當(dāng)操作完成會相應(yīng)完成Block挽懦。在你實現(xiàn)的處理程序,你應(yīng)該檢查會話的狀態(tài)值猎物,決定了這個輸出是否成功角塑,失敗,或者取消堤如。
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
break;
}
}];
你可以通過對會話發(fā)送cancelExport來取消輸出窒朋。
當(dāng)你嘗試覆蓋一個存在文件或者把文件寫入這個應(yīng)用外的沙河時候侥猩,這個輸出將會失敗。
以下也有可能導(dǎo)致失斊劾汀:
- 一個電話打入
- 應(yīng)用在后臺,或者其他應(yīng)用開始工作枫弟。
在這些情況下鹏往,你應(yīng)該通常通知用戶導(dǎo)出失敗,并允許用戶重新導(dǎo)出韩容。