1. 视频采集主要流程

a. 创建并初始化输入(AVCaptureInput)和输出(AVCaptureOutput)

//初始化Input
AVCaptureDevice *inputCamera = nil;
NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for (AVCaptureDevice *device in devices)
{
    if ([device position] == AVCaptureDevicePositionFront)//AVCaptureDevicePositionBack
   {
        inputCamera = device;
   }
}
    
self.mCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:inputCamera error:nil];

//初始化ouput
dispatch_queue_t mProcessQueue = dispatch_queue_create("mProcessQueue", DISPATCH_QUEUE_SERIAL);
self.mCaptureDeviceOutput = [[AVCaptureVideoDataOutput alloc] init];
[self.mCaptureDeviceOutput setAlwaysDiscardsLateVideoFrames:NO];
[self.mCaptureDeviceOutput setVideoSettings:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey]];
[self.mCaptureDeviceOutput setSampleBufferDelegate:self queue:mProcessQueue];

b. 创建并初始化AVCaptureSession,把AVCaptureInput和AVCaptureOutput添加到AVCaptureSession中;

self.mCaptureSession = [[AVCaptureSession alloc] init];
self.mCaptureSession.sessionPreset = AVCaptureSessionPreset640x480;

if ([self.mCaptureSession canAddInput:self.mCaptureDeviceInput]) 
{
    [self.mCaptureSession addInput:self.mCaptureDeviceInput];
}

if ([self.mCaptureSession canAddOutput:self.mCaptureDeviceOutput]) 
{
    [self.mCaptureSession addOutput:self.mCaptureDeviceOutput];
}

c. 开启采集;

[self.mCaptureSession startRunning];

d. 处理采集处理

- (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection;

获取采集图像的属性

//分辨率
CVImageBufferRef cameraFrame = CMSampleBufferGetImageBuffer(sampleBuffer);
int frameWidth = (int)CVPixelBufferGetWidth(cameraFrame);
int frameHeight = (int)CVPixelBufferGetHeight(cameraFrame);

2. 关键环节说明

视频流聚焦关注的的属性有:
  • 分辨率
  • 帧率
  • 码率
  • 开播方向(videoOrientation)

2.1. 设置采集分辨率

AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset320x240 API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos);
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset352x288 API_AVAILABLE(macos(10.7), ios(5.0)) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset640x480 API_AVAILABLE(macos(10.7), ios(4.0)) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset960x540 API_AVAILABLE(macos(10.7)) API_UNAVAILABLE(ios, watchos, tvos);
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset1280x720 API_AVAILABLE(macos(10.7), ios(4.0)) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset1920x1080 API_AVAILABLE(ios(5.0)) API_UNAVAILABLE(macos) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;
AVF_EXPORT AVCaptureSessionPreset const AVCaptureSessionPreset3840x2160 API_AVAILABLE(ios(9.0)) API_UNAVAILABLE(macos) __WATCHOS_PROHIBITED __TVOS_PROHIBITED;

设备对应的最大sessionPreset

