AVFoundation-07拍攝定制

概述

AVFoundation 是一個可以用來使用和創(chuàng)建基于時間的視聽媒體數(shù)據(jù)的框架。AVFoundation 的構建考慮到了目前的硬件環(huán)境和應用程序,其設計過程高度依賴多線程機制。充分利用了多核硬件的優(yōu)勢并大量使用block和GCD機制,將復雜的計算機進程放到了后臺線程運行。會自動提供硬件加速操作,確保在大部分設備上應用程序能以最佳性能運行。該框架就是針對64位處理器設計的,可以發(fā)揮64位處理器的所有優(yōu)勢。

iOS 媒體環(huán)境.png

切換攝像頭

一般來說iPhone都具有前后兩個攝像頭,在做相機應用的時候一個基本的需求就是前后攝像頭的切換。在切換相機的時候我們需要注意的是我們都需要判斷當前設備支不支持相機切換、用戶是否開啟了相應的權限、以及設置的圖片尺寸前后攝像頭是否支持這樣的尺寸。

#pragma mark - 切換攝像頭
- (AVCaptureDevice *)deviceWithPostion:(AVCaptureDevicePosition)position
{
    NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in devices) {
        if (device.position == position) {
            return device;
        }
    }
    return nil;
}

- (BOOL)canSwitchCamera
{
    return [[AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo] count] > 1;
}

- (void)switchCamera
{
    if (![self canSwitchCamera]) {
        return;
    }
    
    AVCaptureDevicePosition devicePosition;
    if (self.deviceInput.device.position == AVCaptureDevicePositionBack) {
        devicePosition = AVCaptureDevicePositionFront;
    }else {
        devicePosition = AVCaptureDevicePositionBack;
    }
    
    [self.captureSession beginConfiguration];
    [self.captureSession removeInput:_deviceInput];
    NSError *error;
    AVCaptureDevice *device = [self deviceWithPostion:devicePosition];
    self.deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
    if (!self.deviceInput) {
        [self.captureSession commitConfiguration];
        return;
    }
    [self.captureSession addInput:self.deviceInput];
    [self.captureSession commitConfiguration];
}
調整焦距

iOS設備大多都支持基于給定的興趣點設置對焦,我們只需要傳入一個位置,系統(tǒng)就會自動在當前位置進行對焦。 需要注意的是,定要先設置位置,再設置曝光模式。需要注意的是,要先設置位置,再設置對焦模式。這里的 CGPoint 取值范圍是取景框左上角(0,0)到取景框右下角(1,1)之間。

