Brightcove-Player-SDK 5.3.4

Brightcove-Player-SDK 5.3.4

测试已测试
Lang语言 Obj-CObjective C
许可证 商业
发布最后发布2017年8月

Jim WhisenantSteve BushellTim Rodgers 维护。



  • Brightcove

Brightcove Player SDK for iOS,版本 5.3.4.774

重要提示

本次发布,版本 5.3.4,将是最终出现在 cocoapods.org 上的版本。如果您正在寻找 Brightcove Player SDK 的最新版本,请访问 https://github.com/brightcove/brightcove-player-sdk-ios

您仍然可以使用 CocoaPods 进行安装,但 Brightcove Player SDK 的 podspec 将不再存放在 cocoapods.org 上。从版本 6.0 开始,Brightcove Player SDK 的 podspec 存放在一个新的私有 podspecs 仓库中,网址为 https://github.com/brightcove/BrightcoveSpecs.git

有关安装和使用最新版本的全部详细信息,请访问 https://github.com/brightcove/brightcove-player-sdk-ios

支持平台

iOS 8.0 及以上。

tvOS 9.0 及以上。

需要 ARC。

请注意

  • Brightcove PlayerUI 插件现已被整合到核心 Brightcove Player SDK 框架中。这为您提供了在播放器中完全功能化和可定制的控件集合。
    • PlayerUI 控件不支持在 Apple TV 上使用。
    • 在播放过程中,PlayerUI 控件会自动切换到广告模式。这适用于 Once 和 FreeWheel 广告。Google IMA 广告使用它们自己的广告控件。
    • 请参阅下文关于内置 PlayerUI 控件的重要信息,包括此整合、使用 Brightcove PlayerUI 控件以及迁移到集成 PlayerUI 控件。

安装

Brightcove Player SDK 为 iOS 提供了两种安装包,静态库框架和动态框架。部署支持 iOS 8 及以上版本。

Brightcove Player SDK 为 tvOS 9.0 及以上版本提供动态框架支持。

手动

要将 Brightcove Player SDK 手动添加到项目中

  1. 从我们的 发布页面 下载最新的压缩发布版。
  2. BrightcovePlayerSDK.framework 添加到您的项目中。请确保使用与您的目标相应的版本,即 iOS 或 tvOS。
  3. 在您的应用程序目标的“构建设置”选项卡上,确保“框架搜索路径”包括框架的路径。除非框架存储在与项目不同的根目录下,否则此操作应已自动完成。
  4. 在您的应用程序目标的“常规”选项卡上,将以下内容添加到“链接二进制与库”部分
    • AVFoundation
    • CoreMedia
    • CoreMotion
    • GLKit
    • MediaPlayer
    • SafariServices
    • WebKit
    • BrightcovePlayerSDK.framework
  5. (仅限 动态框架) 在应用程序目标的“常规”选项卡上,将 'BrightcovePlayerSDK.framework' 添加到“嵌入的二进制”部分。
  6. (仅限 动态框架) 在“构建阶段”选项卡上,添加一个带命令 bash ${BUILT_PRODUCTS_DIR}/${FRAMEWORKS_FOLDER_PATH}/BrightcovePlayerSDK.framework/strip-frameworks.sh 的 “运行脚本”阶段。检查“仅在安装时运行脚本”。这将删除构建中不需要的架构,这对于应用商店提交很重要。
  7. (仅限 静态框架) 在应用程序目标的“构建设置”选项卡上,将 -ObjC 添加到“其他链接器标志”构建设置。
  8. (仅限 静态框架) 定位到 BrightcovePlayerSDK.framework 包中的 bcovpuiiconfont.ttf 文件,并将其直接拖放到项目列表中,以便字体文件成为您应用的组成部分。拖动文件后,当提示时,务必将其添加到应用的构建目标中。一旦应用构建完毕,字体文件应位于与应用的 Info.plist 文件相同的级别中。字体文件提供了一些 BrightcovePlayerUI 接口元素,但它不需要在 plist 中列出。

导入

iOS 版本的 Brightcove Player SDK 可以通过几种不同的方法导入到代码中

@import BrightcovePlayerSDK;
#import <BrightcovePlayerSDK/BrightcovePlayerSDK.h>
#import <BrightcovePlayerSDK/[specific-class].h>

快速入门

使用 iOS 版本的 Brightcove Player SDK 播放视频

// ** Customize these values with your own account information **
static NSString * const kViewControllerPlaybackServicePolicyKey = @"...";
static NSString * const kViewControllerAccountID = @"...";
static NSString * const kViewControllerVideoID = @"...";

BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
id<BCOVPlaybackController> controller = [manager createPlaybackController];
self.controller = controller; // store this to a strong property
[self.view addSubview:controller.view];  
 
BCOVPlaybackService *service = [[BCOVPlaybackService alloc] initWithAccountId:kAccountId
                                                                    policyKey:kPlaybackServicePolicyKey];
								[service findVideoWithVideoID:kViewControllerVideoID
                   								   parameters:nil
			       		                 		   completion:^(BCOVVideo    *video,
                                 							    NSDictionary *jsonResponse,
																NSError      *error) {

										[controller setVideos:@[ video ]];
										[controller play];
                         
             			        }];

您需要防止控制器在方法结束时自动释放。一种常见的方法是将控制器的引用存储在一个强实例变量中。

内置 PlayerUI 控件

截至版本 5.1.0,Brightcove Player SDK 已经将 Brightcove PlayerUI 插件集成到了其框架中,因此您可以直接使用其功能健全的控件集进行播放和广告。

PlayerUI 设置快速,显示 Once 和 FreeWheel 的广告控件,并且可以通过创建自己的布局进行自定义。

从原生控件转换为 PlayerUI 控件

如果您之前像这样通过 defaultControlsViewStrategy 使用原生控件

BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
id<BCOVPlaybackController> playbackController = [manager createPlaybackControllerWithViewStrategy:[manager defaultControlsViewStrategy]];

您现在应将视图策略设置为 nil

BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
id<BCOVPlaybackController> playbackController = [manager createPlaybackControllerWithViewStrategy:nil];

您也不再需要将播放控制器视图添加到您的层级结构中,因此您可以移除类似以下的代码

self.playbackController.view.frame = self.videoView.bounds;
self.playbackController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[self.videoView addSubview:self.playbackController.view]

相反,您将使用新的 Player View 关联播放控制器,并将其添加到视图层级结构中,就像在本文件的 设置 PlayerUI 控件 部分中描述的那样。

从 Brightcove PlayerUI 插件迁移

