iOS VideoPreview Landscape 颠倒了

iOS VideoPreview Landscape is upside down

出于某种原因,当我将 phone 设置为横向模式时,相机预览倒置(水平翻转)。我正在使用 Xamarin 移植的示例项目; AVCamBarcode.

我最终通过横向使用 GeometryFlipped 完成了一半的修复。但是,现在绘制的条形码在横向模式下没有绘制在正确的位置。

  1. 这是 device/os 问题还是样本不完整?
  2. 推荐的纠正方法是什么?

    public override void ViewWillTransitionToSize (CGSize toSize, IUIViewControllerTransitionCoordinator coordinator)
    {
        base.ViewWillTransitionToSize (toSize, coordinator);
    
        var videoPreviewLayerConnection = PreviewView.VideoPreviewLayer.Connection;
        if (videoPreviewLayerConnection != null) {
            var deviceOrientation = UIDevice.CurrentDevice.Orientation;
            if (!deviceOrientation.IsPortrait () && !deviceOrientation.IsLandscape ())
                return;
    
            var newVideoOrientation = VideoOrientationFor (deviceOrientation);
            var oldSize = View.Frame.Size;
            var oldVideoOrientation = videoPreviewLayerConnection.VideoOrientation;
            videoPreviewLayerConnection.VideoOrientation = newVideoOrientation;
    
            //THIS IS THE HALF FIX I CAME UP WITH
            if (deviceOrientation.IsLandscape())
                videoPreviewLayerConnection.VideoPreviewLayer.GeometryFlipped = true;
            else
                videoPreviewLayerConnection.VideoPreviewLayer.GeometryFlipped = false;
            //END FIX
    
            // When we transition to the new size, we need to adjust the region
            // of interest's origin and size so that it stays anchored relative
            // to the camera.
            coordinator.AnimateAlongsideTransition (context => {
                var oldRegion = PreviewView.RegionOfInterest;
                var newRegion = new CGRect ();
    
                if (oldVideoOrientation == LandscapeRight && newVideoOrientation == LandscapeLeft) {
                    newRegion = oldRegion.WithX (oldSize.Width - oldRegion.X - oldRegion.Width);
                } else if (oldVideoOrientation == LandscapeRight && newVideoOrientation == Portrait) {
                    newRegion.X = toSize.Width - oldRegion.Y - oldRegion.Height;
                    newRegion.Y = oldRegion.X;
                    newRegion.Width = oldRegion.Height;
                    newRegion.Height = oldRegion.Width;
                } else if (oldVideoOrientation == LandscapeLeft && newVideoOrientation == LandscapeRight) {
                    newRegion = oldRegion.WithX (oldSize.Width - oldRegion.X - oldRegion.Width);
                } else if (oldVideoOrientation == LandscapeLeft && newVideoOrientation == Portrait) {
                    newRegion.X = oldRegion.Y;
                    newRegion.Y = oldSize.Width - oldRegion.X - oldRegion.Width;
                    newRegion.Width = oldRegion.Height;
                    newRegion.Height = oldRegion.Width;
                } else if (oldVideoOrientation == Portrait && newVideoOrientation == LandscapeRight) {
                    newRegion.X = oldRegion.Y;
                    newRegion.Y = toSize.Height - oldRegion.X - oldRegion.Width;
                    newRegion.Width = oldRegion.Height;
                    newRegion.Height = oldRegion.Width;
                } else if (oldVideoOrientation == Portrait && newVideoOrientation == LandscapeLeft) {
                    newRegion.X = oldSize.Height - oldRegion.Y - oldRegion.Height;
                    newRegion.Y = oldRegion.X;
                    newRegion.Width = oldRegion.Height;
                    newRegion.Height = oldRegion.Width;
                }
    
                PreviewView.SetRegionOfInterestWithProposedRegionOfInterest (newRegion);
            }, context => {
                sessionQueue.DispatchAsync (() => {
                    metadataOutput.RectOfInterest = PreviewView.VideoPreviewLayer.MapToLayerCoordinates (PreviewView.RegionOfInterest);
                });
                // Remove the old metadata object overlays.
                RemoveMetadataObjectOverlayLayers ();
            });
        }
    }
    

编辑

AVCaptureVideoOrientation VideoOrientationFor (UIDeviceOrientation deviceOrientation)
{
    switch (deviceOrientation) {
    case UIDeviceOrientation.Portrait:
        return Portrait;
    case UIDeviceOrientation.PortraitUpsideDown:
        return PortraitUpsideDown;
    case UIDeviceOrientation.LandscapeLeft:
        return LandscapeLeft;
    case UIDeviceOrientation.LandscapeRight:
        return LandscapeRight;
    default:
        throw new InvalidProgramException ();
    }
}

设备和视频方向对于横向具有不同的含义。

The docs say (for video):

case landscapeLeft

Indicates that video should be oriented horizontally, top on the right.

case landscapeRight

Indicates that video should be oriented horizontally, top on the left.

但是 device orientation 说:

case landscapeLeft

The device is in landscape mode, with the device held upright and the home button on the right side.

case landscapeRight

The device is in landscape mode, with the device held upright and the home button on the left side.

因此,您需要更改为:

case UIDeviceOrientation.LandscapeLeft:
    return LandscapeRight;
case UIDeviceOrientation.LandscapeRight:
    return LandscapeLeft;