经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 移动开发 » iOS » 查看文章
自定义相机碰到的问题,比如常见的拍照录制视频方向,镜像左右颠倒等问题
来源:cnblogs  作者:辣手小火星  时间:2020/11/9 16:00:46  对本文有异议

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

原文链接:http://www.cnblogs.com/smallMas/p/13809349.html

 友情链接: NPS