2010-08-24 68 views
41

因此,我遵循Apple的指示使用AVCaptureSessionhttp://developer.apple.com/iphone/library/qa/qa2010/qa1702.html來捕捉視頻會話。我面臨的一個問題是,即使相機/ iPhone設備的方向是垂直的(並且AVCaptureVideoPreviewLayer顯示了垂直相機流),輸出圖像似乎仍處於橫向模式。我檢查了示例代碼imageFromSampleBuffer:中imageBuffer的寬度和高度,我分別獲得了640px和480px。有誰知道爲什麼會出現這種情況?爲什麼AVCaptureSession輸出方向錯誤?

謝謝!

回答

38

看看頭文件AVCaptureSession.h。定義了一個名爲AVCaptureVideoOrientation的枚舉,該枚舉定義了各種視頻方向。在AVCaptureConnection對象上有一個名爲videoOrientation的屬性,它是AVCaptureVideoOrientation。你應該可以設置這個來改變視頻的方向。你可能想要AVCaptureVideoOrientationLandscapeRightAVCaptureVideoOrientationLandscapeLeft

您可以通過查看會話的輸出來找到會話的AVCaptureConnections。輸出具有連接屬性,該連接屬性是該輸出的一組連接。

+8

'住宅「videoOrientation」在類型的對象AVCaptureSession *'' – cheeesus 2012-10-03 16:35:27

+1

右未找到回答,應該被接受。 – Rivera 2013-03-11 00:23:08

+10

@cheesus videoOrientation在AVCaptureConnection,而不是AVCaptureSession – GabCas 2013-08-28 15:34:45

19

我對imageFromSampleBuffer做了一個簡單的單行修改來糾正方向問題(請參閱我在「I modified ...」中的代碼中的評論)。希望它能幫助別人,因爲我在這方面花費了太多時間。

// Create a UIImage from sample buffer data 
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer { 
    // Get a CMSampleBuffer's Core Video image buffer for the media data 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    // Lock the base address of the pixel buffer 
    CVPixelBufferLockBaseAddress(imageBuffer, 0); 

    // Get the number of bytes per row for the pixel buffer 
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer); 

    // Get the number of bytes per row for the pixel buffer 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    // Get the pixel buffer width and height 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    // Create a device-dependent RGB color space 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    // Create a bitmap graphics context with the sample buffer data 
    CGContextRef context1 = CGBitmapContextCreate(baseAddress, width, height, 8, 
               bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 

    // Create a Quartz image from the pixel data in the bitmap graphics context 
    CGImageRef quartzImage = CGBitmapContextCreateImage(context1); 
    // Unlock the pixel buffer 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

    // Free up the context and color space 
    CGContextRelease(context1); 
    CGColorSpaceRelease(colorSpace); 

    // Create an image object from the Quartz image 
    //I modified this line: [UIImage imageWithCGImage:quartzImage]; to the following to correct the orientation: 
    UIImage *image = [UIImage imageWithCGImage:quartzImage scale:1.0 orientation:UIImageOrientationRight]; 

    // Release the Quartz image 
    CGImageRelease(quartzImage); 

    return (image); 
} 
+1

謝謝,對我有幫助。 注意採取從以下方法:http://stackoverflow.com/questions/8924299/ios-capturing-image-using-avframework – 2014-03-31 04:28:26

+0

你'達人!我無法弄清楚這一點,因爲我沒有使用AVCaptureConnection ...這個伎倆。謝謝! – 2014-04-14 23:15:40

+0

@ReidBelton你不能使用AVCaptureConnection,它在你有輸入和輸出時自動創建,你只需要檢索它並改變方向。 – Pochi 2014-10-09 04:48:59

8

例如:

AVCaptureConnection *captureConnection = <a capture connection>; 
if ([captureConnection isVideoOrientationSupported]) { 
    captureConnection.videoOrientation = AVCaptureVideoOrientationPortrait; 
} 

默認似乎是AVCaptureVideoOrientationLandscapeRight。請參閱QA1744: Setting the orientation of video with AV Foundation

+0

