2013-11-26 9 views
6

Sto provando a convertire il video .mov in .mp4 e allo stesso tempo correggere l'orientamento. Il codice che uso qui di seguito grandi opere durante la registrazione di un video utilizzando UIImagePickerController se il video è selezionato dal rullino fotografico ottengo questo errore e non vedo il motivo per cui:Errore di rotazione di AVAssetExportSession quando il video proviene dal rullino fotografico

esportazione non riuscita: un'operazione interrotta: Errore dominio = Codice AVFoundationErrorDomain = -11.841 "Operazione Stopped" UserInfo = {0x1815ca50 NSLocalizedDescription = Operazione Arrestato, NSLocalizedFailureReason = il video non poteva essere composto.}

ho provato prima il salvataggio del video in un altro file, ma non ha fatto differenza.

Ecco il codice che sto usando per convertire il video:

- (void)convertVideoToLowQuailtyAndFixRotationWithInputURL:(NSURL*)inputURL handler:(void (^)(NSURL *outURL))handler 
{ 
    if ([[inputURL pathExtension] isEqualToString:@"MOV"]) 
    { 
     NSURL *outputURL = [inputURL URLByDeletingPathExtension]; 
     outputURL = [outputURL URLByAppendingPathExtension:@"mp4"]; 

     AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:inputURL options:nil]; 

     AVAssetTrack *sourceVideoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 
     AVAssetTrack *sourceAudioTrack = [[avAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; 

     AVMutableComposition* composition = [AVMutableComposition composition]; 

     AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo 
                        preferredTrackID:kCMPersistentTrackID_Invalid]; 
     [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceVideoTrack 
             atTime:kCMTimeZero error:nil]; 
     [compositionVideoTrack setPreferredTransform:sourceVideoTrack.preferredTransform]; 

     AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio 
                        preferredTrackID:kCMPersistentTrackID_Invalid]; 
     [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceAudioTrack 
             atTime:kCMTimeZero error:nil]; 

     AVMutableVideoComposition *videoComposition = [self getVideoComposition:avAsset]; 

     NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset]; 
     if ([compatiblePresets containsObject:AVAssetExportPresetMediumQuality]) 
     { 
      AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]initWithAsset:composition presetName:AVAssetExportPresetMediumQuality]; 
      exportSession.outputURL = outputURL; 
      exportSession.outputFileType = AVFileTypeMPEG4; 
      exportSession.shouldOptimizeForNetworkUse = YES; 
      exportSession.videoComposition = videoComposition; 
      [exportSession exportAsynchronouslyWithCompletionHandler:^{ 

       switch ([exportSession status]) 
       { 
        case AVAssetExportSessionStatusFailed: 
         NSLog(@"Export failed: %@ : %@", [[exportSession error] localizedDescription], [exportSession error]); 
         handler(nil); 

         break; 
        case AVAssetExportSessionStatusCancelled: 

         NSLog(@"Export canceled"); 
         handler(nil); 

         break; 
        default: 

         handler(outputURL); 

         break; 

       } 
      }]; 
     } 

    } else { 
     handler(inputURL); 
    } 
} 

- (AVMutableVideoComposition *)getVideoComposition:(AVAsset *)asset 
{ 
    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; 
    AVMutableComposition *composition = [AVMutableComposition composition]; 
    AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; 
    CGSize videoSize = videoTrack.naturalSize; 
    BOOL isPortrait_ = [self isVideoPortrait:asset]; 
    if(isPortrait_) { 
//  NSLog(@"video is portrait "); 
     videoSize = CGSizeMake(videoSize.height, videoSize.width); 
    } 
    composition.naturalSize  = videoSize; 
    videoComposition.renderSize = videoSize; 
    videoComposition.frameDuration = CMTimeMakeWithSeconds(1/videoTrack.nominalFrameRate, 600); 

    AVMutableCompositionTrack *compositionVideoTrack; 
    compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
    [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:videoTrack atTime:kCMTimeZero error:nil]; 
    AVMutableVideoCompositionLayerInstruction *layerInst; 
    layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack]; 
    [layerInst setTransform:videoTrack.preferredTransform atTime:kCMTimeZero]; 
    AVMutableVideoCompositionInstruction *inst = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
    inst.timeRange = CMTimeRangeMake(kCMTimeZero, asset.duration); 
    inst.layerInstructions = [NSArray arrayWithObject:layerInst]; 
    videoComposition.instructions = [NSArray arrayWithObject:inst]; 
    return videoComposition; 
} 

