Ios 合并具有不同分辨率的剪辑

Ios 合并具有不同分辨率的剪辑,ios,video,merge,avfoundation,avassetexportsession,Ios,Video,Merge,Avfoundation,Avassetexportsession,我有一套视频剪辑,我想合并在一起,然后把它的水印 我能够单独完成这两个功能,但是在一起执行时会出现问题 将合并的所有剪辑都是1920x1080或960x540 由于某些原因,AVAssetExportSession无法将它们很好地显示在一起 以下是基于3种不同场景的2个错误: 此图像是以下原因造成的: 将剪辑合并在一起 正如您所看到的,这里没有任何错误,输出视频产生了所需的效果 但是,当我尝试添加水印时,会产生以下问题: 此图像是以下原因造成的: 将剪辑合并在一起 在上面加上水印 错

我有一套视频剪辑,我想合并在一起,然后把它的水印

我能够单独完成这两个功能,但是在一起执行时会出现问题

将合并的所有剪辑都是1920x1080或960x540

由于某些原因,AVAssetExportSession无法将它们很好地显示在一起

以下是基于3种不同场景的2个错误:

此图像是以下原因造成的:

  • 将剪辑合并在一起
正如您所看到的,这里没有任何错误,输出视频产生了所需的效果

但是,当我尝试添加水印时,会产生以下问题:

此图像是以下原因造成的:

  • 将剪辑合并在一起
  • 在上面加上水印
错误1:视频中的某些剪辑会因任何原因调整大小,而其他剪辑则不会

此图像是以下原因造成的:

  • 将剪辑合并在一起
  • 调整960x540到1920x1080的剪辑大小
  • 在上面加上水印
Bug 2现在需要调整大小的剪辑已调整大小,但是旧的未调整大小的剪辑仍然存在

合并/调整代码大小:

