我有一组视频片段,我想将它们合并在一起,然后在上面放上水印。
我可以单独执行这两个功能,但是同时执行它们会出现问题。
将要合并的所有剪辑均为1920x1080或960x540。
由于某些原因,AVASsetExportSession无法将它们很好地显示在一起。
以下是基于3种不同情况的2个错误:

该图像是以下结果的结果:

  • 合并剪辑

  • 如您所见,这里没有错,输出视频产生了预期的效果。
    但是,当我尝试添加水印时,它会产生以下问题:

    该图像是以下结果的结果:
  • 合并剪辑
  • 上加水印

  • 错误1:出于某些原因,视频中的某些剪辑会调整大小,而其他剪辑则不会。

    该图像是以下结果的结果:
  • 合并剪辑
  • 将960x540到1920x1080的剪辑的大小调整为
  • 上加水印

  • 错误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;
            }
        }];
    });
    }
    
    完成此操作后,我将通过一个仅添加水印的不同导出 session 来运行它。
    我的代码或过程中有什么地方做错了吗?
    有没有更简单的方法可以实现这一目标?
    感谢您的时间!

    最佳答案

    我能够解决我的问题。
    由于某些原因,AVASsetExportSession实际上不会为合并的剪辑创建一个“平坦”的视频文件,因此在添加水印导致其调整大小时,它仍能识别较低分辨率的剪辑及其位置。

    我要做的是,首先使用AVAssetWriter合并我的剪辑并创建一个“平面”文件。然后,我可以添加水印而不会出现大小调整问题。

    希望这对将来可能遇到此问题的任何人有所帮助!

    关于ios - 合并具有不同分辨率的剪辑,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/31363396/

    10-13 07:37