2010-09-07 74 views
34

我一直在撕裂我的頭髮,試圖讓AVFoundation相機以正確的方向(即設備方向)捕捉圖片,但我無法使它工作。iPhone AVFoundation相機方向

我看過教程,我看過WWDC演示文稿,我已經下載了WWDC示例程序,但即使這樣做也不行。

從我的應用程序中的代碼是...

AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]]; 
if ([videoConnection isVideoOrientationSupported]) 
{ 
    [videoConnection setVideoOrientation:[UIApplication sharedApplication].statusBarOrientation]; 
} 

[imageCaptureOutput captureStillImageAsynchronouslyFromConnection:videoConnection 
               completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) 
{ 
    if (imageDataSampleBuffer != NULL) 
    { 
     //NSLog(@"%d", screenOrientation); 

     //CMSetAttachment(imageDataSampleBuffer, kCGImagePropertyOrientation, [NSString stringWithFormat:@"%d", screenOrientation], 0); 

     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; 
     UIImage *image = [[UIImage alloc] initWithData:imageData]; 

     [self processImage:image]; 
    } 
}]; 

(processImage來使用相同的writeImage ...方法作爲WWDC代碼)

和代碼從WWDC應用程序是...

AVCaptureConnection *videoConnection = [AVCamDemoCaptureManager connectionWithMediaType:AVMediaTypeVideo fromConnections:[[self stillImageOutput] connections]]; 
     if ([videoConnection isVideoOrientationSupported]) { 
      [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait]; 
     } 

[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:videoConnection 
                  completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { 
                   if (imageDataSampleBuffer != NULL) { 
                    NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; 
                    UIImage *image = [[UIImage alloc] initWithData:imageData];                 
                    ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init]; 
                    [library writeImageToSavedPhotosAlbum:[image CGImage] 
                           orientation:(ALAssetOrientation)[image imageOrientation] 
                          completionBlock:^(NSURL *assetURL, NSError *error){ 
                           if (error) { 
                            id delegate = [self delegate]; 
                            if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) { 
                             [delegate captureStillImageFailedWithError:error]; 
                            }                        
                           } 
                          }]; 
                    [library release]; 
                    [image release]; 
                   } else if (error) { 
                    id delegate = [self delegate]; 
                    if ([delegate respondsToSelector:@selector(captureStillImageFailedWithError:)]) { 
                     [delegate captureStillImageFailedWithError:error]; 
                    } 
                   } 
                  }]; 

在其代碼的開始,他們設置AVOrientation爲縱向,這似乎很奇怪,但我想要得到它的檢測設備當前的方向和使用。

正如你所看到的我已經把[UIApplication sharedApplication] statusBarOrientation嘗試並獲得這個,但它仍然只能保存肖像照片。

任何人都可以提供任何幫助或建議,我需要做什麼?

謝謝!

Oliver

回答

44

嗯,這是帶我永遠fracking,但我已經做到了!

的代碼,我一直在尋找該位

[UIDevice currentDevice].orientation; 

這正好爲這樣

AVCaptureConnection *videoConnection = [CameraVC connectionWithMediaType:AVMediaTypeVideo fromConnections:[imageCaptureOutput connections]]; 
if ([videoConnection isVideoOrientationSupported]) 
{ 
    [videoConnection setVideoOrientation:[UIDevice currentDevice].orientation]; 
} 

而且它完美的作品:d

WOOP WOOP!

+2

好吧,我以爲我已經修復它,但可惜我錯了。它修復了在手機上顯示圖像並正確保存到庫的問題,但是當上傳到Facebook或在我的電腦上查看時,它們仍然是錯誤的方式:( – Fogmeister 2010-09-08 12:57:21

+2

你最終的解決方案是什麼?我注意到你的文章UIDeviceOrientation和AVCaptureVideoOrientation不完全相同,LandscapeRight和LandscapeLeft在枚舉中交換,我做了很長時間(如果縱向/縱向,如果橫向離開/設置橫向離開),我的風景圖片總是顛倒過來!似乎交換是必需的,以保持映射正確,不知道如何工作。 – 2011-01-08 17:40:33

+0

嗯。對我而言,照片庫中的縮略圖方向會旋轉,但圖像本身很好。 – 2011-08-09 09:42:52

-1

如何使用AVCaptureFileOutput?

- (void)detectVideoOrientation:(AVCaptureFileOutput *)captureOutput { 
    for(int i = 0; i < [[captureOutput connections] count]; i++) { 
     AVCaptureConnection *captureConnection = [[captureOutput connections] objectAtIndex:i]; 
     if([captureConnection isVideoOrientationSupported]) { 
      [captureConnection setVideoOrientation:[[UIDevice currentDevice] orientation]]; 
     } 
    } 
} 
+0

謝謝,我明天晚上會去。直到那時才能訪問我的MBP。 – Fogmeister 2010-09-13 15:38:00

4

有兩件事情需要注意

一)布賴恩王寫道 - LandscapeRight和LandscapeLeft枚舉被交換。看到AVCamCaptureManager例如:

// AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation) 
else if (deviceOrientation == UIDeviceOrientationLandscapeLeft) 
    orientation = AVCaptureVideoOrientationLandscapeRight; 
else if (deviceOrientation == UIDeviceOrientationLandscapeRight) 
    orientation = AVCaptureVideoOrientationLandscapeLeft; 

B)也有UIDeviceOrientationFaceUpUIDeviceOrientationFaceDown狀態,如果你嘗試設置爲視頻的方向,您的視頻將無法記錄。請確保在撥打[UIDevice currentDevice].orientation時不要使用它們!

11

以下是AVCam,我加入過它:

- (void)deviceOrientationDidChange{ 

    UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation]; 

    AVCaptureVideoOrientation newOrientation; 

    if (deviceOrientation == UIDeviceOrientationPortrait){ 
     NSLog(@"deviceOrientationDidChange - Portrait"); 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 
    else if (deviceOrientation == UIDeviceOrientationPortraitUpsideDown){ 
     NSLog(@"deviceOrientationDidChange - UpsideDown"); 
     newOrientation = AVCaptureVideoOrientationPortraitUpsideDown; 
    } 

    // AVCapture and UIDevice have opposite meanings for landscape left and right (AVCapture orientation is the same as UIInterfaceOrientation) 
    else if (deviceOrientation == UIDeviceOrientationLandscapeLeft){ 
     NSLog(@"deviceOrientationDidChange - LandscapeLeft"); 
     newOrientation = AVCaptureVideoOrientationLandscapeRight; 
    } 
    else if (deviceOrientation == UIDeviceOrientationLandscapeRight){ 
     NSLog(@"deviceOrientationDidChange - LandscapeRight"); 
     newOrientation = AVCaptureVideoOrientationLandscapeLeft; 
    } 

    else if (deviceOrientation == UIDeviceOrientationUnknown){ 
     NSLog(@"deviceOrientationDidChange - Unknown "); 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 

    else{ 
     NSLog(@"deviceOrientationDidChange - Face Up or Down"); 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 

    [self setOrientation:newOrientation]; 
} 

而且一定要添加到您的init方法:

NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; 
[notificationCenter addObserver:self 
    selector:@selector(deviceOrientationDidChange) 
    name:UIDeviceOrientationDidChangeNotification object:nil]; 
[self setOrientation:AVCaptureVideoOrientationPortrait]; 
+0

這不是一點點清潔劑嗎? – 2013-09-19 15:52:06

+0

此解決方案與UIImage + fixOrientation.h一起修復了完全定向的問題 – 2015-02-05 19:01:36

0

您還可以創建一箇中間CIImage,並搶屬性詞典

NSDictionary *propDict = [aCIImage properties]; 
NSString *orientString = [propDict objectForKey:kCGImagePropertyOrientation]; 

並據此轉換:)

我很喜歡在iOS5中訪問所有這些圖像元數據的容易程度!

3

如果您使用AVCaptureVideoPreviewLayer,您可以在視圖控制器中執行以下操作。

(假設你有一個名爲 「previewLayer」 AVCaptureVideoPreviewLayer的實例)

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { 
    [self.previewLayer setOrientation:[[UIDevice currentDevice] orientation]]; 
} 
+4

AVCaptureVideoPreviewLayer setOrientation:已棄用。 – 2013-02-13 17:52:05

+1

@TalYaniv在寫這個迴應的時候,它並沒有被棄用。 – 2013-11-08 15:03:04

12

這是不是乾淨了一點?

AVCaptureVideoOrientation newOrientation; 
    switch ([[UIDevice currentDevice] orientation]) { 
    case UIDeviceOrientationPortrait: 
     newOrientation = AVCaptureVideoOrientationPortrait; 
     break; 
    case UIDeviceOrientationPortraitUpsideDown: 
     newOrientation = AVCaptureVideoOrientationPortraitUpsideDown; 
     break; 
    case UIDeviceOrientationLandscapeLeft: 
     newOrientation = AVCaptureVideoOrientationLandscapeRight; 
     break; 
    case UIDeviceOrientationLandscapeRight: 
     newOrientation = AVCaptureVideoOrientationLandscapeLeft; 
     break; 
    default: 
     newOrientation = AVCaptureVideoOrientationPortrait; 
    } 
    [stillConnection setVideoOrientation: newOrientation]; 
+4

可能。這個問題雖然是三歲。我甚至不記得當我問它時我正在寫的應用程序:) – Fogmeister 2013-09-19 15:57:00

+0

如果我以設備橫向方向捕捉它,它仍然會生成橫向圖像。我總是希望肖像模式下的圖像。請給我建議。 – 2016-05-24 07:26:21

+0

非常感謝。它與Image + fixOrientation一起工作。 – 2016-05-24 07:43:48

1

這使用視圖控制器的方向方法。這適用於我,希望能爲你工作。

- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 
{ 
    [super willRotateToInterfaceOrientation:toInterfaceOrientation duration:duration]; 

    AVCaptureConnection *videoConnection = self.prevLayer.connection; 
    [videoConnection setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation]; 
} 
1

