¿Cómo configuro la orientación de un video generado por cuadro mediante AVFoundation?

Estoy escribiendo una aplicación para iPhone que toma video de la camera, lo ejecuta a través de un código de sombreador OpenGL y luego escribe la salida en un file de video usando AVFoundation . La aplicación se ejecuta en orientación horizontal (cualquiera) y, por lo tanto, todo el video grabado debe ser horizontal.

El código actual que uso antes de comenzar a grabar para get el video de la manera correcta es:

 [[self videoWriterInput] setTransform:CGAffineTransformScale(CGAffineTransformMakeRotation(M_PI), -1.0, 1.0)]; 

donde videoWriterInput es una instancia de AVAssetWriterInput y el objective es compensar el modo horizontal y la orientación reverencial de OpenGL.

Esto produce un video que al downloadse y reproducirse en el reproductor Quicktime se reproduce correctamente. Sin embargo, si agrego el video grabado a la biblioteca de fotos del iPhone, la miniatura se muestra correctamente pero el video reproduce girado 90 grados si el teléfono se mantiene en el paisaje. Si el teléfono está retenido, el video se reproduce correctamente pero se recorta horizontalmente para ajustarse a las dimensiones del retrato.

De acuerdo con esta nota tecnológica de Apple, la salida de captura para AVCaptureVideoDataOutput , que uso para procesar los frameworks de video, no es compatible con la configuration de la orientación del video.

¿Alguien ha registrado con éxito el video generado por el paisaje que se puede agregar a la biblioteca de iPhone y se reproduce correctamente en el paisaje y, de ser así, cómo?

Tu publicación me abrió los ojos acerca de cómo la aplicación Apples Videos reproduce videos. Grabé varios elementos con mi aplicación con el dispositivo en las cuatro orientaciones. Todos reproducen correctamente orientados. Acabo de notar que la aplicación Videos no admite la rotation como el reproductor en la aplicación Fotos Album. La aplicación Videos espera que mantengas el dispositivo (al less mi iPod touch) en el paisaje. Hice algunas grabaciones de retrato, las agregué a iTunes, y todas, incluida la creada con la aplicación de camera de Apple, no rotaron al girar el dispositivo a la orientación vertical.

De todas forms…

Mi aplicación es una aplicación de lapso de time que no realiza ningún procesamiento adicional en los frameworks como lo está haciendo, por lo que YMMV en lo siguiente. Tengo mi aplicación configurada para que no gire la window a medida que gira el dispositivo. De esta manera siempre estoy tratando con una orientación del dispositivo. Utilizo AVFoundation para tomar cada fotogtwig Nth de la transmisión de video y escribirlo.

Mientras preparo la grabación, hago lo siguiente.

 inputWriterBuffer = [AVAssetWriterInput assetWriterInputWithMediaType: AVMediaTypeVideo outputSettings: outputSettings]; // I call this explicitly before recording starts. Video plays back the right way up. [self detectOrientation]; inputWriterBuffer.transform = playbackTransform; 

That detectOrientation llama al siguiente método. He networkingucido el código real para mayor claridad aquí. En mi aplicación también roté algunos botones, así que nota que no obtienen la misma transformación. Lo que debo prestar atención es cómo configuro el ivory playbackTransform.

 -(void) detectOrientation { CGAffineTransform buttonTransform; switch ([[UIDevice currentDevice] orientation]) { case UIDeviceOrientationUnknown: NULL; case UIDeviceOrientationFaceUp: NULL; case UIDeviceOrientationFaceDown: NULL; break; case UIDeviceOrientationPortrait: [UIButton beginAnimations: @"myButtonTwist" context: nil]; [UIButton setAnimationDuration: 0.25]; buttonTransform = CGAffineTransformMakeRotation( ( 0 * M_PI ) / 180 ); recordingStarStop.transform = buttonTransform; [UIButton commitAnimations]; playbackTransform = CGAffineTransformMakeRotation( ( 90 * M_PI ) / 180 ); break; case UIDeviceOrientationLandscapeLeft: [UIButton beginAnimations: @"myButtonTwist" context: nil]; [UIButton setAnimationDuration: 0.25]; buttonTransform = CGAffineTransformMakeRotation( ( 90 * M_PI ) / 180 ); recordingStarStop.transform = buttonTransform; [UIButton commitAnimations]; // Transform depends on which camera is supplying video if (theProject.backCamera == YES) playbackTransform = CGAffineTransformMakeRotation( 0 / 180 ); else playbackTransform = CGAffineTransformMakeRotation( ( -180 * M_PI ) / 180 ); break; case UIDeviceOrientationLandscapeRight: [UIButton beginAnimations: @"myButtonTwist" context: nil]; [UIButton setAnimationDuration: 0.25]; buttonTransform = CGAffineTransformMakeRotation( ( -90 * M_PI ) / 180 ); recordingStarStop.transform = buttonTransform; [UIButton commitAnimations]; // Transform depends on which camera is supplying video if (theProject.backCamera == YES) playbackTransform = CGAffineTransformMakeRotation( ( -180 * M_PI ) / 180 ); else playbackTransform = CGAffineTransformMakeRotation( 0 / 180 ); break; case UIDeviceOrientationPortraitUpsideDown: [UIButton beginAnimations: @"myButtonTwist" context: nil]; [UIButton setAnimationDuration: 0.25]; buttonTransform = CGAffineTransformMakeRotation( ( 180 * M_PI ) / 180 ); recordingStarStop.transform = buttonTransform; [UIButton commitAnimations]; playbackTransform = CGAffineTransformMakeRotation( ( -90 * M_PI ) / 180 ); break; default: playbackTransform = CGAffineTransformMakeRotation( 0 / 180 ); // Use the default, although there are likely other issues if we get here. break; } } 

Como nota al margen, ya que quiero que se invoque el método cuando el dispositivo se gira y he desactivado la rotation automática, tengo lo siguiente en mi método viewDidLoad.

 [[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(detectOrientation) name:@"UIDeviceOrientationDidChangeNotification" object:nil]; 

Esa es una sugerencia que encontré en este SOF Q & A.

Mucho más simple …

En tu shader de vértice:

flotación preferente uniforme Rotacion; . . . Mat4 rotationMatrix = mat4 (cos (Variación preferida), -sin (Variación preferida), 0.0, 0.0, sin (Variación preferida), cos (Variación preferida), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0). ;

 /* 90-degrees mat4 rotationMatrix = mat4( cos(prefernetworkingRotation), -sin(prefernetworkingRotation), (1.0 - cos(prefernetworkingRotation)) - sin(prefernetworkingRotation), 0.0, -sin(prefernetworkingRotation), cos(prefernetworkingRotation), 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0); 

En la vista o controller de vista que llama al sombreador:

if ([videoTrack statusOfValueForKey: @ "prefernetworkingTransform" error: nil] == AVKeyValueStatusLoaded) {CGAffineTransform prefernetworkingTransform = [videoTrack prefernetworkingTransform]; self.playerView.prefernetworkingRotation = -1 * atan2 (prefernetworkingTransform.b, prefernetworkingTransform.a);

…y así…