随着 Brightcove Player SDK 5.1 版本的推出,PlayerUI 控件已集成到核心框架中,因此不再需要使用单独的 Brightcove PlayerUI 插件。如果您之前使用 Brightcove PlayerUI 插件,并且已手动安装,则可能需要在项目中做一些修改

  • 从您的项目列表中删除 BrightcovePlayerUI.framework 的引用
  • 在目标项目的构建设置中,从框架搜索路径中移除对BrightcovePlayerUI.framework的任何引用。
  • 在目标项目的常规设置中,从嵌入的可执行文件和链接框架和库部分移除对BrightcovePlayerUI的任何引用。

如果您使用CocoaPods安装Brightcove库,您可以从Podfile中移除BrightcovePlayerUI依赖关系,然后在终端中运行pod update

在项目代码中,任何针对PlayerUI头文件的特定#import可以转换为从#import <BrightcovePlayerUI/filename.h>#import <BrightcovePlayerSDK/filename.h>。或者,您还可以使用@import BrightcovePlayerSDK;一次性导入所有头文件。

设置PlayerUI控件

请遵循以下指南来设置PlayerUI控件。

在您的UIViewController中创建一个属性以跟踪BCOVPUIPlayerView。BCOVPUIPlayerView将包含播放控制器视图和控件视图。

// PlayerUI's Player View
@property (nonatomic) BCOVPUIPlayerView *playerView;

创建BCOVPUIBasicControlView,然后创建BCOVPUIPlayerView。这是我们将播放控制器(以及它播放的所有视频)与控件关联的地方。设置播放视图与布局中的视频容器(例如videoView)匹配,当它调整大小时。

// Create and configure Control View.
BCOVPUIBasicControlView *controlView = [BCOVPUIBasicControlView basicControlViewWithVODLayout];
self.playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:self.playbackController options:nil controlsView:controlView];
self.playerView.frame = self.videoView.bounds;
self.playerView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

最后,将BCOVPUIPlayerView添加到您的视频容器videoView中。

// Add BCOVPUIPlayerView to your video view.
[self.videoView addSubview:self.playerView];

注意事项:PlayerUI使用一个小的字体文件来处理各种图形。如果您正在安装静态框架且不正使用CocoaPods,请确保将BrightcovePlayerSDK.framework包中的bcovpuiiconfont.ttf文件直接添加到项目列表中,以便字体文件被复制到应用的包中。

BCOVPUIPlayerViewOptions

BCOVPUIPlayerViewOptions类允许您在初始化时自定义一些BCOVPlayerUI行为。您可以自定义以下各项:

  • jumpBackInterval 当按下回跳按钮时,播放器将回转的秒数。
  • hideControlsInterval 自最后一个触摸事件后的秒数,在这段时间内控件被隐藏。
  • hideControlsAnimationDuration 控件渐变为隐藏所需的时间(以秒为单位)。
  • showControlsAnimationDuration 控件渐变为可见所需的时间(以秒为单位)。
  • learnMoreButtonBrowserStyle 此设置确定在广告中点击“了解更多”按钮时,是否应在外部浏览器(默认设置)或内部浏览器中显示点击链接。
  • presentingViewController 用于展示其他视图控制器的UIViewController子类(例如,关闭字幕选择视图控制器)。

可以使用以下方法设置选项:

    BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
    id<BCOVPlaybackController> controller = [manager createPlaybackController];

    BCOVPUIPlayerViewOptions *options = [[BCOVPUIPlayerViewOptions alloc] init];
    options.jumpBackInterval = 5;

    BCOVPUIPlayerView *playerView = [[BCOVPUIPlayerView alloc] initWithPlaybackController:playbackController options:options];

提供布局

提供了三种布局以支持不同类型的视频。

  • BCOVPUIControlLayout basicVODControlLayout 是通用的按需视频流的布局。

  • BCOVPUIControlLayout basicLiveControlLayout 是直播视频的布局。

  • BCOVPUIControlLayout basicLiveDVRControlLayout 是带有DVR控件直播视频流的布局。

通常在创建BCOVPUIPlayerView后立即设置新布局,但您也可以随时设置新布局。例如,您可以像这样设置新的VOD布局:

playerView.controlsView.layout = [BCOVPUIControlLayout basicVODControlLayout]

自定义布局

除了默认布局外,您还可以通过使用您自己的设计来实例化一个新的BCOVPUIControlLayout来创建高度自定义的布局。

  1. 首先,使用BCOVPUIBasicControlView layoutViewWithControlFromTag:width:elasticity:创建将要放在布局中的控件。每个控件都包裹在BCOVPUILayoutView中,从而确定控件间距。

  2. 您可以设置每个布局视图的width为默认宽度(基于控件类型),或者可以指定自己的宽度。

  3. 使用elasticity参数来确定包含控件的布局视图如何调整其宽度以填充控件栏。

    • 弹性值为零表示布局视图的大小是固定的。
    • 大于零的弹性值决定了布局视图相对于该控件栏中所有其他弹性视图的可填充空间增长量。弹性值为2.0的布局视图将比弹性值为1.0的布局视图增长速度快一倍。通常,一行布局视图至少有一个弹性值大于零的控件。

以下是创建各种基本控件的示例。

// Create various standard layout views
// Standard play/pause button
BCOVPUILayoutView *playbackLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagButtonPlayback width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];

// Standard jump back button
BCOVPUILayoutView *jumpBackButtonLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagButtonJumpBack width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];

// Current time indicator
BCOVPUILayoutView *currentTimeLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagLabelCurrentTime width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];

// Time separator - typically the '/' character
BCOVPUILayoutView *timeSeparatorLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagLabelTimeSeparator width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];

// Video duration label
BCOVPUILayoutView *durationLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagLabelDuration width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];

// Slider bar used for scrubbing through the video
// The elasticity is set to 1 so that it can resize to fill available space
BCOVPUILayoutView *progressLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagSliderProgress width:kBCOVPUILayoutUseDefaultValue elasticity:1.0];

// Closed caption button
// This button is initially hidden ('removed'), and will be shown
// if closed captions or audio tracks are available.
BCOVPUILayoutView *closedCaptionLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagButtonClosedCaption width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];
closedCaptionLayoutView.removed = YES;

// The full-screen button
BCOVPUILayoutView *screenModeLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagButtonScreenMode width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];

// AirPlay button
// This button is initially hidden ('removed'), and will be shown
// if AirPlay devices are available.
BCOVPUILayoutView *externalRouteLayoutView = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagViewExternalRoute width:kBCOVPUILayoutUseDefaultValue elasticity:0.0];
externalRouteLayoutView.removed = YES;

// Empty view - used as a spacer
BCOVPUILayoutView     *spacerLayoutView1 = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagViewEmpty width:1.0 elasticity:1.0];