在斯威夫特,你應該這樣做:

videoOutput = AVCaptureVideoDataOutput() 
    videoOutput!.setSampleBufferDelegate(self, queue: dispatch_queue_create("sample buffer delegate", DISPATCH_QUEUE_SERIAL)) 

    if captureSession!.canAddOutput(self.videoOutput) { 
     captureSession!.addOutput(self.videoOutput) 
    } 

    videoOutput!.connectionWithMediaType(AVMediaTypeVideo).videoOrientation = AVCaptureVideoOrientation.PortraitUpsideDown 

它可以完美的我!

1

我寫這段代碼在Swift中,以防萬一需要某人。

第1步:生成定向通知(在你的viewDidLoad

UIDevice.currentDevice().beginGeneratingDeviceOrientationNotifications() 
NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("deviceOrientationDidChange:"), name: UIDeviceOrientationDidChangeNotification, object: nil) 

步驟2:取照片。我們將在這裏交換方向videoConnection。在AVFoundation中,特別是在橫向方向上有一個小的改變。所以我們只是交換它。例如,我們將改變LandscapeRightLandscapeLeft,反之亦然

func takePicture() { 
if let videoConnection = stillImageOutput!.connectionWithMediaType(AVMediaTypeVideo) { 

    var newOrientation: AVCaptureVideoOrientation? 
    switch (UIDevice.currentDevice().orientation) { 
    case .Portrait: 
     newOrientation = .Portrait 
     break 
    case .PortraitUpsideDown: 
     newOrientation = .PortraitUpsideDown 
     break 
    case .LandscapeLeft: 
     newOrientation = .LandscapeRight 
     break 
    case .LandscapeRight: 
     newOrientation = .LandscapeLeft 
     break 
    default : 
     newOrientation = .Portrait 
     break 

    } 
    videoConnection.videoOrientation = newOrientation! 


    stillImageOutput!.captureStillImageAsynchronouslyFromConnection(videoConnection) { 
    (imageDataSampleBuffer, error) -> Void in 

    let imageData = AVCaptureStillImageOutput.jpegStillImageNSDataRepresentation(imageDataSampleBuffer) 

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) { 

     dispatch_async(dispatch_get_main_queue()) { 

     let image = UIImage(data: imageData!)! 
     let portraitImage = image.fixOrientation() 


     } 
    } 


    } 
} 

    } 

注:請注意景觀方向的新方向值。它正好相反。 (這是罪魁禍首:: Joey:嗯)

步驟3:修復方向(延長的UIImage)

extension UIImage { 

func fixOrientation() -> UIImage { 

    if imageOrientation == UIImageOrientation.Up { 
     return self 
    } 

    var transform: CGAffineTransform = CGAffineTransformIdentity 

    switch imageOrientation { 
    case UIImageOrientation.Down, UIImageOrientation.DownMirrored: 
     transform = CGAffineTransformTranslate(transform, size.width, size.height) 
     transform = CGAffineTransformRotate(transform, CGFloat(M_PI)) 
     break 
    case UIImageOrientation.Left, UIImageOrientation.LeftMirrored: 
     transform = CGAffineTransformTranslate(transform, size.width, 0) 
     transform = CGAffineTransformRotate(transform, CGFloat(M_PI_2)) 
     break 
    case UIImageOrientation.Right, UIImageOrientation.RightMirrored: 
     transform = CGAffineTransformTranslate(transform, 0, size.height) 
     transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2)) 
     break 
    case UIImageOrientation.Up, UIImageOrientation.UpMirrored: 
     break 
    } 

    switch imageOrientation { 
    case UIImageOrientation.UpMirrored, UIImageOrientation.DownMirrored: 
     CGAffineTransformTranslate(transform, size.width, 0) 
     CGAffineTransformScale(transform, -1, 1) 
     break 
    case UIImageOrientation.LeftMirrored, UIImageOrientation.RightMirrored: 
     CGAffineTransformTranslate(transform, size.height, 0) 
     CGAffineTransformScale(transform, -1, 1) 
    case UIImageOrientation.Up, UIImageOrientation.Down, UIImageOrientation.Left, UIImageOrientation.Right: 
     break 
    } 

    let ctx: CGContextRef = CGBitmapContextCreate(nil, Int(size.width), Int(size.height), CGImageGetBitsPerComponent(CGImage), 0, CGImageGetColorSpace(CGImage), CGImageAlphaInfo.PremultipliedLast.rawValue)! 

    CGContextConcatCTM(ctx, transform) 

    switch imageOrientation { 
    case UIImageOrientation.Left, UIImageOrientation.LeftMirrored, UIImageOrientation.Right, UIImageOrientation.RightMirrored: 
     CGContextDrawImage(ctx, CGRectMake(0, 0, size.height, size.width), CGImage) 
     break 
    default: 
     CGContextDrawImage(ctx, CGRectMake(0, 0, size.width, size.height), CGImage) 
     break 
    } 

    let cgImage: CGImageRef = CGBitmapContextCreateImage(ctx)! 

    return UIImage(CGImage: cgImage) 
} 


    }