Recadrage AVAsset vidéo avec AVFoundation
Je suis en utilisant AVCaptureMovieFileOutput
enregistrement d'une vidéo. J'ai l'aperçu de la couche de affichées à l'aide de AVLayerVideoGravityResizeAspectFill
qui agrandit légèrement. Le problème que j'ai, c'est que la vidéo finale est plus grand, contenant de l'image supplémentaire qui ne correspondait pas à l'écran lors de la visualisation.
C'est l'aperçu de l'image résultant de la vidéo
Est-il une manière que je peux spécifier un CGRect
que je veux couper à partir de la vidéo à l'aide de AVAssetExportSession
?
EDIT ----
Lorsque j'applique un CGAffineTransformScale
à la AVAssetTrack
il effectue un zoom avant dans la vidéo, et avec le AVMutableVideoComposition
renderSize
ensemble de view.bounds
c'cultures au large de l'extrémité. Super, il y a juste 1 problème de de gauche. La largeur de la vidéo n'est pas extensible à la bonne largeur, il est juste rempli de noir.
MODIFIER 2 ----
La suggestion de question/réponse est incomplète..
Certains de mon code:
Dans mon - (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
méthode que j'ai ce pour recadrer et redimensionner la vidéo.
- (void)flipAndSave:(NSURL *)videoURL withCompletionBlock:(void(^)(NSURL *returnURL))completionBlock
{
AVURLAsset *firstAsset = [AVURLAsset assetWithURL:videoURL];
//1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
//2 - Video track
AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, firstAsset.duration)
ofTrack:[[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];
//2.1 - Create AVMutableVideoCompositionInstruction
AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange = CMTimeRangeMake(CMTimeMakeWithSeconds(0, 600), firstAsset.duration);
//2.2 - Create an AVMutableVideoCompositionLayerInstruction for the first track
AVMutableVideoCompositionLayerInstruction *firstlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:firstTrack];
AVAssetTrack *firstAssetTrack = [[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
UIImageOrientation firstAssetOrientation_ = UIImageOrientationUp;
BOOL isFirstAssetPortrait_ = NO;
CGAffineTransform firstTransform = firstAssetTrack.preferredTransform;
if (firstTransform.a == 0 && firstTransform.b == 1.0 && firstTransform.c == -1.0 && firstTransform.d == 0) {
firstAssetOrientation_ = UIImageOrientationRight;
isFirstAssetPortrait_ = YES;
}
if (firstTransform.a == 0 && firstTransform.b == -1.0 && firstTransform.c == 1.0 && firstTransform.d == 0) {
firstAssetOrientation_ = UIImageOrientationLeft;
isFirstAssetPortrait_ = YES;
}
if (firstTransform.a == 1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == 1.0) {
firstAssetOrientation_ = UIImageOrientationUp;
}
if (firstTransform.a == -1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == -1.0) {
firstAssetOrientation_ = UIImageOrientationDown;
}
// [firstlayerInstruction setTransform:firstAssetTrack.preferredTransform atTime:kCMTimeZero];
// [firstlayerInstruction setCropRectangle:self.view.bounds atTime:kCMTimeZero];
CGFloat scale = [self getScaleFromAsset:firstAssetTrack];
firstTransform = CGAffineTransformScale(firstTransform, scale, scale);
[firstlayerInstruction setTransform:firstTransform atTime:kCMTimeZero];
//2.4 - Add instructions
mainInstruction.layerInstructions = [NSArray arrayWithObjects:firstlayerInstruction,nil];
AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1, 30);
// CGSize videoSize = firstAssetTrack.naturalSize;
CGSize videoSize = self.view.bounds.size;
BOOL isPortrait_ = [self isVideoPortrait:firstAsset];
if(isPortrait_) {
videoSize = CGSizeMake(videoSize.height, videoSize.width);
}
NSLog(@"%@", NSStringFromCGSize(videoSize));
mainCompositionInst.renderSize = videoSize;
//3 - Audio track
AVMutableCompositionTrack *AudioTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio
preferredTrackID:kCMPersistentTrackID_Invalid];
[AudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, firstAsset.duration)
ofTrack:[[firstAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil];
//4 - Get path
NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"cutoutput.mov"];
NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath];
NSFileManager *manager = [[NSFileManager alloc] init];
if ([manager fileExistsAtPath:outputPath])
{
[manager removeItemAtPath:outputPath error:nil];
}
//5 - Create exporter
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL=outputURL;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
exporter.videoComposition = mainCompositionInst;
[exporter exportAsynchronouslyWithCompletionHandler:^{
switch ([exporter status])
{
case AVAssetExportSessionStatusFailed:
NSLog(@"Export failed: %@ : %@", [[exporter error] localizedDescription], [exporter error]);
completionBlock(nil);
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Export canceled");
completionBlock(nil);
break;
default: {
NSURL *outputURL = exporter.outputURL;
dispatch_async(dispatch_get_main_queue(), ^{
completionBlock(outputURL);
});
break;
}
}
}];
}
J'ai regardé le code précédemment. Même la réponse des commentaires disent que c'est incomplet.
OK, désolé à ce sujet. Vous pourriez montrer votre code...
Code ajouté. Je me demandais si je devrais peut-être utiliser
AVCaptureVideoDataOutput
au lieu de cela, et de la culture que les images viennent. La valeur par défaut d'iOS app appareil photo enregistre un peu ce qui se passe sur l'écran, de sorte qu'il doit être possible. J'ai l'impression que je suis absent quelque chose de simple.Bonne utilisation de la bounty. J'allais le suggérer.
OriginalL'auteur Darren | 2014-01-12
Vous devez vous connecter pour publier un commentaire.
Voici mon interprétation de votre question: Vous êtes à la capture de la vidéo sur un appareil doté d'un écran de format 4:3, et donc, votre
AVCaptureVideoPreviewLayer
est de 4:3, mais l'entrée vidéo de l'appareil de capture vidéo en 16:9 de sorte que la vidéo est "plus grand" que vu dans l'aperçu.Si vous êtes simplement à la recherche pour recadrer les pixels supplémentaires n'est pas pris par l'aperçu, puis vérifier cette http://www.netwalk.be/article/record-square-video-ios. Cet article montre comment recadrer la vidéo dans un carré. Cependant, vous aurez seulement besoin d'un peu de modifications à la récolte de 4:3. J'ai fait et testé, voici les modifications que j'ai apportées:
Une fois que vous avez la
AVAssetTrack
pour la vidéo, vous aurez besoin de calculer une nouvelle hauteur.Ensuite modifier ces deux lignes, à l'aide de newHeight.
Donc ce que nous avons fait ici est de définir la renderSize à un ratio de 4:3 - la dimension exacte sont fondées sur le dispositif d'entrée. Nous utilisons ensuite un
CGAffineTransform
traduire la vidéo de position de façon à ce que nous avons vu dans leAVCaptureVideoPreviewLayer
est ce qui est rendu à notre fichier.Edit: Si vous voulez mettre tout cela ensemble et le recadrage d'une vidéo en se basant sur l'écran de l'appareil ratio (3:2, 4:3, 16:9) et de prendre la vidéo de l'orientation dans l'esprit, nous avons besoin d'ajouter quelques choses.
D'abord voici le modifié le code de l'échantillon avec un peu de critique des altérations:
Ce que nous avons ajouté ici est un appel à la nouvelle taille de rendu de la vidéo basée sur les cultures ses dimensions pour le ratio de l'écran. Une fois que nous avons des cultures de la taille vers le bas, nous avons besoin de traduire la position de recadrer la vidéo. Afin de nous emparer de son orientation pour le déplacer dans la bonne direction. Cela permettra de résoudre la question, nous l'avons vu avec
UIInterfaceOrientationLandscapeLeft
. EnfinCGAffineTransform t2, t3
miroir de la vidéo à l'horizontale.Et voici les deux nouvelles méthodes qui font cela se produise:
Ces sont assez directe. La seule chose à noter est que, dans le
getComplimentSize:
méthode que nous avons à régler manuellement le ratio de 16:9 depuis le iPhone5+ résolution est mathématiquement timide de 16:9.J'ai élargi ma réponse originale à cette question pour inclure d'autres de l'écran de ratios et d'orientation.
Ajouter n'oubliez pas de mettre à jour ce:
[transformer setTransform:t2 atTime:kCMTimeZero];
Malheureusement, je ne suis pas assez familier avec les transformations de proposer une solution rapide. J'ai essayé un peu les choses, mais ils n'ont pas résolu le problème. Ma conjecture est que si l'on applique la CGAffineTransformTranslate et faire pivoter la vidéo, la position suivante et les changements d'échelle sont touchés par le nouveau point d'ancrage/matrice. Essayez de fausser un peu avec elle ou de poser une question originale. Je suis sûr que quelqu'un peut offrir une meilleure compréhension des transformations - je tourne un peu dans le noir avec mes suppositions.
Mise à jour de ma réponse. Écrasé la question que vous avez vu dans
UIInterfaceOrientationLandscapeLeft
. Et ajouté un couple se transforme en miroir horizontale. Cela devrait le faire 🙂OriginalL'auteur
AVCaptureVideoDataOutput est un béton sous-classe de AVCaptureOutput à utiliser pour traiter les trames non compressées à partir de la vidéo en cours d'acquisition, ou l'accès à des images compressées.
Une instance de AVCaptureVideoDataOutput produit des images vidéo, vous pouvez traiter à l'aide d'autres médias Api. Vous pouvez accéder aux images avec le
captureOutput:didOutputSampleBuffer:fromConnection:
méthode du délégué.Configuration d'une Session
Vous utilisez un preset sur la session pour spécifier la qualité de l'image et de la résolution que vous voulez. Une présélection est une constante qui identifie un certain nombre de configurations possibles; dans certains cas, la configuration est spécifique à l'appareil:
https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/Articles/04_MediaCapture.html
les valeurs réelles de ces presets représentent pour les appareils divers, voir “Le fait d'enregistrer un Fichier vidéo” et “la Capture d'Images.”
Si vous souhaitez définir une taille spécifique de configuration, vous devez vérifier si il est pris en charge avant de le définir:
OriginalL'auteur