// Empty view - used as a spacer
BCOVPUILayoutView *spacerLayoutView2 = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagViewEmpty width:1.0 elasticity:1.0];

// Empty view - will have a custom UIImageView added as a subview
BCOVPUILayoutView *logoLayoutView1 = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagViewEmpty width:80.0 elasticity:1.0];

// Empty view - will have a custom UIImageView added as a subview
BCOVPUILayoutView *logoLayoutView2 = [BCOVPUIBasicControlView layoutViewWithControlFromTag:BCOVPUIViewTagViewEmpty width:36.0 elasticity:0.0];

注意,您还可以创建一个空的布局视图,然后将您自己的视图(徽标、控件、无等)放入其中。此代码演示了如何将UIImage徽标放置在我们上面创建的logoLayoutView1中。

// Create logo image inside an image view for display in control bar.
UIImage *logoImage1 = [UIImage imageNamed:@"myLogo"];
UIImageView *logoImageView1 = [[UIImageView alloc] initWithImage:logoImage1];

logoImageView1.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
logoImageView1.contentMode = UIViewContentModeScaleAspectFit;
logoImageView1.frame = logoLayoutView1.frame;

// Add image view to our empty layout view.
[logoLayoutView1 addSubview:logoImageView1];

现在,将各种控件包装在布局视图中,并将它们排序到数组中,每个数组代表一行控件,即控件栏。注意,您可以针对横向和纵向方向设置不同的布局,因此通常需要设置两个不同的控件栏数组。

在横向标准布局中,控件排列在一个单独的数组中,然后该数组存储在表示整个控件集合的另一个数组中。

        NSArray *standardLayoutLine1 = @[ playbackLayoutView, jumpBackButtonLayoutView, currentTimeLayoutView, timeSeparatorLayoutView, durationLayoutView, progressLayoutView, spacerLayoutView1, logoLayoutView1, spacerLayoutView2, closedCaptionLayoutView, screenModeLayoutView, externalRouteLayoutView ];
        NSArray *standardLayoutLines = @[ standardLayoutLine1 ];

在纵向紧凑布局中,创建两个控件数组,每个数组对应一行。这些数组被包装在表示紧凑布局的另一个数组中。

请注意,每个布局的大多数控件使用的是完全相同的对象。当您这样做,并在横向和纵向方向之间切换时,对象将使用平滑动画移动到其新位置。

        NSArray *compactLayoutLine1 = @[ currentTimeLayoutView, progressLayoutView, durationLayoutView ];
        NSArray *compactLayoutLine2 = @[ playbackLayoutView, jumpBackButtonLayoutView, spacerLayoutView1, closedCaptionLayoutView, screenModeLayoutView, externalRouteLayoutView, logoLayoutView2 ];
        NSArray *compactLayoutLines = @[ compactLayoutLine1, compactLayoutLine2 ];

最后,现在有两套布局配置(一套用于满宽,一套用于紧凑宽度),您可以创建一个新的BCOVPUIControlLayout对象,并将其设置在播放器的控件视图中。

        BCOVPUIControlLayout *customLayout = [[BCOVPUIControlLayout alloc] initWithStandardControls:standardLayoutLines compactControls:compactLayoutLines];
		playerView.controlsView.layout = customLayout;

如果您有需要经常显示或隐藏的控件,您可以设置该控件布局视图中该控件的removed属性。当您更改控件后,请调用播放器视图的控件视图上的setNeedsLayout

	logoLayoutView1.removed = YES;
    [playerView.controlsView setNeedsLayout];

您还可以自定义几个通用的BCOVPUIControlLayout属性

  • controlBarHeight设置每行控件的大小。
  • horizontalItemSpacing设置每个控件栏中每个BCOVPUILayoutView之间的间距。
  • compactLayoutMaximumWidth决定了使用哪个控件集合。如果控件视图小于compactLayoutMaximumWidth,则使用紧凑控件集合,否则使用标准控件。

要更改显示的控件集合,您必须创建并安装一个新的BCOVPUIControlLayout。新控件可以随时安装。

更多自定义示例

有关更多PlayerUI自定义示例,您可以在BrightcoveOS GitHub存储库的PlayerUI文件夹中的示例代码中查找

https://github.com/BrightcoveOS/ios-player-samples

视频360

本地播放器SDK包括对交互式显示360度球面视频的支持。360度视频应带有包含值为“equirectangular”的“projection”字段属性。这些视频将以与其他视频相同的方式加载和播放,但它们将显示在OpenGL ES层而不是AVPlayerLayer中。

注意:“equirectangular”是目前支持360度源视频的唯一投影格式。

PlayerUI还内置了对360视频的支持,提供默认的平移手势、视图的陀螺仪运动检测以及当播放360视频资源时出现的新的“视频360”按钮。此按钮仅在iPhone上显示,并允许您在普通视图和“VR眼镜”视图之间切换,屏幕分为两部分,每个眼睛渲染相同的场景,以便设备可以以头戴式配置使用。在iPad上不需要视频360按钮,因为只有一个操作模式:带有平移手势的运动检测。

支持视频360与播放视频一样简单。当检测到“投影”字段属性时,Native Player SDK将自动处理在OpenGL ES中设置并显示视频以及根据需要安装“视频360”按钮。

如果您在Video Cloud之外播放360视频,请确保向《code》BCOVVideo《/code》对象添加“投影”属性,其值为“等经度”。

为了在VR眼镜模式下提供最佳的用户体验,您应该使用《code》BCOVPUIPlayerViewDelegate《/code》方法来检测此模式是否启用。这使您可以将设备强制进入横屏方向(因为这是VR眼镜视图的唯一合逻辑的方向)。

以下代码显示了如何在普通360视图和VR眼镜模式之间切换时处理强制方向更改。

	// Set this to YES when displaying a VR goggles video
	@property (nonatomic) BOOL landscapeOnly;

	// UIViewController override:
   // Lets us control the orientation of the device
	- (UIInterfaceOrientationMask)supportedInterfaceOrientations
	{
	    if (self.landscapeOnly)
	    {
	        return UIInterfaceOrientationMaskLandscape;
	    }
	
	    return UIInterfaceOrientationMaskAll;
	}

    // BCOVPUIPlayerViewDelegate method
	- (void)didSetVideo360NavigationMethod:(BCOVPUIVideo360NavigationMethod)navigationMethod
	                       projectionStyle:(BCOVVideo360ProjectionStyle)projectionStyle
	{
	    switch (projectionStyle)
	    {
	        case BCOVVideo360ProjectionStyleNormal:
	            NSLog(@"BCOVVideo360ProjectionStyleNormal");
	            self.landscapeOnly = NO;
	            break;
	
	        case BCOVVideo360ProjectionStyleVRGoggles:
	            NSLog(@"BCOVPUIVideo360NavigationDeviceMotionTracking");
	            
	            self.landscapeOnly = YES;
	            
	            {
	                UIDeviceOrientation currentDeviceOrientation = [UIDevice currentDevice].orientation;
	                switch (currentDeviceOrientation)
	                {
	                    case UIDeviceOrientationLandscapeLeft:
	                    case UIDeviceOrientationLandscapeRight:
	                        // all good
	                        break;
	                    default:
	                    {
	                        // switch orientation
	                        NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
	                        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
	                        break;
	                    }
	                }
	            }
	            break;
	    }
	    
	    [UIViewController attemptRotationToDeviceOrientation];
	}

