最近幫朋友做個(gè)小功能,視頻添加聲音纯趋,可以修改添加音頻開(kāi)始時(shí)間憎兽、音量大小等,封裝了個(gè)工具類结闸,不多說(shuō)唇兑,直接看代碼吧。
XXWVideoEditor.h文件
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface XXWVideoEditor : NSObject
/**
視頻添加音頻
@param videoUrl 視頻URL
@param audioUrl 音頻URL
@param startTime 音頻插入開(kāi)始時(shí)間
@param endTime 音頻插入結(jié)束時(shí)間
@param isOriginal 是否保留原聲
@param oriVolume 原聲音量
@param newVolume 插入的音頻音量
@param completionHandle 完成回調(diào)
*/
+ (void)addBackgroundMiusicWithVideoUrlStr:(NSURL *)videoUrl
audioUrl:(NSURL *)audioUrl
start:(CGFloat)startTime
end:(CGFloat)endTime
isOriginalSound:(BOOL)isOriginal
oriVolume:(float)oriVolume
newVolume:(float)newVolume
completion:(void (^)(NSString *outPath,BOOL isSuccess))completionHandle;
@end
XXWVideoEditor.m文件
#import "XXWVideoEditor.h"
@implementation XXWVideoEditor
+ (void)addBackgroundMiusicWithVideoUrlStr:(NSURL *)videoUrl
audioUrl:(NSURL *)audioUrl
start:(CGFloat)startTime
end:(CGFloat)endTime
isOriginalSound:(BOOL)isOriginal
oriVolume:(float)oriVolume
newVolume:(float)newVolume
completion:(void (^)(NSString *outPath,BOOL isSuccess))completionHandle
{
//音頻來(lái)源路徑
NSURL *audio_inputFileUrl = audioUrl;
//視頻來(lái)源路徑
NSURL *video_inputFileUrl = videoUrl;
//導(dǎo)出路徑
NSString *outputFilePath = [XXWVideoEditor fileSavePath];
NSURL *outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
CMTime nextClipStartTime = kCMTimeZero;
//創(chuàng)建可變的音頻視頻組合
AVMutableComposition* mixComposition =[AVMutableComposition composition];
//視頻采集
AVURLAsset* videoAsset =[[AVURLAsset alloc]initWithURL:video_inputFileUrl options:nil];
CMTimeRange video_timeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
AVMutableCompositionTrack*a_compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[a_compositionVideoTrack insertTimeRange:video_timeRange
ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:nextClipStartTime
error:nil];
CMTime start = CMTimeMakeWithSeconds(startTime, videoAsset.duration.timescale);
CMTime duration = CMTimeMakeWithSeconds(endTime - startTime,videoAsset.duration.timescale);
CMTimeRange audio_timeRange = CMTimeRangeMake(start, duration);
//創(chuàng)建最終混合的音頻實(shí)例
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];
//新添加的音頻
AVURLAsset* audioAsset =[[AVURLAsset alloc]initWithURL:audio_inputFileUrl options:nil];
AVMutableCompositionTrack *newAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[newAudioTrack insertTimeRange:audio_timeRange
ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio]objectAtIndex:0]
atTime:start
error:nil];
AVMutableAudioMixInputParameters *newAudioInputParams = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:newAudioTrack] ;
[newAudioInputParams setVolumeRampFromStartVolume:newVolume toEndVolume:.0f timeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)];
[newAudioInputParams setTrackID:newAudioTrack.trackID];
//視頻文件原始音頻通道
if (isOriginal) {
//視頻聲音采集(也可不執(zhí)行這段代碼不采集視頻音軌桦锄,合并后的視頻文件將沒(méi)有視頻原來(lái)的聲音)
AVMutableCompositionTrack *originVoiceTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
CMTimeRange videoTimeRange = CMTimeRangeMake(kCMTimeZero,videoAsset.duration);
[originVoiceTrack insertTimeRange:videoTimeRange ofTrack:([videoAsset tracksWithMediaType:AVMediaTypeAudio].count>0)?[videoAsset tracksWithMediaType:AVMediaTypeAudio].firstObject:nil atTime:kCMTimeZero error:nil];
AVMutableAudioMixInputParameters *originAudioInputParams = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:originVoiceTrack] ;
[originAudioInputParams setVolumeRampFromStartVolume:oriVolume toEndVolume:.0f timeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration)];
[originAudioInputParams setTrackID:originVoiceTrack.trackID];
audioMix.inputParameters = [NSArray arrayWithObjects:newAudioInputParams,originAudioInputParams,nil];
}else{
audioMix.inputParameters = [NSArray arrayWithObject:newAudioInputParams];
}
//創(chuàng)建一個(gè)輸出
AVAssetExportSession *_assetExport =[[AVAssetExportSession alloc]initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
_assetExport.outputFileType = AVFileTypeQuickTimeMovie;
_assetExport.outputURL = outputFileUrl;
_assetExport.shouldOptimizeForNetworkUse= YES;
_assetExport.audioMix = audioMix;
[_assetExport exportAsynchronouslyWithCompletionHandler:
^(void ) {
switch ([_assetExport status]) {
case AVAssetExportSessionStatusFailed: {
NSLog(@"合成失斣健:%@",[[_assetExport error] description]);
completionHandle(outputFilePath,NO);
} break;
case AVAssetExportSessionStatusCancelled: {
completionHandle(outputFilePath,NO);
} break;
case AVAssetExportSessionStatusCompleted: {
completionHandle(outputFilePath,YES);
} break;
default: {
completionHandle(outputFilePath,NO);
} break;
}
}
];
}
+ (NSString *)fileSavePath
{
NSString *documentsDirectory =[NSHomeDirectory()
stringByAppendingPathComponent:@"Documents"];
//最終合成輸出路徑
NSString *outputFilePath =[documentsDirectory stringByAppendingPathComponent:@"output.mp4"];
if([[NSFileManager defaultManager]fileExistsAtPath:outputFilePath])
[[NSFileManager defaultManager]removeItemAtPath:outputFilePath error:nil];
return outputFilePath;
}
@end