iOS视频裁剪、拼接、添加水印、添加背景音乐
利用GPUImage,实现视频的操作,GPUImage下载地址:点击打开链接
方法声明:
///使用AVfoundation添加水印
- (void)AVsaveVideoPath:(NSURL*)videoPath WithWaterImg:(UIImage*)img WithInfoDic:(NSDictionary*)infoDic WithFileName:(NSString*)fileName completion:(void(^)(NSURL*outputURL,BOOLisSuccess))completionHandle;
//视频合成,添加背景音乐
-(void)addFirstVideo:(NSURL*)firstVideoPath andSecondVideo:(NSURL*)secondVideo withMusic:(NSURL*)musicPath completion:(void(^)(NSURL*outputURL,BOOLisSuccess))completionHandle;
//视频裁剪
- (void)cropWithVideoUrlStr:(NSURL*)videoUrl start:(CGFloat)startTime end:(CGFloat)endTime completion:(void(^)(NSURL*outputURL, Float64 videoDuration,BOOLisSuccess))completionHandle;
以下是具体的实现:
#import"VideoManager.h"
#import<Photos/Photos.h>
#import"GPUImage.h"
@interfaceVideoManager()
{
///GPUImage
GPUImageMovie *movieFile;
GPUImageOutput<GPUImageInput> *filter;
GPUImageMovieWriter *movieWriter;
CADisplayLink* dlink;
///AVFoundation
AVAsset* videoAsset;
AVAssetExportSession*exporter;
}
@end
///使用AVfoundation添加水印
- (void)AVsaveVideoPath:(NSURL*)videoPath WithWaterImg:(UIImage*)img WithInfoDic:(NSDictionary*)infoDic WithFileName:(NSString*)fileName completion:(void(^)(NSURL*outputURL,BOOLisSuccess))completionHandle
{
if(!videoPath) {
return;
}
//1 创建AVAsset实例 AVAsset包含了video的所有信息 self.videoUrl输入视频的路径
//封面图片
NSDictionary*opts = [NSDictionarydictionaryWithObject:@(YES) forKey:AVURLAssetPreferPreciseDurationAndTimingKey];
videoAsset = [AVURLAssetURLAssetWithURL:videoPath options:opts];//初始化视频媒体文件
CMTimestartTime =CMTimeMakeWithSeconds(0.2,600);
CMTimeendTime =CMTimeMakeWithSeconds(videoAsset.duration.value/videoAsset.duration.timescale-0.2, videoAsset.duration.timescale);
//声音采集
AVURLAsset* audioAsset = [[AVURLAssetalloc] initWithURL:videoPath options:opts];
//2 创建AVMutableComposition实例. apple developer 里边的解释 【AVMutableComposition is a mutable subclass of AVComposition you use when you want to create a new composition from existing assets. You can add and remove tracks, and you can add, remove, and scale time ranges.】
AVMutableComposition*mixComposition = [[AVMutableCompositionalloc] init];
//3 视频通道 工程文件中的轨道,有音频轨、视频轨等,里面可以插入各种对应的素材
AVMutableCompositionTrack*videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
//把视频轨道数据加入到可变轨道中 这部分可以做视频裁剪TimeRange
[videoTrack insertTimeRange:CMTimeRangeFromTimeToTime(startTime, endTime)
ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:kCMTimeZero error:nil];
//音频通道
AVMutableCompositionTrack* audioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudiopreferredTrackID:kCMPersistentTrackID_Invalid];
//音频采集通道
AVAssetTrack* audioAssetTrack = [[audioAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
[audioTrack insertTimeRange:CMTimeRangeFromTimeToTime(startTime, endTime) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];
//3.1 AVMutableVideoCompositionInstruction 视频轨道中的一个视频,可以缩放、旋转等
AVMutableVideoCompositionInstruction*mainInstruction = [AVMutableVideoCompositionInstructionvideoCompositionInstruction];
mainInstruction.timeRange =CMTimeRangeFromTimeToTime(kCMTimeZero, videoTrack.timeRange.duration);
// 3.2 AVMutableVideoCompositionLayerInstruction 一个视频轨道,包含了这个轨道上的所有视频素材
AVMutableVideoCompositionLayerInstruction*videolayerInstruction = [AVMutableVideoCompositionLayerInstructionvideoCompositionLayerInstructionWithAssetTrack:videoTrack];
AVAssetTrack*videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
// UIImageOrientation videoAssetOrientation_ = UIImageOrientationUp;
BOOLisVideoAssetPortrait_ =NO;
CGAffineTransformvideoTransform = videoAssetTrack.preferredTransform;
if(videoTransform.a ==0&& videoTransform.b ==1.0&& videoTransform.c ==-1.0&& videoTransform.d ==0) {
// videoAssetOrientation_ = UIImageOrientationRight;
isVideoAssetPortrait_ =YES;
}
if(videoTransform.a ==0&& videoTransform.b ==-1.0&& videoTransform.c ==1.0&& videoTransform.d ==0) {
// videoAssetOrientation_ = UIImageOrientationLeft;
isVideoAssetPortrait_ =YES;
}
// if (videoTransform.a == 1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == 1.0) {
// videoAssetOrientation_ = UIImageOrientationUp;
// }
// if (videoTransform.a == -1.0 && videoTransform.b == 0 && videoTransform.c == 0 && videoTransform.d == -1.0) {
// videoAssetOrientation_ = UIImageOrientationDown;
// }
[videolayerInstruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero];
[videolayerInstruction setOpacity:0.0atTime:endTime];
// 3.3 - Add instructions
mainInstruction.layerInstructions = [NSArrayarrayWithObjects:videolayerInstruction,nil];
//AVMutableVideoComposition:管理所有视频轨道,可以决定最终视频的尺寸,裁剪需要在这里进行
AVMutableVideoComposition*mainCompositionInst = [AVMutableVideoCompositionvideoComposition];
CGSizenaturalSize;
if(isVideoAssetPortrait_){
naturalSize =CGSizeMake(videoAssetTrack.naturalSize.height, videoAssetTrack.naturalSize.width);
}else{
naturalSize = videoAssetTrack.naturalSize;
}
floatrenderWidth, renderHeight;
renderWidth = naturalSize.width;
renderHeight = naturalSize.height;
mainCompositionInst.renderSize =CGSizeMake(renderWidth, renderHeight);
mainCompositionInst.renderSize =CGSizeMake(renderWidth, renderHeight);
mainCompositionInst.instructions = [NSArrayarrayWithObject:mainInstruction];
mainCompositionInst.frameDuration =CMTimeMake(1,25);
//shuiyin
//[self applyVideoEffectsToComposition:mainCompositionInst WithWaterImg:img WithCoverImage:coverImg WithQustion:question size:CGSizeMake(renderWidth, renderHeight)];
//by yangyunfei
[selfapplyVideoEffectsToComposition:mainCompositionInst WithWaterImg:img WithInfoDic:infoDic size:CGSizeMake(renderWidth, renderHeight)];
// //UI操作放到主线程执行
// dispatch_async(dispatch_get_main_queue(), ^{
//
// [self applyVideoEffectsToComposition:mainCompositionInst WithWaterImg:img WithCoverImage:coverImg WithQustion:question size:CGSizeMake(renderWidth, renderHeight)];
//
// });
// 4 - 输出路径
NSArray*paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*documentsDirectory = [paths objectAtIndex:0];
NSString*myPathDocs = [documentsDirectory stringByAppendingPathComponent:
[NSStringstringWithFormat:@"%@-%d.mov",fileName,arc4random() %1000]];
// NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov",fileName]];
unlink([myPathDocs UTF8String]);
//如果文件已经存在,先移除,否则会报无法存储的错误
NSFileManager*manager = [NSFileManagerdefaultManager];
[manager removeItemAtPath:myPathDocs error:nil];
NSURL* videoUrl = [NSURLfileURLWithPath:myPathDocs];
dlink = [CADisplayLinkdisplayLinkWithTarget:selfselector:@selector(updateProgress)];
[dlink setFrameInterval:15];
[dlink addToRunLoop:[NSRunLoopcurrentRunLoop] forMode:NSDefaultRunLoopMode];
[dlink setPaused:NO];
// 5 - 视频文件输出
exporter = [[AVAssetExportSessionalloc] initWithAsset:mixComposition
presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL=videoUrl;
exporter.outputFileType =AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse =YES;
exporter.videoComposition = mainCompositionInst;
[exporter exportAsynchronouslyWithCompletionHandler:^{
// dispatch_async(dispatch_get_main_queue(), ^{
// //这里是输出视频之后的操作,做你想做的
// [self exportDidFinish:exporter];
// });
switch([exporter status]) {
caseAVAssetExportSessionStatusFailed:
{
NSLog(@"添加水印失败:%@", [[exporter error] description]);
completionHandle(videoUrl,NO);
}
break;
caseAVAssetExportSessionStatusCancelled:
{
completionHandle(videoUrl,NO);
}
break;
caseAVAssetExportSessionStatusCompleted:
{
//成功
NSLog(@"添加水印成功");
completionHandle(videoUrl,YES);
}
break;
default:
{
completionHandle(videoUrl,NO);
}break;
}
}];
}
//添加水印
- (void)applyVideoEffectsToComposition:(AVMutableVideoComposition*)composition WithWaterImg:(UIImage*)img WithCoverImage:(UIImage*)coverImg WithQustion:(NSString*)question size:(CGSize)size {
UIFont*font = [UIFontsystemFontOfSize:30.0];
CATextLayer*subtitle1Text = [[CATextLayeralloc] init];
[subtitle1Text setFontSize:30];
[subtitle1Text setString:question];
[subtitle1Text setAlignmentMode:kCAAlignmentCenter];
[subtitle1Text setForegroundColor:[[UIColorwhiteColor]CGColor]];
subtitle1Text.masksToBounds =YES;
subtitle1Text.cornerRadius =23.0f;
[subtitle1Text setBackgroundColor:[UIColorcolorWithRed:0green:0blue:0alpha:0.5].CGColor];
CGSizetextSize = [question sizeWithAttributes:[NSDictionarydictionaryWithObjectsAndKeys:font,NSFontAttributeName,nil]];
[subtitle1Text setFrame:CGRectMake(50,100, textSize.width+20, textSize.height+10)];
//水印
CALayer*imgLayer = [CALayerlayer];
imgLayer.contents = (id)img.CGImage;
// imgLayer.bounds = CGRectMake(0, 0, size.width, size.height);
imgLayer.bounds =CGRectMake(0,0,210,50);
imgLayer.position =CGPointMake(size.width/2.0, size.height/2.0);
//第二个水印
CALayer*coverImgLayer = [CALayerlayer];
coverImgLayer.contents = (id)coverImg.CGImage;
// [coverImgLayer setContentsGravity:@"resizeAspect"];
coverImgLayer.bounds =CGRectMake(50,200,210,50);
coverImgLayer.position =CGPointMake(size.width/4.0, size.height/4.0);
// 2 - The usual overlay
CALayer*overlayLayer = [CALayerlayer];
[overlayLayer addSublayer:subtitle1Text];
[overlayLayer addSublayer:imgLayer];
overlayLayer.frame =CGRectMake(0,0, size.width, size.height);
[overlayLayer setMasksToBounds:YES];
CALayer*parentLayer = [CALayerlayer];
CALayer*videoLayer = [CALayerlayer];
parentLayer.frame =CGRectMake(0,0, size.width, size.height);
videoLayer.frame =CGRectMake(0,0, size.width, size.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:overlayLayer];
[parentLayer addSublayer:coverImgLayer];
//设置封面
CABasicAnimation*anima = [CABasicAnimationanimationWithKeyPath:@"opacity"];
anima.fromValue = [NSNumbernumberWithFloat:1.0f];
anima.toValue = [NSNumbernumberWithFloat:0.0f];
anima.repeatCount =0;
anima.duration =5.0f;//5s之后消失
[anima setRemovedOnCompletion:NO];
[anima setFillMode:kCAFillModeForwards];
anima.beginTime =AVCoreAnimationBeginTimeAtZero;
[coverImgLayer addAnimation:anima forKey:@"opacityAniamtion"];
composition.animationTool = [AVVideoCompositionCoreAnimationTool
videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
}
//添加水印
- (void)applyVideoEffectsToComposition:(AVMutableVideoComposition*)composition WithWaterImg:(UIImage*)img WithInfoDic:(NSDictionary*)infoDic size:(CGSize)size {
CGFloatfontSize =46.0;
CGFloatleftLength =60;
UIFont*font = [UIFontsystemFontOfSize:fontSize];
CATextLayer*nameText = [[CATextLayeralloc] init];
[nameText setFontSize:fontSize];
[nameText setString:[infoDic objectForKey:@"name"]];
[nameText setAlignmentMode:kCAAlignmentLeft];
[nameText setForegroundColor:[[UIColorwhiteColor]CGColor]];
CGSizetextSize = [[infoDic objectForKey:@"name"] sizeWithAttributes:[NSDictionarydictionaryWithObjectsAndKeys:font,NSFontAttributeName,nil]];
[nameText setFrame:CGRectMake(leftLength, size.height/2.0+textSize.height/2.0+(28+textSize.height)*2, textSize.width+10, textSize.height+10)];
CATextLayer*shengaoText = [[CATextLayeralloc] init];
[shengaoText setFontSize:fontSize];
NSString*text3 = [NSStringstringWithFormat:@"%@cm",[infoDic objectForKey:@"shengao"]];
[shengaoText setString:text3];
[shengaoText setAlignmentMode:kCAAlignmentLeft];
[shengaoText setForegroundColor:[[UIColorwhiteColor]CGColor]];
CGSizetextSize3 = [text3 sizeWithAttributes:[NSDictionarydictionaryWithObjectsAndKeys:font,NSFontAttributeName,nil]];
[shengaoText setFrame:CGRectMake(leftLength, size.height/2.0+textSize3.height/2.0+28+textSize3.height, textSize3.width+10, textSize3.height+10)];
CATextLayer*tizhongText = [[CATextLayeralloc] init];
[tizhongText setFontSize:fontSize];
NSString*text2 = [NSStringstringWithFormat:@"%@kg",[infoDic objectForKey:@"tizhong"]];
[tizhongText setString:text2];
[tizhongText setAlignmentMode:kCAAlignmentLeft];
[tizhongText setForegroundColor:[[UIColorwhiteColor]CGColor]];
CGSizetextSize2 = [text2 sizeWithAttributes:[NSDictionarydictionaryWithObjectsAndKeys:font,NSFontAttributeName,nil]];
[tizhongText setFrame:CGRectMake(leftLength, size.height/2.0+textSize2.height/2.0, textSize2.width+10, textSize2.height+10)];
CATextLayer*sanText = [[CATextLayeralloc] init];
[sanText setFontSize:fontSize];
NSString*text4 = [NSStringstringWithFormat:@"%@-%@-%@",[infoDic objectForKey:@"xiongwei"],[infoDic objectForKey:@"yaowei"],[infoDic objectForKey:@"tunwei"]];
[sanText setString:text4];
[sanText setAlignmentMode:kCAAlignmentLeft];
[sanText setForegroundColor:[[UIColorwhiteColor]CGColor]];
CGSizetextSize4 = [text4 sizeWithAttributes:[NSDictionarydictionaryWithObjectsAndKeys:font,NSFontAttributeName,nil]];
[sanText setFrame:CGRectMake(leftLength, size.height/2.0-textSize4.height/2.0-28, textSize4.width+10, textSize4.height+10)];
CATextLayer*xiemaText = [[CATextLayeralloc] init];
[xiemaText setFontSize:fontSize];
NSString*text5 = [NSStringstringWithFormat:@"%@",[infoDic objectForKey:@"xiema"]];
[xiemaText setString:text5];
[xiemaText setAlignmentMode:kCAAlignmentLeft];
[xiemaText setForegroundColor:[[UIColorwhiteColor]CGColor]];
CGSizetextSize5 = [text5 sizeWithAttributes:[NSDictionarydictionaryWithObjectsAndKeys:font,NSFontAttributeName,nil]];
[xiemaText setFrame:CGRectMake(leftLength, size.height/2.0-textSize4.height/2.0-28-textSize4.height-28, textSize5.width+10, textSize5.height+10)];
//水印
CALayer*imgLayer = [CALayerlayer];
imgLayer.contents = (id)img.CGImage;
imgLayer.bounds =CGRectMake(0,0, img.size.width, img.size.height);
imgLayer.position =CGPointMake(size.width - img.size.width, img.size.height+10);
// 2 - The usual overlay
CALayer*overlayLayer = [CALayerlayer];
[overlayLayer addSublayer:nameText];
[overlayLayer addSublayer:shengaoText];
[overlayLayer addSublayer:tizhongText];
[overlayLayer addSublayer:sanText];
[overlayLayer addSublayer:xiemaText];
[overlayLayer addSublayer:imgLayer];
overlayLayer.frame =CGRectMake(0,0, size.width, size.height);
CALayer*parentLayer = [CALayerlayer];
CALayer*videoLayer = [CALayerlayer];
parentLayer.frame =CGRectMake(0,0, size.width, size.height);
videoLayer.frame =CGRectMake(0,0, size.width, size.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:overlayLayer];
//设置动画
CABasicAnimation*anima = [CABasicAnimationanimationWithKeyPath:@"opacity"];
anima.fromValue = [NSNumbernumberWithFloat:0.0f];
anima.toValue = [NSNumbernumberWithFloat:1.0f];
anima.repeatCount =0;
anima.duration =3.0f;//5s之后消失
[anima setRemovedOnCompletion:NO];
[anima setFillMode:kCAFillModeForwards];
anima.beginTime =AVCoreAnimationBeginTimeAtZero;
[overlayLayer addAnimation:anima forKey:@"opacityAniamtion"];
composition.animationTool = [AVVideoCompositionCoreAnimationTool
videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
}
//保存视频到相册
- (void)exportDidFinish:(AVAssetExportSession*)session {
if(session.status ==AVAssetExportSessionStatusCompleted) {
NSURL*outputURL = session.outputURL;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
__block PHObjectPlaceholder *placeholder;
if(UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(outputURL.path)) {
NSError*error;
[[PHPhotoLibrary sharedPhotoLibrary] performChangesAndWait:^{
PHAssetChangeRequest* createAssetRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:outputURL];
placeholder = [createAssetRequest placeholderForCreatedAsset];
} error:&error];
if(error) {
//[SVProgressHUD showErrorWithStatus:[NSString stringWithFormat:@"%@",error]];
}
else{
//[SVProgressHUD showSuccessWithStatus:@"视频已经保存到相册"];
}
}else{
//[SVProgressHUD showErrorWithStatus:NSLocalizedString(@"视频保存相册失败,请设置软件读取相册权限", nil)];
}
});
}
}
//视频合成,添加背景音乐
-(void)addFirstVideo:(NSURL*)firstVideoPath andSecondVideo:(NSURL*)secondVideo withMusic:(NSURL*)musicPath completion:(void(^)(NSURL*outputURL,BOOLisSuccess))completionHandle{
AVAsset*firstAsset = [AVAssetassetWithURL:firstVideoPath];
AVAsset*secondAsset = [AVAssetassetWithURL:secondVideo];
AVAsset*musciAsset = [AVAssetassetWithURL:musicPath];
// 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
AVMutableComposition*mixComposition = [[AVMutableCompositionalloc] init];
// 2 - Video track
AVMutableCompositionTrack*firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[firstTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, firstAsset.duration)
ofTrack:[[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];
[firstTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, secondAsset.duration)
ofTrack:[[secondAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:firstAsset.duration error:nil];
if(musciAsset!=nil){//添加背景音乐
AVMutableCompositionTrack*AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[AudioTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero,CMTimeAdd(firstAsset.duration, secondAsset.duration))
ofTrack:[[musciAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
}else{//不添加背景音乐
#pragma注意这里需要加上音频轨道信息,否则合成的视频没有声音
//添加 by yang
AVMutableCompositionTrack*AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[AudioTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, firstAsset.duration)
ofTrack:[[firstAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
[AudioTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, secondAsset.duration)
ofTrack:[[secondAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:firstAsset.duration error:nil];
}
// 4 - Get path
NSArray*paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*documentsDirectory = [paths objectAtIndex:0];
NSString*myPathDocs = [documentsDirectory stringByAppendingPathComponent:
[NSStringstringWithFormat:@"mergeVideo-%d.mov",arc4random() %1000]];
// NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:
// [NSString stringWithFormat:@"%@.mov",@"combinVideo"]];
//如果文件已经存在,先移除,否则会报无法存储的错误
NSFileManager*manager = [NSFileManagerdefaultManager];
[manager removeItemAtPath:myPathDocs error:nil];
NSURL*videoUrl = [NSURLfileURLWithPath:myPathDocs];
// 5 - Create exporter
exporter = [[AVAssetExportSessionalloc] initWithAsset:mixComposition
presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL=videoUrl;
exporter.outputFileType =AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse =YES;
[exporter exportAsynchronouslyWithCompletionHandler:^{
// dispatch_async(dispatch_get_main_queue(), ^{
// [self exportDidFinish:exporter];
// });
switch([exporter status]) {
caseAVAssetExportSessionStatusFailed:
{
NSLog(@"视频拼接失败:%@", [[exporter error] description]);
completionHandle(videoUrl,NO);
}
break;
caseAVAssetExportSessionStatusCancelled:
{
completionHandle(videoUrl,NO);
}
break;
caseAVAssetExportSessionStatusCompleted:
{
//成功
NSLog(@"视频拼接成功");
completionHandle(videoUrl,YES);
}
break;
default:
{
completionHandle(videoUrl,NO);
}break;
}
}];
}
//视频裁剪
- (void)cropWithVideoUrlStr:(NSURL*)videoUrl start:(CGFloat)startTime end:(CGFloat)endTime completion:(void(^)(NSURL*outputURL, Float64 videoDuration,BOOLisSuccess))completionHandle
{
AVURLAsset*asset =[[AVURLAssetalloc] initWithURL:videoUrl options:nil];
//获取视频总时长
Float64 duration =CMTimeGetSeconds(asset.duration);
//NSString *outputPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"dafei.mov"];
NSArray*paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES);
NSString*documentsDirectory = [paths objectAtIndex:0];
NSString*outputPath = [documentsDirectory stringByAppendingPathComponent:
[NSStringstringWithFormat:@"dafei-%d.mov",arc4random() %1000]];
NSURL*outputURL = [NSURLfileURLWithPath:outputPath];
//如果文件已经存在,先移除,否则会报无法存储的错误
NSFileManager*manager = [NSFileManagerdefaultManager];
[manager removeItemAtPath:outputPath error:nil];
NSArray*compatiblePresets = [AVAssetExportSessionexportPresetsCompatibleWithAsset:asset];
if([compatiblePresets containsObject:AVAssetExportPresetMediumQuality])
{
AVAssetExportSession*exportSession = [[AVAssetExportSessionalloc]
initWithAsset:asset presetName:AVAssetExportPresetPassthrough];
exportSession.outputURL = outputURL;
//视频文件的类型
exportSession.outputFileType =AVFileTypeQuickTimeMovie;
//输出文件是否网络优化
exportSession.shouldOptimizeForNetworkUse =YES;
//要截取的开始时间
CMTimestart =CMTimeMakeWithSeconds(startTime, asset.duration.timescale);
//要截取的总时长
CMTimeduration =CMTimeMakeWithSeconds(endTime - startTime,asset.duration.timescale);
CMTimeRangerange =CMTimeRangeMake(start, duration);
exportSession.timeRange = range;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch([exportSession status]) {
caseAVAssetExportSessionStatusFailed:
{
NSLog(@"合成失败:%@", [[exportSession error] description]);
completionHandle(outputURL, endTime,NO);
}
break;
caseAVAssetExportSessionStatusCancelled:
{
completionHandle(outputURL, endTime,NO);
}
break;
caseAVAssetExportSessionStatusCompleted:
{
//成功
completionHandle(outputURL, endTime,YES);
}
break;
default:
{
completionHandle(outputURL, endTime,NO);
}break;
}
}];
}
}
//展示进度
- (void)updateProgress{
}
本文地址:https://blog.csdn.net/qq_21743659/article/details/110126216
上一篇: JavaScript ES 模块的使用