PlayerUI会安装手势来处理360视频的导航,但如果您正在使用自己的控件,您可以自己设置虚拟摄像机的视图参数。《code》BCOVPlaybackController《/code》协议的《code》viewProjection《/code》属性允许您设置这些参数。该属性是《code》BCOVVideo360ViewProjection《/code》类,具有基本的虚拟摄像机设置,如《code》pan《/code》、`tilt`和《code`zoom`。要更改设置,请复制当前实例,更改新实例上的设置,然后将其重新指定给《code`viewProjection《/code`属性。

体系结构概述

Architectural Overview 1

iOS Brightcove Player SDK的入口是《code》BCOVPlayerSDKManager《/code》单例对象。此Manager负责插件组件的注册和一些其他维护任务,但它主要充当对象工厂。您的应用程序视图控制器获得管理器的引用,并使用它来创建《code`BCOVPlaybackController`。播放控制器的`view`属性公开一个包含AVPlayerLayer对象的UIView,最终将视频内容呈现在屏幕上。播放控制器还接受一个《code`BCOVPlaybackControllerDelegate`,您可以实现它以响应对视频播放事件的各种响应。

播放控制器提供方法和属性来影响当前视频的播放。然而,在内部,播放控制器委托给《code`BCOVPlaybackSession`对象。播放会话执行准备和播放视频内容的实际工作,并包含视频的元数据和《code`AVPlayer`。播放控制器有机制从当前播放会话切换到下一个播放会话,无论是在视频结束时自动进行,还是通过方法调用手动进行。一旦播放控制器切换到新的会话,先前会话将被丢弃并且不能再次使用。

播放控制器还有两个其他元素:一个BCOVPlaybackSessionProvider, 以及一个BCOVPlaybackSessionConsumer的列表。正如名称所示,播放会话提供者负责创建播放会话并将它们交付给播放控制器。然后播放控制器将会话交付给列表中的每个播放会话消费者。会话提供者和会话消费者API是为插件开发者设计的,且在此文档中未详细介绍。

除了上述类提供的播放功能外,还有一些值类。这些类用于存放与iOS播放器SDK相关的特定数据。下面将详细介绍每一个。

播放、暂停和定位

iOS Brightcove播放器SDK提供BCOVPlaybackController上的播放、暂停和定位方法。**重要:请使用这些方法而不是AVPlayer的等价方法**。它们的默认实现会直接将调用转发到AVPlayer的相应方法。但是,如果您使用插件,它们可能会覆盖默认行为以添加功能。例如,如果使用广告插件,第一次调用BCOVPlaybackController play可能在没有开始内容之前播放预加载的视频。要了解更多关于插件如何覆盖默认行为的信息,请参阅每个插件的README.md或检查插件是否在BCOVSessionProviderExtension上添加了类别扩展。

直接在AVPlayer上调播放、暂停或定位可能会导致未定义的行为。

预加载视频

注意: 不再推荐预加载视频,此功能可能在未来的版本中删除。

iOS Brightcove播放器SDK提供了预加载播放列表中即将播放视频的能力。默认情况下,由于预加载可能会使用大量内存,此功能是禁用的。您可以将预加载打开以确保未来视频能够快速加载,但是要注意客户端设备上可用的内存和他们的连接速度。如果不在Wi-Fi上,预加载视频可能会影响当前视频的网络资源。

BCOVBasicSessionProviderOptionsBCOVBasicSessionLoadingPolicy提供了两个工厂方法来修改预加载行为,如下所述

  • +sessionPreloadingNever此方法返回一个永不会预加载视频的会话预加载策略。这是默认设置。
  • +sessionPreloadingWithProgressPercentage:此方法返回一个会话预加载策略,在提供的百分比达到当前视频后开始预加载下一视频。如果使用小于0或大于100的值,则使用sessionPreloadingNever。某些插件可能会忽略此设置。

一个例子

     BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
 [1] BCOVBasicSessionLoadingPolicy *policy = [BCOVBasicSessionLoadingPolicy sessionPreloadingWithProgressPercentage:50];     
      BCOVBasicSessionProviderOptions *options = [[BCOVBasicSessionProviderOptions alloc] init];
      options.sessionPreloadingPolicy = policy;
      id<BCOVPlaybackSessionProvider> provider = [manager createBasicSessionProviderWithOptions:options];
  1. 创建一个会话预加载策略,当当前会话达到50%进度时开始预加载后续会话。

源选择(HLS、MP4、HTTP/HTTPS)

Brightcove Player SDK for iOS 允许客户端将多个 URL 和交付类型(BCOVSource)附加到单个视频(BCOVVideo)。例如,如果您的视频由播放服务获取,则单个视频可能包含 HLS 或 MP4 格式,以及 HTTP 和 HTTPS 版本。选择哪个源由源选择策略块决定。默认源选择策略将选择每个 BCOVVideo 上的第一个 HLS BCOVSource,HTTPS 源优先于 HTTP。

可以通过创建一个 BCOVBasicSessionProviderOptions 并使用它来创建一个 BCOVBasicSessionProvider 来覆盖源选择。例如

BCOVPlayerSDKManager *sdkManager = [BCOVPlayerSDKManager sharedManager];

BCOVBasicSessionProviderOptions *options = [[BCOVBasicSessionProviderOptions alloc] init];    
options.sourceSelectionPolicy = <policy>

id<BCOVPlaybackSessionProvider> provider = [sdkManager createBasicSessionProviderWithOptions:options];
id<BCOVPlaybackController> playbackController = [sdkManager createPlaybackControllerWithSessionProvider:provider viewStrategy:nil];

如果默认选择策略不符合您的要求,有几种选择源的方法。

  • 在通过播放服务从 Video Cloud 获取视频之前,在调用 -[BCOVPlaybackController setVideos:] 之前,使用 BCOVVideo 的更新方法只包含您想要的源(更多信息请参见“值”部分)。

  • 可以使用辅助方法 [BCOVBasicSourceSelectionPolicy sourceSelectionHLSWithScheme:scheme] 创建一个偏好特定方案的策略。这是创建默认源选择策略并偏好 HTTPS 的方法。

  • 类似于更新视频对象,您也可以实现自己的源选择块。

      options.sourceSelectionPolicy = ^ BCOVSource *(BCOVVideo *video) {
      
         <Check video.sources for source>
         <Return source>
    
      };
    