#pragma mark - 自動對焦
- (void)autoFocus
{
    if (!self.deviceInput.device) {
        return;
    }
    
    if ([self.deviceInput.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
        NSError *error;
        if ([self.deviceInput.device lockForConfiguration:&error]) {
            self.deviceInput.device.focusMode = AVCaptureFocusModeAutoFocus;
            [self.deviceInput.device unlockForConfiguration];
        }
    }
}

#pragma mark - 調整焦距
- (BOOL)canTapFoucus
{
    return [self.deviceInput.device isFocusPointOfInterestSupported];
}

- (void)focusAtPoint:(CGPoint)point
{
    if (![self canTapFoucus]) {
        return;
    }
    
    if ([self.deviceInput.device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) {
        NSError *error;
        if ([self.deviceInput.device lockForConfiguration:&error]) {
            self.deviceInput.device.focusPointOfInterest = point;
            self.deviceInput.device.focusMode = AVCaptureFocusModeAutoFocus;
            [self.deviceInput.device unlockForConfiguration];
        }
    }
}

曝光

iOS設備大多都支持基于給定的興趣點設置曝光數(shù)據(jù),我們只需要傳入一個位置,系統(tǒng)就會自動在當前位置進行曝光。 需要注意的是,定要先設置位置,再設置曝光模式。這里的 CGPoint 取值范圍是取景框左上角(0,0)到取景框右下角(1,1)之間。

#pragma mark - 曝光
- (BOOL)canTapExpose
{
    return [self.deviceInput.device isExposurePointOfInterestSupported];
}

- (void)exposeAtPoint:(CGPoint)point
{
    if (![self canTapExpose]) {
        return;
    }
    
    if ([self.deviceInput.device isExposureModeSupported:AVCaptureExposureModeAutoExpose]) {
        NSError *error;
        if ([self.deviceInput.device lockForConfiguration:&error]) {
            self.deviceInput.device.exposurePointOfInterest = point;
            self.deviceInput.device.exposureMode = AVCaptureExposureModeAutoExpose;
            [self.deviceInput.device unlockForConfiguration];
        }
    }
}

閃光燈

閃光燈的使用比較簡單,有以下幾個模式:AVCaptureFlashModeOff 、AVCaptureFlashModeOn、AVCaptureFlashModeAuto。

#pragma mark - 閃光燈
- (BOOL)haveFlash
{
    return [self.deviceInput.device hasFlash];
}

- (AVCaptureFlashMode)currentFlashMode
{
    return self.deviceInput.device.flashMode;
}

- (void)setFlashModel:(AVCaptureFlashMode)flashModel
{
    if (self.deviceInput.device.flashMode == flashModel) {
        return;
    }
    
    if ([self.deviceInput.device isFlashModeSupported:flashModel]) {
        NSError *error;
        if ([self.deviceInput.device lockForConfiguration:&error]) {
            self.deviceInput.device.flashMode = flashModel;
            [self.deviceInput.device unlockForConfiguration];
        }
    }
}

手電筒

手電筒的使用比較簡單,有以下幾個模式:AVCaptureTorchModeOff,AVCaptureTorchModeOn,AVCaptureTorchModeAuto 。

#pragma mark - 手電筒
- (BOOL)haveTorch
{
    return [self.deviceInput.device hasTorch];
}

- (AVCaptureTorchMode)currentTorchMode
{
    return self.deviceInput.device.torchMode;
}

- (void)setTorchModel:(AVCaptureTorchMode)torchModel
{
    if (self.deviceInput.device.torchMode == torchModel) {
        return;
    }
    
    if ([self.deviceInput.device isTorchModeSupported:torchModel]) {
        NSError *error;
        if ([self.deviceInput.device lockForConfiguration:&error]) {
            self.deviceInput.device.torchMode = torchModel;
            [self.deviceInput.device unlockForConfiguration];
        }
    }
}

- (void)setTorchLevel:(float)torchLevel
{
    if ([self.deviceInput.device isTorchActive]) {
        NSError *error;
        if ([self.deviceInput.device lockForConfiguration:&error]) {
            [self.deviceInput.device setTorchModeOnWithLevel:torchLevel error:&error];
            [self.deviceInput.device unlockForConfiguration];
        }
    }
}

保存圖片

使用ALAssetsLibrary,我們可以很方便地將照片或視頻寫入用戶的資源庫中。在使用的時候需要注意用戶權限的控制。

#pragma mark - 保存圖片
- (void)writeImageToPhotosAlbum:(UIImage *)image
{
    ALAssetsLibrary *assetsLib = [[ALAssetsLibrary alloc] init];
    [assetsLib writeImageToSavedPhotosAlbum:image.CGImage
                                orientation:(NSInteger)image.imageOrientation
                            completionBlock:^(NSURL *assetURL, NSError *error) {
        NSLog(@"%@", assetURL);
    }];
}

視頻縮放

縮放的屬性是videoMaxZoomFactor,它的最小值是1.0(不進行縮放),最大值由videoMaxZoomFactor確定。

#pragma mark - 視頻縮放
- (BOOL)videoCanZoom
{
    return self.deviceInput.device.activeFormat.videoMaxZoomFactor > 1.0f;
}

- (float)videoMaxZoomFactor
{
    return MIN(self.deviceInput.device.activeFormat.videoMaxZoomFactor, 4.0f);
}

- (void)setVideoZoomFactor:(float)factor
{
    if (self.deviceInput.device.isRampingVideoZoom) {
        return;
    }
    
    NSError *error;
    if ([self.deviceInput.device lockForConfiguration:&error]) {
        self.deviceInput.device.videoZoomFactor = pow([self videoMaxZoomFactor], factor);
        [self.deviceInput.device unlockForConfiguration];
    }
}

- (void)rampZoomToFactor:(float)factor
{
    if (self.deviceInput.device.isRampingVideoZoom) {
        return;
    }

    NSError *error;
    if ([self.deviceInput.device lockForConfiguration:&error]) {
        [self.deviceInput.device rampToVideoZoomFactor:pow([self videoMaxZoomFactor], factor) withRate:1.0f];
        [self.deviceInput.device unlockForConfiguration];
    }
}

CoreVideo渲染

為什么要用快速紋理上傳,相比OpenGLES快速紋理上傳大大加快了紋理上傳的速度。這也是GPUImage中為什么優(yōu)先使用快速紋理上傳的原因。在閱讀GPUImage源碼的時候你可以看到這樣的注釋:// Note: the fast texture caches speed up 640x480 frame reads from 9.6 ms to 3.1 ms on iPhone 4S
詳見框架中的 GPUImageRawDataOutput.m 文件

- (void)setupOpenGLTextureCache
{
    CVReturn statuts = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault,
                                                    NULL,
                                                    _context,
                                                    NULL,
                                                    &_openGLESTextureCache);
    if (statuts != kCVReturnSuccess) {
        exit(0);
    }
}

#pragma mark - GLTexture
- (void)genTetureFromImage:(CVImageBufferRef)imageRef
{
    CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault,
                                                _openGLESTextureCache,
                                                imageRef,
                                                NULL,
                                                GL_TEXTURE_2D,
                                                GL_RGBA,
                                                (GLsizei)CVPixelBufferGetWidth(imageRef),
                                                (GLsizei)CVPixelBufferGetHeight(imageRef),
                                                GL_BGRA,
                                                GL_UNSIGNED_BYTE,
                                                0,
                                                &_openGLESTexture);

    glBindTexture(GL_TEXTURE_2D, CVOpenGLESTextureGetName(_openGLESTexture));
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glUniform1i(glGetUniformLocation(_program, "image"), 0);

    if (_openGLESTexture) {
        CFRelease(_openGLESTexture);
        _openGLESTexture = NULL;
        CVOpenGLESTextureCacheFlush(_openGLESTextureCache, 0);
    }
}

