objective guide documentacion developer apple objective-c cocoa video qtkit

objective-c - guide - ios frameworks



QTKit: unir dos videos con diferente ancho y alto (1)

Acabo de crear una aplicación simple que utiliza QTKit para fusionar dos videos juntos

Aquí está el problema:

Acabo de descubrir que si trato de fusionar dos videos con ancho y alto diferentes, la salida es un video cuyo alto y ancho es el mismo del video grande pero contiene el pequeño con bordes negros y anchos.

Pregunta:

¿Cómo puedo fusionar dos videos y obtener un video de salida con un formato correcto (ancho / alto)?

Ejemplo para comprender mejor lo que necesito:

Tengo dos videos:

Video 1 = 1920 x 1280 VIdeo 2 = 1280 x 960

Lo que quiero: un video en 1920 x 1280 (Necesito subir de escala y recortar el pequeño)

Código:

-(void)voidMethodToCombine { NSError *err = nil; QTMovie *myCombinedMovie = [[QTMovie alloc] initToWritableData:[NSMutableData data] error:&err]; if (err) { NSRunAlertPanel(@"Errore nella creazione del video",[err localizedDescription], nil, @"Chiudi", nil, nil); return; return; } // Create the File Open Dialog class. NSSavePanel *savePanel = [NSSavePanel savePanel]; //Dove salvo il video ? if ([savePanel runModal])//Se premo ok { [indicatore setUsesThreadedAnimation:YES]; [indicatore startAnimation:self]; NSURL *saveURL = savePanel.URL; NSString *savePath = [saveURL path]; //Prelevo i 2 percorsi e gli inserisco negli array NSString *video1 = [URLVideo1 stringValue]; NSString *video2 = [URLVideo2 stringValue]; NSURL *theURLvideo1 = [NSURL fileURLWithPath:video1]; NSURL *theURLvideo2 = [NSURL fileURLWithPath:video2]; if((theURLvideo1) && (theURLvideo2)) { NSArray *myMovieURLs = [NSArray arrayWithObjects:theURLvideo1,theURLvideo2, nil]; for (NSURL *url in myMovieURLs) { QTMovie *theMovie = [QTMovie movieWithURL:url error:&err]; if (err){ NSRunAlertPanel(@"Errore durante il caricamento di uno dei film",[err localizedDescription], nil, @"Chiudi", nil, nil); return; } QTTimeRange timeRange = QTMakeTimeRange(QTZeroTime, [theMovie duration]); QTTime insertionTime = [myCombinedMovie duration]; [myCombinedMovie insertSegmentOfMovie:theMovie timeRange:timeRange atTime:insertionTime]; } NSDictionary *writeAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], QTMovieFlatten, nil]; //Pannello di path salvataggio bool success = [myCombinedMovie writeToFile:savePath withAttributes:writeAttributes error:&err]; [indicatore stopAnimation:self]; NSBeep(); NSString *dove = [[NSString alloc] initWithFormat:@"Video esportato in:/n%@",savePath]; NSRunAlertPanel(@"Esportazione avvenuta con successo!", dove, @"Ok", nil, nil); if (!success) { NSRunAlertPanel(@"Errore durante il salvataggio del video.",[err localizedDescription], nil, @"Chiudi", nil, nil); return; return; } } //Se non esiste alcun percorso else { NSRunAlertPanel(@"Impossibile selezionare i file.", @"Controlla di aver specificato un percorso.", @"Chiudi", nil, nil); }


Para hacer esto, es más fácil usar frameworks de AVFoundation en lugar de QTKit, ya que editar / manipular el video es mucho más fácil (imo), aunque parece ser un poco más lento y el código puede ser menos compacto.

Sugiero comenzar leyendo la guía de programación AVFoundation en https://developer.apple.com/library/mac/documentation/AudioVideo/Conceptual/AVFoundationPG/AVFoundationPG.pdf

Pero aquí hay un ejemplo básico para comenzar. Antes de comenzar, asegúrese de haber vinculado con los frameworks de AVFoundation y CoreMedia.

En su encabezado, además de otros métodos o ivars, puede agregar un AVAssetExportSession *exporter y NSTimer *timer , así como un método - (void) monitorProgress; .

Su archivo de implementación incluiría los siguientes métodos (suponiendo que está activando el método con un IBAction llamado doIt). Y no se olvide de #import <AVFoundation/ AVFoundation.h> y #import <CoreMedia/CoreMedia.h> :

- (IBAction)doIt:(id)sender { // Initial array of movie URLs NSArray *myMovieURLs = [NSArray arrayWithObjects:[NSURL fileURLWithPath:@"/path/to/first.mov"], [NSURL fileURLWithPath:@"/path/to/second.mov"], nil]; // Create the composition & A/V tracks AVMutableComposition *comp = [AVMutableComposition composition]; AVMutableCompositionTrack *compositionVideoTrack = [comp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; AVMutableCompositionTrack *compositionAudioTrack = [comp addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; // A reference for insertion start time CMTime startTime = kCMTimeZero; for (int i=0; i< [myMovieURLs count]; i++){ // Get asset NSURL *movieURL = [myMovieURLs objectAtIndex:i]; AVURLAsset *asset = [AVURLAsset URLAssetWithURL:movieURL options:nil]; // Get video and audio tracks (assuming video exists - test for audio as an empty track will crash the program!) and insert in composition tracks AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]; bool success = [compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:videoTrack atTime:startTime error:nil]; if ([[asset tracksWithMediaType:AVMediaTypeAudio]count]){ AVAssetTrack *audioTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0]; success = [compositionAudioTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:audioTrack atTime:startTime error:nil]; } // increment the start time to the end of this first video startTime = CMTimeAdd(startTime, [asset duration]); } //Set the output URL NSURL *outputURL = [NSURL fileURLWithPath:@"/path/to/output.mov"]; /* Create the exporter. Note the preset type is up to you to choose. If you wanted, you could check the asset''s size (with [asset naturalSize]) or other values above and use that to base your preset on. Use exportPresetsCompatibleWithAsset: to get a list of presets that are compatible with a specific asset. */ NSLog(@"Compat presets you could use: %@", [AVAssetExportSession exportPresetsCompatibleWithAsset:comp]); exporter = [[AVAssetExportSession alloc] initWithAsset:comp presetName:AVAssetExportPreset640x480]; [exporter setOutputURL:outputURL]; [exporter setOutputFileType:AVFileTypeQuickTimeMovie]; [exporter exportAsynchronouslyWithCompletionHandler:^(void){ switch ([exporter status]) { case AVAssetExportSessionStatusFailed: NSLog(@"Export failed: %@", [[exporter error] localizedDescription]); break; case AVAssetExportSessionStatusCancelled: NSLog(@"Export canceled"); break; default: break; } }]; // This is just a simple timer that will call a method to log the progress timer=[NSTimer scheduledTimerWithTimeInterval:5 target:self selector:@selector(monitorProgress) userInfo:nil repeats:YES]; } -(void)monitorProgress{ if ([exporter progress] == 1.0){ [timer invalidate]; } NSLog(@"Progress: %f",[exporter progress]* 100);

}