请注意,App Store 对使用 MP4 视频有使用限制。有关详细信息,请参阅最新的 Apple 开发者信息。

获取内容和广告播放信息

Brightcove Player SDK for iOS 提供了两种获取播放信息的机制。播放控制器提供了一个实现 BCOVPlaybackControllerDelegate 的代理属性。代理可以实现这些可选方法来获取有关播放元数据的通知,例如进度、持续时间更改和其他事件。如果安装了广告插件,它可能还会使用此代理提供有关 广告播放 的信息。生命周期事件代理方法提供了用于指示播放状态变化的信号事件。例如,当播放器从暂停状态转换为播放状态时,生命周期事件代理方法将使用 kBCOVPlaybackSessionLifecycleEventPlay 事件被调用。默认的生命周期事件在 BCOVPlaybackSession 中声明。Brightcove 提供的插件添加了额外的生命周期事件,这些事件在每个插件中定义。

播放控制器允许一个代理。在大多数情况下,这足以检索信息;代理实现可以根据需要将值和事件分发到应用程序的各个部分。在需要多个代理的情况下,例如在开发插件时,BCOVPlaybackSessionConsumer 代理提供了与 BCOVPlaybackControllerDelegate 方法等效的功能,包括 广告数据

以下是如何使用 BCOVPlaybackSessionConsumer 创建分析插件的示例。

@interface XYZAnalytics : NSObject <BCOVPlaybackSessionConsumer>
@end

@implementation XYZAnalytics

- (void)playbackSession:(id<BCOVPlaybackSession>)session didProgressTo:(NSTimeInterval)progress
{
    //react to progress event
}

@end

要使用此插件。

BCOVPlayerSDKManager *sdkManager = [BCOVPlayerSDKManager sharedManager];
id<BCOVPlaybackController> controller = [sdkManager createPlaybackController];
XYZAnalytics *analytics = [[XYZAnalytics alloc] init];
[controller addSessionConsumer:analytics];

处理网络中断和放缓

当应用程序遇到网络中断时,如果中断持续时间过长,BCOVPlaybackController使用的AVPlayer可能会停止尝试恢复。如果发生这种情况,将调用生命周期代理方法,并带上kBCOVPlaybackSessionLifecycleEventFailedToPlayToEndTime事件。当发生此事件时,播放不会自动恢复。为了从该事件中恢复,你需要在客户端代码中检测网络何时恢复。

一旦你确定网络已恢复,你可以使用- [BCOVPlaybackController resumeVideoAtTime:withAutoPlay:]来重新初始化播放器。你需要记录想要恢复的位置。播放器将尽力抑制生命周期事件和进度事件,以防止广告重复播放或影响分析。

在调用- [BCOVPlaybackController resumeVideoAtTime:withAutoPlay:]之后,播放器将发送类型为kBCOVPlaybackSessionLifecycleEventResumeBegin的生命周期事件。如果此次操作成功,将发送kBCOVPlaybackSessionLifecycleEventResumeComplete,否则发送kBCOVPlaybackSessionLifecycleEventResumeFail

你必须等待收到来自之前的调用的kBCOVPlaybackSessionLifecycleEventResumeCompletekBCOVPlaybackSessionLifecycleEventResumeFail,然后才能第二次调用- [BCOVPlaybackController resumeVideoAtTime:withAutoPlay:]。在通知用户其网络不稳定之前,你可能想要设置重试限制。

AVPlayer还可以访问网络时,但因网络太慢而导致视频停滞时,将使用kBCOVPlaybackSessionLifecycleEventPlaybackStalled事件调用生命周期代理方法。当播放能够继续时,将使用kBCOVPlaybackSessionLifecycleEventPlaybackRecovered事件调用生命周期代理方法。这些事件仅涵盖正常播放停止的情况,不包括在搜索或视频的初始加载期间发生的缓冲。

当视频正在加载,发生搜索或因网络速度慢而停滞播放时,将使用kBCOVPlaybackSessionLifecycleEventPlaybackBufferEmpty事件调用生命周期代理方法。当播放能够继续时,将使用kBCOVPlaybackSessionLifecycleEventPlaybackLikelyToKeepUp事件调用生命周期代理方法。在这种情况下,你可能希望实现一个加载旋转器。

子类化

除非明确说明,否则iOS播放器SDK中的任何类都不应设计为可供子类化。创建非明确设计为可供子类化的任何SDK类(尤其是任何值类)的子类可能会导致不可预测的行为。

也称为“模型对象”,这些类(BCOVPlaylistBCOVVideoBCOVSourceBCOVCuePointBCOVCuePointCollection)用于在iOS播放器SDK中表示数据。必须理解这些数据类型被视为,而不是标识。这意味着,如果两个值类的实例具有完全相同的数据,它们代表了相同的概念或值,尽管在技术上它们是两个在内存地址上不同的对象。换句话说,SDK代码或你的客户端代码永远不应该使用身份比较(“指针相等”)来与值对象进行操作。相反,每个值类都实现了-isEqual:并提供了一个类特定的相等方法重载,可以替换使用其中任何一个。

这是不好的

if (myVideo == session.video) // Could lead to bugs!

这些是好的(职能等效的)

if ([myVideo isEqualToVideo:session.video])
if ([myVideo isEqual:session.video])

对于iOS播放器SDK的内部机制,可能会做像缓存值或多重复制防御性拷贝这样的操作,因此依赖指针地址来检查相等进行比较最终会导致你痛苦。

iOS Player SDK 中的值类还具有一个特性:它们是 不可变 的。一旦有了某个值的实例,就不应该试图以任何方式破坏这种不可变性,因为这可能会导致不可预测的行为。如果你的代码中想要“修改”某个值,唯一的方法是创建一个新的值。为了方便客户端获取“修改后”的值,每个值类都提供了一个 -update: 方法,该方法接受一个块,允许你在原始值的可变副本上操作。

以下是使用此方法创建一个具有不同属性的现有视频对象的“修改”版本的示例

BCOVVideo *video1; // (properties include a key "foo" whose value is "bar")
BCOVVideo *video2 = [video1 update:^(id<BCOVMutableVideo> mutable) {
    
    mutable.properties = @{ @"foo": @"quux" };
    
}];

NSLog(@"foo is %@", video1.properties[@"foo"]); // prints "foo is bar"
NSLog(@"foo is %@", video2.properties[@"foo"]); // prints "foo is quux"

