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

#import"GPUImage.h"

@interfaceVideoManager()

{

///GPUImage

    GPUImageMovie *movieFile;

    GPUImageOutput *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{


}

你可能感兴趣的:(iOS视频裁剪、拼接、添加水印、添加背景音乐)