2010-08-24 72 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

相关问题