在這里不再介紹如何實時渲染相機視頻,當前在本文的例子中完成了相機視頻的實時渲染,具體請參考之前的文章或本文的相關示例。

參考

AVFoundation開發(fā)秘籍:實踐掌握iOS & OSX應用的視聽處理技術

源碼地址:AVFoundation開發(fā) https://github.com/QinminiOS/AVFoundation

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 索尼黑卡RX100設置與后期詳解(歡迎指正與補充)一、拍照1、影像尺寸分20M、10M、5 M,這里不是指文件大小...
    justin_pan閱讀 1,725評論 1 5
  • public classCamera.Parametersextends Objectjava.lang.Obje...
    冉冉升起的小太陽閱讀 11,212評論 0 7
  • iOS 蘋果官方Demo合集 字數(shù)10517閱讀21059評論18喜歡144 其實, 開發(fā)了這么久, 不得不說, ...
    bingo居然被占了閱讀 10,615評論 2 31
  • 晚飯后,村里兩老頭聚在一起,一邊吧啦著水煙,一邊興高采烈地講著昨天的事情。 “唉呀,昨天回家后,我頭都有點暈了” ...
    聽雨軒清秋閱讀 221評論 5 2
  • 人總是很能注意到自己生活中所遇到的不如意,特別是心情不好情緒低落的時候,在一個人的世界遇到的小小不如意都可以放大很...
    天外來客人閱讀 287評論 0 0

友情鏈接更多精彩內容