How to detect if a video file was recorded in portrait orientation, or landscape in iOS

会有一股神秘感。 提交于 2019-11-26 19:47:35

Based on the previous answer, you can use the following to determine the video orientation:

+ (UIInterfaceOrientation)orientationForTrack:(AVAsset *)asset
{
    AVAssetTrack *videoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    CGSize size = [videoTrack naturalSize];
    CGAffineTransform txf = [videoTrack preferredTransform];

    if (size.width == txf.tx && size.height == txf.ty)
        return UIInterfaceOrientationLandscapeRight;
    else if (txf.tx == 0 && txf.ty == 0)
        return UIInterfaceOrientationLandscapeLeft;
    else if (txf.tx == 0 && txf.ty == size.width)
        return UIInterfaceOrientationPortraitUpsideDown;
    else
        return UIInterfaceOrientationPortrait;
}
George C.

Somebody on apple dev forums suggested getting the transform of the video track, this does the job. You can see from the logs below that for these orientations the results make sense and our web developer is now able to rotate a variety of vids so they all match and composite them into one video.

AVAssetTrack* videoTrack = [[avAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CGSize size = [videoTrack naturalSize];
NSLog(@"size.width = %f size.height = %f", size.width, size.height);
CGAffineTransform txf = [videoTrack preferredTransform];
NSLog(@"txf.a = %f txf.b = %f txf.c = %f txf.d = %f txf.tx = %f txf.ty = %f", txf.a, txf.b, txf.c, txf.d, txf.tx, txf.ty);

Logs using 4 iPhone 4 videos with the normal cam: (1) landscape cam on right side (home button on left) (2) landscape left (3) portrait upside-down (4) portrait up-right (home button at bottom)

  1. 2011-01-07 20:07:30.024 MySecretApp[1442:307] size.width = 1280.000000 size.height = 720.000000 2011-01-07 20:07:30.027 MySecretApp[1442:307] txf.a = -1.000000 txf.b = 0.000000 txf.c = 0.000000 txf.d = -1.000000 txf.tx = 1280.000000 txf.ty = 720.000000

  2. 2011-01-07 20:07:45.052 MySecretApp[1442:307] size.width = 1280.000000 size.height = 720.000000 2011-01-07 20:07:45.056 MySecretApp[1442:307] txf.a = 1.000000 txf.b = 0.000000 txf.c = 0.000000
    txf.d = 1.000000 txf.tx = 0.000000
    txf.ty = 0.000000

  3. 2011-01-07 20:07:53.763 MySecretApp[1442:307] size.width = 1280.000000 size.height = 720.000000 2011-01-07 20:07:53.766 MySecretApp[1442:307] txf.a = 0.000000 txf.b = -1.000000 txf.c = 1.000000
    txf.d = 0.000000 txf.tx = 0.000000 txf.ty = 1280.000000

  4. 2011-01-07 20:08:03.490 MySecretApp[1442:307] size.width = 1280.000000 size.height = 720.000000 2011-01-07 20:08:03.493 MySecretApp[1442:307] txf.a = 0.000000 txf.b = 1.000000 txf.c = -1.000000
    txf.d = 0.000000 txf.tx = 720.000000 txf.ty = 0.000000

AVAssetImageGenerator

If you are using AVAssetImageGenerator to generate images from AVAssets, you can simply set the .appliesPreferredTrackTransform property of AVAssetImageGenerator to true and it will return you images from your asset in the correct orientation! :)


Swift 3

But to extend on @onmyway133's answer in Swift 3:

import UIKit
import AVFoundation

extension AVAsset {


    var g_size: CGSize {
        return tracks(withMediaType: AVMediaTypeVideo).first?.naturalSize ?? .zero
    }


    var g_orientation: UIInterfaceOrientation {

        guard let transform = tracks(withMediaType: AVMediaTypeVideo).first?.preferredTransform else {
            return .portrait
        }

        switch (transform.tx, transform.ty) {
        case (0, 0):
            return .landscapeRight
        case (g_size.width, g_size.height):
            return .landscapeLeft
        case (0, g_size.width):
            return .portraitUpsideDown
        default:
            return .portrait
        }
    }
}

If you do not want to use AVFoundation Framework just to get the orientation of the recorded video then try it out

-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo: (NSDictionary *)info {

   NSString *orientation;

   NSString *videoPath = [[info objectForKey:UIImagePickerControllerMediaURL] path];
   NSURL *myURL = [[NSURL alloc] initFileURLWithPath:videoPath];

   self.movieController = [[MPMoviePlayerController alloc] initWithContentURL:myURL];       
   UIImage *thumbImage = [movieController thumbnailImageAtTime:1.0 timeOption:MPMovieTimeOptionNearestKeyFrame];

   float width = thumbImage.size.width;
   float height = thumbImage.size.height;

   if (width > height){

        orientation  = @"Landscape";

      }else{

         orientation  = @"Portrait";
      }

 [self dismissViewControllerAnimated:YES completion:nil];

}

While several of the answers here are correct, they are not comprehensive. For instance, you may also need to know which camera device was used to apply the proper transforms. I created a gist to do this very thing; extract the UIInterfaceOrientation and the AVCaptureDevicePosition.

Extract AVAsset Orientation and Camera Position

In my use case I only needed to know if a video is in portrait or not (landscape).

guard let videoTrack = AVAsset(url: videoURL).tracks(withMediaType: AVMediaTypeVideo).first else {
    return ...
}

let transformedVideoSize = videoTrack.naturalSize.applying(videoTrack.preferredTransform)
let videoIsPortrait = abs(transformedVideoSize.width) < abs(transformedVideoSize.height)

This has been tested with both front and rear cameras for all orientation possibilities.

evya
- (UIImageOrientation)getImageOrientationWithVideoOrientation:(UIInterfaceOrientation)videoOrientation {

    UIImageOrientation imageOrientation;
    switch (videoOrientation) {
    case UIInterfaceOrientationLandscapeLeft:
        imageOrientation = UIImageOrientationUp;
        break;
    case UIInterfaceOrientationLandscapeRight:
        imageOrientation = UIImageOrientationDown;
        break;
    case UIInterfaceOrientationPortrait:
        imageOrientation = UIImageOrientationRight;
        break;
    case UIInterfaceOrientationPortraitUpsideDown:
        imageOrientation = UIImageOrientationLeft;
        break;
    }
    return imageOrientation;
}

Extending on George's answer in Swift 2

UIInterfaceOrientation is the same with UIImageOrientation

extension AVAsset {

  var g_size: CGSize {
    return tracksWithMediaType(AVMediaTypeVideo).first?.naturalSize ?? .zero
  }

  var g_orientation: UIInterfaceOrientation {
    guard let transform = tracksWithMediaType(AVMediaTypeVideo).first?.preferredTransform else {
      return .Portrait
    }

    switch (transform.tx, transform.ty) {
    case (0, 0):
      return .LandscapeRight
    case (g_size.width, g_size.height):
      return .LandscapeLeft
    case (0, g_size.width):
      return .PortraitUpsideDown
    default:
      return .Portrait
    }
  }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!