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

iOS开发了好几年了,自定义相机都碰到过很多次,每次都是从网上copy代码使用,但是很多时候都会有方向等问题,从来没有真正研究过,现在在这里记录一下自定义相机碰到的问题,以防忘记
问题一:横向拍照/录制视频,得到的视频也需要横屏。
    要实现这个功能,就需要获取到设备的方向,这里有两种方法获取方向
    方法一:根据设备方向开关来获取方向,[UIDevice currentDevice].orientation
    方法二:根据重力感应获取方向


  1. DN_WEAK_SELF
  2. if([self.cmmotionManager isDeviceMotionAvailable]) {
  3. [self.cmmotionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMAccelerometerData * _Nullable accelerometerData, NSError * _Nullable error) {
  4. DN_STRONG_SELF
  5. double x = accelerometerData.acceleration.x;
  6. double y = accelerometerData.acceleration.y;
  7. if (fabs(y) >= fabs(x)) {
  8. if (y >= 0) {
  9. //Down
  10. self.deviceOrientation = UIDeviceOrientationPortraitUpsideDown;
  11. } else {
  12. //Portrait
  13. self.deviceOrientation = UIDeviceOrientationPortrait;
  14. }
  15. } else {
  16. if (x >= 0) {
  17. //Righ
  18. self.deviceOrientation = UIDeviceOrientationLandscapeRight;
  19. } else {
  20. //Left
  21. self.deviceOrientation = UIDeviceOrientationLandscapeLeft;
  22. }
  23. }
  24. }];
  25. }

 

     获取到方向后,在拍照前设置方向


  1. AVCaptureConnection *myVideoConnection = [self.ImageOutPut connectionWithMediaType:AVMediaTypeVideo];
  2. if ([myVideoConnection isVideoOrientationSupported]) {
  3. myVideoConnection.videoOrientation = [self getCaptureVideoOrientation:self.deviceOrientation];
  4. }

 

     在录制视频前设置方向


  1. AVCaptureConnection *connection = [self.captureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
  2. if ([connection isVideoOrientationSupported]) {
  3. connection.videoOrientation = [self getCaptureVideoOrientation:self.deviceOrientation];
  4. }

 

 

问题二: 前置摄像头拍照时,照片和视频左右颠倒(类似微信)

    这个问题其实很简单,只要设置一下输出对象的镜像开关就可以了


  1. AVCaptureSession *session = (AVCaptureSession *)self.session;
  2. for (AVCaptureVideoDataOutput* output in session.outputs) {
  3. for (AVCaptureConnection * av in output.connections) {
  4. //判断是否是前置摄像头状态
  5.  
  6. if ([self.input device].position == AVCaptureDevicePositionFront) {
  7. if (av.supportsVideoMirroring) {
  8. //镜像设置
  9. av.videoMirrored = YES;
  10. }
  11. }
  12. }
  13. }

 

 

    录制视频的话,解决左右颠倒 只能用以上的方法

    而拍照的话,解决左右颠倒,还有一种方法,在拍完照片后,设置图片方向


  1. UIImageOrientation imgOrientation; //拍摄后获取的的图像方向
  2.  
  3. if ([self.input device].position == AVCaptureDevicePositionFront &&
  4. self.isFixLeftRightProblem) {
  5. NSLog(@"前置摄像头");
  6. // 前置摄像头图像方向 UIImageOrientationLeftMirrored
  7. // IOS前置摄像头左右成像
  8. imgOrientation = UIImageOrientationLeftMirrored;
  9. if (image.imageOrientation == UIImageOrientationRight) {
  10. imgOrientation = UIImageOrientationLeftMirrored;
  11. }else if (image.imageOrientation == UIImageOrientationLeft) {
  12. imgOrientation = UIImageOrientationRightMirrored;
  13. }else if (image.imageOrientation == UIImageOrientationDown) {
  14. imgOrientation = UIImageOrientationDownMirrored;
  15. }else if (image.imageOrientation == UIImageOrientationUp) {
  16. imgOrientation = UIImageOrientationUpMirrored;
  17. }
  18. image = [[UIImage alloc]initWithCGImage:image.CGImage scale:1.0f orientation:imgOrientation];
  19. }

 

问题三:自定义相机拍照后,在其他端查看时,方向不正确

    这时候就需要矫正方向了


  1. /*
    !
  2. ** 矫正图片方向 参考 http://www.cocoachina.com/articles/12021
  3.  
  4. */
  5.  
  6. - (UIImage *)fixOrientation {
  7. // No-op if the orientation is already correct
  8.  
  9. if (self.imageOrientation == UIImageOrientationUp) return self;
  10. // We need to calculate the proper transformation to make the image upright.
  11. // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
  12. CGAffineTransform transform = CGAffineTransformIdentity;
  13. switch (self.imageOrientation) {
  14. case UIImageOrientationDown:
  15. case UIImageOrientationDownMirrored:
  16. transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
  17. transform = CGAffineTransformRotate(transform, M_PI);
  18. break;
  19. case UIImageOrientationLeft:
  20. case UIImageOrientationLeftMirrored:
  21. transform = CGAffineTransformTranslate(transform, self.size.width, 0);
  22. transform = CGAffineTransformRotate(transform, M_PI_2);
  23. break;
  24. case UIImageOrientationRight:
  25. case UIImageOrientationRightMirrored:
  26. transform = CGAffineTransformTranslate(transform, 0, self.size.height);
  27. transform = CGAffineTransformRotate(transform, -M_PI_2);
  28. break;
  29. case UIImageOrientationUp:
  30. case UIImageOrientationUpMirrored:
  31. break;
  32. }
  33. switch (self.imageOrientation) {
  34. case UIImageOrientationUpMirrored:
  35. case UIImageOrientationDownMirrored:
  36. transform = CGAffineTransformTranslate(transform, self.size.width, 0);
  37. transform = CGAffineTransformScale(transform, -1, 1);
  38. break;
  39. case UIImageOrientationLeftMirrored:
  40. case UIImageOrientationRightMirrored:
  41. transform = CGAffineTransformTranslate(transform, self.size.height, 0);
  42. transform = CGAffineTransformScale(transform, -1, 1);
  43. break;
  44. case UIImageOrientationUp:
  45. case UIImageOrientationDown:
  46. case UIImageOrientationLeft:
  47. case UIImageOrientationRight:
  48. break;
  49. }
  50. // Now we draw the underlying CGImage into a new context, applying the transform
  51. // calculated above.
  52. CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
  53. CGImageGetBitsPerComponent(self.CGImage), 0,
  54. CGImageGetColorSpace(self.CGImage),
  55. CGImageGetBitmapInfo(self.CGImage));
  56. CGContextConcatCTM(ctx, transform);
  57. switch (self.imageOrientation) {
  58. case UIImageOrientationLeft:
  59. case UIImageOrientationLeftMirrored:
  60. case UIImageOrientationRight:
  61. case UIImageOrientationRightMirrored:
  62. // Grr...
  63. CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
  64. break;
  65. default:
  66. CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
  67. break;
  68. }
  69. // And now we just create a new UIImage from the drawing context
  70. CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
  71. UIImage *img = [UIImage imageWithCGImage:cgimg];
  72. CGContextRelease(ctx);
  73. CGImageRelease(cgimg);
  74. return img;
  75. }

 

