2014年10月20日 星期一

解析 iOS 照相和錄影如何達成

請參考 AVCam SampleAV Foundation Programming Guide

iOS 拍照和錄影是透過 AV Foundation framework 來完成的。首先先介紹幾個類別:
1. AVCaptureDevice - 用來描述輸入硬體元件,例如:攝影機或麥克風。
2. AVCautureInput - 用來設定輸入硬體元件輸出埠。
3. AVCaptureOutput - 用來描述要輸出的結果,例出要輸出成照片檔 (AVCaptureStillImageOutput) 或 影片檔 (AVCaptureMovieFileOutput)等。
4. AVCaptureConnection - 用來描述和串聯輸入物件和輸出物件的類別,被使用於 AVCaptureSession 內部,通常會使用 AVCatureSession 物件,而不會直接使用 AVCaptureConnection。
5. AVCaptureSession - 所有輸入硬體物件(AVCaputureInput objects)和輸入物件(AVCaptureOutput objects,可能是照片檔或影片檔)都會被加入 AVCaptureSession 物件,最後透過 -(void)startRunning; 和 -(void)stopRunning; 來啟動和停止工作。
6. AVCaptureVideoPreviewLayer - 這是一個滿重要的類別,如其名,就是用於在螢幕上產生預覽畫面用。在此預覽的畫面是指輸入影像串流直接即時顯示在View上,而不是指拍照後的預覽。

接著,就來分解 AVCam source code 吧~
先來看看初始化要作些什麼吧!

1. 產生 AVCaptureSession 物件,先把 AVCaptureVideoPreviewLayer 指定給 session.

 AVCaptureSession *session = [[AVCaptureSession alloc] init];
[[self previewView] setSession:session];

2. 找到適當的 AVCaptureDevice ,產生適當的 AVCaptureInput
AVCaptureDevice *videoDevice = [AVCamViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject]; AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];

3. 把 AVCaptureInput 加入 session。
if ([session canAddInput:videoDeviceInput])
{
    [session addInput:videoDeviceInput];
    ...
}
if ([session canAddInput:audioDeviceInput])
{
    [session addInput:audioDeviceInput];
    ...
}

4. 初始要輸出的影片檔和圖片檔加到 session。
AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([session canAddOutput:movieFileOutput])
{
    [session addOutput:movieFileOutput];
    ...
}
    
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
if ([session canAddOutput:stillImageOutput])
{
    [session addOutput:stillImageOutput];
    ...
}

接著,來拍照吧!拍照的指令就是
[AVCaptureStillImageOutput captureStillImageAsynchronouslyFromConnection:completionHandler:];
來看看 Sample source code 怎麼寫的。
- (IBAction)snapStillImage:(id)sender
{
    dispatch_async([self sessionQueue], ^{
        ...
        [[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
            if (imageDataSampleBuffer)  // imageDataSampleBuffer 指向儲存照片內容的地方
            {
                // 將數據用 NSData 物件化
                NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
                // 再轉成 UIImage 物件
                UIImage *image = [[UIImage alloc] initWithData:imageData];
                // 最後,儲存到系統相簿
                [[[ALAssetsLibrary alloc] init] writeImageToSavedPhotosAlbum:[image CGImage] orientation:(ALAssetOrientation)[image imageOrientation] completionBlock:nil];
            }
        }];
    });
}

驚 ~! 拍照怎麼這麼簡單;那攝影呢?來看看吧~!

    //開始錄影並指定錄影要暫存到那個檔案。
    [AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] 
    //結束錄影
    [AVCaptureMovieFileOutput stopRecording]  

不難,看原始碼就懂了

沒有留言:

張貼留言