2010-06-30 95 views
22

我試圖從相機捕捉視頻。我得到captureOutput:didOutputSampleBuffer:回調觸發,它給了我一個樣本緩衝區,然後我轉換爲CVImageBufferRef。然後我嘗試將該圖像轉換爲UIImage,然後我可以在我的應用程序中查看該圖像。如何將CVImageBufferRef轉換爲UIImage

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection 
{ 
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    /*Lock the image buffer*/ 
    CVPixelBufferLockBaseAddress(imageBuffer,0); 
    /*Get information about the image*/ 
    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer); 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 

    /*We unlock the image buffer*/ 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

    /*Create a CGImageRef from the CVImageBufferRef*/ 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGImageRef newImage = CGBitmapContextCreateImage(newContext); 

    /*We release some components*/ 
    CGContextRelease(newContext); 
    CGColorSpaceRelease(colorSpace); 

    /*We display the result on the custom layer*/ 
    /*self.customLayer.contents = (id) newImage;*/ 

    /*We display the result on the image view (We need to change the orientation of the image so that the video is displayed correctly)*/ 
    UIImage *image= [UIImage imageWithCGImage:newImage scale:1.0 orientation:UIImageOrientationRight]; 
    self.capturedView.image = image; 

    /*We relase the CGImageRef*/ 
    CGImageRelease(newImage); 
} 

代碼似乎正常工作,直到調用CGBitmapContextCreate。它總是返回一個NULL指針。所以其餘的功能都不起作用。無論我似乎傳遞它,函數返回null。我不知道爲什麼。

回答

19

要傳遞的baseAddress的方式假定所述圖像數據的形式是

ACCC

(其中C是一些顏色分量,R || ||ģB)。

如果您已經將AVCaptureSession設置爲以本機格式捕獲視頻幀,則很可能您將視頻數據恢復爲平面YUV420格式。 (請參閱:link text)爲了完成您在此嘗試做的事情,最簡單的做法可能是指定您希望在kCVPixelFormatType_32RGBA中捕獲視頻幀。 Apple建議您捕捉kCVPixelFormatType_32BGRA中的視頻幀(如果您完全採用非平面格式捕捉視頻幀),其原因沒有說明,但我可以合理地假設是由於性能方面的考慮。

警告:我沒有這樣做,並且假設訪問像這樣的CVPixelBufferRef內容是構建圖像的合理方法。我不能擔保這個實際工作,但我/可以/告訴你,你現在正在做的事情的方式可靠地不會工作,因爲你是(可能)捕獲視頻幀的像素格式。

+8

完全正確的答案,所以只是作爲註釋:kCVPixelFormatType_32RGBA不能作爲至少的iOS 4.2.1的iPhone 4捕獲格式。 BGRA已全面實施。 – Tommy

10

如果你只是需要將CVImageBufferRef轉換爲UIImage,它似乎比它應該更加困難。基本上你需要轉換爲CIImage,然後是CGImage,然後是UIImage。我希望我能告訴你爲什麼。誰知道。

-(void) screenshotOfVideoStream:(CVImageBufferRef)imageBuffer 
{ 
    CIImage *ciImage = [CIImage imageWithCVPixelBuffer:imageBuffer]; 
    CIContext *temporaryContext = [CIContext contextWithOptions:nil]; 
    CGImageRef videoImage = [temporaryContext 
          createCGImage:ciImage 
          fromRect:CGRectMake(0, 0, 
          CVPixelBufferGetWidth(imageBuffer), 
          CVPixelBufferGetHeight(imageBuffer))]; 

    UIImage *image = [[UIImage alloc] initWithCGImage:videoImage]; 
    [self doSomethingWithOurUIImage:image]; 
    CGImageRelease(videoImage); 
} 

這種特殊的方式爲我工作,當我使用VTDecompressionSession回調以獲取CVImageBufferRef(但它應該對任何CVImageBufferRef工作)轉換H.264視頻。我使用的是iOS 8.1,XCode 6.2。

+2

你不需要所有這些步驟。你可以調用[[UIImage alloc] initWithCIImage ...] –

+1

我試過這樣做,但它不適合我,我剛剛得到一個純白色的圖像。出於某種原因,我需要CIContext來做到這一點(如[這個答案](http://stackoverflow.com/a/7788510/3841734))。也許這只是我的具體情況,我需要它。我會誠實地說,我不完全理解所有這些圖像格式和上下文的東西。 –

+1

可能想圍繞在@autorelease區塊中的所有這些... – theprojectabot

1

您可以直接撥打:

self.yourImageView.image=[[UIImage alloc] initWithCIImage:[CIImage imageWithCVPixelBuffer:imageBuffer]]; 
+0

這是行得通的,但似乎比Livy Storks方法慢得多 –