iOS实录6:iOS中实现全景播放器(GVR For iOS)

[这是第六篇]
导语:VR是个比较火的话题,在iOS中集成全景和VR播放功能,是个值得考虑和去实践的idea。目前有一些能帮助我们快速实现VR的项目,其中Google提供的GVRSDK(Google VR SDK)就是非常好的代表,基于此,我们可以快速地实现一个性能不错的全景和VR播放器。(图片全景播放+视频全景播放)

一、背景

1、集成GVRSDK(Google VR SDK)很容易。目前最新版本是1.40.0
2、GVRSDK提供了图片的视频的全景和VR播放接口。
3、全景图片和全景视频功能可以支持手势处理和重力感应,支持VR播放
4、在Google VR SDK的基础上做了简单的定制,可以达到较好的效果。

二、项目中集成GVRSDK

1、Podfile文件中定义
target 'QSUseGoogleVRDemo' do
    #google VR SDK
  pod 'GVRSDK'
end
2、安装GVRSDK
pod install
  • 通过pod install安装慢的话,建议使用 pod install --verbose --no-repo-update

  • GVRSDK下载下来的库比较大,约320MB。获取GVRSDK库的同时,还会获取与其相关的GoogleToolboxForMac和GTMSessionFetcher

  • 遇到的问题:pod install安装下来的不是最新版本,是1.0.1版本。原因是:Cocoapods的全局缓存带来的,好的解决办法是,删除全局的缓存。使用命令如下:

    sudo rm -fr ~/Library/Caches/CocoaPodssudo 
    rm -fr ~/.cocoapods/repos/master
    

三、全景图片的播放器

1、GVRSDK提供的
  • GVRSDK提供全景图片播放的类是GVRPanoramaView,它支持两个load接口,分别如下:

      - (void)loadImage:(UIImage *)image;
    
      - (void)loadImage:(UIImage *)image ofType:(GVRPanoramaImageType)imageType;
    

接口分析:

  1. 从接口中可以看出,并不可以直接load线上的图片资源,所以在使用这两个接口之前,需要先从网络上下载图片资源。

  2. 枚举类型GVRPanoramaImageType的有两个可选值。 kGVRPanoramaImageTypeMono和 kGVRPanoramaImageTypeStereoOverUnder,前者指定单个图像源图像,后者指有上下两部分图像源的图像,上半部分对应左眼,下半部对应右眼。demo中使用的是kGVRPanoramaImageTypeMono,这也是loadImage: 接口默认使用的参数值。

  3. GVRPanoramaView的父类GVRWidgetView,从GVRWidgetView头文件中看出,它可以允许操作某些属性,如在View上是否显示信息按钮、跳转VR的按钮等,如展示模式(嵌入父View/全景/全景+VR/)。我们根据需要在GVRPanoramaView的子类中设置好值。GVRWidgetView还提供代理,可以帮我开发者去了解GVRPanoramaView的load情况(如load成功或失败)。

2、我们可以做的

1)实现图片的下载。使用SDWebImage库提供的下载器去下载图片是个不错的办法。但是我选择了自己实现一个下载器QSDownloadManager。目的是不仅仅支持图片的下载,还支持视频等资源的下载,此外QSDownloadManager还支持多任务下载,下载进度的监听,暂停下载 以及 资源的断点下载,支持文件的缓存和清理。QSDownloadManager的接口定义如下:

@interface QSDownloadManager : NSObject

+ (instancetype)sharedInstance;

/**
 *  下载
 */
- (void)download:(NSString *)url progress:(QSDownloadProgressBlock)progressBlock completedBlock:(QSDownloadCompletedBlock)completedBlock;

/**
 *  取消下载
 */
- (void)cancelDownLoad:(NSString *)url;


#pragma mark - 缓存文件的大小 & 删除
/**
 所有缓存资源大小
 */
- (NSString *)getAllCacheFileSizeString;

/**
 *  删除url对应的资源 && 如果url对应的资源还在下载,立即取消下载并清除对应未下载完整的资源
 */
- (void)deleteFileCache:(NSString *)url;

/**
 *  清空所有下载资源
 */
- (void)deleteAllFileCache;

@end

2)增加placeholderView和ProgressHUD
这是为了在图片播放前(图片下载过程 和 图片加载到GVRSDK),让用户等待不再那么无聊。此外,为了简单起见,placeholderView只是一张纯白的View。