// Both video1 and video2 are still immutable objects:
video1.properties = otherDictionary; // causes compiler error
video2.properties = otherDictionary; // causes compiler error

如示例所示,video1-update 方法调用后并未改变。相反,此方法返回 video1 的一个副本,除了其块体 中所进行的修改之外。你不应该允许可变的副本离开该块(例如,将其分配给 __block 变量),而应该在修改完成后使用 -update 方法返回的不可变对象。

使用播放服务检索 Brightcove 资产

播放服务类 BCOVPlaybackService 提供了通过 Brightcove 播放 API 检索您的 Brightcove 视频资产和播放列表的功能,包括丰富的元数据,例如文本轨道、预览和缩略图。以下示例展示了如何通过视频 ID 检索视频。还有可以检索带有该视频引用 ID 的视频或播放列表的方法。

[1] NSString *policyKey = <your-policy-key>;
    NSString *accountId = <your-account-id>;
    NSString *videoID = <your-video-id>;

    BCOVPlayerSDKManager *manager = [BCOVPlayerSDKManager sharedManager];
    id<BCOVPlaybackController> controller = [manager createPlaybackControllerWithViewStrategy:nil];
    [self.view addSubview:controller.view];  
 
    BCOVPlaybackService *playbackService = [[BCOVPlaybackService alloc] initWithAccountId:accoundId
                                                                                policyKey:policyKey];
    [playbackService findVideoWithVideoID:videoID
                               parameters:nil
                               completion:^(BCOVVideo *video,
                                            NSDictionary *jsonResponse,
                                            NSError      *error) {

                                   [controller setVideos:@[ video ]];
                                   [controller play];

                               }];
  1. 播放服务请求 策略密钥 以进行身份验证。有关策略密钥的更多信息以及如何获取它,请参阅 策略密钥文档

视图策略

注意: 使用视图策略块不再推荐,因为这功能可能会在未来版本中移除。

BCOVPlaybackController 对象使用 视图策略 构建,这允许你作为 SDK 的客户端定义播放控制器 view 属性返回的确切 UIView 对象。当使用会影响播放控制器视图的插件时(例如,将广告视图覆盖在视频视图上的广告插件),这一点特别重要。想象一下要如何与这样的插件集成自定义控件:通常,自定义控件只是视图层次结构中的普通 UIView 对象,漂浮在播放控制器的视频视图之上。但是,与广告插件一起,你通常希望广告漂浮在你的自定义控件之上。如何在没有深入了解播放控制器视图层次结构结构的情况下完成这件事?解决方案是构建一个视图策略,在该策略中根据你的选择将视频视图、你的自定义控件和广告视图组织在一起。播放控制器将在第一次访问它的 view 属性时调用此视图策略。策略返回的最终 UIView 对象将永久性地作为其视图(直到控制器被销毁)。

许多应用程序不需要创建视图策略,可以直接在创建新的播放控制器时传递 nil。这将创建播放控制器中的标准视频视图。但是,对于需要视图策略提供的控制权的应用程序,我们在此提供更详细的说明。

BCOVPlaybackControllerViewStrategy typedef 别名(并文档化)了这个更复杂的块签名

UIView *(^)(UIView *view, id<BCOVPlaybackController> playbackController);

此签名描述了一个Objective-C块,该块返回一个UIView并接受两个参数:一个UIView和一个播放控制器。返回值易于理解:它是您希望播放控制器的《code=view属性指向的UIView对象。但是关于块参数;传递给第一个参数的UIView是什么?为什么将播放控制器作为第二个参数传递?

第一个参数是一个UIView,如果您的视图策略不指定其他方式,则该UIView将变为播放控制器《code)view属性。为了说明这一点,您可以通过直接返回《code)view参数来创建一个无意义的函数视图策略。

BCOVPlaybackControllerViewStrategy viewStrategy =
        ^ UIView *(UIView *videoView, id<BCOVPlaybackController> playbackController) {

    return videoView;

};

这相当于在创建播放控制器时传递一个《code>nil视图策略。

第二个参数是与视图策略已经传递给同样的播放控制器对象。视图策略为什么要引用它的播放控制器?在许多情况下,可能不需要,第二个参数可以安全忽略。但某些应用程序可能需要一个需要在播放控制器中添加会话消费者的视图策略。例如,当控制器推进到新的播放会话时,更新自定义控件,需要接收新的会话通知。通过块参数将播放控制器提供给第二个参数,以便视图策略可以添加所需的任何会话消费者。

非常重要的一点是不要保留对播放控制器的此引用。也就是说,如果需要在块中使用它,那是安全的,但不要尝试将其分配给《code>__block变量或全局变量,以便您可以稍后访问它。参数传递的仅因为定义视图策略时,无法在块内封闭覆盖播放控制器引用。

以下是一个更合理的视图策略实现的示例

BCOVPlaybackControllerViewStrategy viewStrategy =
        ^(UIView *videoView, id<BCOVPlaybackController> playbackController) {

    // Create some custom controls for the video view,
    // and compose both into a container view.
    UIView<BCOVPlaybackSessionConsumer> *myControlsView = [[MyControlsView alloc] init];
    UIView *controlsAndVideoView = [[UIView alloc] init];
    [controlsAndVideoView addSubview:videoView];
    [controlsAndVideoView addSubview:myControlsView];

    // Compose the container with an advertising view
    // into another container view.
    UIView<BCOVPlaybackSessionConsumer> *adView = [[SomeAdPluginView alloc] init];
    UIView *adAndVideoView = [[UIView alloc] init];
    [adAndVideoView addSubview:controlsAndVideoView];
    [adAndVideoView addSubview:adView];

    [playbackController addSessionConsumer:myControlsView];
    [playbackController addSessionConsumer:adView];

    // This container view will become `playbackController.view`.
    return adAndVideoView;

};

让我们详细审查此视图策略做了什么:首先,它创建了一个符合《code>BCOVPlaybackSessionConsumer协议的自定义控件视图。(注意,自定义视图不必要符合此协议;可以添加某些其他非视图对象作为会话消费者。这只是为了使示例更容易理解。)请注意,在这段视图策略块中是如何组成视图层次结构的:创建一个容器视图来容纳视频视图和控件。这些视图按顺序添加,使得控件将显示在视频视图之上。然后,创建一个容器视图来容纳广告视图和第一个容器视图。它们按顺序添加,使得广告视图将显示在自定义控件和视频视图的容器之上。最后,将自定义控件和广告视图注册为会话消费者,以便在播放控制器接收到新的播放会话时,这些视图可以订阅会话上的适当事件。

