美文网首页about iOSiOS 开发 iOS Developer
使用系统界面拍摄视频及系统问题

使用系统界面拍摄视频及系统问题

作者: RY_zheng | 来源:发表于2015-12-20 20:47 被阅读1321次

    目前,将视频捕获集成到你的应用中的最简单的方法是使用 UIImagePickerController。这是一个封装了完整视频捕获管线和相机 UI 的 view controller。用UIImagePickerController可以自定义系统提供的界面来拍摄并保存视频和照片。

    UIImagePickerController 里有几个比较重要的属性.
    • ** Source type** :
      这个参数是用来确定是调用摄像头还是调用图片库.
      UIImagePickerControllerSourceTypeCamera : 提供调用摄像头的界面来拍摄照片视频。
      UIImagePickerControllerSourceTypePhotoLibrary 调用图片库作为UIImagePickerController数据源。
      UIImagePickerControllerSourceTypeSavedPhotosAlbum iOS设备中的胶卷相机的图片.作为UIImagePickerController数据源

    • Mediatypes:
      NSArray数组。拍摄时:这个属性决定UIImagePickerController界面模式是拍照还是录像.查看已保存多媒体数据,可决定展示的是照片还是视频。
      kUTTypeImage 表示静态图片, kUTTypeMovie表示录像.把空数组传给这个属性会报异常。在设置此属性前,需要用availableMediaTypesForSourceType:类方法判断这种多媒体类型是否被支持。

    • **Editing controls **:
      用来指定是否可编辑.将allowsEditing 属性设置为YES表示可编辑,NO表示不可编辑.

    • delegate
      id <UINavigationControllerDelegate, UIImagePickerControllerDelegate> delegate:
      使用 UIImagePickerController,必须提供遵守UIImagePickerControllerDelegate和UINavigationControllerDelegate协议
      的delegate对象.UIImagePickerControllerDelegate提供了两个方法来在照相完成后,与UIImagePickerController对象界面进行交互。
      imagePickerController:didFinishPickingMediaWithInfo: delegate使用拍摄的照片或者视频的处理逻辑.
      imagePickerControllerDidCancel(_:) 取消picker view。

    步骤

    1.首先要检查设备是否支持相机录制, 否则设备不支持相机时,会crash 。

       if ([UIImagePickerController
             isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO) return;
        UIImagePickerController *camera = [[UIImagePickerController alloc] init];
        camera.sourceType = UIImagePickerControllerSourceTypeCamera;
    
    

    2.检查在 source type中支持的多媒体类型,并设置mediatypes

    camera.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
    
    

    如果只想让摄像头只能摄像,而不能拍照,那应该设置mediaTypes
    cameraUI.mediaTypes = [[NSArray alloc] initWithObjects: (NSString *) kUTTypeMovie , nil];
    kUTTypeImage 对应拍照
    kUTTypeMovie 对应摄像
    这要导入MobileCoreServices.framework,然后再
    #import <MobileCoreServices/UTCoreTypes.h>

    3.设置delegate,定义拍摄完成后的交互事件处理

    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
    {
        NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
        UIAlertView *alertView =  [[UIAlertView alloc] initWithTitle:@"选择视频" message:nil delegate:self cancelButtonTitle:@"好" otherButtonTitles:nil, nil];
        [alertView show];
        NSLog(@"didFinishPickingMediaWithInfo info=%@;type = %@", info, mediaType);
    }
    
    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
    {
        NSLog(@"imagePickerControllerDidCancel");
        
        [picker dismissViewControllerAnimated:YES completion:nil];
    }
    
    
    完整代码:

    ViewController.m

    #import <MobileCoreServices/UTCoreTypes.h>
    #import <MediaPlayer/MediaPlayer.h>
    #import <AVFoundation/AVFoundation.h>
    
    #import "ViewController.h"
    
    @interface ViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate, UIAlertViewDelegate>
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        UIBarButtonItem *rightItem = [[UIBarButtonItem alloc] initWithTitle:@"拍摄" style:UIBarButtonItemStylePlain target:self action:@selector(startCameraControllerFromViewController:)];
        self.navigationItem.rightBarButtonItem = rightItem;
    }
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
    {
        NSString *mediaType = [info objectForKey: UIImagePickerControllerMediaType];
        UIAlertView *alertView =  [[UIAlertView alloc] initWithTitle:@"选择视频" message:nil delegate:self cancelButtonTitle:@"好" otherButtonTitles:nil, nil];
        [alertView show];
        NSLog(@"didFinishPickingMediaWithInfo info=%@;type = %@", info, mediaType);
    }
    
    - (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
    {
        NSLog(@"imagePickerControllerDidCancel");
        
        [picker dismissViewControllerAnimated:YES completion:nil];
    }
    
    // 设备是否被授权访问相机
    -(BOOL)isCameraAuthorized
    {
        AVAuthorizationStatus auth = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
        return (auth == AVAuthorizationStatusAuthorized);
    }
    
    // 请访问求相机授权
    - (void)requestCameraAuthorization
    {
        NSString *title = @"请在\设置-隐私-相机\"选项中,允许访问你的相机。";
        AVAuthorizationStatus auth = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
        if (auth == AVAuthorizationStatusNotDetermined) {
            [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:nil delegate:self cancelButtonTitle:@"好" otherButtonTitles:nil];
                    [alertView show];
                });
            }];
        }
        else {
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:title message:nil delegate:self cancelButtonTitle:@"好" otherButtonTitles:nil];
            [alertView show];
        }
    }
    
    - (void)startCameraControllerFromViewController: (UIViewController*)controller
    {
        if (![self isCameraAuthorized]) {
            [self requestCameraAuthorization];
        }
        
        if ([UIImagePickerController
             isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera] == NO) return;
        
        UIImagePickerController *camera = [[UIImagePickerController alloc] init];
        camera.sourceType = UIImagePickerControllerSourceTypeCamera;
        camera.delegate = self;
        
        camera.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
        
        [self presentViewController:camera animated:YES completion:nil];
    
    }
    @end
    
    

    AppDelegate.m

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        // Override point for customization after application launch.
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        self.viewController = [[ViewController alloc] init];
        self.navigationController = [[UINavigationController alloc] init];
        [self.navigationController pushViewController:self.viewController animated:YES];
        self.window.rootViewController = self.navigationController;
        return YES;
    }
    
    bug:

    横向拍摄视频,完成拍摄后点击“使用视频”,摄像头被打开,背景出现摄像流。

    bug.png

    设备和系统
    iPhone6Plus 9.1 ,上述情况
    iPhone5s 8.3 , 上述情况
    iPhone4s 7.1.1, 上述情况,但是显示是已拍摄视频的最后一帧。

    问题原因:
    调用系统摄像机录像时,UIImagePickerController视图有两个关键子view,CMKVideoPreviewViewPLAVPlayerView
    PLAVPlayerView 用来播放已录制的视频。
    CMKVideoPreviewView 负责展示摄像头实时拍摄的视频流。 PreviewView在不同系统版本有不同的名字:

    • 9.1系统的类名是CMKVideoPreviewView;
    • 8.3系统是CAMVideoPreviewView;
    • 7.1系统是 PLVideoPreviewView)

    视图层次结构:CMKVideoPreviewView在下,PLAVPlayerView 在上。横屏拍摄视频,完成拍摄后,由于UIImagePickerController官方只支持竖屏模式,系统自动转为竖屏模式并更新PLVideoPosterFrameView的UIImageView(已录制视频的快照)的frame为 (0, 212,75, 414, 310,5),所以原本被遮挡的CMKVideoPreviewView就显示出来了。

    Paste_Image.png

    解决方案:
    思路:在点击“使用视频”之后,弹出“压缩”toast提示之前,获取CMKVideoPreviewView对象的指针,并讲该对象的hidden属性设为YES.由于CMKVideoPreviewView是private frameworks中的类,无法直接获取对象,但可通过public api : view.subviews ,在子view中递归查找目标对象,安全地获取到该对象。此方法可以通过appstore的审查。 如何安全使用私有库类

    - (void)setVideoPreviewHidden:(BOOL)hidden inPicker:(UIImagePickerController *)picker
    {
        UIView *view = nil;
        float systemVersion = UIDevice.currentDevice.systemVersion.floatValue;
        if (systemVersion>= 10.0) {
            return;
        }
        else if (systemVersion>= 9.0) {
            view = UIViewFindSubview(picker.view, [NSClassFromString(@"CMKVideoPreviewView") class]);
        }
        else if (systemVersion >= 8.0) {
            view = UIViewFindSubview(picker.view, [NSClassFromString(@"CAMVideoPreviewView") class]);
        }
        else if (systemVersion >= 7.0) {
            view = UIViewFindSubview(picker.view, [NSClassFromString(@"PLVideoPreviewView") class]);
        }
        view.hidden = hidden;
    }
    
    NS_INLINE UIView *UIViewFindSubview(UIView *view, Class viewClass)
    {
     for (UIView *subview in view.subviews) {
      if ([subview isKindOfClass:viewClass])  {
       return subview;
      } else {
       UIView *ret = UIViewFindSubview(subview, viewClass);
       if (ret) return ret;
      }
     }
     
     return nil;
    }
    

    Taking Pictures and Movies

    ios设备上捕获视频

    文档翻译

    相关文章

      网友评论

      本文标题:使用系统界面拍摄视频及系统问题

      本文链接:https://www.haomeiwen.com/subject/xilmhttx.html