risposta

13

AVFoundation errore costante -11.841 significa che si ha una composizione di video non valida. Vedi questo link se desideri maggiori informazioni sulle costanti di errore: https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVFoundation_ErrorConstants/Reference/reference.html

Mentre non ci sono errori importanti che mi vengono immediatamente fuori, posso suggerire i seguenti modi per restringere la fonte del tuo problema.

Prima, invece di passare nil per il parametro error in queste chiamate:

[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceVideoTrack 
             atTime:kCMTimeZero error:nil]; 

crea un oggetto NSError e passare il riferimento a esso in questo modo:

NSError *error = nil; 
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, avAsset.duration) 
             ofTrack:sourceVideoTrack 
             atTime:kCMTimeZero error:&error]; 

Esaminare l'errore di rendere sicuro che le tracce video e audio vengano inserite correttamente nella traccia di composizione. L'errore dovrebbe essere nil se tutto va bene.

if(error) 
    NSLog(@"Insertion error: %@", error); 

Si consiglia inoltre di controllare il vostro AVAsset composable e exportable e hasProtectedContent proprietà. Se questi non sono YES, YES e NO, rispettivamente, potresti avere problemi a creare il tuo nuovo file video.

Occasionalmente ho riscontrato un problema in cui la creazione di un intervallo di tempo per una traccia audio non è gradita alla scala cronologica 600 se utilizzata in una composizione con una traccia video. Si consiglia di creare un nuovo CMTime per la durata (avAsset.duration) in

CMTimeRangeMake(kCMTimeZero, avAsset.duration) 

solo per inserire la traccia audio. Nel nuovo CMTime, usa una scala cronologica di 44100 (o qualunque sia la frequenza di campionamento della traccia audio). Lo stesso vale per il tuo videoComposition.frameDuration. A seconda dello nominalFrameRate della tua traccia video, il tuo tempo potrebbe non essere rappresentato correttamente con 600 scale di tempo.

Infine, c'è un utile strumento fornito da Apple per composizioni video di debug:

https://developer.apple.com/library/mac/samplecode/AVCompositionDebugViewer/Introduction/Intro.html

dà una rappresentazione visiva della vostra composizione e si può vedere dove le cose non vanno come dovrebbero.

+0

Grazie per la vostra risposta molto dettagliata. Non riesco ancora a far funzionare :( 'componable',' exportable' e 'hasProtectedContent' sono4 tutto come dici tu.Non ci sono errori restituiti dal tuo primo suggerimento.Ho provato a cambiare la traccia audio per usare 44.100. Se commento "exportSession.videoComposition = videoComposition;" funziona bene, tuttavia il video non viene ruotato, quindi il problema deve essere lì da qualche parte. Grazie – Darren

+0

Mi accorgo che crei un 'AVMutableComposition' in' - (AVMutableVideoComposition *) getVideoComposition', e crea 'AVMutableCompositionTrack's da quello.Tuttavia, in' - (void) convertVideoToLowQuailtyAndFixRotationWithInputURL: handler: ' , hai un _different_' AVMutableComposition' che stai passando a 'AVExportSession'. Prova a passare questa composizione a getVideoComposition per creare AVMutableCompositionTracks da questo, quindi ce n'è uno solo. – jlw

+0

I just ho provato a spostare "AVMutableVideoComposition' con" AVMutableVideoCompositionLayerInstruction' verso l'alto nel metodo di conversione principale in modo che abbia solo 1 "AVMutableComposition' ma abbia sempre gli stessi risultati. Quando si seleziona un video dal rullino fotografico, lo comprime prima di passarlo sopra, non è sicuro se questo è ciò che fa la differenza. – Darren

2

Prova commentando la riga sottostante ed eseguire il progetto

exportSession.videoComposition = videoComposition; 
+0

Questo ha funzionato per me. Grazie –

+2

Questo rimuoverà tutte le trasformazioni, le colture ecc aggiunte alla composizione video mutabile, quindi non usare in questo caso. –

+0

Questo ha funzionato anche per me. Sono curioso perché, comunque. Qualcuno sa? –

1

Si dovrebbe utilizzare il metodo isValidForAsset: TimeRange: validationDelegate: di AVVideoCompostion, sarà diagnosticare qualsiasi problema con la vostra composizione video. Ho avuto lo stesso problema e la soluzione per me è stato quello di creare il layerInstruction con l'AVMutableCompositionTrack al posto della traccia originale:

layerInst = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];