AVCaptureSession前置摄像头方向问题

4
我正在使用AVCaptureSession录制视频,并使用AVAssetWriterInput将视频写入文件。
我的问题在于视频方向。使用苹果的RosyWriter示例,我可以转换AVAssetWriterInput,使视频处于正确的方向。
- (CGFloat)angleOffsetFromPortraitOrientationToOrientation:(AVCaptureVideoOrientation)orientation
{
    CGFloat angle = 0.0;

    switch (orientation) {
        case AVCaptureVideoOrientationPortrait:
            angle = 0.0;
            break;
        case AVCaptureVideoOrientationPortraitUpsideDown:
            angle = M_PI;
            break;
        case AVCaptureVideoOrientationLandscapeRight:
            angle = -M_PI_2;
            break;
        case AVCaptureVideoOrientationLandscapeLeft:
            angle = M_PI_2;
            break;
        default:
            break;
    }

    return angle;
}

- (CGAffineTransform)transformFromCurrentVideoOrientationToOrientation:(AVCaptureVideoOrientation)orientation
{
    CGAffineTransform transform = CGAffineTransformIdentity;

    // Calculate offsets from an arbitrary reference orientation (portrait)
    CGFloat orientationAngleOffset = [self angleOffsetFromPortraitOrientationToOrientation:orientation];
    CGFloat videoOrientationAngleOffset = [self angleOffsetFromPortraitOrientationToOrientation:self.videoOrientation];

    // Find the difference in angle between the passed in orientation and the current video orientation
    CGFloat angleOffset = orientationAngleOffset - videoOrientationAngleOffset;
    transform = CGAffineTransformMakeRotation(angleOffset);

    return transform;
}  

问题出在前置摄像头方向上,使用这段代码在用户切换到前置摄像头后就无法正常工作。
似乎问题的根源是当我切换到前置摄像头时,AVCaptureConnection 会改变,从而导致前后摄像头的方向不同。
因此,也许我需要适应后置和前置摄像头的初始方向差异。
我并不想每次用户切换摄像头时都更改连接的方向,因为苹果称它会影响性能(而且看起来很糟糕), 所以苹果建议使用 AVAssetWriterInputtransform 属性来更改输出方向,但我不确定是否可以使用 transform,因为我想在录制时让用户切换摄像头,但我无法在开始录制后更改 transform(这会导致崩溃)...
你有什么解决方法吗?
2个回答

1

由于前置摄像头拍摄的图像是镜像的,因此您需要同样进行转换。实现这一点的函数只需使用-1缩放其中一个维度即可。尝试调整以下内容:

transform = CGAffineTransformConcat(CGAffineTransformMakeRotation(angle), CGAffineTransformMakeScale(1.0, -1.0));

注意可能的排列方式是(除了角度之外)X比例因子为-1,或者交换concat的顺序。
编辑:解释
AVCaptureSession会返回与您的设备不同方向的图像数据,自然而然地,我相信这将是横向左侧或右侧。如果您需要根据设备的持握方式使视频具有正确的方向,则需要对其应用一些变换,大多数情况下仅需应用一些旋转即可。然而,前置摄像头是一个特殊情况,因为它在您仍在接收非镜像帧时模拟镜像。结果,您的视频似乎上下颠倒或左右翻转,或者根据您应用的旋转而产生所有其他组合,因此正如您所说的“我尝试了很多角度,但我就是无法弄对...”。再次强调,要模拟镜像效果,您应该通过-1来缩放其中一个轴。
编辑:交换方向(来自评论)
这只是一个想法,我认为它很好。不要使用资源转换,自己创建。创建一个视图,大小为您希望视频的大小,然后创建一个图像视图子视图,其中包含所有所需的变换、剪切和内容模式。从您获得的示例中创建图像,将其设置为图像视图,并从视图获取层快照。然后将快照发送给资产编写器。
我知道你在想什么,这里是“开销”。嗯,我不这么认为。由于视图和图像视图在 CPU 上进行变换,与资产编写器执行相同的操作,因此您所做的就是取消其内部变换并使用自己的系统。如果您尝试了这个方法,我非常想听听您的结果。
获取层图像的方法:
- (UIImage *)imageFromLayer:(CALayer *)layer {
    UIGraphicsBeginImageContext([layer frame].size);
    [layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return outputImage;
}

再次思考后,我不确定是否可以使用AVAssetWriterInput转换。我想在录制过程中让用户切换相机,但是我不能在开始写入后更改AVAssetWriterInput转换(会崩溃),所以我认为我别无选择,只能更改AVCaptureConnection方向(我知道这会影响性能),你觉得呢? - Eyal
如果它能够正常工作,那应该不会太糟糕。这里更好的问题是当样本具有不同分辨率时会发生什么。无论如何,如果您交换相机,您可以开始一个新视频,然后在用户停止录制时将它们全部添加在一起。 - Matic Oblak

0
不是最简单的方法,但我认为如果你拦截帧并执行自己的转换,它肯定会起作用。你不需要任何UIView来做到这一点-AVFoundation允许直接访问和操作其帧(在写入文件时可以替换为自己的缓冲区,如果需要的话)。我看到的唯一缺点是性能。即使只是翻转图像,在旧设备和高分辨率上可能也会非常慢。
如果这确实影响了性能,您可以将视频保存为原样,并维护每个帧的单独方向数组。保存视频后,重新打开它,为每个帧执行转换,并将其保存到新文件中。我做过类似的事情,它确实有效。
顺便说一句,AVAssetWriterInput的“transform”属性仅在iPhone上工作。例如,如果您使用AVFoundation录制视频并将其上传到某个地方,在浏览器中观看,则它的方向将不正确。因此,如果您想要彻底的解决方案,自己的转换方式是行之有效的。
如果您经常进行视频/图像处理(例如在此示例中翻转/旋转),请考虑使用OpenCV库。学习需要一些时间,但它很值得。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接