视频采集
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;
}
文章来源于互联网,如有雷同请联系站长删除:视频采集