I import a video from the iPhone library and I apply some effects to that video. The problem is that the video has a wrong orientation (landscape). How can I rotate the video to portrait mode?
Have you tried a transform on the AVPlayerLayer?
self.videoLayer = [AVPlayerLayer playerLayerWithPlayer:self.videoPlayer];
self.videoLayer.transform = CATransform3DMakeRotation(M_PI / 2.0f, 0, 0, 1);
Related
Question: why would an OpenGL scene render upside down in portrait mode but right-side up in landscape and visa-versa?
If I create a view matrix with UPx = 0, UPy = 0, UPz = 1 I get my viewport upside down in portrait mode and right-side up in landscape.
If I create a view matrix with UPx = 0, UPy = 0, UPz = -1 I get my viewport right-side up in portrait mode and upside down in landscape.
Should I be looking at other functions other than where I create my LookAt and Perspective matrices?
Got it - my FOVY angle was in degrees for Android - but GLKit for IOS requires radians. Dohhh.
I am merging multiple videos and I want to detect which ones are in portrait mode and rotate them in landscape so that all movies are in landscape mode... I have done everything and works perfectly except the actual rotate, I guess it's something with the center of the rotation or a composed rotation.
AVMutableVideoCompositionLayerInstruction *videoTrackLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack];
if([[AppDelegate sharedInstance] orientationForTrack:avAsset] == UIDeviceOrientationPortrait)
{
CGAffineTransform rotation = CGAffineTransformMakeRotation(M_PI/2);
//CGAffineTransform translateToCenter = CGAffineTransformMakeTranslation(640, 480);
//CGAffineTransform mixedTransform = CGAffineTransformConcat(rotation, translateToCenter);
[videoTrackLayerInstruction setTransform:rotation atTime:nextClipStartTime];
}
else if([[AppDelegate sharedInstance] orientationForTrack:avAsset] == UIDeviceOrientationPortraitUpsideDown)
{
CGAffineTransform rotation = CGAffineTransformMakeRotation(-M_PI/2);
[videoTrackLayerInstruction setTransform:rotation atTime:nextClipStartTime];
}
else if([[AppDelegate sharedInstance] orientationForTrack:avAsset] == UIDeviceOrientationLandscapeLeft)
{
CGAffineTransform rotation = CGAffineTransformMakeRotation(M_PI);
[videoTrackLayerInstruction setTransform:rotation atTime:nextClipStartTime];
}
else if([[AppDelegate sharedInstance] orientationForTrack:avAsset] == UIDeviceOrientationLandscapeRight)
{
[videoTrackLayerInstruction setTransform:CGAffineTransformIdentity atTime:nextClipStartTime];
}
How can I rotate them properly? I have tried multiple sources but nothing rotates them as they should. I am not interested in the 320 scale fit solution I want the video to keep as much resolution as possible before exporting using AVAssetExportSession.
A solution like this:
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotateTransform,320,0);
won't suit my needs as I have tried it. Do you have any ideas? Some help will be pretty much appreciated.
I use AVFoundation framework to get access to camera.
In the standard camera application, when the orientation changes only the rotation of the icons on the buttons.
But when I try to do something like, I have a problem related to the orientation changes animation. Preview view is rotated and the area behind it is black and has image jerks when turning.
Now I have this code:
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[CATransaction begin];
[CATransaction setValue:[NSNumber numberWithFloat:duration]
forKey:kCATransactionAnimationDuration];
if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft){
captureManager.previewLayer.transform=CATransform3DMakeRotation(M_PI/2, 0, 0, 1.0);
captureManager.previewLayer.frame = CGRectMake(0, 0, 480, 320);
} else if (toInterfaceOrientation==UIInterfaceOrientationPortrait){
captureManager.previewLayer.transform=CATransform3DMakeRotation(0, 0, 0, 1.0);
captureManager.previewLayer.frame = CGRectMake(0, 0, 320, 480);
} else if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight){
captureManager.previewLayer.transform=CATransform3DMakeRotation(M_PI+M_PI/2, 0, 0, 1.0);
captureManager.previewLayer.frame = CGRectMake(0, 0, 480, 320);
}
[CATransaction commit];
}
My idea it is use transform animation to deal with rotation animation but I get problems with glithes.
How can create camera preview view and solve problems with orientation change?
May be I must use other instrument to work with camera? Not AVFoundation framework?
I know that I can lock orientation and use accelerometer to deal with buttons icons. But the i get problems with some subviewcontrollers.
Sorry for terrible english.
You need to disable landscape orientation for your controller and update layout of icons etc by handling orientation change notifications. In this topic it is described right - How to handle autorotation in AVCaptureVideoPreviewLayer?
Nikita's answer works but requires extra code to handle the behavior of the UI elements when the device rotates. If that's too much trouble, another option (which I implemented and works) is to have 2 different UIWindow instances, one for the camera's preview layer and one for the UI elements to display on to. Notice that for this to work, the Window with the UI elements needs to have a transparent background.
I handle preview rotation change in the following way.
P.S all subviews have corresponding constraints set on storyboard so i only update the frame of videoPreviewLayer.
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
DispatchQueue.main.async {
self.videoPreviewLayer.frame = self.previewView.bounds
self.setRotation()
}
}
func setRotation() {
let deviceOrientation = UIDevice.current.orientation
switch deviceOrientation {
case .landscapeLeft:
videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeRight
break
case .landscapeRight:
videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.landscapeLeft
break
case .portrait:
videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portrait
break
case .portraitUpsideDown:
videoPreviewLayer?.connection?.videoOrientation = AVCaptureVideoOrientation.portraitUpsideDown
break
default:
break
}
}
I'm having a strange problem with UIWebView. I have to set it's orientation manually by rotating and sizing it. But after i've done that there are areas of the web content that aren't usable.
The iPad is in Portrait, but the web content is built in Landscape. So what I do is rotate the container by 90 degrees, set the bounds of the container, and resize the container and webframe.
Here's the code I use for this:
//rotate
CGRect contentRect;
CGAffineTransform transform;
transform = CGAffineTransformMakeRotation(-3.14159/2);
contentRect = CGRectMake(0,0,1024,768);
//set container bounds and transform
[_container setBounds:contentRect];
[_container setTransform:transform];
//set frame
containerFrame = CGRectMake(0,0,768,1024);
webViewFrame = CGRectMake(0,0,768,1024);
[_webview setFrame:webViewFrame];
[_container setFrame:containerFrame];
So after this rotation happens, the ipad is still in Portrait, the web content is displayed correctly on the screen (rotated). But content below 768 pixels is not interactable.
I'm not sure what's going on. This has stumped me for a while now. Any ideas?
I'm shooting video on an iPhone 4 with the front camera and combining the video with some other media assets. I'd like for this video to be portrait orientation - the default orientation for all video is landscape and in some circumstances, you have to manage this manually.
I'm using AVFoundation and specifically AVAssetExportSession with a AVMutableVideoComposition. Based on the WWDC videos, it's clear that I have to handle 'fixing' the orientation myself when I'm combining videos into a new composition.
So, I've created an AVMutableVideoCompositionLayerInstruction attached to my AVMutableVideoCompositionInstruction and I'm using the setTransform:atTime: method to set a transform designed to rotate the video:
AVMutableVideoCompositionLayerInstruction *passThroughLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
CGAffineTransform portraitRotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
[passThroughLayer setTransform:portraitRotationTransform atTime:kCMTimeZero];
The problem is that when I view the video that is exported, none of the actual contents are on the screen. If I reduce the rotation angle to something like 45 degrees, I can see part of the video on the screen - it's almost as if it's not rotating at the center point. I'm including images below to make it more clear what I'm talking about.
The natural size of the video is coming back as 480x360. I've tried changing that to 360x480 and it doesn't impact the core issue.
0 Degree Rotation:
45 Degree Rotation:
A 90 degree rotation is just all green.
Anyway, I'm hoping someone who has done this before can point me in the right direction. I can't find any docs on some of the more advanced topics in AVFoundation compositions and exports.
Building on what was answered so far. I found a very good way of debugging and finding out what went wrong with your transforms. Using the ramp methods available, you are able to animate the transforms making it easier to see what your transform is doing.
Most of the time I found myself having transforms that appeared to do nothing until I realised that just using preferredTransform property of a video track alone may result in the video feed moving out of the render screen.
AVMutableVideoCompositionLayerInstruction *videoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[videoLayerInstruction setTransformRampFromStartTransform:CGAffineTransformIdentity
toEndTransform:videoTrack.preferredTransform
timeRange:CMTimeRangeMake(projectClipStart, projectClipDuration)];
Eventually, I found that in some cases I needed to apply a translation to bring back the rotated video into the render screen.
CGAffineTransformConcat(videoTrack.preferredTransform, CGAffineTransformMakeTranslation(0, renderSize.height))
Note: Your translation values may be different.
Try this:
AVMutableVideoCompositionLayerInstruction *passThroughLayer = AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotateTransform,320,0);
[passThroughLayer setTransform:rotateTranslate atTime:kCMTimeZero];
Essentially the idea is to create a rotation and translation matrix. You rotate it to the proper orientation and then translate it into the view. I did not see any way to specify a center point while I was glancing through the API.
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;
Also may be relevant, but there is a bug in the preferredTransform being set when using the front-facing camera .. see here for example, where the guys in the SDAVAssetExportSession project have coded a work-around:
https://github.com/rs/SDAVAssetExportSession/pull/70
I found solution in Flutter plugin project.
- (CGAffineTransform)fixTransform:(AVAssetTrack*)videoTrack {
CGAffineTransform transform = videoTrack.preferredTransform;
if (transform.tx == 0 && transform.ty == 0) {
NSInteger rotationDegrees = (NSInteger)round(radiansToDegrees(atan2(transform.b, transform.a)));
NSLog(#"TX and TY are 0. Rotation: %ld. Natural width,height: %f, %f", (long)rotationDegrees,
videoTrack.naturalSize.width, videoTrack.naturalSize.height);
if (rotationDegrees == 90) {
NSLog(#"Setting transform tx");
transform.tx = videoTrack.naturalSize.height;
transform.ty = 0;
} else if (rotationDegrees == 270) {
NSLog(#"Setting transform ty");
transform.tx = 0;
transform.ty = videoTrack.naturalSize.width;
}
}
return transform;
}
// set layerInstruction
[firstVideoLayerInstruction setTransform:[self fixTransform:firstVideoAssetTrack] atTime:kCMTimeZero];
Flutter VideoPlayerPlugin