前言
從本文開始逐漸學(xué)習(xí)iOS自帶的多媒體處理框架踱阿,例如AVFoundation透罢,VideoToolbox,CoreMedia虏肾,CoreVideo實現(xiàn)多媒體的處理廓啊,并且將實現(xiàn)方式以及效果和ffmpeg的方式做對比
截取一個音視頻文件中的某個時間段的音視頻然后保存是很常見的需求,AVFoundation就提供了這樣的接口封豪,它其實也是利用AVMutableComposition來實現(xiàn)的
本文的目的:
截取一個音視頻文件中的某個時間段的音視頻然后保存到本地
音視頻截取相關(guān)流程
上圖介紹了AVFoundation框架中關(guān)于音視頻截取的相關(guān)的對象關(guān)系圖谴轮,可以看到使用AVFoundation截取音視頻中某一段還是相對比較簡單的。
相關(guān)對象及函數(shù)介紹
1吹埠、AVURLAsset
容器對象第步,代表了要操作的容器。封裝缘琅,解封裝粘都,音視頻播放,以及音視頻合并等等操作的基礎(chǔ)都涉及到這個對象刷袍。2翩隧、AVAssetTrack
音視頻軌道對象,代表了文件中的一路音頻流或者一路視頻流呻纹,它作為每一個要被合并的音頻或者視頻流被添加到組合對象中最終進(jìn)行合并3鸽心、AVMutableCompositionTrack
組合軌道對象,它作為音視頻合并的基礎(chǔ)居暖,通過它添加要合并的音頻流或者視頻流顽频,分為兩種類型:音頻組合軌道對象和視頻組合軌道對象,音頻組合軌道對象只能添加音頻流太闺,視頻組合軌道對象只能添加視頻流
通過此對象定義要截取的時間段即可實現(xiàn)音視頻內(nèi)容的截取4糯景、AVMutableComposition
組合對象,通過它構(gòu)建組合軌道對象5省骂、AVAssetExportSession
執(zhí)行合并操作并導(dǎo)出為文件對象蟀淮,該對象內(nèi)部應(yīng)該是封裝了合并多個音頻流或者視頻流的操作和封裝操作
實現(xiàn)代碼
這里例子中為截取源音視頻中中5-15秒的內(nèi)容然后保存為MP4
#import <Foundation/Foundation.h>
@interface AVVideoCut : NSObject
/** 實現(xiàn)功能:截取音視頻文件中指定范圍段的內(nèi)容
*/
- (void)cutVideo:(NSURL*)srcURL dst:(NSURL*)dstURL;
@end
#import "AVVideoCut.h"
#import <AVFoundation/AVFoundation.h>
@implementation AVVideoCut
{
dispatch_semaphore_t processSemaphore;
}
- (void)cutVideo:(NSURL*)srcURL dst:(NSURL*)dstURL
{
processSemaphore = dispatch_semaphore_create(0);
AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:srcURL options:nil];
[asset loadValuesAsynchronouslyForKeys:@[@"tracks"] completionHandler:^{
NSError *error = nil;
AVKeyValueStatus status = [asset statusOfValueForKey:@"tracks" error:&error];
if (status != AVKeyValueStatusLoaded) {
NSLog(@"loaded error %@",error);
return;
}
[self processAsset:asset dst:dstURL];
}];
dispatch_semaphore_wait(processSemaphore, DISPATCH_TIME_FOREVER);
NSLog(@"結(jié)束了");
}
- (void)processAsset:(AVAsset*)asset dst:(NSURL*)dstURL
{
// 獲取容器中的音視頻軌道對象
NSArray *videotracks = [asset tracksWithMediaType:AVMediaTypeVideo];
NSArray *audiotracks = [asset tracksWithMediaType:AVMediaTypeAudio];
AVAssetTrack *videoTrack = videotracks?videotracks[0]:nil;
AVAssetTrack *audioTrack = audiotracks?audiotracks[0]:nil;
// 劃定要截取的時間;這里選擇的時間為5-15秒的視頻
CMTime start = CMTimeMake(5*1000, 1000);
CMTime time = CMTimeMake(10*1000, 1000);
CMTimeRange range = CMTimeRangeMake(start, time);
// 創(chuàng)建組合對象
AVMutableComposition *compostion = [AVMutableComposition composition];
if (audioTrack) {
// 添加組合音頻軌道
AVMutableCompositionTrack *audiocomtrack = [compostion addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error = nil;
// 在音頻軌道中選取指定的時間范圍的音頻插入到組合音頻軌道中
[audiocomtrack insertTimeRange:range ofTrack:audioTrack atTime:kCMTimeZero error:&error];
}
if (videoTrack) {
AVMutableCompositionTrack *videocomtrack = [compostion addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
NSError *error = nil;
[videocomtrack insertTimeRange:range ofTrack:videoTrack atTime:kCMTimeZero error:&error];
}
// 執(zhí)行合并
if ([[NSFileManager defaultManager] fileExistsAtPath:dstURL.path]) {
[[NSFileManager defaultManager] removeItemAtURL:dstURL error:nil];
}
// 執(zhí)行組合對象中組合軌道的編輯任務(wù)
AVAssetExportSession *extSession = [[AVAssetExportSession alloc] initWithAsset:compostion presetName:AVAssetExportPresetHighestQuality];
extSession.outputURL = dstURL;
extSession.outputFileType = AVFileTypeMPEG4;
NSLog(@"開始編輯");
[extSession exportAsynchronouslyWithCompletionHandler:^{
if (extSession.status != AVAssetExportSessionStatusCompleted) {
NSLog(@"編輯 error %@",extSession.error);
}
NSLog(@"編輯完畢");
dispatch_semaphore_signal(self->processSemaphore);
}];
}
@end
遇到問題
項目地址
https://github.com/nldzsz/ffmpeg-demo
位于AVFoundation目錄下文件AVVideoCut.h/AVVideoCut.m中