多段视频合并核心代码

来源:互联网 发布:国泰安数据库怎么查找 编辑:程序博客网 时间:2024/05/21 10:35

//将所有分段视频合成为一段完整视频,并且裁剪为正方形包含所有视频分段的文件URL数组,必须是[NSURL fileURLWithString:...]得到的

- (void)mergeAndExportVideosAtFileURLs:(NSArray *)fileArray{

    /// fileArray 是多短视频的本地存储路径数组,,视频存于沙盒目录

    NSMutableArray *fileURLArray = [NSMutableArrayarray];

    //// fileArray里的视频路径是字符串类型,,转换成URL

    for (NSString *strin fileArray) {

        [fileURLArray addObject:[NSURLfileURLWithPath:str]];

    }

    NSError *error =nil;

    CGSize renderSize =CGSizeMake(0,0);

    NSMutableArray *layerInstructionArray = [[NSMutableArrayalloc] init];

    AVMutableComposition *mixComposition = [[AVMutableCompositionalloc] init];

    CMTime totalDuration =kCMTimeZero;

    //先去assetTrack也为了取renderSize

    NSMutableArray *assetTrackArray = [[NSMutableArrayalloc] init];

    NSMutableArray *assetArray = [[NSMutableArrayalloc] init];

    for (NSURL *fileURLin fileURLArray) {

        AVAsset *asset = [AVAssetassetWithURL:fileURL];

        if (!asset) {

            continue;

        }

        [assetArray addObject:asset];

         NSArray *dataSourceArray = [NSArrayarrayWithArray: [asset tracksWithMediaType:AVMediaTypeVideo]];

        AVAssetTrack *assetTrack = ([dataSourceArraycount]>0)?[dataSourceArrayobjectAtIndex:0]:nil;

        [assetTrackArray addObject:assetTrack];

        renderSize.width =MAX(renderSize.width, assetTrack.naturalSize.height);

        renderSize.height =MAX(renderSize.height, assetTrack.naturalSize.width);

    }

    CGFloat renderW =MIN(renderSize.width, renderSize.height);

    for (int i =0; i < [assetArray count] && i < [assetTrackArray count]; i++) {

        AVAsset *asset = [assetArrayobjectAtIndex:i];

        AVAssetTrack *assetTrack = [assetTrackArrayobjectAtIndex:i];

        AVMutableCompositionTrack *audioTrack = [mixCompositionaddMutableTrackWithMediaType:AVMediaTypeAudiopreferredTrackID:kCMPersistentTrackID_Invalid];

        [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)

                            ofTrack:([[assettracksWithMediaType:AVMediaTypeAudio]count]>0)?[[assettracksWithMediaType:AVMediaTypeAudio]objectAtIndex:0]:nil

                             atTime:totalDurationerror:nil];

        AVMutableCompositionTrack *videoTrack = [mixCompositionaddMutableTrackWithMediaType:AVMediaTypeVideopreferredTrackID:kCMPersistentTrackID_Invalid];

        [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)

                            ofTrack:assetTrack

                             atTime:totalDuration

                              error:&error];

        //fix orientationissue

        AVMutableVideoCompositionLayerInstruction *layerInstruciton = [AVMutableVideoCompositionLayerInstructionvideoCompositionLayerInstructionWithAssetTrack:videoTrack];

        totalDuration = CMTimeAdd(totalDuration, asset.duration);

        CGFloat rate;

        rate = renderW / MIN(assetTrack.naturalSize.width, assetTrack.naturalSize.height);

        CGAffineTransform layerTransform =CGAffineTransformMake(assetTrack.preferredTransform.a, assetTrack.preferredTransform.b, assetTrack.preferredTransform.c, assetTrack.preferredTransform.d, assetTrack.preferredTransform.tx * rate, assetTrack.preferredTransform.ty * rate);

        layerTransform = CGAffineTransformConcat(layerTransform,CGAffineTransformMake(1,0, 0,1, 0, -(assetTrack.naturalSize.width - assetTrack.naturalSize.height) /2.0));//向上移动取中部影响

        layerTransform = CGAffineTransformScale(layerTransform, rate, rate);//放缩,解决前后摄像结果大小不对称

        [layerInstruciton setTransform:layerTransformatTime:kCMTimeZero];

        [layerInstruciton setOpacity:0.0atTime:totalDuration];

        [layerInstructionArray addObject:layerInstruciton];

    }

    //获取保存路径

    NSString *timeStr = [CamerToolgetVideoName]; /// 合并视频的存储名

    NSURL *mergeFileURL = [NSURLfileURLWithPath:[[FLGfileManagershareManager] getVideoPath:timeStr]];

    //导出合并的视频

    AVMutableVideoCompositionInstruction *mainInstruciton = [AVMutableVideoCompositionInstructionvideoCompositionInstruction];

    mainInstruciton.timeRange =CMTimeRangeMake(kCMTimeZero, totalDuration);

    mainInstruciton.layerInstructions = layerInstructionArray;

    AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoCompositionvideoComposition];

    mainCompositionInst.instructions =@[mainInstruciton];

    mainCompositionInst.frameDuration =CMTimeMake(1,30);

    mainCompositionInst.renderSize =CGSizeMake(renderW, renderW);

#pragma mark // 录制视频压缩质量调整

    AVAssetExportSession *exporter = [[AVAssetExportSessionalloc] initWithAsset:mixCompositionpresetName:AVAssetExportPresetHighestQuality];

    exporter.videoComposition = mainCompositionInst;

    exporter.outputURL = mergeFileURL;

    exporter.outputFileType =AVFileTypeMPEG4;

    exporter.shouldOptimizeForNetworkUse =YES;

    [exporter exportAsynchronouslyWithCompletionHandler:^{

        // 如果导出的状态为完成

        if ([exporterstatus] == AVAssetExportSessionStatusCompleted) {

            dispatch_async(dispatch_get_main_queue(), ^{

              NSLog(@"视频合并成功");

                /// 反归档出合并视频名称的数组,,,,,沙盒路径每次启动会发生改变,,不能直接存视频路径,,存名称,,每次启动取出视频的时候重新拼接视频路径。。。

                NSMutableArray *plist = [NSMutableArrayarray];

                plist = [NSKeyedUnarchiverunarchiveObjectWithFile:[[FLGfileManagershareManager] getPathPlist]];

                if (plist.count ==0) {

                    plist = [NSMutableArrayarrayWithObject:timeStr];

                }else{

                    [plist addObject:timeStr];

                } 

                 /// 将合并视频的名称数组归档到本地

                [NSKeyedArchiverarchiveRootObject:plist toFile:[[FLGfileManagershareManager] getPathPlist]];

                //// 视频合并成功,,到播放器视频播放查看

                VideoPlayViewController *video = [[VideoPlayViewControlleralloc] init];

                video.videoUrl = mergeFileURL;

                UINavigationController *nan = [[UINavigationControlleralloc] initWithRootViewController:video];

                 /// 视频合并成功删除子视频

                [selfpresentViewController:nananimated:YEScompletion:^{

                    for (NSString *urlin fileArray) {

                         /// 已知路径数组,,去删除好了

                        [[FLGfileManagershareManager] deleteVideo:url];

                    }

                }];

            });

        }elseif ([exporterstatus] == AVAssetExportSessionStatusFailed){

            NSLog(@"视频合并失败");

        }

    }];

}


原创粉丝点击