寫(xiě)在前面
如果大家需要學(xué)習(xí)了解AVFoundation的可以關(guān)注我的專(zhuān)題《AVFounation官方穩(wěn)當(dāng)翻譯》
正文
Assets可以來(lái)自文件扁眯,也可以來(lái)自于用戶(hù)的iPod庫(kù)或照片庫(kù)中的媒體。當(dāng)您創(chuàng)建一個(gè)asset對(duì)象時(shí),您可能想要檢索的所有信息并沒(méi)有立即得到。一旦你有了電影asset裤翩,你就可以從它中提取靜止的圖像,將其轉(zhuǎn)換成另一種格式调榄,或者修改內(nèi)容踊赠。
Creating an Asset Object(創(chuàng)建一個(gè)Asset對(duì)象)
創(chuàng)建一個(gè)asset來(lái)表示任何asset,你可以使用一個(gè)URL識(shí)別,您使用AVURLAsset
的。最簡(jiǎn)單的例子是從文件中創(chuàng)建asset:
NSURL *url = <#一個(gè)URL每庆,用來(lái)標(biāo)識(shí)諸如電影文件之類(lèi)的視聽(tīng)asset#>;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
Options for Initializing an Asset(初始化asset的選項(xiàng))
AVURLAsset的初始化方法作為第二個(gè)參數(shù)的選項(xiàng)字典筐带。本詞典使用的唯一關(guān)鍵是 AVURLAssetPreferPreciseDurationAndTimingKey。對(duì)應(yīng)的值是一個(gè)布爾值(包含在一個(gè)NSValue對(duì)象中)缤灵,表示該asset是否應(yīng)該準(zhǔn)備好表示精確的持續(xù)時(shí)間伦籍,并按時(shí)間提供精確的隨機(jī)訪(fǎng)問(wèn)蓝晒。
獲取asset的確切時(shí)間可能需要大量的處理開(kāi)銷(xiāo)。使用近似持續(xù)時(shí)間通常是一個(gè)更便宜的操作和足夠的回放鸽斟。因此:
如果你只打算播放asset,通過(guò)nil而不是一本詞典,或通過(guò)字典包含AVURLAssetPreferPreciseDurationAndTimingKey鍵和一個(gè)相應(yīng)的值(包含在一個(gè)NSValue對(duì)象)拔创。
-
如果您想將asset添加到一個(gè)組合(AVMutableComposition
),您通常需要精確的隨機(jī)訪(fǎng)問(wèn)富蓄。通過(guò)字典包含AVURLAssetPreferPreciseDurationAndTimingKey鍵和一個(gè)相應(yīng)的值,是的(包含在一個(gè)NSValue object-recall NSNumber繼承自NSValue):NSURL *url = <#一個(gè)URL剩燥,用來(lái)標(biāo)識(shí)諸如電影文件之類(lèi)的視聽(tīng)asset#>; NSDictionary *options = @{ AVURLAssetPreferPreciseDurationAndTimingKey : @YES }; AVURLAsset *anAssetToUseInAComposition = [[AVURLAsset alloc] initWithURL:url options:options];
Accessing the User’s Assets(訪(fǎng)問(wèn)用戶(hù)的asset)
要訪(fǎng)問(wèn)由iPod庫(kù)或照片應(yīng)用程序管理的asset,您需要獲得您想要的asset的URL立倍。
- 訪(fǎng)問(wèn)iPod圖書(shū)館,你創(chuàng)建一個(gè)MPMediaQuery
實(shí)例來(lái)找到你想要的商品,然后使用 MPMediaItemPropertyAssetURL得到它的URL灭红。
有關(guān)媒體庫(kù)的更多信息,請(qǐng)參閱Multimedia Programming Guide口注。
- 要訪(fǎng)問(wèn)由照片應(yīng)用程序管理的asset变擒,您可以使用ALAssetsLibrary。
下面的示例演示如何獲得一個(gè)asset來(lái)表示保存的Photos相冊(cè)中的第一個(gè)視頻寝志。
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
// 列舉只是利用ALAssetsGroupSavedPhotos照片和視頻組娇斑。
[library enumerateGroupsWithTypes:ALAssetsGroupSavedPhotos usingBlock:^(ALAssetsGroup *group, BOOL *stop) {
// 在組枚舉塊中,篩選以枚舉視頻材部。
[group setAssetsFilter:[ALAssetsFilter allVideos]];
// 對(duì)于本例毫缆,我們只對(duì)第一項(xiàng)感興趣。
[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];
//做一些有趣的AV asset苦丁。
}
}];
}
failureBlock: ^(NSError *error) {
// 通常,您應(yīng)該更優(yōu)雅地處理一個(gè)錯(cuò)誤物臂。
NSLog(@"No groups");
}];
Preparing an Asset for Use(準(zhǔn)備asset以供使用)
初始化asset(或跟蹤)并不意味著您可能想要檢索的所有信息都立即可用旺拉。它可能需要一些時(shí)間來(lái)計(jì)算一個(gè)條目的持續(xù)時(shí)間(例如,MP3文件可能不包含摘要信息)棵磷。而不是阻塞當(dāng)前線(xiàn)程,而一個(gè)值被計(jì)算,你應(yīng)該使用AVAsynchronousKeyValueLoading蛾狗、 protocol _要求值,得到一個(gè)答案后通過(guò)使用一塊完成處理器定義。(AVAsset和AVAssetTrack符合AVAsynchronousKeyValueLoading協(xié)議仪媒。)
你測(cè)試值是否加載屬性使用 statusOfValueForKey:error:淘太。當(dāng)asset第一次加載時(shí),它的大部分或全部屬性的值都是AVKeyValueStatusUnknown规丽。加載一個(gè)值為一個(gè)或多個(gè)屬性,您調(diào)用loadValuesAsynchronouslyForKeys:completionHandler:蒲牧。在完成處理程序中,根據(jù)屬性的狀態(tài)赌莺,采取適當(dāng)?shù)牟僮鞅馈D鷳?yīng)該始終做好加載不完全成功的準(zhǔn)備,要么因?yàn)樗捎谀承┰蚴∷蚁粒热缁诰W(wǎng)絡(luò)的URL無(wú)法訪(fǎng)問(wèn)挎扰,或者因?yàn)樨?fù)載被取消了翠订。
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,應(yīng)該加載其跟蹤屬性遵倦。有關(guān)播放asset的更多信息尽超,請(qǐng)參見(jiàn) Playback。
Getting Still Images From a Video(從視頻中獲取靜止圖像)
為了得到從一個(gè)asset的縮略圖中得到的靜態(tài)圖像梧躺,你可以使用一個(gè)AVAssetImageGenerator
對(duì)象似谁。您用您的asset初始化一個(gè)圖像生成器。初始化可能會(huì)成功,即使asset擁有沒(méi)有視覺(jué)跟蹤初始化的時(shí)候,所以如果有必要你應(yīng)該測(cè)試asset是否使用tracksWithMediaCharacteristic:掠哥。
AVAsset anAsset = <#Get an asset#>;
if ([[anAsset tracksWithMediaType:AVMediaTypeVideo] count] > 0) {
AVAssetImageGenerator *imageGenerator =
[AVAssetImageGenerator assetImageGeneratorWithAsset:anAsset];
// Implementation continues...
}
您可以配置圖像生成器的幾個(gè)方面巩踏,例如,您可以分別指定其生成的圖像的 maximumSize和使用apertureMode
续搀。然后塞琼,您可以在給定的時(shí)間或一系列圖像中生成單個(gè)圖像。您必須確保您對(duì)圖像生成器有很強(qiáng)的引用禁舷,直到它生成了所有的圖像彪杉。
Generating a Single Image(生成一個(gè)圖像)
你使用 copyCGImageAtTime:actualTime:error:生成一個(gè)圖像在一個(gè)特定時(shí)間。AVFoundation在您請(qǐng)求的時(shí)候可能無(wú)法生成圖像牵咙,因此您可以將第二個(gè)參數(shù)作為一個(gè)指針指向一個(gè)CMTime派近,它在返回時(shí)包含實(shí)際生成圖像的時(shí)間。
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(生成一系列圖像)
生成一系列的圖像,你發(fā)送圖像發(fā)生器generateCGImagesAsynchronouslyForTimes:completionHandler:
消息霜大。第一個(gè)參數(shù)是一個(gè)NSValue對(duì)象數(shù)組构哺,每個(gè)對(duì)象包含一個(gè)CMTime結(jié)構(gòu)革答,指定要生成圖像的資產(chǎn)時(shí)間战坤。第二個(gè)參數(shù)是一個(gè)塊,它充當(dāng)為生成的每個(gè)映像調(diào)用的block 残拐。block參數(shù)提供了一個(gè)結(jié)果常量途茫,它告訴您圖像是成功創(chuàng)建的,還是被取消的操作溪食,以及適當(dāng)?shù)?
- 圖像
- 您請(qǐng)求映像的時(shí)間和生成映像的實(shí)際時(shí)間
- 描述生成失敗原因的錯(cuò)誤對(duì)象
在你的程序塊的實(shí)現(xiàn)中囊卜,檢查結(jié)果常數(shù),以確定圖像是否被創(chuàng)建错沃。此外栅组,確保您對(duì)圖像生成器有很強(qiáng)的引用,直到它完成創(chuà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");
}
}];
你可以取消圖像序列的生成通過(guò)發(fā)送圖像發(fā)生器cancelAllCGImageGeneration消息玉掸。
Trimming and Transcoding a Movie(修剪和修改電影)
您可以將電影從一種格式轉(zhuǎn)換為另一種格式,并使用AVAssetExportSession對(duì)象修改電影醒叁。工作流如圖1 - 1所示司浪。導(dǎo)出會(huì)話(huà)是管理資產(chǎn)異步導(dǎo)出的控制器對(duì)象泊业。您使用想要導(dǎo)出的資產(chǎn)初始化會(huì)話(huà),并使用出口預(yù)置的名稱(chēng)來(lái)表示您想要應(yīng)用的導(dǎo)出選項(xiàng)(請(qǐng)參閱 allExportPresets)啊易。然后配置導(dǎo)出會(huì)話(huà)以指定輸出URL和文件類(lèi)型吁伺,以及其他一些設(shè)置,例如元數(shù)據(jù)租谈,以及輸出是否應(yīng)該針對(duì)網(wǎng)絡(luò)使用進(jìn)行優(yōu)化篮奄。
你可以檢查你是否可以導(dǎo)出一個(gè)給定的資產(chǎn)使用給定預(yù)設(shè)使用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.
}
通過(guò)提供輸出URL來(lái)完成會(huì)話(huà)的配置(URL必須是一個(gè)文件URL)。AVAssetExportSession可以從URL的路徑擴(kuò)展中推斷出輸出文件類(lèi)型;但是垦垂,通常使用outputFileType
直接設(shè)置它宦搬。您還可以指定其他屬性,例如時(shí)間范圍劫拗,輸出文件長(zhǎng)度的限制间校,導(dǎo)出文件是否應(yīng)該優(yōu)化為網(wǎng)絡(luò)使用,以及視頻組合页慷。下面的例子說(shuō)明了如何使用 timeRange屬性來(lái)修整電影:
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)建新的文件,您調(diào)用 exportAsynchronouslyWithCompletionHandler:憔足。當(dāng)導(dǎo)出操作結(jié)束時(shí)調(diào)用完成處理block ;在執(zhí)行處理程序時(shí),應(yīng)該檢查會(huì)話(huà)的status酒繁,以確定導(dǎo)出是否成功滓彰、失敗或被取消:
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch ([exportSession status]) {
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@", [[exportSession error] localizedDescription]);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
break;
default:
break;
}
}];
您可以通過(guò)向會(huì)話(huà)發(fā)送一個(gè) cancelExport消息來(lái)取消導(dǎo)出。
如果您試圖覆蓋現(xiàn)有的文件州袒,或者在應(yīng)用程序的沙箱之外編寫(xiě)文件揭绑,那么導(dǎo)出將會(huì)失敗。如果:
- 有一個(gè)來(lái)電
- 您的應(yīng)用程序在后臺(tái)郎哭,另一個(gè)應(yīng)用程序開(kāi)始播放
在這些情況下他匪,通常應(yīng)該通知用戶(hù)導(dǎo)出失敗,然后允許用戶(hù)重新啟動(dòng)導(dǎo)出夸研。