再次强调,对于大多数使用情况,不需要使用视图策略。只需将播放控制器的视图添加到视图层次结构中,并在其上方组合自定义控件。但对于更精细的情况,如同使用某些插件时,有机会控制播放控制器视图的组合很有帮助,这也是为什么可以向《code>BCOVPlayerSDKManager传递视图策略以创建新的播放控制器。

使用视图策略有一个例外:您不能在视图策略块中访问播放控制器的《code>view属性。由于块被执行是因为第一次访问播放控制器的《code>view属性,在视图策略块内再次访问《code>view属性将导致您的程序崩溃。

在后台播放视频和画中画

默认情况下,当iOS应用被发送到后台或设备锁定时,iOS将暂停播放的所有视频。要改变这种行为,请将BCOVPlaybackController对象的allowsBackgroundAudioPlayback属性设置为YES。(默认值是NO,表示后台播放将暂停。)

您还应该遵循苹果在技术问答QA1668中设置的应用程序适当的后台模式和音频会话类别的指南。

在应用切换到后台之前(当应用返回到前台时重新连接),重要的是将AVPlayerLayerAVPlayer中分离出来。当allowsBackgroundAudioPlayback设置为YES时,Brightcove Player SDK将为您处理此操作。

最后,当播放背景视频(尤其是使用播放列表时),您应该使用iOS的MPRemoteCommandCenter API来允许用户在锁屏和控制中心上对播放进行控制。请注意,MPRemoteCommandCenter仅适用于iOS 7.1及以上版本;如果需要支持iOS 7.0,您应使用UIApplicationbeginReceivingRemoteControlEventsendReceivingRemoteControlEvents

重要画中画注意:当您想要在同一个播放器上支持后台音频和画中画时,您必须使用画中画状态更新BCOVPlaybackController上的pictureInPictureActive属性。如果您使用的是AVPictureInPictureController,则可以使用pictureInPictureControllerDidStartPictureInPicture:pictureInPictureControllerDidStopPictureInPicture:代理方法来更新此属性。

组合插件

如果您需要组合Player SDK插件,例如向由Google IMA管理的广告播放DRM保护的视频添加字幕。为此,创建每个插件的BCOVSessionProviders并将其连接起来,并使用该链来构建BCOVPlaybackController

BCOVPlayerSDKManager *sdkManager = [BCOVPlayerSDKManager sharedManager];
        
IMASettings *imaSettings = [[IMASettings alloc] init];
imaSettings.ppid = kViewControllerIMAPublisherID;
imaSettings.language = kViewControllerIMALanguage;
imaSettings.enableBackgroundPlayback = self.allowBackgroundAudioPlayback;
        
IMAAdsRenderingSettings *renderSettings = [[IMAAdsRenderingSettings alloc] init];
renderSettings.webOpenerPresentingController = self;
        
BCOVIMAAdsRequestPolicy *adsRequestPolicy =
    [BCOVIMAAdsRequestPolicy videoPropertiesVMAPAdTagUrlAdsRequestPolicy];


// create the sidecar subtitles session provider. it has no upstream session provider.
id<BCOVPlaybackSessionProvider> *sidecarSessionProvider =
    [sdkManager createSidecarSubtitlesSessionProviderWithUpstreamSessionProvider:nil];
    
// create the IMA session provider with an upstream sidecar subtitles session provider.
id<BCOVPlaybackSessionProvider> *imaSessionProvider =
    [sdkManager createIMASessionProviderWithSettings:imaSettings
                                adsRenderingSettings:renderSettings
                                    adsRequestPolicy:adsRequestPolicy
                                         adContainer:self.playerView.contentOverlayView
                                      companionSlots:nil
                             upstreamSessionProvider:sidecarSessionProvider];

// create the playback controller using the session provider chain.
id<BCOVPlaybackController> *playbackController =
    [sdkManager createPlaybackControllerWithSessionProvider:imaSessionProvider
                                               viewStrategy:nil];

会话提供者的链创建了一个对象的链表,其顺序对于Player SDK的正确功能是重要的。在上面的例子中,Sidecar Subtitles会话提供者放置在IMA会话提供者的上游。当与FairPlay插件结合使用时,Fairplay放置在Sidecar Subtitles会话提供者的上游。

缓冲优化

概述

随着iOS 10的发布,现在您可以控制由AVPlayer使用的向前播放缓冲区的大小。这是通过在AVPlayerItem类中设置preferredForwardBufferDuration属性来完成的。

默认情况下,Brightcove Native Player SDK以优化整体带宽而不影响播放质量的方式设置preferredForwardBufferDuration属性。可以使用自己的值覆盖此行为。

默认行为

每个人都为带宽付费,因此减少带宽消耗而不影响播放质量是很重要的。从版本5.2.0开始,Brightcove Native Player SDK会根据视频的播放动态地为您管理缓冲区大小。

在 iOS 10 之前,AVPlayer 会尽可能缓冲尽可能多的视频数据,大约 50 兆字节。这对于用户选择视频并观看至结束的观影模式来说是没有问题的,但许多现代应用现在使用 autoplay(自动播放)的方式来吸引用户,希望在几秒钟之后锁定用户。许多用户则对此视而不见,继续滚动看其他视频。这种激进的缓冲方式可能会导致缓冲几分钟的视频,而这些视频最终并无用途。

Brightcove Native Player SDK 通过从一个小基准缓冲区开始播放视频,然后在用户观看更多视频时逐步增加缓冲区大小来解决这个问题。经过一段时间后,缓冲区大小会达到上限,因为过大的缓冲区并不可行也没有帮助。

修改默认行为

如果您想保持 Brightcove Native Player SDK 的默认行为,但修改用于缓冲大小的最小值和最大值,您可以在设置 BCOVPlaybackController 时这样做

// Create mutable dictionary to hold new values
NSMutableDictionary *options = self.playbackController.options.mutableCopy;

// Set new values in dictionary
options[kBCOVBufferOptimizerMethodKey] = @(BCOVBufferOptimizerMethodDefault);
options[kBCOVBufferOptimizerMinimumDurationKey] = @(min);
options[kBCOVBufferOptimizerMaximumDurationKey] = @(max);

// Set new dictionary in your playback controller
self.playbackController.options = options;

以下选项应在调用 -BCOVPlaybackController setVideos: 之前设置。

minmax 的值

  • 这些是可设置为目标最小和最大缓冲时长的浮点值。
  • 如果设置得太小,在网络条件不稳定的情况下,播放可能会中断。
  • 如果设置得太大,AVPlayer 可能会缓冲从未被查看的数据。
  • 根据您预期的使用案例进行测试非常重要。
  • 数值指定为时间秒,且必须大于或等于 1.0。(0 是一个特殊的值,在 AVPlayerItem 中表示告诉 AVPlayer 确定其自己的缓冲区大小,就像 iOS 9 及更早版本所做的那样)。

