Article:
Lập trình hiển thị và ghi lại hình ảnh từ camera trên iPhone
2887
ngocdaothanh.myopenid.com 172Updated over 2 years ago |
Tại tại thời điểm đầu năm 2009 này iPhone đã bước sang thế hệ thứ 2 với phiên bản firmware 2.2. Tuy vậy iPhone ngay sau khi đập hộp vẫn chưa có sẵn tính năng quay phim! Người ta đồn Apple làm vậy để chống người ta quay trộm phim trong rạp. Có lẽ đây đồn đại đó có nhiều phần đúng vì Google T-Mobile G1 ra sau nhưng cũng vậy, không có sẵn tính năng quay phim.
Gần đây có hacker tuyên bố đã viết được chương trình quay được phim tới tận 30-45 hình/s. Như vậy thật ra iPhone có cấu hình phần cứng cao, có thể vừa ghi hình ảnh từ camera vừa nén hình ảnh thành phim, nhưng API để ghi hình ảnh hiện nằm trong số nhiều API chưa được công khai. Dù dùng API không công khai, có vẻ chương trình viết xong vẫn có thể phân phối thông qua AppStore
.
Bài viết này bàn cách sử dụng API không công khai liên quan đến camera, để hiển thị và ghi lại hình ảnh. Bài viết này giả sử bạn dùng SDK và Xcode do Apple cung cấp chính thức, thay vì tìm tự do bằng cách jailbreak iPhone rồi dùng toolchain.
Tạo tập tin header từ thư viện SDK
SDK của iPhone sau khi cài nằm ở thư mục /Developer/Platforms/iPhoneOS.platform/Developer/SDKs. Trong này có thể cùng lúc chứa nhiều phiên bản SDK. SDK chia làm 2 phần: công khai và không công khai. Phần công khai được Apple cung cấp sẵn các tập tin header, khi viết chương trình chỉ việc include/import vào là dùng được. Phần không công khai thì không có sẵn, muốn dùng chúng ta phải tự tạo.
Phần công khai chỉ cho phép thao tác rất hạn chế với camera thông qua UIImagePickerController. Phần "của chìm" quí giá nằm ở /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/System/Library/PrivateFrameworks/PhotoLibrary.framework (với SDK 2.2). Chúng ta dùng chương trình class-dump-x để tạo (không dùng được class-dump vì nó không đọc được thư viện biên dịch cho CPU ARM của iPhone):
class-dump-x /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/System/Library/PrivateFrameworks/PhotoLibrary.framework
Hoặc
class-dump-x -H /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/System/Library/PrivateFrameworks/PhotoLibrary.framework
Class chúng ta cần là PLCameraController (PL là Private Library).
Hiển thị
Ta viết thử chương trình hiển thị ảnh từ camera lên màn hình.
- Dùng Xcode tạo project Example có kiểu View-Based Application.
- Sửa ExampleAppDelegate.m thành:
#import "ExampleAppDelegate.h"
#import "ExampleViewController.h"
@interface PLCameraController : NSObject
{
CALayer *_cameraLayer;
struct CameraDevice *_camera;
struct CameraImageQueueHelper *_cameraHelper;
id _delegate;
UIView *_previewView;
BOOL _isPreviewing;
BOOL _isLocked;
BOOL _wasPreviewingBeforeDeviceLock;
}
+ (id)sharedInstance;
- (id)init;
- (void)dealloc;
- (void)_setIsReady;
- (BOOL)isReady;
- (void)_applicationSuspended;
- (void)_applicationResumed;
- (void)_tookPicture:(struct __CoreSurfaceBuffer *)fp8;
- (void)_tookPicture:(struct CGImage *)fp8 jpegData:(struct __CFData *)fp12 imageProperties:(struct __CFDictionary *)fp16;
- (struct CameraImageQueueHelper *)_cameraHelper;
- (BOOL)_setupCamera;
- (void)_tearDownCamera;
- (void)setDelegate:(id)fp8;
- (id)delegate;
- (struct CGRect)_cameraFrame;
- (id)previewView;
- (void)startPreview;
- (void)stopPreview;
- (void)capturePhoto;
@end
@implementation ExampleAppDelegate
@synthesize window;
@synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
PLCameraController *cam = [PLCameraController sharedInstance];
UIView *view = [cam previewView];
[cam startPreview];
[window addSubview:view];
// Override point for customization after app launch
//[window addSubview:viewController.view];
[window makeKeyAndVisible];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
@end - Chỉ định link với PhotoLibrary: từ Frameworks -> Add -> Existing Frameworks, chọn /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS2.2.sdk/System/Library/PrivateFrameworks/PhotoLibrary.framework.
Trong đoạn mã trên ta nhúng thẳng class PLCameraController cho gọn. Ta cũng có thể lưu thành tập tin riêng. Để "Build and Go" được, phải chọn target là "Device - 2.2", vì thư viện dùng cho simulator không chứa những thứ như PLCameraController.
Ghi lại hình ảnh
Ghi một ảnh
Nếu chỉ muốn ghi lại một tấm ảnh từ camera thì quá dễ:
- Tạo class có chứa 2 phương thức callback/observer/delegate:
- (void) cameraControllerReadyStateChanged: (NSNotification *) aNotification;
- (void) cameraController: (id) sender tookPicture: (UIImage *) picture withPreview: (* UIImage) preview jpegData: (NSData *) rawData imageProperties: (struct __CFDictionary *) imageProperties; - Gọi cam = [PLCameraController sharedInstance], [cam setDelegate: object của class trên], [cam capturePhoto].
- Trong phương thức cameraController, nếu muốn ghi ảnh vào thư viện ảnh chuẩn (tiện lợi vì có thể xem bằng chương trình Photos trên iPhone), gọi:
UIImageWriteToSavedPhotosAlbum(preview, self, nil, nil); Hoặc nếu muốn ghi ảnh ra đĩa: NSString *filePath = [NSString stringWithFormat:@"%@%@", NSHomeDirectory(), @"/Documents/image.jpg"]; [imageData writeToFile:filePath atomically:YES];
Cách trên có thể dùng khi muốn xử lí ảnh trước khi hiện ra màn hình.
Ghi video
Nếu muốn ghi lại video thì khó hơn, vì phải giải quyết 2 câu hỏi:
- Làm sao lấy ảnh từ camera càng nhanh càng tốt trong một đơn vị thời gian?
- Làm sao để nén nhiều ảnh lại thành một video?
Gọi capturePhoto liên tục (phải bằng timer, không thể gọi nối nhau) không cho frame rate cao. Có cách khá dễ thực hiện là truy cập thẳng frame buffer của window đang hiển thị previewView (xem ví dụ phần Hiển thị):
CGImageRef *cGImageRef = [window _createCGImageRefRepresentationInFrame: [window bounds]];
NSData *rawData = UIImageJPEGRepresentation([UIImage imageWithCGImage: cGImageRef], compressRatio);
Cách cao cấp hơn là truy cập thẳng frame buffer của camera.
Tham khảo
- Indice » Lavori degli Utenti » Progetti finiti » Video recorder
- iPhone Open Application Development (phần phụ lục Taking Camera Photos)
- スポイトができるまで - Demo - Mua trên AppStore
- Squidge (chỉ chạy được trên iPhone < 2.2)
- iphonetest (chạy rất tốt, giấy phép MIT)
172

over 2 years ago