這段時間由于工作需要,了解了一些關(guān)于iOS中視頻處理功能,發(fā)現(xiàn)AVFoundation功能強大,今天聊一聊視頻截取和添加背景音樂的一些功能,這里面涉及到得一些類類名和方法都比較長,但是用法還是相對簡單,主要是能理解多媒體的一些概念,先來介紹一下常用到的幾個AVFoundation下得類:
- AVURLAsset:AVAsset的子類,此類主要用于獲取多媒體的信息,包括視頻、音頻的類型、時長、每秒幀數(shù),其實還可以用來獲取視頻的指定位置的縮略圖。
- AVMutableCompositionTrack:視頻和音頻的采集都需要通過這個類,我覺得可以理解為采集的一個視頻或音頻資源對應(yīng)一個track對象。
- AVMutableComposition:這個類點進去你會發(fā)現(xiàn)其實它也是AVAsset的子類,對應(yīng)有一個方法[AVMutableComposition composition],返回一個nil的AVMutableComposition對象。
- CMTime:這個時間并不是平時我們說到的分秒的時間,后面用到的時候會再說。
- AVAssetExportSession:用于合并你采集的視頻和音頻,最終會保存為一個新文件,可以設(shè)置文件的輸出類型、路徑,以及合并的一個狀態(tài)AVAssetExportSessionStatus。
這里單獨創(chuàng)建了一個工具類MediaManager來做操作
下面是MediaManager.h的方法接口:
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
/**
添加音樂完成回調(diào)的block
*/
typedef void (^MixcompletionBlock)(void);
@interface MediaManager : NSObject
/**
截取視頻并添加背景音樂
*/
+ (void)addBackgroundMiusicWithVideoUrlStr:(NSURL *)videoUrl audioUrl:(NSURL *)audioUrl andCaptureVideoWithRange:(NSRange)videoRange completion:(MixcompletionBlock)completionHandle;
/**
獲取多媒體時長
*/
+ (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr;
/**
獲取合并后的多媒體文件路徑
*/
+ (NSString *)getMediaFilePath;
@end
MediaManager.m中方法實現(xiàn):
在添加背景音樂的方法中先創(chuàng)建視頻和音頻對應(yīng)的AVURLAsset對象
//AVURLAsset此類主要用于獲取媒體信息,包括視頻、聲音等
AVURLAsset* audioAsset = [[AVURLAsset alloc] initWithURL:audioUrl options:nil];
AVURLAsset* videoAsset = [[AVURLAsset alloc] initWithURL:videoUrl options:nil];
//創(chuàng)建AVMutableComposition對象來添加視頻音頻資源的AVMutableCompositionTrack
AVMutableComposition* mixComposition = [AVMutableComposition composition];
我們要截取一段視頻就一定涉及到截取的時間點和長度,下面來具體介紹一下CMTime和CMTimeRange。
- CMTime一個用于描述多媒體幀數(shù)和播放速率的結(jié)構(gòu)體,可以通過 CMTimeMake(int64_t value, int32_t timescale) 來生成一個CMTime變量,value視頻的總幀數(shù),timescale是指每秒視頻播放的幀數(shù),視頻播放速率,(value / timescale)才是視頻實際的秒數(shù)時長,timescale一般情況下不改變,截取視頻長度通過改變value的值。
或者通過 CMTimeMakeWithSeconds(Float64 seconds, int32_t preferredTimeScale) 方法也可以,這里的seconds對應(yīng)的是平時說的秒數(shù),preferredTimeScale是每秒播放的幀數(shù)。 - CMTimeRange有點類似NSRange,只不過它對應(yīng)的是視頻的起始時間點和視頻的長度,可以通過方法CMTimeRangeMake(start, duration)創(chuàng)建變量,start起始時間,duration時長,都是CMTime類型。方法中我直接傳入NSRange,在內(nèi)部做了一些轉(zhuǎn)換。
了解完這些就可以開始采集視頻音頻了,下面是對視頻的采集,如果需要也可以去獲取視頻原有的音軌。
這里經(jīng)常會遇到到tracksWithMediaType方法返回empty的數(shù)組,導(dǎo)致程序奔潰,我從Stack Overflow弄下來的一段解釋:

屏幕快照 2015-12-02 下午2.25.17.png
//開始位置startTime
CMTime startTime = CMTimeMakeWithSeconds(videoRange.location, videoAsset.duration.timescale);
//截取長度videoDuration
CMTime videoDuration = CMTimeMakeWithSeconds(videoRange.length, videoAsset.duration.timescale);
CMTimeRange videoTimeRange = CMTimeRangeMake(startTime, videoDuration);
//視頻采集compositionVideoTrack
AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
#warning 避免數(shù)組越界 tracksWithMediaType 找不到對應(yīng)的文件時候返回空數(shù)組
//TimeRange截取的范圍長度
//ofTrack來源
//atTime插放在視頻的時間位置
[compositionVideoTrack insertTimeRange:videoTimeRange ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeVideo].count>0) ? [videoAsset tracksWithMediaType:AVMediaTypeVideo].firstObject : nil atTime:kCMTimeZero error:nil];
對背景音頻的采集
//聲音長度截取范圍==視頻長度
CMTimeRange audioTimeRange = CMTimeRangeMake(kCMTimeZero, videoDuration);
//音頻采集compositionCommentaryTrack
AVMutableCompositionTrack *compositionAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
[compositionAudioTrack insertTimeRange:audioTimeRange ofTrack:([audioAsset tracksWithMediaType:AVMediaTypeAudio].count > 0) ? [audioAsset tracksWithMediaType:AVMediaTypeAudio].firstObject : nil atTime:kCMTimeZero error:nil];
然后就是合并獲取的視頻和背景音頻,這里需要對輸出的文件設(shè)置保存路徑以及文件類型。
//AVAssetExportSession用于合并文件,導(dǎo)出合并后文件,presetName文件的輸出類型
AVAssetExportSession *assetExportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetPassthrough];
NSString *outPutPath = [NSTemporaryDirectory() stringByAppendingPathComponent:MediaFileName];
//混合后的視頻輸出路徑
NSURL *outPutPath = [NSURL fileURLWithPath:outPutPath];
if ([[NSFileManager defaultManager] fileExistsAtPath:outPutPath])
{
[[NSFileManager defaultManager] removeItemAtPath:outPutPath error:nil];
}
//輸出視頻格式 AVFileTypeMPEG4 AVFileTypeQuickTimeMovie...
assetExportSession.outputFileType = AVFileTypeQuickTimeMovie;
// NSArray *fileTypes = assetExportSession.
assetExportSession.outputURL = outPutPath;
//輸出文件是否網(wǎng)絡(luò)優(yōu)化
assetExportSession.shouldOptimizeForNetworkUse = YES;
[assetExportSession exportAsynchronouslyWithCompletionHandler:^{
completionHandle();
}];
這是獲取多媒體文件時長的方法實現(xiàn)。
+ (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr {
NSURL *mediaUrl = [NSURL URLWithString:mediaUrlStr];
AVURLAsset *mediaAsset = [[AVURLAsset alloc] initWithURL:mediaUrl options:nil];
CMTime duration = mediaAsset.duration;
return duration.value / duration.timescale;
}
最后只要在外部添加背景音樂的方法簡單的調(diào)用即可。
- (IBAction)addBackgroundmusic:(id)sender {
if (_videoUrl && _audioUrl && self.endTextField.text && self.startTextField.text) {
[MediaManager addBackgroundMiusicWithVideoUrlStr:_videoUrl audioUrl:_audioUrl andCaptureVideoWithRange:NSMakeRange([self.startTextField.text floatValue], [self.endTextField.text floatValue] - [self.startTextField.text floatValue]) completion:^{
NSLog(@"視頻合并完成");
}];
}
}
代碼上傳到Github:
https://github.com/ShelinShelin/VideoEditing.git
界面做的比較簡陋,......大家多包涵,最好運行在真機上,視頻采集是通過相機或者相冊資源,最近也想利用業(yè)余時間寫一個相對完整的開源項目互相學(xué)習(xí),剛起了個頭,希望能堅持下去!