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{


}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351