- (NSString *)getMaxPresetInDevice
{
    NSArray *totallArray = @[
        @"iPhone1,1",  @"iPhone 2G (A1203)",                         AVCaptureSessionPreset352x288,
        @"iPhone1,2",  @"iPhone 3G (A1241/A1324)",                   AVCaptureSessionPreset352x288,
        @"iPhone2,1",  @"iPhone 3GS (A1303/A1325)",                  AVCaptureSessionPreset352x288,
        @"iPhone3,1",  @"iPhone 4 (A1332)",                          AVCaptureSessionPreset640x480,
        @"iPhone3,2",  @"iPhone 4 (A1332)",                          AVCaptureSessionPreset640x480,
        @"iPhone3,3",  @"iPhone 4 (A1349)",                          AVCaptureSessionPreset640x480,
        @"iPhone4,1",  @"iPhone 4S (A1387/A1431)",                   AVCaptureSessionPreset640x480,
        @"iPhone5,1",  @"iPhone 5 (A1428)",                          AVCaptureSessionPreset1280x720,
        @"iPhone5,2",  @"iPhone 5 (A1429/A1442)",                    AVCaptureSessionPreset1280x720,
        @"iPhone5,3",  @"iPhone 5c (A1456/A1532)",                   AVCaptureSessionPreset1280x720,
        @"iPhone5,4",  @"iPhone 5c (A1507/A1516/A1526/A1529)",       AVCaptureSessionPreset1280x720,
        @"iPhone6,1",  @"iPhone 5s (A1453/A1533)",                   AVCaptureSessionPreset1280x720,
        @"iPhone6,2",  @"iPhone 5s (A1457/A1518/A1528/A1530)",       AVCaptureSessionPreset1280x720,
        @"iPhone7,1",  @"iPhone 6 Plus (A1522/A1524)",               AVCaptureSessionPreset1280x720,
        @"iPhone7,2",  @"iPhone 6 (A1549/A1586)",                    AVCaptureSessionPreset1280x720,
        @"iPod1,1",    @"iPod Touch 1G (A1213)",                     AVCaptureSessionPreset352x288,
        @"iPod2,1",    @"iPod Touch 2G (A1288)",                     AVCaptureSessionPreset352x288,
        @"iPod3,1",    @"iPod Touch 3G (A1318)",                     AVCaptureSessionPreset352x288,
        @"iPod4,1",    @"iPod Touch 4G (A1367)",                     AVCaptureSessionPreset640x480,
        @"iPod5,1",    @"iPod Touch 5G (A1421/A1509)",               AVCaptureSessionPreset1280x720,
        @"iPad1,1",    @"iPad 1G (A1219/A1337)",                     AVCaptureSessionPreset640x480,
        @"iPad2,1",    @"iPad 2 (A1395)",                            AVCaptureSessionPreset640x480,
        @"iPad2,2",    @"iPad 2 (A1396)",                            AVCaptureSessionPreset640x480,
        @"iPad2,3",    @"iPad 2 (A1397)",                            AVCaptureSessionPreset640x480,
        @"iPad2,4",    @"iPad 2 (A1395+New Chip)",                   AVCaptureSessionPreset640x480,
        @"iPad2,5",    @"iPad Mini 1G (A1432)",                      AVCaptureSessionPreset1280x720,
        @"iPad2,6",    @"iPad Mini 1G (A1454)",                      AVCaptureSessionPreset1280x720,
        @"iPad2,7",    @"iPad Mini 1G (A1455)",                      AVCaptureSessionPreset1280x720,
        @"iPad3,1",    @"iPad 3 (A1416)",                            AVCaptureSessionPreset640x480,
        @"iPad3,2",    @"iPad 3 (A1403)",                            AVCaptureSessionPreset640x480,
        @"iPad3,3",    @"iPad 3 (A1430)",                            AVCaptureSessionPreset640x480,
        @"iPad3,4",    @"iPad 4 (A1458)",                            AVCaptureSessionPreset1280x720,
        @"iPad3,5",    @"iPad 4 (A1459)",                            AVCaptureSessionPreset1280x720,
        @"iPad3,6",    @"iPad 4 (A1460)",                            AVCaptureSessionPreset1280x720,
        @"iPad4,1",    @"iPad Air (A1474)",                          AVCaptureSessionPreset1280x720,
        @"iPad4,2",    @"iPad Air (A1475)",                          AVCaptureSessionPreset1280x720,
        @"iPad4,3",    @"iPad Air (A1476)",                          AVCaptureSessionPreset1280x720,
        @"iPad4,4",    @"iPad Mini 2G (A1489)",                      AVCaptureSessionPreset1280x720,
        @"iPad4,5",    @"iPad Mini 2G (A1490)",                      AVCaptureSessionPreset1280x720,
        @"iPad4,6",    @"iPad Mini 2G (A1491)",                      AVCaptureSessionPreset1280x720,];

struct utsname systemInfo;//#import 
uname(&systemInfo);
NSString* modelName = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
NSInteger modelIndex = [totallArray indexOfObject:modelName];
if (modelIndex >= 0 && modelIndex 

2.2 帧率

根据设定的分辨率,查看对应分辨率可以支持的最大帧率

for (AVCaptureDeviceFormat *vFormat in [videoDevice formats]) {
        CMFormatDescriptionRef description = vFormat.formatDescription;
        float maxSupportedRate = ((AVFrameRateRange*)[vFormat.videoSupportedFrameRateRanges objectAtIndex:0]).maxFrameRate;
        CMVideoDimensions dimensions = CMVideoFormatDescriptionGetDimensions(description);
        FourCharCode mediaSubType = CMFormatDescriptionGetMediaSubType(description);
        
        int width = dimensions.width;
        int height = dimensions.height;
        
        if (preWidth == width &&
            preHeight == height &&
            mediaSubType == '420f') {
              .......
        }
    }

根据帧率设置帧时长

if (YES == [videoDevice lockForConfiguration:NULL]) 
{
     videoDevice.activeFormat = vFormat;
     [videoDevice setActiveVideoMinFrameDuration:CMTimeMake(1, maxSupportedRate)];
     [videoDevice setActiveVideoMaxFrameDuration:CMTimeMake(1, maxSupportedRate)];
     [videoDevice unlockForConfiguration];
}

2.3 切换摄像头,设置方向

  录制过程中,切换前后摄像头是不可避免的,设置过程必须调用 beginConfiguration 和 commitConfiguration;

AVCaptureDevicePosition  currentCamera;
AVCaptureSession    *captureSession;

/*!
 @method beginConfiguration
 @abstract
    When paired with commitConfiguration, allows a client to batch multiple configuration operations on a running session into atomic updates.
 
 @discussion
    -beginConfiguration / -commitConfiguration are AVCaptureSession's mechanism for batching multiple configuration operations on a running session into atomic updates. After calling [session beginConfiguration], clients may add or remove outputs, alter the sessionPreset, or configure individual AVCaptureInput or Output properties. All changes will be pended until the client calls [session commitConfiguration], at which time they will be applied together. -beginConfiguration / -commitConfiguration pairs may be nested, and will only be applied when the outermost commit is invoked.
 */
[captureSession beginConfiguration];
  
AVCaptureInput *input = [[captureSession inputs] objectAtIndex:0];
if(currentCamera == AVCaptureDevicePositionFront && input == frontCamera && backCamera != nil)
{
   [captureSession removeInput:input];
   [captureSession addInput: backCamera];
   currentCamera = AVCaptureDevicePositionBack;
} 
else if (currentCamera == AVCaptureDevicePositionBack && frontCamera != nil) 
{
   [captureSession removeInput:input];
   [captureSession addInput: frontCamera];
   currentCamera = AVCaptureDevicePositionFront;
}
    
//设置竖屏采集
AVCaptureVideoOrientation videoOrientation = AVCaptureVideoOrientationPortrait;
    
for(NSUInteger index = 0; index 

2.4 镜像

  IOS的前置摄像头采集到的数据本来就是翻转的,这里设置为镜像把画面转回来;否则保存下来的视频是Y轴镜像的,如果有文字的话就会看的比较清晰,字体是反的;

//处理前置摄像头的镜像效果
AVCaptureConnection *connection = [self.mCaptureDeviceOutput connectionWithMediaType:AVMediaTypeVideo];
[connection setVideoOrientation:AVCaptureVideoOrientationPortraitUpsideDown];
AVCaptureDevicePosition currentPosition=[inputCamera position];
if (currentPosition == AVCaptureDevicePositionUnspecified || currentPosition == AVCaptureDevicePositionFront) 
{
    connection.videoMirrored = YES;//注意这里需要进行镜面翻转处理,否则录制的效果是反的。
} 
else
{
    connection.videoMirrored = NO;
}

文章来源于互联网,如有雷同请联系站长删除:视频采集

发表评论