2011-07-04 31 views
27

Tôi đang cố gắng kết hợp một số video clip thành một sử dụng AVFoundation. tôi có thể tạo một video duy nhất sử dụng AVMutableComposition sử dụng mã dưới đâyCách kết hợp các video clip với định hướng khác nhau bằng cách sử dụng AVFoundation

AVMutableComposition *composition = [AVMutableComposition composition]; 

AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 

AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 

CMTime startTime = kCMTimeZero; 

/*videoClipPaths is a array of paths of the video clips recorded*/ 

//for loop to combine clips into a single video 
for (NSInteger i=0; i < [videoClipPaths count]; i++) { 

    NSString *path = (NSString*)[videoClipPaths objectAtIndex:i]; 

    NSURL *url = [[NSURL alloc] initFileURLWithPath:path]; 

    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil]; 
    [url release]; 

    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 
    AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; 

    //set the orientation 
    if(i == 0) 
    { 
     [compositionVideoTrack setPreferredTransform:videoTrack.preferredTransform]; 
    } 

    ok = [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:videoTrack atTime:startTime error:nil]; 
    ok = [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:audioTrack atTime:startTime error:nil]; 

    startTime = CMTimeAdd(startTime, [asset duration]); 
} 

//export the combined video 
NSString *combinedPath = /* path of the combined video*/; 

NSURL *url = [[NSURL alloc] initFileURLWithPath: combinedPath]; 

AVAssetExportSession *exporter = [[[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPreset640x480] autorelease]; 

exporter.outputURL = url; 
[url release]; 

exporter.outputFileType = [[exporter supportedFileTypes] objectAtIndex:0]; 

[exporter exportAsynchronouslyWithCompletionHandler:^(void){[self combineVideoFinished:exporter.outputURL status:exporter.status error:exporter.error];}]; 

Đoạn mã trên hoạt động tốt nếu tất cả các video clip được ghi lại trong cùng một định hướng (chân dung hoặc phong cảnh). Tuy nhiên nếu tôi có một hỗn hợp các định hướng trong các clip, video cuối cùng sẽ có một phần của nó xoay 90 độ sang phải (hoặc trái).

Tôi đã tự hỏi là có một cách để chuyển đổi tất cả các clip sang cùng một hướng (ví dụ: hướng của clip đầu tiên) trong khi soạn chúng. Từ những gì tôi đọc từ tài liệu XCode AVMutableVideoCompositionLayerInstruction dường như có thể được sử dụng để chuyển đổi AVAsset, nhưng tôi không chắc chắn cách tạo và áp dụng một số hướng dẫn lớp khác nhau cho các clip tương ứng và sau đó sử dụng trong bố cục (AVMutableComposition*)

Bất kỳ trợ giúp nào được đánh giá cao!

Trả lời

25

Đây là những gì tôi làm. Sau đó, tôi sử dụng AVAssetExportSession để tạo tệp thực. nhưng tôi cảnh báo bạn, CGAffineTransforms đôi khi được áp dụng muộn, vì vậy bạn sẽ thấy một hoặc hai bản gốc trước khi video chuyển đổi. Tôi không biết tại sao điều này xảy ra, một sự kết hợp khác của video sẽ mang lại kết quả mong đợi, nhưng đôi khi nó kết thúc.

AVMutableComposition *composition = [AVMutableComposition composition]; AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 

AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; videoComposition.frameDuration = CMTimeMake(1,30); videoComposition.renderScale = 1.0; 

AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack]; 

// Get only paths the user selected NSMutableArray *array = [NSMutableArray array]; for(NSString* string in videoPathArray){ 
if(![string isEqualToString:@""]){ 
    [array addObject:string]; 
} 

self.videoPathArray = array; 

float time = 0; 

for (int i = 0; i<self.videoPathArray.count; i++) { 

    AVURLAsset *sourceAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[videoPathArray objectAtIndex:i]] options:[NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey]]; 

    NSError *error = nil; 

    BOOL ok = NO; 
    AVAssetTrack *sourceVideoTrack = [[sourceAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 

    CGSize temp = CGSizeApplyAffineTransform(sourceVideoTrack.naturalSize, sourceVideoTrack.preferredTransform); 
    CGSize size = CGSizeMake(fabsf(temp.width), fabsf(temp.height)); 
    CGAffineTransform transform = sourceVideoTrack.preferredTransform; 

    videoComposition.renderSize = sourceVideoTrack.naturalSize; 
    if (size.width > size.height) { 
     [layerInstruction setTransform:transform atTime:CMTimeMakeWithSeconds(time, 30)]; 
    } else { 

     float s = size.width/size.height; 

     CGAffineTransform new = CGAffineTransformConcat(transform, CGAffineTransformMakeScale(s,s)); 

     float x = (size.height - size.width*s)/2; 

     CGAffineTransform newer = CGAffineTransformConcat(new, CGAffineTransformMakeTranslation(x, 0)); 

     [layerInstruction setTransform:newer atTime:CMTimeMakeWithSeconds(time, 30)]; 
    } 

    ok = [compositionVideoTrack insertTimeRange:sourceVideoTrack.timeRange ofTrack:sourceVideoTrack atTime:[composition duration] error:&error]; 

    if (!ok) { 
     // Deal with the error. 
     NSLog(@"something went wrong"); 
    } 

    NSLog(@"\n source asset duration is %f \n source vid track timerange is %f %f \n composition duration is %f \n composition vid track time range is %f %f",CMTimeGetSeconds([sourceAsset duration]), CMTimeGetSeconds(sourceVideoTrack.timeRange.start),CMTimeGetSeconds(sourceVideoTrack.timeRange.duration),CMTimeGetSeconds([composition duration]), CMTimeGetSeconds(compositionVideoTrack.timeRange.start),CMTimeGetSeconds(compositionVideoTrack.timeRange.duration)); 

    time += CMTimeGetSeconds(sourceVideoTrack.timeRange.duration); 
    } 

instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction]; instruction.timeRange = compositionVideoTrack.timeRange; 

videoComposition.instructions = [NSArray arrayWithObject:instruction]; 

Đây là những gì tôi làm. Sau đó, tôi sử dụng AVAssetExportSession để tạo tệp thực. nhưng tôi cảnh báo bạn, CGAffineTransforms đôi khi được áp dụng muộn, vì vậy bạn sẽ thấy một hoặc hai bản gốc trước khi video chuyển đổi. Tôi không biết tại sao điều này xảy ra, một sự kết hợp khác của video sẽ mang lại kết quả mong đợi, nhưng đôi khi nó kết thúc.

+0

có vẻ như đang hoạt động, tuy nhiên tôi không gặp phải các biến đổi đang được áp dụng sau này – Song

+2

Lạ. Tôi không cố gắng hợp nhất hai tập tin, tôi chỉ cố gắng để có được một AVAssetExportSession để duy trì định hướng video. Bạn được cho là chỉ có thể gọi '[compositionVideoTrack setPreferredTransform: transform]' nhưng nó không hoạt động. Sử dụng phương pháp của bạn cũng không hiệu quả với tôi. Nhưng sử dụng * cả hai * đã hoạt động. Âm thanh như một lỗi khuôn khổ. Tôi cũng đang sử dụng cài đặt phiên xuất khẩu 'AVAssetExportPresetPassthrough'. – Dex

+0

Tôi cũng gặp vấn đề rất lạ với thời gian. Thường xuyên hơn không, 1 giây cuối cùng của video bị cắt. – Dex

Các vấn đề liên quan