3、图片的全景播放QSPanoramaView

1)QSPanoramaView继承GVRPanoramaView,实现GVRWidgetViewDelegate协议方法。对外提供两个接口

//GVRPanoramaView.h
/**
 全景图片播放 + VR
 */
@interface QSPanoramaView : GVRPanoramaView
/**
加载线上图片
*/
- (void)loadImageUrl:(NSURL *)imageUrl;

- (void)loadImageUrl:(NSURL *)imageUrl ofType:(GVRPanoramaImageType)imageType;

@end

说明:你也可以直接使用GVRPanoramaView的接口。

2)主要代码实现

- (void)loadImageUrl:(NSURL *)imageUrl{

    [self loadImageUrl:imageUrl ofType:kGVRPanoramaImageTypeMono];
}

- (void)loadImageUrl:(NSURL *)imageUrl ofType:(GVRPanoramaImageType)imageType{

    if ([self.imageUrl isEqual:imageUrl]) {
        return;
    }

    [self cancelCurrentDownLoad];
    self.imageUrl = imageUrl;
    self.placeholderView.alpha = 1.0f; //遮盖
    [MBProgressHUD showHUDWithContent:@"图片加载中..." toView:self];

    [[QSDownloadManager sharedInstance]download:[imageUrl absoluteString]
                                   progress:^(CGFloat progress, NSString *speed, NSString *remainingTime) {

                                       NSLog(@"当前下载进度:%.2lf%%,当前的下载速度是:%@,还需要时间:%@,",progress * 100,speed,remainingTime);
    
                                   } completedBlock:^(NSString *fileCacheFile) {
                                       
                                       NSData *imageData = [NSData dataWithContentsOfFile:fileCacheFile];
                                       UIImage *image = [UIImage imageWithData:imageData];
                                       [self loadImage:image ofType:imageType];
                                   }];
}
4、效果图

1)图片load过程,显示ProgressHUD

iOS实录6:iOS中实现全景播放器(GVR For iOS)_第1张图片
图片load过程.png

2)图片全景播放中,支持重力感应和手势控制,调整视角,实现360度全方位的观看。右下角是VR播放的按钮

图片全景播放.png

3)VR播放的效果,分屏,支持360度全方位的观看

iOS实录6:iOS中实现全景播放器(GVR For iOS)_第2张图片
图片VR播放.png

四、全景视频的播放器

1、GVRSDK提供的
  • GVRSDK提供全景图片播放的类是GVRVideoView,它支持load和对视频源播放、暂停和停止的控制,接口分别如下:

     - (void)loadFromUrl:(NSURL*)videoUrl;
    
     - (void)loadFromUrl:(NSURL*)videoUrl ofType:(GVRVideoType)videoType;
    
     - (void)pause;
    
     - (void)play;
    
     - (void)stop;
    

接口分析:

  1. loadFromUrl:中的参数videoUrl,不仅可以是线上的视频源的URL,还可以是本地的视频资源的URL,比GVRPanoramaView的load接口更强大些。我们可以不用去操心下载视频的问题的。(QSDownloadManager完全能驾驭下载视频,但是这里不需要了)

  2. 枚举类型GVRVideoType的有三个可选值。 kGVRVideoTypeMono、 kGVRVideoTypeStereoOverUnder 和 kGVRVideoTypeSphericalV2,kGVRVideoTypeMono代表单个视频源的视频,kGVRVideoTypeStereoOverUnder是有上下两部分视频源的视频,kGVRVideoTypeSphericalV2代表是球形视频源的视频。

  3. GVRVideoView的也是父类GVRWidgetView。

  4. GVRVideoView还提供GVRVideoViewDelegate,代理中方法可以获得视频的播放进度。

2、我们能做的

1)增加placeholderView、ProgressHUD、播放进度条和播放按钮

  • 在视频加载的同时,使用placeholderView和ProgressHUD遮盖其上,告诉用户app在干啥,加载结束后,默认不立即play,出现play按钮,点击play按钮,视频才真正的去play。播放进度条显示视频播放的进度。

2)处理耳机的插入和拔出

  • 增加耳机的处理,是因为耳机的插入和拔出会影响视频的播放,提供简单的UI处理,如拔出耳机,视频暂停,出现play按钮,点击按钮,继续播放,这些简单的UI使用户操作更加自然。
3、视频的全景播放QSVideoView#####

