2012-12-29 15 views
7

Tôi đang quay các video clip nhỏ (khoảng một giây hoặc lâu hơn, với cả camera phía trước và phía sau, với các hướng khác nhau có thể). Và sau đó cố gắng hợp nhất chúng bằng cách sử dụng AVAssetExportSession. Về cơ bản, tôi tạo bố cục và videoComposition với các biến thể thích hợp và âm thanh & các bản nhạc video.exportAsynchronouslyWithCompletionHandler không thành công với nhiều tệp video (Code = -11820)

Vấn đề là trên iOS 5 nó không thành công nếu bạn có nhiều hơn 4 video clip và trên iOS 6 giới hạn có vẻ là 16 clip.

Điều này với tôi có vẻ thực sự khó hiểu. Có phải AVAssetExportSession đang làm điều gì đó kỳ quặc hoặc nó có một số giới hạn không có giấy tờ về số lượng clip có thể được truyền cho nó không? Dưới đây là một số trích đoạn từ mã của tôi:

-(void)exportVideo 
{ 
    AVMutableComposition *composition = video.composition; 
    AVMutableVideoComposition *videoComposition = video.videoComposition; 
    NSString * presetName = AVAssetExportPresetMediumQuality; 

    AVAssetExportSession *_assetExport = [[AVAssetExportSession alloc] initWithAsset:composition presetName:presetName]; 
    self.exportSession = _assetExport; 

    videoComposition.renderSize = CGSizeMake(640, 480); 
    _assetExport.videoComposition = videoComposition; 

    NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent: @"export.mov"]; 
    NSURL *exportUrl = [NSURL fileURLWithPath:exportPath]; 

    // Delete the currently exported files if it exists 
    if([[NSFileManager defaultManager] fileExistsAtPath:exportPath]) 
     [[NSFileManager defaultManager] removeItemAtPath:exportPath error:nil]; 

    _assetExport.outputFileType = AVFileTypeQuickTimeMovie; 
    _assetExport.outputURL = exportUrl; 
    _assetExport.shouldOptimizeForNetworkUse = YES; 

    [_assetExport exportAsynchronouslyWithCompletionHandler:^{ 
     switch (_assetExport.status) 
     { 
      case AVAssetExportSessionStatusCompleted: 
       NSLog(@"Completed exporting!"); 
       break; 
      case AVAssetExportSessionStatusFailed: 
       NSLog(@"Failed:%@", _assetExport.error.description); 
       break; 
      case AVAssetExportSessionStatusCancelled: 
       NSLog(@"Canceled:%@", _assetExport.error); 
       break; 
      default: 
       break; 
     } 
    }]; 
} 

Và dưới đây là cách các tác phẩm được thực hiện:

-(void)setVideoAndExport 
{ 
    video = nil; 
    video = [[VideoComposition alloc] initVideoTracks]; 

    CMTime localTimeline = kCMTimeZero; 

    // Create the composition of all videofiles 
    for (NSURL *url in outputFileUrlArray) { 
     AVAsset *asset = [[AVURLAsset alloc]initWithURL:url options:nil]; 
     [video setVideo:url at:localTimeline]; 
     localTimeline = CMTimeAdd(localTimeline, asset.duration); // Increment the timeline 
    } 
    [self exportVideo]; 
} 

Và đây là thịt của lớp VideoComposition:

-(id)initVideoTracks 
{ 
    if((self = [super init])) 
    { 
     composition = [[AVMutableComposition alloc] init]; 
     addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
     mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
     instructions = [[NSMutableArray alloc] init]; 
     videoComposition = [AVMutableVideoComposition videoComposition]; 
    } 
    return self; 
} 


-(void)setVideo:(NSURL*) url at:(CMTime)to 
{ 
    asset = [[AVURLAsset alloc]initWithURL:url options:nil]; 

    AVAssetTrack *assetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 

    AVMutableCompositionTrack *compositionTrackVideo = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [compositionTrackVideo insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack: assetTrack atTime:to error:nil]; 

    AVMutableCompositionTrack *compositionTrackAudio = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [compositionTrackAudio insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:[[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:to error:nil]; 

    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeAdd(to, asset.duration)); 

    AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionTrackVideo]; 

    [layerInstruction setTransform: assetTrack.preferredTransform atTime: kCMTimeZero]; 
    [layerInstruction setOpacity:0.0 atTime:CMTimeAdd(to, asset.duration)]; 
    [instructions addObject:layerInstruction]; 

    mainInstruction.layerInstructions = instructions; 
    videoComposition.instructions = [NSArray arrayWithObject:mainInstruction]; 
    videoComposition.frameDuration = CMTimeMake(1, 30); 
} 

Trả lời

2

Tôi cũng đã gặp phải vấn đề tương tự. Tôi đã cố gắng khắc phục nó bằng cách chèn nội dung vào bố cục chứ không phải theo dõi các bản nhạc có thể thay đổi. Vì vậy, trong mã của bạn cho "setVideo" thay vì dòng này:

[compositionTrackVideo insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack: assetTrack atTime:to error:nil]; 

thử điều này:

[self insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofAsset:asset atTime:to error:nil] 
+1

Tốt, tôi nghĩ rằng tôi cần phải thử điều này. Tôi đã phá vỡ vấn đề bằng cách luôn làm một bố cục sau mỗi lần ghi âm (trong nền) nên không quá hai video thực sự được tổng hợp. – Karvapallo

+0

Tôi thực sự không thể làm việc này. Có lẽ các biến đổi cần phải được áp dụng khác nhau (hoặc chúng sẽ không hoạt động) với cách tiếp cận này. Bạn sẽ có một số mã ví dụ nằm xung quanh? – Karvapallo

+0

Mã tạo thành phần gần đây trong dự án của chúng tôi được viết lại bằng cách sử dụng AVCompositionTrackSegment. Chúng tôi tạo ra một mảng các phân đoạn theo dõi, xác nhận chúng và gán cho các thuộc tính phân đoạn của AVMutableCompositionTrack. Chúng tôi đang làm rất nhiều thời gian kéo dài/nén (thay đổi tốc độ video) và phương pháp này cung cấp thành phần chính xác hơn. – Jeepston

7

Được rồi, tôi cũng đã liên lạc với Apple về vấn đề này và họ đã đưa ra một câu trả lời:

"Đây là một điều kiện đã biết. Bạn đang nhấn giới hạn bộ giải mã được thiết lập trong AVFoundation."

Họ cũng yêu cầu tôi gửi báo cáo lỗi về vấn đề này, vì thông báo lỗi mà AVAssetExportSession đưa ra nếu mơ hồ và gây nhầm lẫn. Vì vậy, tôi đã gửi một báo cáo lỗi cho táo phàn nàn về thực tế là thông báo lỗi là xấu.

Vì vậy, các giới hạn này trong AVAssetExportSession được xác nhận. Trong iOS 5 giới hạn bộ giải mã là 4 và trong iOS 6 nó được nâng lên 16. Vấn đề chính ở đây là lỗi được báo cáo bởi AVAssetExportSession là xấu vì nó chỉ báo cáo: 11820 "Không thể hoàn thành xuất khẩu" thay vì thực sự nói với chúng ta rằng chúng ta có đạt đến giới hạn.