禁用缓冲优化

如果您不想在当前播放会话中进行任何缓冲优化,可以使用相同的技术,但将优化方法设置为“None”,如下所示

// Create mutable dictionary to hold new values
NSMutableDictionary *options = self.playbackController.options.mutableCopy;

// Set new values in dictionary
options[kBCOVBufferOptimizerMethodKey] = @(BCOVBufferOptimizerMethodNone);

// Set new dictionary in your playback controller
self.playbackController.options = options;

当方法设置为“None”时,iOS 将保持对前向缓冲大小的完全控制,就像 iOS 9 及更早版本那样。

实现自己的缓冲优化方法

如果您想为播放设置自己的缓冲区大小,首先要关闭上一节中描述的缓冲优化。然后,您可以在以下 BCOVPlaybackController 代理方法中实现以下内容

- (void)playbackController:(id<BCOVPlaybackController>)controller didAdvanceToPlaybackSession:(id<BCOVPlaybackSession>)session
{
  // Make sure the property exists on the current AVPlayerItem. This will return false for iOS 9 or earlier.
  if ([session.player.currentItem respondsToSelector:NSSelectorFromString(@"preferredForwardBufferDuration")])
  {
    // Set your preferredForwardBufferDuration value here.
	 session.player.currentItem.preferredForwardBufferDuration = newPreferredForwardBufferDurationValue;
  }
}

重要:您必须针对 iOS 10 SDK 进行编译才能直接使用 preferredForwardBufferDuration 属性。不要尝试在 iOS 9 或更早版本中访问此属性,否则您的应用程序将崩溃。

如果您想动态地随时间改变缓冲区大小,您可以在 BCOVPlaybackController 的进度代理方法中以类似的方式设置 session.player.currentItem.preferredForwardBufferDuration

- (void)playbackController:(id<BCOVPlaybackController>)controller playbackSession:(id<BCOVPlaybackSession>)session didProgressTo:(NSTimeInterval)progress
{
  // Make sure the property exists on the current AVPlayerItem. This will return false for iOS 9 or earlier.
  if ([session.player.currentItem respondsToSelector:NSSelectorFromString(@"preferredForwardBufferDuration")])
  {
    // Set preferredForwardBufferDuration based on your own logic here
	 session.player.currentItem.preferredForwardBufferDuration = newPreferredForwardBufferDurationValue;
  }
}

注意:Apple 在 preferredForwardBufferDuration 中特意使用了“preferred”这个词,因为您可以设置任何您想要的值,但通常来说,AVPlayer 只会将它作为参考。还要记住,将其设置为 zero 会将缓冲区大小的完全控制权交还给 AVPlayer

在使用 BCOVPlaybackController 时使用 AVPlayerViewController

概述

BCOVPlaybackSession类中使用的AVPlayerLayer可以被AVPlayerViewController替代。使用AVPlayerViewController可以让播放器使用本地的iOS和tvOS播放控件,但这种方法也有一些限制(见下文)。

要使用AVPlayerViewController,可以设置一个名为kBCOVAVPlayerViewControllerCompatibilityKey的BCOVPlaybackController字典属性

BCOVPlayerSDKManager *sdkManager = [BCOVPlayerSDKManager sharedManager];

id<BCOVPlaybackController> playbackController;

NSMutableDictionary *mutableOptions = self.playbackController.options.mutableCopy;
// To use the AVPlayerViewController
mutableOptions[kBCOVAVPlayerViewControllerCompatibilityKey] = @YES;

// To use the BCOVPlaybackSession's AVPlayerLayer
// mutableOptions[kBCOVAVPlayerViewControllerCompatibilityKey] = @NO;

self.playbackController.options = mutableOptions;

kBCOVAVPlayerViewControllerCompatibilityKey的默认值是@NO,这意味着在未明确设置此字典属性的情况下创建的BCOVPlaybackController将默认使用BCOVPlaybackSession的AVPlayerLayer。

使用AVPlayerViewController的限制

广告:使用AVPlayerViewController的AVPlayerLayer不与以下iOS SDK广告插件兼容:IMA插件、FreeWheel插件、OnceUX插件。

因为这些插件使用了一个独立的AVPlayer实例。

分析:当使用AVPlayerViewController时,发送到Brightcove分析服务器的video_engagement事件中的player_width和player_height将报告为0。

常见问题

我的内容无法加载。有没有简单的方法来测试URL是否指向有效的视频?

如果内容封装为MP4格式,可以直接将URL粘贴到大多数Web浏览器中,视频应该可以播放(或下载到您的文件系统,然后可以在本地播放)。如果内容封装为HLS格式,可以使用QuickTime Player进行测试:选择文件 -> 打开位置…并将.m3u8播放列表URL粘贴进去,视频应该可以播放。

我可以听到音频轨道在播放,但视频偶尔会冻结几秒钟。这是怎么回事?

这是从非主线程调用只在主线程上调用UIKit或AVFoundation方法时的常见症状。《BCOVPlaybackControllerDelegate》上的代理方法总是在主线程上调用。

为什么在日志中看到一条信息表明未找到源?

此信息表明默认源选择策略无法确定选择哪个源。默认策略选择第一个其deliveryMethodkBCOVSourceDeliveryHLS("HLS")的源。如果找不到HLS源,其回退行为将选择第一个其deliveryMethodkBCOVSourceDeliveryMP4("MP4")的源。如果在视频中没有"是HLS"或"MP4"的源,该策略将选择视频的第一个源(无论其deliveryMethod是什么)。如果您不满意其选择,可以使用-[BCOVPlayerSDKManager createBasicSessionProviderWithOptions:] 并传入一个具有自定义sourceSelectionPolicy属性的BCOVBasicSessionProviderOptions实例。在手动创建视频和源时,请确保源是用适当的deliveryMethod创建的。

Apple建议播放视频的应用在设备静音时还应播放音频。为什么iOS Brightcove播放器SDK不遵守这些指南?

控制iOS应用中应用程序是否输出音频的API是AVAudioSession API。音频会话是在应用程序范围内的全局配置,这意味着它的配置会影响由Player SDK创建的AVPlayers所输出的声音以及其他应用程序可能产生的声音。由于Player SDK无法知道应用程序希望如何为这些其他声音配置音频会话,因此它不会影响音频会话。这意味着除非您明确配置应用程序的音频会话,否则默认行为是当设备静音时不输出任何音频,包括AVPlayers输出的音频。为了遵守苹果关于音频播放的建议,您(应用程序开发者)必须根据应用程序的具体需求配置音频会话。