2010-06-30 30 views
22

Tôi đang cố gắng quay video từ máy ảnh. tôi đã nhận được gọi lại captureOutput:didOutputSampleBuffer: để kích hoạt và nó mang lại cho tôi một bộ đệm mẫu mà sau đó tôi chuyển đổi thành CVImageBufferRef. sau đó tôi cố gắng chuyển đổi hình ảnh đó thành một số UIImage mà tôi có thể xem trong ứng dụng của mình.cách chuyển đổi CVImageBufferRef sang 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); 
} 

mã dường như hoạt động tốt cho đến khi cuộc gọi đến CGBitmapContextCreate. nó luôn trả về con trỏ NULL. do đó không có phần còn lại của hàm hoạt động. không có vấn đề gì tôi dường như vượt qua nó hàm trả về null. Tôi không biết tại sao.

Trả lời

19

Cách mà bạn đang đi trên baseAddress giả định rằng các dữ liệu hình ảnh ở dạng

ACCC

(trong đó C là một số thành phần màu sắc, R || G || B).

Nếu bạn đã thiết lập AVCaptureSession để chụp các khung hình video ở định dạng gốc, nhiều khả năng bạn sẽ nhận được dữ liệu video ở định dạng YUV420 phẳng. (xem: link text) Để làm những gì bạn đang cố gắng làm ở đây, có lẽ điều dễ nhất để làm là chỉ định rằng bạn muốn các khung hình video được chụp trong kCVPixelFormatType_32RGBA. Apple khuyên bạn nên chụp các khung hình video trong kCVPixelFormatType_32BGRA nếu bạn chụp nó ở định dạng không phẳng, lý do không được nêu ra, nhưng tôi có thể giả định hợp lý là do các cân nhắc về hiệu suất.

Lưu ý: Tôi chưa thực hiện việc này và đang giả định truy cập vào nội dung CVPixelBufferRef như thế này là một cách hợp lý để tạo hình ảnh. Tôi không thể xác minh cho điều này thực sự làm việc, nhưng tôi/có thể/cho bạn biết rằng cách bạn đang làm việc ngay bây giờ đáng tin cậy sẽ không hoạt động do định dạng pixel mà bạn đang (có thể) chụp các khung hình video.

+8

hoàn toàn câu trả lời đúng, vì vậy cũng giống như một lời nhận xét: kCVPixelFormatType_32RGBA không phải là có sẵn như là một định dạng chụp trên iPhone 4 ít nhất trong iOS 4.2.1 . BGRA được thực hiện đầy đủ. – Tommy

2

Benjamin Loulier đã viết một bài đăng thực sự tốt về việc xuất ra CVImageBufferRef dưới sự xem xét tốc độ với nhiều cách tiếp cận.

Bạn cũng có thể tìm thấy ví dụ hoạt động về github;)

Thời gian ngược lại? ;) Ở đây bạn đi: http://web.archive.org/web/20140426162537/http://www.benjaminloulier.com/posts/ios4-and-direct-access-to-the-camera

+0

Bài đăng trên blog này dường như đã biến mất. – Brigham

+0

@Brigham - vừa cập nhật liên kết. Không có gì. – maaalex

10

Nếu bạn chỉ cần chuyển đổi CVImageBufferRef thành UIImage, điều này có vẻ khó khăn hơn nhiều so với mức cần thiết. Về cơ bản bạn cần chuyển đổi sang CIImage, sau đó là CGImage, THEN UIImage. Tôi ước tôi có thể cho bạn biết lý do. Ai biết.

-(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); 
} 

phương pháp đặc biệt này làm việc cho tôi khi tôi đang chuyển đổi video H.264 sử dụng callback VTDecompressionSession để có được những CVImageBufferRef (nhưng nó phải làm việc cho bất kỳ CVImageBufferRef). Tôi đã sử dụng iOS 8.1, XCode 6.2.

+2

Bạn không cần tất cả các bước đó.Bạn có thể gọi [[UIImage alloc] initWithCIImage ...] –

+1

Tôi đã thử làm điều đó nhưng nó không hiệu quả đối với tôi và tôi chỉ có một hình ảnh trắng chắc chắn. Vì một lý do nào đó, tôi cần CIContext để làm điều này (như [câu trả lời này] (http://stackoverflow.com/a/7788510/3841734)). Có lẽ nó chỉ là trường hợp cụ thể của tôi mà tôi cần nó. Tôi sẽ trung thực tôi không hoàn toàn hiểu tất cả các định dạng hình ảnh này và nội dung công cụ. –

+1

có thể muốn bao quanh tất cả điều này trong một khối @autorelease ... – theprojectabot

1

Bạn có thể trực tiếp gọi:

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

Điều này đang hoạt động nhưng có vẻ chậm hơn rất nhiều so với phương pháp tiếp cận Livy Storks –

Các vấn đề liên quan