-(void) mergeClips{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];      
    
    AVMutableCompositionTrack *mutableVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    
    AVMutableCompositionTrack *mutableAudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

    // loop through the list of videos and add them to the track
    CMTime currentTime = kCMTimeZero;
    
    NSMutableArray* instructionArray = [[NSMutableArray alloc] init];
    if (_clipsArray){
        for (int i = 0; i < (int)[_clipsArray count]; i++){
            NSURL* url = [_clipsArray objectAtIndex:i];
            
            AVAsset *asset = [AVAsset assetWithURL:url];
            
            AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
            AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
            
            CGSize size = videoTrack.naturalSize;
            CGFloat widthScale = 1920.0f/size.width;
            CGFloat heightScale = 1080.0f/size.height;
            
// lines that performs resizing
            AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableVideoTrack];
            CGAffineTransform scale = CGAffineTransformMakeScale(widthScale,heightScale);
            CGAffineTransform move = CGAffineTransformMakeTranslation(0,0);
            [layerInstruction setTransform:CGAffineTransformConcat(scale, move) atTime:currentTime];
            [instructionArray addObject:layerInstruction];
            
            
            [mutableVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                                ofTrack:videoTrack
                                 atTime:currentTime error:nil];
            
            [mutableAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration)
                                ofTrack:audioTrack
                                 atTime:currentTime error:nil];
            
            currentTime = CMTimeMakeWithSeconds(CMTimeGetSeconds(asset.duration) + CMTimeGetSeconds(currentTime), asset.duration.timescale);
        }
    }
    
    AVMutableVideoCompositionInstruction * mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    
    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, currentTime);
    mainInstruction.layerInstructions = instructionArray;
    
    
    // 4 - Get path
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    NSString *lastPostedDayPath = [documentsDirectory stringByAppendingPathComponent:@"lastPostedDay"];
    
    //Check if folder exists, if not create folder
    if (![[NSFileManager defaultManager] fileExistsAtPath:lastPostedDayPath]){
        [[NSFileManager defaultManager] createDirectoryAtPath:lastPostedDayPath withIntermediateDirectories:NO attributes:nil error:nil];
    }
    
    
    NSString *fileName = [NSString stringWithFormat:@"%li_%li_%li.mov", (long)_month, (long)_day, (long)_year];
    
    NSString *finalDayPath = [lastPostedDayPath stringByAppendingPathComponent:fileName];
    
    NSURL *url = [NSURL fileURLWithPath:finalDayPath];
    
    BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:finalDayPath];
    if (fileExists){
        NSLog(@"file exists");
        [[NSFileManager defaultManager] removeItemAtURL:url error:nil];
    }
    
    AVMutableVideoComposition *mainComposition = [AVMutableVideoComposition videoComposition];
    
    mainComposition.instructions = [NSArray arrayWithObject:mainInstruction];
    mainComposition.frameDuration = CMTimeMake(1, 30);
    mainComposition.renderSize = CGSizeMake(1920.0f, 1080.0f);
    
    // 5 - Create exporter
    _exportSession = [[AVAssetExportSession alloc] initWithAsset:mixComposition
                                                                            presetName:AVAssetExportPresetHighestQuality];
    _exportSession.outputURL=url;
    _exportSession.outputFileType = AVFileTypeQuickTimeMovie;
    _exportSession.shouldOptimizeForNetworkUse = YES;
    _exportSession.videoComposition = mainComposition;
    
    [_exportSession exportAsynchronouslyWithCompletionHandler:^{
        [merge_timer invalidate];
        merge_timer = nil;
        
        switch (_exportSession.status) {
            case AVAssetExportSessionStatusFailed:
                NSLog(@"Export failed -> Reason: %@, User Info: %@",
                      _exportSession.error.localizedDescription,
                      _exportSession.error.userInfo.description);
                [self showSavingFailedDialog];
                break;
                
            case AVAssetExportSessionStatusCancelled:
                NSLog(@"Export cancelled");
                [self showSavingFailedDialog];
                
                break;
                
            case AVAssetExportSessionStatusCompleted:
                NSLog(@"Export finished");
                [self addWatermarkToExportSession:_exportSession];
                
                break;
                
            default:
                break;
        }
    }];
});
}
-(无效)合并剪辑{
调度异步(调度获取全局队列(调度队列优先级默认为0)^{
AVMutableComposition*mixComposition=[[AVMutableComposition alloc]init];
AVMutableCompositionTrack*mutableVideoTrack=[mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_无效];
AVMutableCompositionTrack*mutableAudioTrack=[mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_无效];
//循环浏览视频列表并将其添加到曲目中
CMTime currentTime=KCMTIME0;
NSMUTABLEARRY*指令数组=[[NSMUTABLEARRY alloc]init];
如果(_clipsArray){
对于(int i=0;i<(int)[u clipsArray count];i++){
NSURL*url=[\u clipsArray objectAtIndex:i];
AVAsset*asset=[AVAsset AssetTwithUrl:url];
AVAssetTrack*videoTrack=[[asset Tracks WithMediaType:AVMediaTypeVideo]对象索引:0];
AVAssetTrack*audioTrack=[[asset Tracks WithMediaType:AVMediaTypeAudio]对象索引:0];
CGSize size=videoTrack.naturalSize;
CGFloat widthScale=1920.0f/size.width;
CGFloat高度刻度=1080.0f/size.height;
//执行大小调整的行
AvmutableVideoCompositionLayerStruction*LayerStruction=[AvmutableVideoCompositionLayerStructionWithAssetTrack:mutableVideoTrack];
CGAffineTransform scale=CGAffineTransformMakeScale(宽度刻度、高度刻度);
CGAffineTransform move=CGAffineTransformMakeTransform(0,0);
[layerInstruction setTransform:CGAffineTransformConcat(缩放、移动)时间:currentTime];
[指令阵列添加对象:层结构];
[mutableVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,asset.duration)
ofTrack:videoTrack
时间:当前时间错误:零];
[mutableAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,asset.duration)
ofTrack:音频轨道
时间:当前时间错误:零];
currentTime=CMTimeMakeWithSeconds(CMTimeGetSeconds(asset.duration)+CMTimeGetSeconds(currentTime),asset.duration.timescale);
}
}
AVMutableVideoCompositionInstruction*Main指令=[AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange=CMTimeRangeMake(KCMTIME0RO,currentTime);
mainInstruction.layerInstructions=指令阵列;
//4-获取路径
NSArray*Path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,是);
NSString*documentsDirectory=[paths objectAtIndex:0];
NSString*lastPostedDayPath=[DocumentsDirectoryStringByAppendingPathComponent:@“lastPostedDay”];
//检查文件夹是否存在,如果不存在,请创建文件夹
如果(![[NSFileManager defaultManager]文件存在路径:lastPostedDayPath]){
[[NSFileManager defaultManager]createDirectoryAtPath:lastPostedDayPath with IntermediateDirectory:无属性:nil错误:nil];
}
NSString*文件名=[NSString stringWithFormat:@“%li_%li_%li.mov”,(长)月,(长)日,(长)年];
NSString*finalDayPath=[lastPostedDayPath stringByAppendingPathComponent:fileName];
NSURL*url=[NSURL fileURLWithPath:finalDayPath];
BOOL fileExists=[[NSFileManager defaultManager]fileExistsAtPath:finalDayPath];
如果(文件存在){
NSLog(@“文件存在”);
[[NSFileManager defaultManager]RemoveItemAttribute:url错误:nil];
}
AVMutableVideoComposition*mainComposition=[AVMutableVideoComposition];
main composition.instructions=[NSArray arrayWithObject:main指令];
mainComposition.frameDuration=CMTimeMake(1,30);
main composition.renderSize=CGSizeMake(1920.0f,1080.0f);
//5-创建导出器
_exportSession=[[AVAssetExportSession alloc]initWithAsset:mixComposition
预设名称:AVAssetExportPresetHighestQuality];
_exportSession.outputURL=url;
_exportSession.outputFileType=AVFileTypeQuickTimeMovie;
_exportSession.shouldOptimizationForNetworkUse=是;
_exportSession.videoComposition=main组合;
[\u exportSession exportAsynchronouslyWithCompletionHandler:^{
[合并计时器失效];
合并计时器=nil;
游泳
[layerInstruction setOpacity:0.0 atTime:duration];