1、视频采集流程

iOS采集器的基本结构图如下:

iOS采集相关架构图

从图里可以看到,我们可以通过AVCapture Device Input创建输入资源,通过Session搭配AVCaptureMovieFileOutput(或者AVCaptureStillImageOutput)来进行资源的输出,也可以通过AVCaptureVideoPreviewLayer来进行预览。本章,我们就简要的介绍下这全流程。

创建Session

// 管理输入和输出映射的采集器

AVCaptureSession* session = [[AVCaptureSession alloc] init];

获取系统设备指针

// 获取系统设备信息

AVCaptureDeviceDiscoverySession* deviceDiscoverySession = [AVCaptureDeviceDiscoverySession discoverySessionWithDeviceTypes:@[AVCaptureDeviceTypeBuiltInWideAngleCamera] mediaType:AVMediaTypeVideo position:self.config.position];

NSArray* devices = deviceDiscoverySession.devices;

for (AVCaptureDevice* device in devices) {

if (device.position == self.config.position) {

self.device = device;

break;

}

}

相关函数原型介绍:

/*!

* @brief 创建相关的采集设备

* @param deviceTypes 设备的类型,可参考AVCaptureDeviceType相关变量,后续在做详细的解释。

* @param mediaType 需要采集的视频格式,音频或者视频。

* @param position 采集摄像头的方位,前置或者后置。

* @return 成功则返回相关的采集设备。

*/

+ (instancetype)discoverySessionWithDeviceTypes:(NSArray *)deviceTypes mediaType:(nullable AVMediaType)mediaType position:(AVCaptureDevicePosition)position;

@end

到此,可以获取到相关的采集设备指针,该指针可用于创建创建输入。

配置Session

之后,我们需要配置Session,以至于其能够很好的对接从device过来的输入,然后转换为我们需要的输出。

[self.session beginConfiguration];

// 从设备中创建输入,之后需要设置到session

NSError* error = nil;

self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:&error];

if (error) {

NSLog(@"%s:%d init input error!!!", __func__, __LINE__);

return;

}

// 设置session的输入

if ([self.session canAddInput:self.videoInput]) {

[self.session addInput:self.videoInput];

}

// 配置session的输出

self.videoOutput = [[AVCaptureVideoDataOutput alloc] init];

// 禁止丢帧

self.videoOutput.alwaysDiscardsLateVideoFrames = NO;

// 设置输出的PixelBuffer的类型,这里可以设置为:

// kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange

// kCVPixelFormatType_420YpCbCr8BiPlanarFullRange

// kCVPixelFormatType_32BGRA

[self.videoOutput setVideoSettings:@{(__bridge NSString*)kCVPixelBufferPixelFormatTypeKey:@(self.config.pixelBufferType)}];

// 设置output的数据回调,需要为AVCaptureVideoDataOutputSampleBufferDelegate协议的实现者。

dispatch_queue_t captureQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

[self.videoOutput setSampleBufferDelegate:self queue:captureQueue];

if ([self.session canAddOutput:self.videoOutput]) {

[self.session addOutput:self.videoOutput];

}

// 设置连接器

AVCaptureConnection* connect = [self.videoOutput connectionWithMediaType:AVMediaTypeVideo];

// 设置图源的显示方位,具体可以参考AVCaptureVideoOrientation枚举。

connect.videoOrientation = self.config.orientation;

if ([connect isVideoStabilizationSupported]) {

connect.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;

}

// 设置图片的缩放程度,实际上的效果不如设置Layer的顶点位置。

connect.videoScaleAndCropFactor = connect.videoMaxScaleAndCropFactor;

[self.session commitConfiguration];

开始采集

- (void)startCapture {

if (self.session) {

[self.session startRunning];

}

}

停止采集

- (void)stopCapture {

if (self.session) {

[self.session stopRunning];

}

}

配置数据回调

#pragma mark AVCaptureVideoDataOutputSampleBufferDelegate

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

if (self.delegate && [self.delegate respondsToSelector:@selector(onVideoWithSampleBuffer:)]) {

[self.delegate onVideoWithSampleBuffer:sampleBuffer];

}

}

结果展示图

结果展示图

2、美颜

音视频使用美颜滤镜,我们会选择GPUImage来获取视频数据。

GPUImage是一个可以为录制视频添加实时滤镜的一个著名第三方库。

该框架大概原理是,使用OpenGL着色器对视频图像进行颜色处理,然后存到frameBuffer,之后可以对此数据再次处理。重复上述过程,即可达到多重滤镜效果。

具体实现不细说,这里简要介绍一下GPUImage的使用,如何美颜,如何获取音视频数据。

使用GPUImage

GPUImage的主要代码在 AWGPUImageAVCapture 这个类中。

初始化AWAVCaptureManager对象时将captureType设为AWAVCaptureTypeGPUImage,就会自动调用AWGPUImageAVCapture类来捕获视频数据。

代码在 onInit 方法中:

-(void)onInit{

//摄像头初始化

// AWGPUImageVideoCamera 继承自 GPUImageVideoCamera。继承是为了获取音频数据,原代码中,默认情况下音频数据发送给了 audioEncodingTarget。

// 这个东西一看类型是GPUImageMovieWriter,应该是文件写入功能。果断覆盖掉processAudioSampleBuffer方法,拿到音频数据后自己处理。

// 音频就这样可以了,GPUImage主要工作还是在视频处理这里。

// 设置预览分辨率 self.captureSessionPreset是根据AWVideoConfig的设置,获取的分辨率。设置前置、后置摄像头。

_videoCamera = [[AWGPUImageVideoCamera alloc] initWithSessionPreset:self.captureSessionPreset cameraPosition:AVCaptureDevicePositionFront];

//开启捕获声音

[_videoCamera addAudioInputsAndOutputs];

//设置输出图像方向,可用于横屏推流。

_videoCamera.outputImageOrientation = UIInterfaceOrientationPortrait;

//镜像策略,这里这样设置是最自然的。跟系统相机默认一样。

_videoCamera.horizontallyMirrorRearFacingCamera = NO;

_videoCamera.horizontallyMirrorFrontFacingCamera = YES;

//设置预览view

_gpuImageView = [[GPUImageView alloc] initWithFrame:self.preview.bounds];

[self.preview addSubview:_gpuImageView];

//初始化美颜滤镜

_beautifyFilter = [[GPUImageBeautifyFilter alloc] init];

//相机获取视频数据输出至美颜滤镜

[_videoCamera addTarget:_beautifyFilter];

//美颜后输出至预览

[_beautifyFilter addTarget:_gpuImageView];

// 到这里我们已经能够打开相机并预览了。

// 因为要推流,除了预览之外,我们还要截取到视频数据。这就需要使用GPUImage中的GPUImageRawDataOutput,它能将美颜后的数据输出,便于我们处理后发送出去。

// AWGPUImageAVCaptureDataHandler继承自GPUImageRawDataOutput,从 newFrameReadyAtTime 方法中就可以获取到美颜后输出的数据。

// 输出的图片格式为BGRA。

_dataHandler = [[AWGPUImageAVCaptureDataHandler alloc] initWithImageSize:CGSizeMake(self.videoConfig.width, self.videoConfig.height) resultsInBGRAFormat:YES capture:self];

[_beautifyFilter addTarget:_dataHandler];

// 令AWGPUImageAVCaptureDataHandler实现AWGPUImageVideoCameraDelegate协议,并且让camera的awAudioDelegate指向_dataHandler对象。

// 将音频数据转到_dataHandler中处理。然后音视频数据就可以都在_dataHandler中处理了

相关文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。