2010-11-13 4 views
7

Je suis en train d'assembler un tas de clips vidéo filmés sur l'iPhone en mode portrait. Pour les assembler, je prends approche directe comme suit:comment contrôler l'orientation de la vidéo assemblée avec AVMutableComposition

AVURLAsset pour mettre la main sur les différentes vidéos bousculent alors ceux-ci dans un AVMutableCompositionTrack puis mettre cela en un AVMutableComposition que je suis l'exportation de déposer auprès AVAssetExportSession

Mon Le problème est que lorsque je viens d'afficher la vidéo dans un UIWebView, il apparaît en mode paysage. Toutefois, si je vois l'une des vues de composants, elles apparaissent en mode Portrait. Est-ce que quelqu'un sait comment régler l'orientation. J'ai essayé de déconner avec AVMutableComposition naturalSize en changeant la largeur et la hauteur autour mais cela a juste rendu mon peuple court et gros! (Alors que de leur côté)

Merci à l'avance de toute réflexion/suggestions

Tudor

+0

quelqu'un sait même comment l'orientation originale est stockée? – Tudor

+0

Il existe une propriété originalTransform sur la piste d'actif que vous pouvez interroger dans certaines circonstances. – Hunter

Répondre

11

Configuration d'une composition vidéo qui va gérer rotation + échelle:

AVMutableVideoComposition* videoComposition = [[AVMutableVideoComposition videoComposition]retain]; 
videoComposition.renderSize = CGSizeMake(320, 240); 
videoComposition.frameDuration = CMTimeMake(1, 30); 

AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30)); 

AVMutableVideoCompositionLayerInstruction* rotator = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]]; 
CGAffineTransform translateToCenter = CGAffineTransformMakeTranslation(0,-320);  
CGAffineTransform rotateBy90Degrees = CGAffineTransformMakeRotation(M_PI_2); 
CGAffineTransform shrinkWidth = CGAffineTransformMakeScale(0.66, 1); // needed because Apple does a "stretch" by default - really, we should find and undo apple's stretch - I suspect it'll be a CALayer defaultTransform, or UIView property causing this 
CGAffineTransform finalTransform = CGAffineTransformConcat(shrinkWidth, CGAffineTransformConcat(translateToCenter, rotateBy90Degrees)); 
[rotator setTransform:finalTransform atTime:kCMTimeZero]; 

instruction.layerInstructions = [NSArray arrayWithObject: rotator]; 
videoComposition.instructions = [NSArray arrayWithObject: instruction]; 
+0

Si vous utilisez la caméra orientée vers l'avant, vous devrez également créer une autre transformation pour reproduire la vidéo, comme le fait l'application intégrée. – Hunter

+0

Quel type de classe est «transformateur»? –

+0

Désolé - copier/coller erreur. Cette ligne était inutile (supprimée maintenant) – Adam

9

Voici un code qui ajusté la rotation utilisant la transformation préférée:

// our composition, with one video and one audio track 
AVMutableComposition* composition = [AVMutableComposition composition]; 
AVMutableCompositionTrack *videoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
AVMutableCompositionTrack *audioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; 

// loop through all the clips, adding them to our track and inserting composition instructions 
NSDictionary* options = @{ AVURLAssetPreferPreciseDurationAndTimingKey: @YES }; 
CMTime insertionPoint = kCMTimeZero; 
NSMutableArray* instructions = [NSMutableArray array]; 
NSError* error = nil; 
for (NSURL* outputFileURL in self.movieFileURLs) { 
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:outputFileURL options:options]; 

    // insert this clip's video track into our composition 
    NSArray *videoAssetTracks = [asset tracksWithMediaType:AVMediaTypeVideo]; 
    AVAssetTrack *videoAssetTrack = (videoAssetTracks.count > 0 ? [videoAssetTracks objectAtIndex:0] : nil); 
    [videoTrack insertTimeRange:CMTimeRangeFromTimeToTime(kCMTimeZero, asset.duration) ofTrack:videoAssetTrack atTime:insertionPoint error:&error]; 

    // create a layer instruction at the start of this clip to apply the preferred transform to correct orientation issues 
    AVMutableVideoCompositionLayerInstruction *instruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoAssetTrack]; 
    [instruction setTransform:videoAssetTrack.preferredTransform atTime:kCMTimeZero]; 

    // create the composition instructions for the range of this clip 
    AVMutableVideoCompositionInstruction * videoTrackInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; 
    videoTrackInstruction.timeRange = CMTimeRangeMake(insertionPoint, asset.duration); 
    videoTrackInstruction.layerInstructions = @[instruction]; 
    [instructions addObject:videoTrackInstruction]; 

    // insert this clip's audio track into our composition 
    NSArray *audioAssetTracks = [asset tracksWithMediaType:AVMediaTypeAudio]; 
    AVAssetTrack *audioAssetTrack = (audioAssetTracks.count > 0 ? [audioAssetTracks objectAtIndex:0] : nil); 
    [audioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, asset.duration) ofTrack:audioAssetTrack atTime:insertionPoint error:nil]; 

    // advance the insertion point to the end of the clip 
    insertionPoint = CMTimeAdd(insertionPoint, asset.duration); 
} 

// create our video composition which will be assigned to the player item 
AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; 
videoComposition.instructions = instructions; 
videoComposition.frameDuration = CMTimeMake(1, videoTrack.naturalTimeScale); 
videoComposition.renderSize = videoTrack.naturalSize; 
_videoComposition = videoComposition; 
+1

J'ai essayé d'utiliser cet extrait de code dans mon application où je fusionne des clips vidéo en une seule vidéo et l'exporte en utilisant 'AVAssetExportSession'. Cependant, j'obtiens une erreur lorsque je mets la propriété 'videoComposition' de' AVAssetExportSession' à mon instance de 'AVMutableVideoComposition'. Savez-vous comment utiliser votre code lors de l'exportation du film? J'ai créé une question ici et si vous avez le temps, pourriez-vous jeter un coup d'œil? http://stackoverflow.com/questions/16385017/error-when-using-avassetexportsession-with-video-composition-set – simonbs

+0

@simonbs avez-vous pu le faire fonctionner? –

11

Si tout vous voulez est vous préserver l'orientation vidéo que vous pouvez attribuer une valeur AVMutableCompositionTrack prefferedTransition de AVAssetTrack comme ceci:

AVAssetTrack *videoAssetTrack= [[videoAsset tracksWithMediaType:AVMediaTypeVideo] lastObject]; 

AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; 
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:&error]; 

videoCompositionTrack.preferredTransform = videoAssetTrack.preferredTransform; 
+0

C'est le moyen le plus pratique. Merci! – AlexeyVMP

+2

Cela ne semble pas fonctionner si la composition contient des pistes avec des orientations différentes ... –

+0

Parce que c'est seulement lastObject qui est pris en compte. C'est une simplification du problème, pas une solution pour tous les cas. – Marcin

Questions connexes