如何在 iOS 中检测视频文件是纵向录制还是横向录制

发布于 2024-10-10 13:18:24 字数 1363 浏览 0 评论 0原文

我正在使用 AlAssetsGroup enumerateAssetsAtIndexes 列出照片(相机)应用程序中的资源。对于给定的视频资源,我想确定它是以纵向模式还是横向模式拍摄的。

在下面的代码中,资产是一个 AlAsset,我已经测试过它是否是一个视频资产 [asset valueForProperty:ALAssetPropertyType]AlAssetTypeVideo ,那么:

int orientation = [[asset valueForProperty:ALAssetPropertyOrientation] intValue];

在这种情况下,orientation 始终为 0,即 ALAssetOrientationUp。也许这是可以预料的,所有视频都是直立的,但是纵向视频在 MPEG-4 中表示为横向视频旋转 90 度(即所有视频实际上都是横向的,如果您不这样做,请尝试 Mac 上的 MediaInfo 应用程序)相信我)。

文件中的哪个位置和/或如何访问告诉我它实际上是在纵向握住手机时录制的信息?

我也尝试过这个,给定资产的 url:

AVURLAsset *avAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
CGSize size = [avAsset naturalSize];
NSLog(@"size.width = %f size.height = %f", size.width, size.height);
CGAffineTransform txf = [avAsset 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);

它总是产生宽度 >对于 iPhone 4,宽度 = 1280 高度 = 720,变换 a 和 d 值为 1.0,其他值为 0.0,无论捕获方向如何。

我已经使用 Mac 上的 MediaInfo 应用程序查看了元数据,我已经完成了 Hexdump,到目前为止还没有发现横向和纵向视频之间有任何区别。但 QuickTime 可以识别并垂直显示纵向视频,如果您在播放时横向握住手机,手机会通过旋转纵向视频来识别,如果纵向握住手机则可以正确显示。

顺便说一句,我无法使用 ffmpeg(无法忍受许可证限制)。有 iPhone SDK 本机方法来执行此操作吗?

I am using AlAssetsGroup enumerateAssetsAtIndexes to list the assets in the Photos (Camera) app. For a given video asset I want to determine whether it was shot in portrait or landscape mode.

In the following code, asset is an AlAsset and I have tested to see if it is a video asset [asset valueForProperty:ALAssetPropertyType] is AlAssetTypeVideo, then:

int orientation = [[asset valueForProperty:ALAssetPropertyOrientation] intValue];

In this case orientation is always 0 which is ALAssetOrientationUp. Maybe this is to be expected, all videos are up right, but a portrait video is represented in MPEG-4 as a landscape video turned 90 degrees (i.e. all videos are actually landscape, try the MediaInfo app on the mac if you don't believe me).

Where within the file and/or how do I access the information that tells me it was actually recorded while holding the phone in portrait orientation?

I have also tried this, given the url of the asset:

AVURLAsset *avAsset = [[AVURLAsset alloc] initWithURL:url options:nil];
CGSize size = [avAsset naturalSize];
NSLog(@"size.width = %f size.height = %f", size.width, size.height);
CGAffineTransform txf = [avAsset 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);

Which always yields a width > height so for iPhone 4, width=1280 height=720 and the transform a and d values are 1.0, the others are 0.0, regardless of the capture orientation.

I have looked at the meta data using MediaInfo app on the Mac, I have done a Hexdump and so far have not found any difference between a landscape and portrait video. But QuickTime knows and displays portrait videos vertically, and the phone knows by rotating a portrait video if you are holding the phone in landscape orientation on playback and correctly displaying it if holding it in portrait.

BTW I can't use ffmpeg (can't live with the license restrictions). Is there an iPhone SDK native way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

祁梦 2024-10-17 13:18:24

根据前面的答案,您可以使用以下方法来确定视频方向:

+ (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;
}

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;
}
心如荒岛 2024-10-17 13:18:24

苹果开发论坛上的有人建议对视频轨道进行转换,这样就可以了。您可以从下面的日志中看到,对于这些方向,结果是有意义的,我们的网络开发人员现在能够旋转各种视频,以便它们全部匹配并将它们合成为一个视频。

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);

使用普通摄像头记录 4 个 iPhone 4 视频:
(1) 横向摄像头位于右侧(主页按钮位于左侧)
(2) 风景左
(3) 肖像颠倒
(4) 纵向右上(主页按钮在底部)

  1. 2011-01-07 20:07:30.024 MySecretApp[1442:307] size.width =
    1280.000000 尺寸.高度 = 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 尺寸.高度 = 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 尺寸.高度 = 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 尺寸.高度 = 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

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

你又不是我 2024-10-17 13:18:24

在我的用例中,我只需要知道视频是否为纵向(横向)。

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)

这已经通过前置和后置摄像头针对所有方向可能性进行了测试。

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.

赠意 2024-10-17 13:18:24

AVAssetImageGenerator

如果您使用 AVAssetImageGeneratorAVAssets 生成图像,您只需设置 AVAssetImageGenerator.appliesPreferredTrackTransform 属性即可设置为 true ,它将以正确的方向从您的资产返回图像! :)


Swift 3

但要扩展 @onmyway133 在 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
        }
    }
}

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
        }
    }
}
剑心龙吟 2024-10-17 13:18:24

如果您不想仅使用 AVFoundation Framework 来获取录制视频的方向,请尝试一下

-(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];

}

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];

}
唠甜嗑 2024-10-17 13:18:24

虽然这里的一些答案是正确的,但它们并不全面。例如,您可能还需要知道使用哪个相机设备来应用正确的变换。我创建了一个要点来完成这件事;提取 UIInterfaceOrientation 和 AVCaptureDevicePosition。

提取 AVAsset 方向和相机位置

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

时光是把杀猪刀 2024-10-17 13:18:24
- (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;
}
- (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;
}
‖放下 2024-10-17 13:18:24

在 Swift 2 UIInterfaceOrientation 中扩展 George 的答案

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
    }
  }
}

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
    }
  }
}
负佳期 2024-10-17 13:18:24

在 swift 5 中试试这个

func checkVideoOrientation(url: URL) {
    let asset = AVAsset(url: url)
    let track = asset.tracks(withMediaType: .video).first
    let size = track?.naturalSize ?? .zero
    let transform = track?.preferredTransform ?? .identity
    
    if size.width == transform.tx && size.height == transform.ty {
        self.postVideoOrientation = false //Portrait
    } else if size.width == transform.ty && size.height == transform.tx {
        self.postVideoOrientation = true //"Landscape"
    } else {
        self.postVideoOrientation = false //"Unknown"
    }
    
}

Try this in swift 5

func checkVideoOrientation(url: URL) {
    let asset = AVAsset(url: url)
    let track = asset.tracks(withMediaType: .video).first
    let size = track?.naturalSize ?? .zero
    let transform = track?.preferredTransform ?? .identity
    
    if size.width == transform.tx && size.height == transform.ty {
        self.postVideoOrientation = false //Portrait
    } else if size.width == transform.ty && size.height == transform.tx {
        self.postVideoOrientation = true //"Landscape"
    } else {
        self.postVideoOrientation = false //"Unknown"
    }
    
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文