這對我有效,我將它添加到myAVCaptureConnection處理程序。它按預期旋轉圖像,但視頻是鏡像的。我發現isMirrored已被棄用,所以不清楚如何解決鏡像問題。b/c新鏡像方法沒有關於使用情況的文檔。 – 2013-04-26 12:26:07

+0

@Jim:由於'AVCaptureVideoPreviewLayer'中的'mirrored'已被棄用,您應該使用'AVCaptureConnection'的'videoMirrored'屬性來代替。至少在頭文件中有記錄,其中'mirrored'及其朋友還明確指出'videoMirrored'和匹配的捕獲連接方法。 – 2013-04-26 14:28:35

+0

看起來這個功能在iOS中不可用 – 2013-04-26 21:22:53

10

這是一個正確的順序:

AVCaptureVideoDataOutput *videoCaptureOutput = [[AVCaptureVideoDataOutput alloc] init]; 

if([self.captureSession canAddOutput:self.videoCaptureOutput]){ 
    [self.captureSession addOutput:self.videoCaptureOutput]; 
}else{ 
    NSLog(@"cantAddOutput"); 
} 

// set portrait orientation 
AVCaptureConnection *conn = [self.videoCaptureOutput connectionWithMediaType:AVMediaTypeVideo]; 
[conn setVideoOrientation:AVCaptureVideoOrientationPortrait]; 
+1

這對我有用。就像這段代碼所顯示的那樣,在更改這些屬性之前將輸出添加到捕獲會話中非常重要。 AVCaptureVideoOrientationLandscapeRight with videoMirrored = true爲我提供了與使用前置攝像頭的標準攝像頭應用程序相同的效果。 – spfursich 2015-02-10 20:06:10

+0

這不僅僅是改變本地'conn'對象的方向,而不是'self.videoCaptureOutput'的方向? – mylogon 2017-07-03 13:56:10

2

定位問題是與前置攝像頭,所以檢查設備類型和產生新的圖像,它肯定會解決的方向問題:

-(void)capture:(void(^)(UIImage *))handler{ 

AVCaptureConnection *videoConnection = nil; 
for (AVCaptureConnection *connection in self.stillImageOutput.connections) 
{ 
    for (AVCaptureInputPort *port in [connection inputPorts]) 
    { 
     if ([[port mediaType] isEqual:AVMediaTypeVideo]) 
     { 
      videoConnection = connection; 
      break; 
     } 
    } 
    if (videoConnection) { break; } 
} 

[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 

    if (imageSampleBuffer != NULL) { 
     NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 
     **UIImage *capturedImage = [UIImage imageWithData:imageData]; 
     if (self.captureDevice == [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo][1]) { 
      capturedImage = [[UIImage alloc] initWithCGImage:capturedImage.CGImage scale:1.0f orientation:UIImageOrientationLeftMirrored]; 
     }** 

     handler(capturedImage); 
    } 
}]; 
} 
15

ÿ 「所有這些都讓這很難。

在DidOutputSampleBuffer中,只需在抓取圖像之前更改方向即可。這是單聲道,但你必須

