iOS开发了好几年了,自定义相机都碰到过很多次,每次都是从网上copy代码使用,但是很多时候都会有方向等问题,从来没有真正研究过,现在在这里记录一下自定义相机碰到的问题,以防忘记
问题一:横向拍照/录制视频,得到的视频也需要横屏。
要实现这个功能,就需要获取到设备的方向,这里有两种方法获取方向
方法一:根据设备方向开关来获取方向,[UIDevice currentDevice].orientation
方法二:根据重力感应获取方向
DN_WEAK_SELF if([self.cmmotionManager isDeviceMotionAvailable]) { [self.cmmotionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) { DN_STRONG_SELF double x = accelerometerData.acceleration.x; double y = accelerometerData.acceleration.y; if (fabs(y) >= fabs(x)) { if (y >= 0) { //Down self.deviceOrientation = UIDeviceOrientationPortraitUpsideDown; } else { //Portrait self.deviceOrientation = UIDeviceOrientationPortrait; } } else { if (x >= 0) { //Righ self.deviceOrientation = UIDeviceOrientationLandscapeRight; } else { //Left self.deviceOrientation = UIDeviceOrientationLandscapeLeft; } } }]; }
获取到方向后,在拍照前设置方向
AVCaptureConnection *myVideoConnection = [self.ImageOutPut connectionWithMediaType:AVMediaTypeVideo]; if ([myVideoConnection isVideoOrientationSupported]) { myVideoConnection.videoOrientation = [self getCaptureVideoOrientation:self.deviceOrientation]; }
在录制视频前设置方向
AVCaptureConnection *connection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo]; if ([connection isVideoOrientationSupported]) { connection.videoOrientation = [self getCaptureVideoOrientation:self.deviceOrientation]; }
问题二: 前置摄像头拍照时,照片和视频左右颠倒(类似微信)
这个问题其实很简单,只要设置一下输出对象的镜像开关就可以了
AVCaptureSession *session = (AVCaptureSession *)self.session; for (AVCaptureVideoDataOutput* output in session.outputs) { for (AVCaptureConnection * av in output.connections) { //判断是否是前置摄像头状态 if ([self.input device].position == AVCaptureDevicePositionFront) { if (av.supportsVideoMirroring) { //镜像设置 av.videoMirrored = YES; } } } }
录制视频的话,解决左右颠倒 只能用以上的方法
而拍照的话,解决左右颠倒,还有一种方法,在拍完照片后,设置图片方向
UIImageOrientation imgOrientation; //拍摄后获取的的图像方向 if ([self.input device].position == AVCaptureDevicePositionFront && self.isFixLeftRightProblem) { NSLog(@"前置摄像头"); // 前置摄像头图像方向 UIImageOrientationLeftMirrored // IOS前置摄像头左右成像 imgOrientation = UIImageOrientationLeftMirrored; if (image.imageOrientation == UIImageOrientationRight) { imgOrientation = UIImageOrientationLeftMirrored; }else if (image.imageOrientation == UIImageOrientationLeft) { imgOrientation = UIImageOrientationRightMirrored; }else if (image.imageOrientation == UIImageOrientationDown) { imgOrientation = UIImageOrientationDownMirrored; }else if (image.imageOrientation == UIImageOrientationUp) { imgOrientation = UIImageOrientationUpMirrored; } image = [[UIImage alloc]initWithCGImage:image.CGImage scale:1.0f orientation:imgOrientation]; }
问题三:自定义相机拍照后,在其他端查看时,方向不正确
这时候就需要矫正方向了
/*! ** 矫正图片方向 参考 http://www.cocoachina.com/articles/12021 */ - (UIImage *)fixOrientation { // No-op if the orientation is already correct if (self.imageOrientation == UIImageOrientationUp) return self; // We need to calculate the proper transformation to make the image upright. // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored. CGAffineTransform transform = CGAffineTransformIdentity; switch (self.imageOrientation) { case UIImageOrientationDown: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height); transform = CGAffineTransformRotate(transform, M_PI); break; case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, 0); transform = CGAffineTransformRotate(transform, M_PI_2); break; case UIImageOrientationRight: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate(transform, 0, self.size.height); transform = CGAffineTransformRotate(transform, -M_PI_2); break; case UIImageOrientationUp: case UIImageOrientationUpMirrored: break; } switch (self.imageOrientation) { case UIImageOrientationUpMirrored: case UIImageOrientationDownMirrored: transform = CGAffineTransformTranslate(transform, self.size.width, 0); transform = CGAffineTransformScale(transform, -1, 1); break; case UIImageOrientationLeftMirrored: case UIImageOrientationRightMirrored: transform = CGAffineTransformTranslate(transform, self.size.height, 0); transform = CGAffineTransformScale(transform, -1, 1); break; case UIImageOrientationUp: case UIImageOrientationDown: case UIImageOrientationLeft: case UIImageOrientationRight: break; } // Now we draw the underlying CGImage into a new context, applying the transform // calculated above. CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height, CGImageGetBitsPerComponent(self.CGImage), 0, CGImageGetColorSpace(self.CGImage), CGImageGetBitmapInfo(self.CGImage)); CGContextConcatCTM(ctx, transform); switch (self.imageOrientation) { case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: case UIImageOrientationRight: case UIImageOrientationRightMirrored: // Grr... CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage); break; default: CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage); break; } // And now we just create a new UIImage from the drawing context CGImageRef cgimg = CGBitmapContextCreateImage(ctx); UIImage *img = [UIImage imageWithCGImage:cgimg]; CGContextRelease(ctx); CGImageRelease(cgimg); return img; }
问题四:自定义相机打开后,这时候来电话了,再切回到相机不能拍照了。
这里就需要监听音频中断的通知AVCaptureSessionWasInterruptedNotification,中断结束的通知AVCaptureSessionInterruptionEndedNotification
还要监听系统电话来电 CTCallCenter callEventHandler,在中断通知AVCaptureSessionWasInterruptedNotification中,将音频输入设备从session中移除,等中断通知结束后,判断是否时系统电话造成的,如果是则将音频输入设备加入session
监听来电的代码 <CoreTelephony/CTCallCenter.h> <CoreTelephony/CTCall.h>
DN_WEAK_SELF self.callCenter = [[CTCallCenter alloc] init]; self.callCenter.callEventHandler = ^(CTCall * call) { DN_STRONG_SELF if([call.callState isEqualToString:CTCallStateDisconnected]) { NSLog(@"Call has been disconnected");//电话被挂断(我们用的这个) self.isSystemCall = NO; } else if([call.callState isEqualToString:CTCallStateConnected]) { NSLog(@"Call has been connected");//电话被接听 } else if([call.callState isEqualToString:CTCallStateIncoming]) { NSLog(@"Call is incoming");//来电话了 self.isSystemCall = YES; [self endCall]; } else if([call.callState isEqualToString:CTCallStateDialing]) { NSLog(@"Call is Dialing");//拨号 self.isSystemCall = YES; [self endCall]; } else { NSLog(@"Nothing is done"); } };
中断音频代码
- (void)initNotification { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVCaptureSessionWasInterruptedNotification:) name:AVCaptureSessionWasInterruptedNotification object:self.session]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVCaptureSessionInterruptionEndedNotification:) name:AVCaptureSessionInterruptionEndedNotification object:self.session]; } #pragma mark - 通知 - (void)AVCaptureSessionWasInterruptedNotification:(NSNotification *)notification { AVCaptureSessionInterruptionReason reason = [notification.userInfo[AVCaptureSessionInterruptionReasonKey] integerValue]; NSLog(@"fanshijian 中断 : %d reason : %ld",self.session.interrupted,(long)reason); if (reason == AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient) { [self removeAudioInput]; } } - (void)AVCaptureSessionInterruptionEndedNotification:(NSNotification *)notification { NSLog(@"fanshijian 中断结束 : %d",self.session.interrupted); if (![DNVideoChatConfig sharedConfig].isSystemCall) { [self addAudioInput]; } } - (void)addAudioInput { if (!_audioCaptureDeviceInput) { //添加一个音频输入设备 AVCaptureDevice *audioCaptureDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject]; //添加音频 NSError *error = nil; AVCaptureDeviceInput *audioCaptureDeviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:audioCaptureDevice error:&error]; if (error) { NSLog(@"取得设备输入对象时出错,错误原因:%@",error.localizedDescription); return; } self.audioCaptureDeviceInput = audioCaptureDeviceInput; } if ([self.session canAddInput:self.audioCaptureDeviceInput]) { [self.session addInput:self.audioCaptureDeviceInput]; } } - (void)removeAudioInput { [self.session removeInput:self.audioCaptureDeviceInput]; }
可以参考demo https://github.com/smallMas/FSEditVideo.git 类FSLiveWindow
文章来源: 博客园
- 还没有人评论,欢迎说说您的想法!