AVAsset Orientation/Rotation issue
Asked Answered
B

2

9

Tried to use Ray great tutorial to fix the orientation issue.

left - how the video should look(portrait), right - unwanted rotated result

enter image description here

Code used

   func setUpVideoNew()
    {

        let originalVideoTrack = asset.tracksWithMediaType(AVMediaTypeVideo)[0]
        let composition = AVMutableComposition()
        let videoTrack = composition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: 1)
        let timeRange = originalVideoTrack.timeRange
        do {
            try videoTrack.insertTimeRange(timeRange, ofTrack: originalVideoTrack, atTime: kCMTimeZero)
        } catch {

        }
        let mainInstruction = AVMutableVideoCompositionInstruction()
        mainInstruction.timeRange = timeRange

        let firstlayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
        let firstAssetTrack = originalVideoTrack


        //MARK - Fix Rotation
        var firstAssetOrientation_ = UIImageOrientation.Up

        var isFirstAssetPortrait_ = false

        var firstTransform = videoTrack.preferredTransform;
        if firstTransform.a == 0 && firstTransform.b == 1.0 && firstTransform.c == -1.0 && firstTransform.d == 0 {
            firstAssetOrientation_ = UIImageOrientation.Right;
            isFirstAssetPortrait_ = true;
        }
        if (firstTransform.a == 0 && firstTransform.b == -1.0 && firstTransform.c == 1.0 && firstTransform.d == 0) {
            firstAssetOrientation_ =  UIImageOrientation.Left;
            isFirstAssetPortrait_ = true;
        }
        if (firstTransform.a == 1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == 1.0) {
            firstAssetOrientation_ =  UIImageOrientation.Up;
        }
        if (firstTransform.a == -1.0 && firstTransform.b == 0 && firstTransform.c == 0 && firstTransform.d == -1.0) {
            firstAssetOrientation_ = UIImageOrientation.Down;
        }

        firstlayerInstruction.setTransform(asset.preferredTransform, atTime: kCMTimeZero)
        mainInstruction.layerInstructions = [firstlayerInstruction]


        let videoComposition = AVMutableVideoComposition()
        videoComposition.frameDuration = CMTimeMake(1, 30)
        videoComposition.instructions = [mainInstruction]

        var naturalSizeFirst = CGSize()

        if(isFirstAssetPortrait_){
            naturalSizeFirst = CGSizeMake(videoTrack.naturalSize.height, videoTrack.naturalSize.width);
        } else {
            naturalSizeFirst = videoTrack.naturalSize;
        }
        videoComposition.renderSize = naturalSizeFirst
        let playerItem = AVPlayerItem(asset: composition)
        playerItem.videoComposition = videoComposition
        player = AVPlayer(playerItem: playerItem)
        let playerLayer = AVPlayerLayer(player: player)
        print(videoPreview.frame)
        print(videoPreview.bounds)
        playerLayer.frame = self.videoPreview.bounds

        player.play()
        self.videoPreview.layer.addSublayer(playerLayer)



    }

Any suggestions?

Boarhound answered 24/2, 2016 at 14:51 Comment(1)
I have added details for what you need to my question. It would be nice if you could elaborate whether or not you want your other views to rotate along with the video, as well as elaborating the current state of rotation in the other views (i.e. does the rest of your app rotate?).Sutra
D
2

You should register for a notification for when the status bar changes orientation, like so:

    NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("statusBarOrientationChange:"), name: UIApplicationDidChangeStatusBarOrientationNotification, object: nil)

After that, a switch statement for this would read like so, for editing the dimensions of your AVLayer:

    switch (UIApplication.sharedApplication().statusBarOrientation){
        case .Unknown :
        case .PortraitUpsideDown :
        case .Portrait
        case .LandscapeLeft :
        case .LandscapeRight :
    }

When you get to the right orientation, you will need to apply a CGAffineTransform like so:

asset.transform = CGAffineTransformMake(M_PI * (180) / 180.0)

Hope this is helpful!

Durazzo answered 4/3, 2016 at 17:58 Comment(4)
Hey dokun. My app is portrait only. The video is being rotated regardless to the screen orientation :\Boarhound
I see. Have you tried registering for UIDevice orientation notifications? UIDevice checks orientation regardless of screen settings.Durazzo
Apparently the problem is with the renderSize and the transform.. Tho i still haven't figured it outBoarhound
Videos can be recored in any orientation so when the video is recorded you expected it to be "UP" correct orientation but if you are 'holding you iPhone incorrectly according to Apple' the orientation may be "RIGHT". The user recording the video controls the orientation, your best bet is if the video is not UP then rotate it yourself, I can provide example code if needed.Hibernate
S
1

If the issue is with rotating the iPhone in the entire app: Make sure that your app has the correct supported interface orientations in your Info.plist file. Pop into Info.plist, and check the bottom two arrays (Supported Interface Orientations and Supported Interface Orientations (iPad). Ensure they both have all four orientations added. If they do not, mouse over Supported Interface Orientations, press the drop-down arrow, and press the + sign that appears over "Supported Interface Orientations" and add any missing orientations. Do the same to the ""Supported Interface Orientations (iPad)" array.

adding supported interface orientations in Info.Plist

If this does not work, it could be an issue with just the video. Check out the question and accepted answer here: How to fix video orientation issue in iOS. And here's a great way to convert objective-c to swift: https://objectivec2swift.com/#/converter/code.

If your app does not rotate, and you want the video only to rotate:

Put this in your views you would like to lock in portrait mode:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
 return UIInterfaceOrientationMask.Portrait
}

Then, in your video view:

override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
 return UIInterfaceOrientationMask.All
}

For good measure - you may want this on both views as well:

override func shouldAutorotate() -> Bool {
 return true
}

Source: how to lock portrait orientation for only main view using swift.

Sutra answered 28/2, 2016 at 16:54 Comment(4)
Tho i don't want my app to be able to rotate. It's just the video preview who i need to show the video with the preffer transformBoarhound
@RoiMulia Let me know if this helps!Sutra
@RoiMulia I added even more; with this you should be able to set only the AVAsset's view to rotate, while not letting the rest of the app rotate.Sutra
Hey John.Sorry for not replying, wasn't around. UNFortunately it didn't helped.. :\Boarhound

© 2022 - 2024 — McMap. All rights reserved.