public class OutputRecorder : AVCaptureVideoDataOutputSampleBufferDelegate {  
     public override void DidOutputSampleBuffer (AVCaptureOutput captureOutput, CMSampleBuffer sampleBuffer, AVCaptureConnection connection) 
     { 
      try { 
       connection.videoOrientation = AVCaptureVideoOrientation.LandscapeLeft; 

在objC它的這種方法

- (void) captureOutput: (AVCaptureOutput *) captureOutput 
    didOutputSampleBuffer: (CMSampleBufferRef) sampleBuffer 
     fromConnection: (AVCaptureConnection *) connection 
+0

試過這個,我得到''AVCaptureConnection'沒有名爲'VideoOrientation''的成員' – drewish 2014-12-10 07:52:27

+0

這是一個大寫問題。應該已經'videoOrientation'編輯了答案。 – drewish 2014-12-10 07:55:32

+0

哦,我錯過了你說這是單聲道的部分...我認爲這是迅速... – drewish 2014-12-10 08:03:58

5

如果AVCaptureVideoPreviewLayer方向是正確的,你可以簡單的設置方向在拍照之前。

AVCaptureStillImageOutput *stillImageOutput; 
AVCaptureVideoPreviewLayer *previewLayer; 
NSData *capturedImageData; 

AVCaptureConnection *videoConnection = [stillImageOutput connectionWithMediaType:AVMediaTypeVideo]; 
if ([videoConnection isVideoOrientationSupported]) { 
    [videoConnection setVideoOrientation:previewLayer.connection.videoOrientation]; 
} 
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:^(CMSampleBufferRef imageSampleBuffer, NSError *error) { 
    CFDictionaryRef exifAttachments = 
      CMGetAttachment(imageSampleBuffer, kCGImagePropertyExifDictionary, NULL); 
    if (exifAttachments) { 
     // Do something with the attachments. 
    } 
    // TODO need to manually add GPS data to the image captured 
    capturedImageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; 
    UIImage *image = [UIImage imageWithData:capturedImageData]; 
}]; 

另外,需要注意的是UIImageOrientationAVCaptureVideoOrientation不同是很重要的。 UIImageOrientationUp指的是風景模式與音量控制向下朝向地面(而不是如果您考慮使用音量控制作爲快門按鈕)。

因此,用電源按鈕指向天空的縱向(AVCaptureVideoOrientationPortrait)實際上是UIImageOrientationLeft

+0

這應該被標記爲正確的答案。您還可以使用:connection.videoMirrored = true – user3344977 2016-04-08 06:08:40

5

對於那些需要使用CIImage和緩衝區方向的人是錯誤的,我使用了這種修正。

就這麼簡單。順便說一句,號碼3,1,6,8是從這裏https://developer.apple.com/reference/imageio/kcgimagepropertyorientation

不要問我爲什麼3,1,6,8是正確的組合。我用蠻力法找到它。如果你知道爲什麼讓解釋的意見,請...

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
    didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
      fromConnection:(AVCaptureConnection *)connection 
{ 

    // common way to get CIImage 

    CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 

    CFDictionaryRef attachments = CMCopyDictionaryOfAttachments(kCFAllocatorDefault, sampleBuffer, kCMAttachmentMode_ShouldPropagate); 

    CIImage *ciImage = [[CIImage alloc] initWithCVPixelBuffer:pixelBuffer 
                 options:(__bridge NSDictionary *)attachments]; 

    if (attachments) { 
     CFRelease(attachments); 
    } 

    // fixing the orientation of the CIImage 

    UIInterfaceOrientation curOrientation = [[UIApplication sharedApplication] statusBarOrientation]; 

    if (curOrientation == UIInterfaceOrientationLandscapeLeft){ 
     ciImage = [ciImage imageByApplyingOrientation:3]; 
    } else if (curOrientation == UIInterfaceOrientationLandscapeRight){ 
     ciImage = [ciImage imageByApplyingOrientation:1]; 
    } else if (curOrientation == UIInterfaceOrientationPortrait){ 
     ciImage = [ciImage imageByApplyingOrientation:6]; 
    } else if (curOrientation == UIInterfaceOrientationPortraitUpsideDown){ 
     ciImage = [ciImage imageByApplyingOrientation:8]; 
    } 



    // .... 

} 
+0

您正在查找的常量在kCGImageProperty方向中定義...這些來自TIFF/EXIF規範: https://www.awaresystems.be/imaging/tiff/tifftags /orientation.html – ibisum 2017-10-03 07:47:05

0

剛剛嘗試這一點;)

private func startLiveVideo() { 

    let captureSession = AVCaptureSession() 
    captureSession.sessionPreset = .photo 
    let captureDevice = AVCaptureDevice.default(for: .video) 

    let input = try! AVCaptureDeviceInput(device: captureDevice!) 
    let output = AVCaptureVideoDataOutput() 
    captureSession.addInput(input) 
    captureSession.addOutput(output) 

    output.setSampleBufferDelegate(self, queue: DispatchQueue(label: "videoQueue")) 
    output.connection(with: .video)?.videoOrientation = .portrait 

    let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession) 
    previewLayer.frame = view.bounds 
    view.layer.addSublayer(previewLayer) 

    captureSession.startRunning() 
} 
+0

你能解釋爲什麼這會起作用嗎?因爲當我「嘗試這個」時,它不會 – 2018-03-06 22:38:20

相關問題