2011-06-24 27 views
7


Tôi đang viết một ứng dụng iPhone tạo ảnh tĩnh từ máy ảnh bằng AVFoundation. Đọc hướng dẫn lập trình Tôi đã tìm thấy mã gần như tôi cần làm, vì vậy tôi đang cố gắng "đảo ngược kỹ thuật" và hiểu nó.
Tôi đã tìm thấy một số khó khăn để hiểu phần chuyển đổi CMSampleBuffer thành hình ảnh.
Vì vậy, đây là những gì tôi hiểu và sau đó là mã.
CMSampleBuffer đại diện cho bộ đệm trong bộ nhớ nơi lưu trữ hình ảnh với dữ liệu bổ sung. Sau đó tôi gọi hàm CMSampleBufferGetImageBuffer() để nhận lại CVImageBuffer chỉ với dữ liệu hình ảnh.
Bây giờ có một chức năng mà tôi không hiểu và tôi chỉ có thể tưởng tượng chức năng của nó: CVPixelBufferLockBaseAddress (imageBuffer, 0); Tôi không thể hiểu nếu nó là một "thread khóa" để tránh nhiều hoạt động trên nó hoặc một khóa đến địa chỉ của bộ đệm để tránh những thay đổi trong quá trình hoạt động (và tại sao nó nên thay đổi? .. khung khác, không phải là dữ liệu sao chép ở một vị trí khác?). Phần còn lại của mã rõ ràng với tôi.
Đã cố gắng tìm kiếm trên google nhưng vẫn không tìm thấy gì hữu ích.
Ai đó có thể mang lại ánh sáng không?CVPixelBufferLockBaseĐịa chỉ lý do tại sao? Chụp ảnh tĩnh bằng cách sử dụng AVFoundation

-(UIImage*) getUIImageFromBuffer:(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); 

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 context = 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(context); 
// Unlock the pixel buffer 
CVPixelBufferUnlockBaseAddress(imageBuffer,0); 

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

// Create an image object from the Quartz image 
UIImage *image = [UIImage imageWithCGImage:quartzImage]; 

// Release the Quartz image 
CGImageRelease(quartzImage); 

return (image); 
} 

Cảm ơn, Andrea

Trả lời

3

File header nói rằng CVPixelBufferLockBaseAddress làm cho bộ nhớ "tiếp cận". Tôi không chắc chắn điều đó có nghĩa là chính xác, nhưng nếu bạn không làm điều đó, CVPixelBufferGetBaseAddress thất bại vì vậy bạn nên làm điều đó.

EDIT

Chỉ cần làm điều đó là câu trả lời ngắn. Đối với lý do tại sao xem xét hình ảnh có thể không sống trong bộ nhớ chính, nó có thể sống trong một kết cấu trên GPU nào đó (CoreVideo cũng hoạt động trên mac) hoặc thậm chí ở định dạng khác với những gì bạn mong đợi, vì vậy các pixel bạn nhận được thực sự là sao chép. Nếu không có Khóa/Mở khóa hoặc một số loại Bắt đầu/Kết thúc, việc triển khai không có cách nào để biết khi nào bạn đã hoàn thành với các pixel trùng lặp để chúng có thể bị rò rỉ một cách hiệu quả. CVPixelBufferLockBaseAddress chỉ đơn giản là cung cấp thông tin về phạm vi CoreVideo, tôi sẽ không quá treo lên nó.

Có, họ có thể chỉ đơn giản trả về các pixel từ CVPixelBufferGetBaseAddress và loại bỏ hoàn toàn CVPixelBufferLockBaseAddress. Tôi không biết tại sao họ không làm thế.

+0

Cảm ơn bạn, đó là một đầu mối.Vì trong các hàm được gọi, không có dấu vết nào về sao chép hoặc tạo, tôi bắt đầu nghĩ rằng bộ đệm được truyền theo tham chiếu, do đó là một loại đóng băng bộ nhớ đệm. – Andrea

+0

Tôi đã thêm một số lý do có thể có về lý do tại sao. –

+0

YEP, tôi đoán lý do chính là điểm giữa câu trả lời của bạn và câu trả lời tôi tìm thấy trên github. "Image.lock(), để xóa tất cả các bản cập nhật bộ đệm cho đến khi Image.unlock() được gọi lại" ngôn ngữ không phải là ObjC nhưng ý nghĩa phải giống nhau. – Andrea

0

Tôi muốn cung cấp thêm thông tin về chức năng này, tôi đã thực hiện một số thử nghiệm cho đến nay và tôi có thể cho bạn biết điều đó.
Khi bạn nhận được địa chỉ cơ sở, bạn có thể nhận được địa chỉ của một số tài nguyên bộ nhớ dùng chung. Điều này trở nên rõ ràng nếu bạn in địa chỉ của địa chỉ cơ sở, làm điều đó bạn có thể thấy rằng địa chỉ cơ sở được lặp đi lặp lại trong khi nhận được khung hình video.
Trong ứng dụng của tôi, tôi chụp các khung hình theo các khoảng thời gian cụ thể và vượt qua CVImageBufferRef đến một lớp con NSOperation chuyển đổi bộ đệm trong một hình ảnh và lưu nó trên điện thoại. Tôi không khóa bộ đệm pixel cho đến khi thao tác bắt đầu chuyển đổi CVImageBufferRef, ngay cả khi đẩy ở vị trí cao hơn địa chỉ cơ sở của pixel và địa chỉ bộ đệm CVImageBufferRef bằng nhau trước khi tạo NSOperation và bên trong nó. Tôi chỉ giữ lại CVImageBufferRef. Tôi dự kiến ​​sẽ thu thập các tham chiếu chưa từng có và thậm chí nếu tôi không nhìn thấy nó, tôi cho rằng mô tả tốt nhất là CVPixelBufferLockBaseAddress khóa phần bộ nhớ nơi bộ đệm được đặt, không thể truy cập được từ các tài nguyên khác. bạn mở khóa nó.

+0

Bạn có thể cung cấp một số mã mẫu để xem bạn đang nói về điều gì không? Tôi có một số vấn đề trong xử lý cụ thể của CMSampleBufferRef và EXC_BAD_ACCESS ngẫu nhiên trong khi CVPixelBufferGetBaseAddress. –

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