问题四:自定义相机打开后,这时候来电话了,再切回到相机不能拍照了。

   这里就需要监听音频中断的通知AVCaptureSessionWasInterruptedNotification,中断结束的通知AVCaptureSessionInterruptionEndedNotification

     还要监听系统电话来电  CTCallCenter  callEventHandler,在中断通知AVCaptureSessionWasInterruptedNotification中,将音频输入设备从session中移除,等中断通知结束后,判断是否时系统电话造成的,如果是则将音频输入设备加入session

   监听来电的代码 <CoreTelephony/CTCallCenter.h>  <CoreTelephony/CTCall.h>


  1. DN_WEAK_SELF
  2. self.callCenter = [[CTCallCenter alloc] init];
  3. self.callCenter.callEventHandler = ^(CTCall * call) {
  4. DN_STRONG_SELF
  5. if([call.callState isEqualToString:CTCallStateDisconnected]) {
  6. NSLog(@"Call has been disconnected");//电话被挂断(我们用的这个)
  7. self.isSystemCall = NO;
  8. } else if([call.callState isEqualToString:CTCallStateConnected]) {
  9. NSLog(@"Call has been connected");//电话被接听
  10. } else if([call.callState isEqualToString:CTCallStateIncoming]) {
  11. NSLog(@"Call is incoming");//来电话了
  12. self.isSystemCall = YES;
  13. [self endCall];
  14. } else if([call.callState isEqualToString:CTCallStateDialing]) {
  15. NSLog(@"Call is Dialing");//拨号
  16. self.isSystemCall = YES;
  17. [self endCall];
  18. } else {
  19. NSLog(@"Nothing is done");
  20. }
  21. };

 

    中断音频代码

 

  1. - (void)initNotification {
  2. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVCaptureSessionWasInterruptedNotification:) name:AVCaptureSessionWasInterruptedNotification object:self.session];
  3. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(AVCaptureSessionInterruptionEndedNotification:) name:AVCaptureSessionInterruptionEndedNotification object:self.session];
  4. }
  5. #pragma mark - 通知
  6.  
  7. - (void)AVCaptureSessionWasInterruptedNotification:(NSNotification *)notification {
  8. AVCaptureSessionInterruptionReason reason = [notification.userInfo[AVCaptureSessionInterruptionReasonKey] integerValue];
  9. NSLog(@"fanshijian 中断 : %d reason : %ld",self.session.interrupted,(long)reason);
  10. if (reason == AVCaptureSessionInterruptionReasonAudioDeviceInUseByAnotherClient) {
  11. [self removeAudioInput];
  12. }
  13. }
  14. - (void)AVCaptureSessionInterruptionEndedNotification:(NSNotification *)notification {
  15. NSLog(@"fanshijian 中断结束 : %d",self.session.interrupted);
  16. if (![DNVideoChatConfig sharedConfig].isSystemCall) {
  17. [self addAudioInput];
  18. }
  19. }
  20. - (void)addAudioInput {
  21. if (!_audioCaptureDeviceInput) {
  22. //添加一个音频输入设备
  23. AVCaptureDevice *audioCaptureDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
  24. //添加音频
  25. NSError *error = nil;
  26. AVCaptureDeviceInput *audioCaptureDeviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:audioCaptureDevice error:&error];
  27. if (error) {
  28. NSLog(@"取得设备输入对象时出错,错误原因:%@",error.localizedDescription);
  29. return;
  30. }
  31. self.audioCaptureDeviceInput = audioCaptureDeviceInput;
  32. }
  33. if ([self.session canAddInput:self.audioCaptureDeviceInput]) {
  34. [self.session addInput:self.audioCaptureDeviceInput];
  35. }
  36. }
  37. - (void)removeAudioInput {
  38. [self.session removeInput:self.audioCaptureDeviceInput];
  39. }

 可以参考demo https://github.com/smallMas/FSEditVideo.git     类FSLiveWindow

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

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号