iOS視頻處理之--視頻截取及添加背景音樂

這段時間由于工作需要,了解了一些關(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í),剛起了個頭,希望能堅持下去!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容