1)QSVideoView继承GVRVideoView,实现GVRWidgetViewDelegate和GVRVideoViewDelegate协议方法。对外提供两个接口

//QSVideoView
@interface QSVideoView : GVRVideoView

/**
 加载线上视频
 */
- (void)loadFromOnlineUrl:(NSURL*)videoUrl;

- (void)loadFromOnlineUrl:(NSURL *)videoUrl ofType:(GVRVideoType)videoType;

@end

2)主要代码实现

- (void)loadFromOnlineUrl:(NSURL*)videoUrl{

    [self loadFromOnlineUrl:videoUrl ofType:kGVRVideoTypeMono];
}

- (void)loadFromOnlineUrl:(NSURL *)videoUrl ofType:(GVRVideoType)videoType{

    if ([self.videoUrl isEqual:videoUrl]) {
        return;
    }

    self.videoUrl = videoUrl;

    [MBProgressHUD showHUDWithContent:@"视频加载中..." toView:self];
    self.placeholderView.alpha = 1.0f;  //遮盖
    [self loadFromUrl:videoUrl ofType:videoType];
}

#pragma mark - GVRVideoViewDelegate & GVRWidgetViewDelegate
- (void)widgetView:(GVRWidgetView *)widgetView didLoadContent:(id)content {

    NSLog(@"视频加载结束...");
    [UIView animateWithDuration:1.0 delay:1.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
    
        self.placeholderView.alpha = 0;
    
    } completion:^(BOOL finished) {
    
        [_placeholderView removeFromSuperview];
        _placeholderView = nil;
        [MBProgressHUD hideHUDInView:self];
       [self seekTo:0];
    }];
}

- (void)widgetView:(GVRWidgetView *)widgetView didFailToLoadContent:(id)content withErrorMessage:(NSString *)errorMessage {
    NSLog(@"Failed to load video: %@", errorMessage);

    [MBProgressHUD hideHUDInView:self];
    UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:@"⚠️"  message:@"视频加载失败..." delegate:self cancelButtonTitle:@"确定" otherButtonTitles:nil, nil];
    [alertView show];
}


- (void)videoView:(GVRVideoView*)videoView didUpdatePosition:(NSTimeInterval)position {
    CGFloat progress = position / videoView.duration;
    NSLog(@"播放进度: %lf", progress);
    BOOL isAnimation = (progress == 0);
    [self.playProgressView setProgress:progress animated:isAnimation];
}

- (void)audioRouteChangeListenerCallback:(NSNotification*)notification{

    NSDictionary *interuptionDict = notification.userInfo;
    NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];
    switch (routeChangeReason) {
       case AVAudioSessionRouteChangeReasonNewDeviceAvailable:{
            NSLog(@"耳机插入");
            [self play];
            [self updateUI];
        }
            break;
        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:{
            NSLog(@"耳机拔出,停止播放操作");
            [self pause];
            [self updateUI];
        }
            break;
        case AVAudioSessionRouteChangeReasonCategoryChange:
            // called at start - also when other audio wants to play
            NSLog(@"AVAudioSessionRouteChangeReasonCategoryChange");
            break;
    }
}
4、效果图#####

1) 视频加载过程中

iOS实录6:iOS中实现全景播放器(GVR For iOS)_第3张图片
视频加载中.png

2) 视频加载成功后,出现play按钮

iOS实录6:iOS中实现全景播放器(GVR For iOS)_第4张图片
加载成功后.png

3) 点击play按钮,播放线上视频,NavigationBar下面是细长的播放进度条,底部是切换到VR的按钮

iOS实录6:iOS中实现全景播放器(GVR For iOS)_第5张图片
视频播放中.png

4) 视频的VR播放

iOS实录6:iOS中实现全景播放器(GVR For iOS)_第6张图片
视频VR.png

五、总结

  • GVR For IOS 可以帮助普通的开发者们,在iOS上快速实现全景视频和图片的播放,这篇文章只是记录了在了解GVR的同时,对它做的一点点优化工作。
  • 在优化工作成功中,最复杂的工作莫过于为优化编写的下载器,虽然没有派上太大用场,但是希望有机会在真正的生产环境中去使用,去发现问题,去完善。
  • Panorama 和 MD360Player4iOS也是不错的库

具体的代码实现见源码QSUseGoogleVRDemo

你可能感兴趣的:(iOS实录6:iOS中实现全景播放器(GVR For iOS))