|
|
|
版本:3.4.4
|
|
\ No newline at end of file |
|
|
|
|
|
日期:2019-05-17
|
|
|
|
|
|
|
|
# 1.概述
|
|
|
|
iOS点播SDK是适用于iOS平台的云点播SDK。使用此SDK可以与CC视频云服务进行对接,在iOS端使用CC视频的点播功能。
|
|
|
|
## 1.1功能特性
|
|
|
|
| 功能 | 描述 |
|
|
|
|
| :--------------------------------------- | :------- |
|
|
|
|
| 播放 | 支持音视频在线和本地播放功能 |
|
|
|
|
|移动端广告|支持添加视频前贴广告和暂停广告|
|
|
|
|
|播放统计|支持用户实现播放的统计|
|
|
|
|
|视频打点|支持用户自定义视频打点功能|
|
|
|
|
|视频问答|支持用户自定义视频问答功能的回调|
|
|
|
|
|视频字幕|支持从服务器获取字幕资源并显示|
|
|
|
|
| 上传 | 支持音视频上传、断点上传功能 |
|
|
|
|
| 下载 | 支持音视频下载、断点下载功能 |
|
|
|
|
|
|
|
|
|
|
|
|
## 1.2阅读对象
|
|
|
|
本文档为技术文档,需要阅读者:
|
|
|
|
|
|
|
|
* 具备基本的iOS开发能力
|
|
|
|
|
|
|
|
* 准备接入CC视频的点播SDK
|
|
|
|
|
|
|
|
# 2.开发准备
|
|
|
|
|
|
|
|
## 2.1开发环境
|
|
|
|
|
|
|
|
* Xcode:苹果官方IDE
|
|
|
|
|
|
|
|
* iOS8+
|
|
|
|
|
|
|
|
## 2.2SDK使用说明
|
|
|
|
|
|
|
|
首先,需要下载最新版本的SDK,下载地址为:[VOD_iOS_DRM_SDK](https://github.com/CCVideo/VOD_iOS_DRM_SDK),然后导入SDK包到工程,在相应的地方引入头文件`#import "DWSDK.h"`
|
|
|
|
|
|
|
|
| 名称 | 描述 |
|
|
|
|
| :--------------------------------------- | :------- |
|
|
|
|
| Demo | 使用SDK对接CC视频云服务的示例源码 |
|
|
|
|
| doc | 存放的是iOS点播SDK开发指南及离线API |
|
|
|
|
| include | SDK开放的头文件及静态库 |
|
|
|
|
|
|
|
|
SDK实现了移动端在线离线播放、上传、下载的必要接口。使用这些接口时,需提供CC视频分配的userId和API KEY。你可以登陆[CC视频管理后台](http://admin.bokecc.com)获取。CC视频云使用userId和API KEY校验你的合法性,在使用SDK接口过程中,通常用它们作为模块初始化参数,填写错误或为空会造成失败。
|
|
|
|
|
|
|
|
# 3.快速集成
|
|
|
|
|
|
|
|
注:快速集成主要提供的是视频播放、上传、下载功能(核心功能)。
|
|
|
|
|
|
|
|
## 3.1播放快速集成
|
|
|
|
|
|
|
|
### 3.1.1在Appdelegate中添加AudioSession设置:
|
|
|
|
|
|
|
|
```
|
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
|
|
{
|
|
|
|
//设置全局AVAudioSession
|
|
|
|
NSError *categoryError = nil;
|
|
|
|
BOOL success = [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&categoryError];
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
NSLog(@"Error setting audio session category: %@", categoryError);
|
|
|
|
}
|
|
|
|
|
|
|
|
NSError *activeError = nil;
|
|
|
|
success = [[AVAudioSession sharedInstance] setActive:YES error:&activeError];
|
|
|
|
if (!success)
|
|
|
|
{
|
|
|
|
NSLog(@"Error setting audio session active: %@", activeError);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.1.2创建播放器并展示在当前视图上
|
|
|
|
|
|
|
|
```
|
|
|
|
DWPlayerView *playerView = [[DWPlayerView alloc]initWithFrame:CGRectMake(0,0,ScreenWidth,ScreenHeight/2-50)];
|
|
|
|
//设置userID key
|
|
|
|
playerView.userId =USERID;
|
|
|
|
playerView.key =APIKEY;
|
|
|
|
//设置视频ID
|
|
|
|
playerView.videoId =@"xxxxxx";
|
|
|
|
//设置代理
|
|
|
|
playerView.delegate =self;
|
|
|
|
[self.view addSubview:playerView];
|
|
|
|
playerView.getPlayUrlsBlock = ^(NSDictionary *playUrls) {
|
|
|
|
//处理返回的播放信息字典
|
|
|
|
NSDictionary *dic =[[playUrls objectForKey:@"qualities"] firstObject];
|
|
|
|
NSURL *playURL =[NSURL URLWithString:[dic objectForKey:@"playurl"]];
|
|
|
|
//加载音视频资源
|
|
|
|
[playerView setURL:playURL withCustomId:nil];
|
|
|
|
//播放
|
|
|
|
[playerView play];
|
|
|
|
|
|
|
|
};
|
|
|
|
//请求播放信息
|
|
|
|
[playerView startRequestPlayInfo];
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
## 3.2上传快速集成
|
|
|
|
|
|
|
|
### 3.2.1初始化DWUploader
|
|
|
|
|
|
|
|
```
|
|
|
|
//videoTitle不得为空 videoPath音视频文件路径
|
|
|
|
DWUploader *uploader = [[DWUploader alloc] initWithuserId:USERID
|
|
|
|
andKey:APIKEY
|
|
|
|
uploadVideoTitle:videoTitle
|
|
|
|
videoDescription:videoDescripton
|
|
|
|
videoTag:videoTag
|
|
|
|
videoPath:videoPath
|
|
|
|
notifyURL:nil];
|
|
|
|
//进度的回调
|
|
|
|
uploader.progressBlock = ^(float progress, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite) {
|
|
|
|
|
|
|
|
};
|
|
|
|
//上传成功的回调
|
|
|
|
uploader.finishBlock = ^() {
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
//上传失败的回调
|
|
|
|
uploader.failBlock = ^(NSError *error) {
|
|
|
|
|
|
|
|
};
|
|
|
|
//开始上传
|
|
|
|
[uploader start];
|
|
|
|
|
|
|
|
```
|
|
|
|
## 3.3下载快速集成
|
|
|
|
注:在项目TARGETS-Build Settings-Other linker Flags添加-ObjC 或者-all_load。-ObjC:链接静态库中所有的Objective-C代码到项目中,-all_load:链接静态库中所有的代码到项目中。
|
|
|
|
### 3.3.1在Appdelegate中进行后台下载设置
|
|
|
|
```
|
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
|
|
|
|
|
|
|
|
//后台下载设置
|
|
|
|
[[DWDownloadSessionManager manager] configureBackroundSession];//必须设置
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.3.2请求下载地址及初始化DWDownloadSessionManager
|
|
|
|
```
|
|
|
|
//hlsSupport必须传 @“0”
|
|
|
|
DWPlayInfo *playinfo = [[DWPlayInfo alloc] initWithUserId:USERID andVideoId:videoid key:APIKEY hlsSupport:@"0"];
|
|
|
|
//1为视频 2为音频 0为视频+音频 若不传该参数默认为视频
|
|
|
|
playinfo.mediatype =@"1";
|
|
|
|
[playinfo start];
|
|
|
|
//设置下载HTTP通信超时时间,默认超时时间为10秒,下载过程中HTTP通信超时时,会调用errorBlock下载失败的block,告知你请求资源超时。playinfo.timeoutSeconds = 20;
|
|
|
|
//请求下载资源成功 返回下载信息 调用DWUtils解析数据
|
|
|
|
playinfo.finishBlock = ^(NSDictionary *response){
|
|
|
|
//解析得到下载信息
|
|
|
|
NSDictionary *playUrls =[DWUtils parsePlayInfoResponse:response];
|
|
|
|
NSDictionary *dic =[[playUrls objectForKey:@"definitions"] firstObject];
|
|
|
|
//下载地址字符串
|
|
|
|
urlString =[dic objectForKey:@"playurl"];
|
|
|
|
}
|
|
|
|
DWDownloadSessionManager *manager =[DWDownloadSessionManager manager];
|
|
|
|
```
|
|
|
|
|
|
|
|
### 3.3.3初始化DWDownloadModel
|
|
|
|
```
|
|
|
|
//urlString:下载地址字符串 filePath:文件下载路径
|
|
|
|
DWDownloadModel *loadModel =[[DWDownloadModel alloc]initWithURLString:urlString filePath:filePath responseToken:nil userId:nil videoId:nil];
|
|
|
|
```
|
|
|
|
### 3.3.4开始下载
|
|
|
|
```
|
|
|
|
[manager startWithDownloadModel:loadModel progress:^(DWDownloadProgress *progress,DWDownloadModel *downloadModel) {
|
|
|
|
progress下载的进度 调用DWDownloadUtility 解析相关进度的信息
|
|
|
|
downloadModel 本次下载的downloadModel
|
|
|
|
|
|
|
|
} state:^(DWDownloadModel *downloadModel,DWDownloadState state, NSString *filePath, NSError *error) {
|
|
|
|
state 下载状态 如下几种
|
|
|
|
DWDownloadStateNone, // 未下载 或 下载删除了
|
|
|
|
DWDownloadStateReadying, // 等待下载
|
|
|
|
DWDownloadStateRunning, // 正在下载
|
|
|
|
DWDownloadStateSuspended, // 下载暂停
|
|
|
|
DWDownloadStateCompleted, // 下载完成
|
|
|
|
DWDownloadStateFailed // 下载失败
|
|
|
|
|
|
|
|
}];
|
|
|
|
```
|
|
|
|
### 3.3.5批量下载
|
|
|
|
```
|
|
|
|
//通过传入userId,key,vid数组,来获取所有vid的下载路径
|
|
|
|
DWBatchDownloadUtility * bdUtility = [[DWBatchDownloadUtility alloc]initWithUserId:DWACCOUNT_USERID key:DWACCOUNT_APIKEY AndVideoIds:videoIds];
|
|
|
|
bdUtility.finishBlock = ^(NSArray * _Nonnull playInfosArray) {
|
|
|
|
//返回获取到的vid下载路径
|
|
|
|
//具体使用方式,请详见demo
|
|
|
|
};
|
|
|
|
bdUtility.errorBlock = ^(NSError * _Nonnull error) {
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
[bdUtility start];
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
# 4.功能使用
|
|
|
|
|
|
|
|
## 4.1播放功能具体使用
|
|
|
|
|
|
|
|
### 4.1.1初始化playerView
|
|
|
|
```
|
|
|
|
DWPlayerView *playerView = [[DWPlayerView alloc] initWithframe:CGRectMake(0,0,ScreenWidth,ScreenHeight/2-50)];
|
|
|
|
// 设置请求播放信息HTTP通信超时时间
|
|
|
|
playerView.timeoutSeconds = 20;
|
|
|
|
//1为视频 2为音频 0为视频+音频 若不传该参数默认为视频
|
|
|
|
playerView.mediatype =@"0";
|
|
|
|
/**
|
|
|
|
设置填充模式 如果要自定义playerView的高,请先改变填充模式
|
|
|
|
AVPlayerLayer的videoGravity属性设置
|
|
|
|
AVLayerVideoGravityResize, // 非均匀模式。两个维度完全填充至整个视图区域
|
|
|
|
AVLayerVideoGravityResizeAspect, // 等比例填充,直到一个维度到达区域边界
|
|
|
|
AVLayerVideoGravityResizeAspectFill, // 等比例填充,直到填充满整个视图区域,其中一个维度的部分区域会被裁剪
|
|
|
|
填充模式默认为AVLayerVideoGravityResizeAspect
|
|
|
|
|
|
|
|
*/
|
|
|
|
playerView.videoGravity =AVLayerVideoGravityResizeAspect;
|
|
|
|
playerView.delegate =self;//设置代理
|
|
|
|
[self.view addSubview:playerView];//添加到目标视图
|
|
|
|
注:在播放过程中(譬如全屏 非全屏的切换等)不要移除playerView,否则会出现有声音无画面的bug
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.1.2getPlayUrlsBlock 获取视频播放信息
|
|
|
|
```
|
|
|
|
player.getPlayUrlsBlock = ^(NSDictionary *playUrls) {
|
|
|
|
// [必须]判断 status 的状态,不为"0"说明该视频不可播放,可能正处于转码、审核等状态。
|
|
|
|
NSNumber *status = [playUrls objectForKey:@"status"];
|
|
|
|
if (status == nil || [status integerValue] != 0) {
|
|
|
|
NSLog("playUrlsBlock invalid");
|
|
|
|
}
|
|
|
|
// 保存解析playUrls 或 选择某种清晰度进行播放。
|
|
|
|
};
|
|
|
|
```
|
|
|
|
当playerView准备好视频播放信息时,会调用该block。你可以在该block中保存播放信息或实现播放逻辑。获取的播放信息NSDictionary *playUrls为UTF-8编码,内容形如:
|
|
|
|
```
|
|
|
|
注意:若mediatype为@"0",返回数据为视频+音频;若mediatype为@"1",则只返回视频数据;若mediatype为@"2",则只返回音频数据;若不设置mediatype,则只返回视频数据。以下以返回视频+音频为例:
|
|
|
|
{
|
|
|
|
defaultquality = 10;
|
|
|
|
qualities = (
|
|
|
|
{
|
|
|
|
desp = "\U6e05\U6670";
|
|
|
|
mediatype = 1;
|
|
|
|
playurl = "http://xxx.play.bokecc.com/...";
|
|
|
|
quality = 10;
|
|
|
|
spareurl = "http://xxx.play.bokecc.com/...";
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desp = "m4a\U539f\U58f0";
|
|
|
|
mediatype = 2;
|
|
|
|
playurl = "http://xxx.play.bokecc.com/...";
|
|
|
|
quality = 50;
|
|
|
|
spareurl = "";
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desp = "mp3\U6807\U51c6";
|
|
|
|
mediatype = 2;
|
|
|
|
playurl = "http://xxx.play.bokecc.com/...";
|
|
|
|
quality = 61;
|
|
|
|
spareurl = "";
|
|
|
|
}
|
|
|
|
);
|
|
|
|
qualityDescription = (
|
|
|
|
"清晰",
|
|
|
|
"m4a原声",
|
|
|
|
"mp3标准"
|
|
|
|
);
|
|
|
|
status = 0;
|
|
|
|
statusinfo = "正常";
|
|
|
|
videomarks = (
|
|
|
|
{
|
|
|
|
markdesc = "\U8428\U5fb7\U7b2c\U4e09\U65b9";
|
|
|
|
marktime = 3;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
markdesc = "\U6ca1\U6709\U7684\U8c0e\U8a00";
|
|
|
|
marktime = 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
questions = (
|
|
|
|
{
|
|
|
|
answers = (
|
|
|
|
{
|
|
|
|
content = "A\U3001\U963f\U65af\U987f\U53d1\U9001\U5230\U53d1";
|
|
|
|
id = 1001;
|
|
|
|
right = 0;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
content = "B\U3001\U963f\U65af\U987f\U53d1\U9001\U5230\U53d1\U4e09";
|
|
|
|
id = 1002;
|
|
|
|
right = 1;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
content = "C\U3001\U53d1\U7684\U53d1\U9001\U5230";
|
|
|
|
id = 1003;
|
|
|
|
right = 0;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
content = "D\U3001\U9632\U8f90\U5c04";
|
|
|
|
id = 1004;
|
|
|
|
right = 0;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
backSecond = "1";
|
|
|
|
content = "\U963f\U5927\U662f\U6253\U53d1\U65af\U8482\U82ac";
|
|
|
|
explainInfo = "\U963f\U65af\U987f\U53d1\U9001\U5230";
|
|
|
|
id = 99;
|
|
|
|
jump = 0;
|
|
|
|
showTime = 2;
|
|
|
|
};
|
|
|
|
subtitleDic = {
|
|
|
|
bottom = "0.23";
|
|
|
|
code = "utf-8";
|
|
|
|
color = 0x0000FF;
|
|
|
|
font = "Times New Roman";
|
|
|
|
size = 42;
|
|
|
|
surroundColor = 0xFF6600;
|
|
|
|
url = "http://1.material.bokecc.com/material/1725A8A9604EAE30/3624.srt";
|
|
|
|
subtitleName = "中文";
|
|
|
|
sort = 1
|
|
|
|
};
|
|
|
|
subtitle2Dic = {
|
|
|
|
bottom = "0.23";
|
|
|
|
code = "utf-8";
|
|
|
|
color = 0x0000FF;
|
|
|
|
font = "Times New Roman";
|
|
|
|
size = 42;
|
|
|
|
surroundColor = 0xFF6600;
|
|
|
|
url = "http://1.material.bokecc.com/material/1725A8A9604EAE30/3624.srt";
|
|
|
|
subtitleName = "英文";
|
|
|
|
sort = 2
|
|
|
|
};
|
|
|
|
defaultSubtitle = 0
|
|
|
|
authvalidate = {
|
|
|
|
enable = 0;
|
|
|
|
freetime = 15;
|
|
|
|
messaage = "\U8bf7\U8d2d\U4e70\U540e\U91cd\U8bd5!";
|
|
|
|
};
|
|
|
|
|
|
|
|
vrmode = 0;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
对其字段解释如下:
|
|
|
|
```
|
|
|
|
- status(整数)和 statusinfo(字符串) status表示这个视频在CC视频云上的当前的状态值,statusinfo 是 状态值的文字描述,如正处于转码、正在审核等。只有当 status 为0时,该视频才可以播放。你在实现App播放逻辑时需特别注意。
|
|
|
|
- defaultquality(整数) 默认清晰度值
|
|
|
|
- qualityDescription(字符串数组) 清晰度及格式文字描述
|
|
|
|
- qualities(字典的列表) 不同清晰度播放url列表
|
|
|
|
- quality(整数)和 desp(字符串)清晰度数值和清晰度文字描述。
|
|
|
|
- playurl(字符串)音视频播放url
|
|
|
|
- spareurl (字符串)音视频播放url
|
|
|
|
- vrmode (整数)1表示当前视频是VR视频 0表示当前视频是普通视频
|
|
|
|
- videomarks (打点数组) marktime为打点时间 markdesc打点描述
|
|
|
|
- questions(问答数组)showTime显示时间 jump能否跳过 content问题及选项(其中{图片URL}) backSecond回退时间 explainInfo解释 right是否正确
|
|
|
|
- subtitleDic(字幕字典信息) bottom离底部的距离比例 code编码格式 color颜色 font字体(如果没有改字体 则用默认字体) size字体大小 surroundColor背景色 url获取字幕的地址 subtitleName字幕名称 sort双语中字幕对应的位置1:上, 2:下 只有一个字幕时sort=0
|
|
|
|
- subtitle2Dic 同subtitleDic
|
|
|
|
- defaultSubtitle字幕默认显示哪条,取值含义 0: subtitleDic, 1: subtitle2Dic, 2 双语 没有字幕信息该值为-1
|
|
|
|
- authvalidate(授权验证字典信息)无此功能的客户返回信息里没有该字段,只有开通了此项功能的客户的返回信息里才有该字段。enable:0代表授权验证不通过,1代表通过 freetime:试看时间 messaage:提示信息
|
|
|
|
|
|
|
|
注:视频数据里playurl与spareurl是两个不同的线路 可切换
|
|
|
|
注:CC视频的播放url具有时效性,你需要在每次播放时请求视频播放信息,以取得最新的视频播放url。
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.1.3设置播放源
|
|
|
|
```
|
|
|
|
/* setURL方法 添加播放资源 如果有正在播放的资源,会释放掉当前播放的资源
|
|
|
|
* customId 用户自定义参数 有自定义统计参数需求/流量统计的客户必须传值
|
|
|
|
* 没有此需求的客户请传nil
|
|
|
|
* 在不需要统计的地方均传nil 譬如广告视频/本地播放
|
|
|
|
*/
|
|
|
|
[playerView setURL:url withCustomId:nil/用户自定义参数];
|
|
|
|
```
|
|
|
|
### 4.1.4播放
|
|
|
|
```
|
|
|
|
[playerView play];
|
|
|
|
```
|
|
|
|
### 4.1.5暂停
|
|
|
|
```
|
|
|
|
[playerView pause];
|
|
|
|
```
|
|
|
|
### 4.1.6滑到XX秒播放视频
|
|
|
|
```
|
|
|
|
[playerView scrub:time];
|
|
|
|
```
|
|
|
|
### 4.1.7切换清晰度
|
|
|
|
```
|
|
|
|
[playerView switchQuality:url];
|
|
|
|
```
|
|
|
|
### 4.1.8停止视频播放统计
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
停止视频播放统计 播放页面关闭时务必调用removeTimer方法
|
|
|
|
注意:播放页面关闭时 如需释放资源 调用方式如下{
|
|
|
|
[playerView removeTimer];
|
|
|
|
[playerView resetPlayer];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
如无需释放播放资源 调用方式如下{
|
|
|
|
[playerView removeTimer];
|
|
|
|
[playerView pause];
|
|
|
|
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
[playerView removeTimer];
|
|
|
|
```
|
|
|
|
### 4.1.9停止播放 释放播放资源
|
|
|
|
```
|
|
|
|
[playerView resetPlayer];
|
|
|
|
```
|
|
|
|
### 4.1.10设置超时时间
|
|
|
|
```
|
|
|
|
//默认30s 譬如设置加载超时时间为20s 20s后视频没加载出来则会回调超时的代理方法 在此方法中可以切换线路等操作
|
|
|
|
playerView.timeOutLoad =20;
|
|
|
|
playerView.timeOutBuffer=20;
|
|
|
|
```
|
|
|
|
### 4.1.11授权验证
|
|
|
|
```
|
|
|
|
//设置了授权验证的客户传值 无此功能的客户无需设置 开通此项功能的客户返回的playurls里含有authvalidate(授权验证字典信息) enable:0代表授权验证不通过 1代表通过 freetime:试看时间 messaage:提示信息
|
|
|
|
playerView.verificationCode =@"xxxxx";
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.1.12DWPlayerView的代理方法
|
|
|
|
```
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
*AVPlayerItem的三种状态
|
|
|
|
*AVPlayerItemStatusUnknown,
|
|
|
|
*AVPlayerItemStatusReadyToPlay,
|
|
|
|
*AVPlayerItemStatusFailed
|
|
|
|
*/
|
|
|
|
|
|
|
|
注:以下代理方法均已切换到主线程 可直接更新UI
|
|
|
|
// 可播放/播放中
|
|
|
|
- (void)videoPlayerIsReadyToPlayVideo:(DWPlayerView *)playerView;
|
|
|
|
|
|
|
|
//播放完毕
|
|
|
|
- (void)videoPlayerDidReachEnd:(DWPlayerView *)playerView;
|
|
|
|
//当前播放时间
|
|
|
|
- (void)videoPlayer:(DWPlayerView *)playerView timeDidChange:(float)time;
|
|
|
|
|
|
|
|
//duration 当前缓冲的长度
|
|
|
|
- (void)videoPlayer:(DWPlayerView *)playerView loadedTimeRangeDidChange:(float)duration;
|
|
|
|
|
|
|
|
//没数据 即播放卡顿
|
|
|
|
- (void)videoPlayerPlaybackBufferEmpty:(DWPlayerView *)playerView;
|
|
|
|
|
|
|
|
//有数据 能够继续播放
|
|
|
|
- (void)videoPlayerPlaybackLikelyToKeepUp:(DWPlayerView *)playerView;
|
|
|
|
|
|
|
|
//加载超时/scrub超时 此方法中可切换线路等操作
|
|
|
|
- (void)videoPlayer:(DWPlayerView *)playerView receivedTimeOut:(DWPlayerViewTimeOut )timeOut;
|
|
|
|
|
|
|
|
//加载失败 此方法中可切换线路
|
|
|
|
- (void)videoPlayer:(DWPlayerView *)playerView didFailWithError:(NSError *)error;
|
|
|
|
注:如遇到频繁切换视频请求失败的情况 可在加载失败的代理方法中切换线路 详情参见Demo
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.1.13字幕显示
|
|
|
|
```
|
|
|
|
//获取字幕信息
|
|
|
|
subtitleDic = {
|
|
|
|
bottom = "0.23";
|
|
|
|
code = "utf-8";
|
|
|
|
color = 0x0000FF;
|
|
|
|
font = "Times New Roman";
|
|
|
|
size = 42;
|
|
|
|
surroundColor = 0xFF6600;
|
|
|
|
url = "http://1.material.bokecc.com/material/1725A8A9604EAE30/3624.srt";
|
|
|
|
};
|
|
|
|
|
|
|
|
```
|
|
|
|
### 4.1.14视频广告
|
|
|
|
用户可以获取广告信息,实现片头广告、暂停广告的播放。
|
|
|
|
```
|
|
|
|
//type:@"1"片头广告 @"2"暂停广告
|
|
|
|
DWAdInfo *adInfo = [[DWAdInfo alloc]initWithUserId:USERID andVideoId:videoId type:type];
|
|
|
|
[adInfo start];
|
|
|
|
//广告接口返回结果response包括如下参数
|
|
|
|
1.返回结果response包括如下参数:
|
|
|
|
参数名称 说明
|
|
|
|
result 1代表成功,0代表失败。int类型
|
|
|
|
adid 广告id。int类型
|
|
|
|
time 播放时间。int类型。
|
|
|
|
canclick 是否能够点击广告跳转。1代表可以,0代表不可以。int类型
|
|
|
|
canskip 是否可以跳过。1代表可以,0代表不可以。int类型
|
|
|
|
skiptime 跳过时间,单位秒,经过若干秒后显示跳过按钮,0代表立即显示跳过按钮。int类型(新增)
|
|
|
|
ad 广告信息
|
|
|
|
|
|
|
|
ad包括如下参数:
|
|
|
|
参数名称 说明
|
|
|
|
materialid 素材id。int类型。
|
|
|
|
material 视频或图片链接。string类型
|
|
|
|
clickurl 跳转连接,返回结果为""代表没有跳转链接。string类型
|
|
|
|
|
|
|
|
2.json示例
|
|
|
|
成功
|
|
|
|
{
|
|
|
|
"response": {
|
|
|
|
"result": 1,
|
|
|
|
"adid":10
|
|
|
|
"time": 15,
|
|
|
|
"hasmaterials":1
|
|
|
|
"canclick":1,
|
|
|
|
"canskip":1,
|
|
|
|
"skiptime":5,
|
|
|
|
"ad": [
|
|
|
|
{
|
|
|
|
"materialid":100
|
|
|
|
"material": "http://1.material.bokecc.com/material/1936D297411C3A27/8769.flv",
|
|
|
|
"clickurl": "www.bokecc.com"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"materialid":101
|
|
|
|
"material": "http://1.material.bokecc.com/material/1936D297411C3A27/8771.flv",
|
|
|
|
"clickurl": "www.bokecc.com"
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
失败
|
|
|
|
{
|
|
|
|
"response": {
|
|
|
|
"result": 0,
|
|
|
|
"error": -1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
3.错误码
|
|
|
|
-1:参数错误,-2:该用户未投放广告,-3:该用户无type对应类型的广告位,-4:该用户type类型下无广告,-5:数据查询异常
|
|
|
|
|
|
|
|
```
|
|
|
|
### 4.1.15播放VR视频
|
|
|
|
```
|
|
|
|
//播放普通视频流程一致 区别是普通视频是放在playerView上,而播放VR视频是可以放在自定义的view上
|
|
|
|
DWVRConfiguration* config = [DWVRLibrary createConfig];
|
|
|
|
[config asVideo:playerView.player.currentItem];//DWVideoPlayer的属性AVPlayer的currentItem
|
|
|
|
[config setContainer:self view:vrView]; //vrView自定义的视图
|
|
|
|
// optional
|
|
|
|
[config projectionMode:DWModeProjectionStereoSphere];//效果
|
|
|
|
[config displayMode:DWModeDisplayNormal];//是否分配
|
|
|
|
[config interactiveMode:DWModeInteractiveTouch];//交互模式
|
|
|
|
[config pinchEnabled:true];
|
|
|
|
[config setDirectorFactory:[[CustomDirectorFactory alloc]init]];
|
|
|
|
self.vrLibrary = [config build];
|
|
|
|
注意事项:1.如果playerView存在,则播放VR视频时必须隐藏,playerView.hidden =YES;
|
|
|
|
2.如果vrView存在,则播放普通视频时必须隐藏,vrView.hidden =YES;
|
|
|
|
3.播放VR视频时 切换资源时 先vrView =nil 再重新创建一次,然后调用切换资源的方法。
|
|
|
|
4.播放VR视频时,如果发现感应模式下的方向不正确,可调用{
|
|
|
|
[self.vrLibrary switchInteractiveMode:DWModeInteractiveTouch];
|
|
|
|
[self.vrLibrary switchInteractiveMode:DWModeInteractiveMotion];
|
|
|
|
}的组合方法来解决这个问题
|
|
|
|
5. DWModeInteractiveTouch,//触摸
|
|
|
|
DWModeInteractiveMotion,//重力感应
|
|
|
|
DWModeInteractiveMotionWithTouch,//触摸及重力感应
|
|
|
|
MotionWithTouch模式下时 触摸控制左右,重力感应控制上下
|
|
|
|
具体详情参见Demo。
|
|
|
|
```
|
|
|
|
### 4.1.16GIF功能
|
|
|
|
DWGIFManger可以将正在播放的视频做成GIF图,流程为:需要先截取视频 ,再将截取的视频转成GIF图。DWGIFManger开放的API如下:
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
截取视频
|
|
|
|
@param videoUrl 视频的URL
|
|
|
|
@param outPath 输出路径
|
|
|
|
@param outputFileType 输出视频格式
|
|
|
|
@param videoRange 截取视频的范围
|
|
|
|
@param completeBlock 视频截取的回调
|
|
|
|
*/
|
|
|
|
- (void)interceptVideoAndVideoUrl:(NSURL *)videoUrl withOutPath:(NSString *)outPath outputFileType:(NSString *)outputFileType range:(NSRange)videoRange intercept:(InterceptBlock)interceptBlock;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@param mediaUrlStr URL字符串
|
|
|
|
@return 返回视频时长
|
|
|
|
*/
|
|
|
|
- (CGFloat)getMediaDurationWithMediaUrl:(NSString *)mediaUrlStr;
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
生成GIF图片
|
|
|
|
@param videoURL 视频的路径URL
|
|
|
|
@param loopCount 播放次数
|
|
|
|
@param time 每帧的时间间隔 默认0.25s
|
|
|
|
@param imagePath 存放GIF图片的文件路径
|
|
|
|
@param completeBlock 完成的回调
|
|
|
|
|
|
|
|
*/
|
|
|
|
- (void)createGIFfromURL:(NSURL*)videoURL loopCount:(int)loopCount delayTime:(CGFloat )time gifImagePath:(NSString *)imagePath complete:(CompleteBlock)completeBlock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
生成GIF图片
|
|
|
|
@param videoURL 视频的路径URL
|
|
|
|
@param frameCount 视频的总时长乘以固定数值 如:视频总时长*4
|
|
|
|
@param time 每帧的时间间隔
|
|
|
|
@param loopCount 播放次数
|
|
|
|
@param imagePath 存放GIF图片的文件路径
|
|
|
|
@param completeBlock 完成的回调
|
|
|
|
*/
|
|
|
|
- (void)createGIFfromURL:(NSURL*)videoURL withFrameCount:(int)frameCount delayTime:(CGFloat )time loopCount:(int)loopCount gifImagePath:(NSString *)imagePath complete:(CompleteBlock)completeBlock;
|
|
|
|
|
|
|
|
注意:1.截取视频前需要用获取截取视频的URL,加密SDK调用drmGIFURL方法,非加密SDK调用unDrmGIFURL方法
|
|
|
|
2.在视频将要结束播放的时候做GIF功能时,要计算截取视频的实际时长以及在播放完成的代理方法中暂停该视频,否则可能出现bug
|
|
|
|
以上API使用详情参见demo。
|
|
|
|
```
|
|
|
|
### 4.1.17音频播放功能
|
|
|
|
DWAudioPlayer可播放音频
|
|
|
|
```
|
|
|
|
//初始化音频播放器
|
|
|
|
DWAudioPlayer *audioPlayer =[[DWAudioPlayer alloc]init];
|
|
|
|
//设置代理
|
|
|
|
audioPlayer.delegate =self;
|
|
|
|
|
|
|
|
//如需播放加密音频,请设置drmServerPort
|
|
|
|
audioPlayer.drmServerPort = DWAPPDELEGATE.drmServer.listenPort;
|
|
|
|
[audioPlayer setPlayInBackground:YES];
|
|
|
|
//设置播放音频URL
|
|
|
|
[audioPlayer setAudioURL:音频URL];
|
|
|
|
//播放
|
|
|
|
[audioPlayer audioPlay];
|
|
|
|
|
|
|
|
```
|
|
|
|
DWAudioPlayer开放的API如下:
|
|
|
|
```
|
|
|
|
//跳到xx秒播放音频
|
|
|
|
- (void)audioScrub:(CGFloat )time;
|
|
|
|
|
|
|
|
//播放
|
|
|
|
- (void)audioPlay;
|
|
|
|
|
|
|
|
//暂停
|
|
|
|
- (void)audioPause;
|
|
|
|
//重播
|
|
|
|
- (void)audioRepeatPlay;
|
|
|
|
|
|
|
|
//停止播放
|
|
|
|
- (void)audioResetPlayer;
|
|
|
|
|
|
|
|
//设置播放倍速 0.5-2.0
|
|
|
|
- (void)setAudioPlayerRate:(CGFloat )rate;
|
|
|
|
|
|
|
|
//获取当前播放的时间
|
|
|
|
- (CGFloat )getCurrentPlayTime;
|
|
|
|
|
|
|
|
//获取总时间长
|
|
|
|
- (CGFloat)getTotalPlayTime;
|
|
|
|
```
|
|
|
|
DWAudioPlayer的代理方法如下:
|
|
|
|
```
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
*AVPlayerItem的三种状态
|
|
|
|
*AVPlayerItemStatusUnknown,
|
|
|
|
*AVPlayerItemStatusReadyToPlay,
|
|
|
|
*AVPlayerItemStatusFailed
|
|
|
|
*/
|
|
|
|
|
|
|
|
//所有的代理方法均已回到主线程
|
|
|
|
// 可播放/播放中
|
|
|
|
- (void)audioPlayerIsReadyToPlayVideo:(DWAudioPlayer *)audioPlayer;
|
|
|
|
//播放完毕
|
|
|
|
- (void)audioPlayerDidReachEnd:(DWAudioPlayer *)audioPlayer;
|
|
|
|
//当前播放时间
|
|
|
|
- (void)audioPlayer:(DWAudioPlayer *)audioPlayer timeDidChange:(CGFloat )time;
|
|
|
|
//duration 当前缓冲的长度
|
|
|
|
- (void)audioPlayer:(DWAudioPlayer *)audioPlayer loadedTimeRangeDidChange:(CGFloat )duration;
|
|
|
|
//进行跳转后没数据 即播放卡顿
|
|
|
|
- (void)audioPlayerPlaybackBufferEmpty:(DWAudioPlayer *)audioPlayer;
|
|
|
|
// 进行跳转后有数据 能够继续播放
|
|
|
|
- (void)audioPlayerPlaybackLikelyToKeepUp:(DWAudioPlayer *)audioPlayer;
|
|
|
|
//加载失败
|
|
|
|
- (void)audioPlayer:(DWAudioPlayer *)audioPlayer didFailWithError:(NSError *)error;
|
|
|
|
```
|
|
|
|
### 4.1.18视频打点
|
|
|
|
```
|
|
|
|
videomarks = (
|
|
|
|
{
|
|
|
|
markdesc = "\U8428\U5fb7\U7b2c\U4e09\U65b9";
|
|
|
|
marktime = 3;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
markdesc = "\U6ca1\U6709\U7684\U8c0e\U8a00";
|
|
|
|
marktime = 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
);
|
|
|
|
videomarks (打点数组) marktime为打点时间 markdesc打点描述
|
|
|
|
```
|
|
|
|
### 4.1.19视频问答
|
|
|
|
```
|
|
|
|
questions = (
|
|
|
|
{
|
|
|
|
answers = (
|
|
|
|
{
|
|
|
|
content = "A\U3001\U963f\U65af\U987f\U53d1\U9001\U5230\U53d1";
|
|
|
|
id = 1001;
|
|
|
|
right = 0;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
content = "B\U3001\U963f\U65af\U987f\U53d1\U9001\U5230\U53d1\U4e09";
|
|
|
|
id = 1002;
|
|
|
|
right = 1;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
content = "C\U3001\U53d1\U7684\U53d1\U9001\U5230";
|
|
|
|
id = 1003;
|
|
|
|
right = 0;
|
|
|
|
},
|
|
|
|
{
|
|
|
|
content = "D\U3001\U9632\U8f90\U5c04";
|
|
|
|
id = 1004;
|
|
|
|
right = 0;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
questions(问答数组)showTime显示时间 jump能否跳过 content问题及选项 backSecond回退时间 explainInfo解释 right是否正确
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.1.20播放本地音视频文件
|
|
|
|
```
|
|
|
|
//path本地音视频文件路径
|
|
|
|
NSURL *fileURL =[NSURL fileURLWithPath:path];
|
|
|
|
//音频调用如下:
|
|
|
|
[audioPlayer setAudioURL:fileURL];
|
|
|
|
[audioPlayer audioPlay];
|
|
|
|
//视频调用如下:
|
|
|
|
[playerView setURL:fileURL withCustomId:nil];
|
|
|
|
[playerView play];
|
|
|
|
|
|
|
|
```
|
|
|
|
### 4.1.21视频问答统计
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
问答统计 有此需求的客户调用 一个问题只发送一次
|
|
|
|
|
|
|
|
@param videoId 视频ID
|
|
|
|
@param questionId 问题ID
|
|
|
|
@param answerId 用户选择的选项ID,以逗号分隔多个选项ID。
|
|
|
|
如1345是单选 2067,3092,4789是多选
|
|
|
|
@param status YES正确 NO错误
|
|
|
|
*/
|
|
|
|
[playerView reportQuestionWithVideoId:videoId questionId:questionId answerId:answerId status:YES/NO];
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.1.22 访客信息收集器
|
|
|
|
```
|
|
|
|
//数据格式展示如下
|
|
|
|
...
|
|
|
|
"visitor": {
|
|
|
|
"visitorId": "123",//收集器ID
|
|
|
|
"title": "访客信息收集样例",//收集器标题
|
|
|
|
"appearTime": 85,//出现的时间(s)
|
|
|
|
"imageURL": "http://1-material.bokecc.com/material/1725A8A9604EAE30/5089.png",//展现的图片地址
|
|
|
|
"jumpURL": "www.baidu.com",//图片的跳转地址
|
|
|
|
"visitorMessage": [. //要收集的信息
|
|
|
|
{
|
|
|
|
"visitorMes": "姓名",
|
|
|
|
"visitorTip": "请输入访客姓名"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"visitorMes": "电话",
|
|
|
|
"visitorTip": "请输入访客电话"
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"visitorMes": "邮箱",
|
|
|
|
"visitorTip": "请输入访客的邮箱"
|
|
|
|
}
|
|
|
|
],
|
|
|
|
"isJump": 0 //是否跳过 0不跳过,1跳过
|
|
|
|
}
|
|
|
|
...
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.1.23 访客信息统计上报
|
|
|
|
```
|
|
|
|
/**
|
|
|
|
访客信息统计上报 有此需求的客户调用
|
|
|
|
|
|
|
|
@param visitorId 访客信息收集器ID 必填
|
|
|
|
@param videoId 视频ID 必填
|
|
|
|
@param userId CC账号ID 必填
|
|
|
|
@param message 上报信息 必填 具体格式详见demo
|
|
|
|
*/
|
|
|
|
-(void)reportVisitorCollectWithVisitorId:(NSString *)visitorId VideoId:(NSString *)videoId UserId:(NSString *)userId AndMessage:(NSString *)message;
|
|
|
|
```
|
|
|
|
|
|
|
|
## 4.2上传功能具体使用
|
|
|
|
|
|
|
|
### 4.2.1初始化DWUploader
|
|
|
|
|
|
|
|
```
|
|
|
|
//首次上传视频 videoTitle不得为空
|
|
|
|
DWUploader *uploader = [[DWUploader alloc] initWithuserId:userId
|
|
|
|
andKey:apiKey
|
|
|
|
uploadVideoTitle:videoTitle
|
|
|
|
videoDescription:videoDescripton
|
|
|
|
videoTag:videoTag
|
|
|
|
videoPath:videoPath
|
|
|
|
notifyURL:nil];
|
|
|
|
//断点续传
|
|
|
|
DWUploader *uploader = [[DWUploader alloc] initWithVideoContext:dictionary];
|
|
|
|
// 默认超时时间为10秒,若上传过程中产生HTTP通信超时,则会调用DWErrorBlock,可以在该block设置错误处理逻辑。
|
|
|
|
uploader.timeoutSeconds = 20;
|
|
|
|
//设置代理
|
|
|
|
uploader.delegate =self;
|
|
|
|
```
|
|
|
|
### 4.2.2回调的block及代理方法
|
|
|
|
|
|
|
|
```
|
|
|
|
typedef void (^DWUploaderFinishBlock)();
|
|
|
|
typedef void (^DWErrorBlock)(NSError *error);
|
|
|
|
typedef void (^DWUploaderVideoContextForRetryBlock)(NSDictionary *videoContext);
|
|
|
|
typedef void (^DWUploaderProgressBlock)(float progress, NSInteger totalBytesWritten, NSInteger totalBytesExpectedToWrite);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 在该block获取上传进度,可以在block内更新UI,如更新上传进度条。
|
|
|
|
*/
|
|
|
|
@property (copy, nonatomic)DWUploaderProgressBlock progressBlock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 上传完成时回调该block,可以在block内更新UI,如将视频标记为上传完成。
|
|
|
|
*/
|
|
|
|
@property (copy, nonatomic)DWUploaderFinishBlock finishBlock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 上传失败时回调该block,可以在该block内更新UI,如将视频标记为上传失败。
|
|
|
|
*/
|
|
|
|
@property (copy, nonatomic)DWErrorBlock failBlock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 在该block内获取上传上下文,并保存上传上下文,用来实现断线续传。
|
|
|
|
*/
|
|
|
|
@property (copy, nonatomic)DWUploaderVideoContextForRetryBlock videoContextForRetryBlock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 当遇到网络问题或服务器原因时上传暂停,回调该block。
|
|
|
|
*/
|
|
|
|
@property (copy, nonatomic)DWErrorBlock pausedBlock;
|
|
|
|
|
|
|
|
/*
|
|
|
|
*第一次请求成功后保存信息 发生异常后如果能获取到此信息 则调用initWithVideoContext:方法做断点续传
|
|
|
|
*/
|
|
|
|
@protocol DWUploaderDelegate <NSObject>
|
|
|
|
@optional
|
|
|
|
//第一次请求成功的回调
|
|
|
|
- (void)checkUploadWithFilePath:(NSString *)filePath;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
注:通常情况下,不可对同一视频多次使用第一种初始化方式初始化上传,这样会造成大量重复视频,增加你后期管理视频的同事的工作量,且CC视频会根据你的付费套餐对每天的上传次数有不同的限制,超过最大上传次数,当天便无法上传视频。
|
|
|
|
```
|
|
|
|
### 4.2.3暂停
|
|
|
|
```
|
|
|
|
[uploader pause];
|
|
|
|
```
|
|
|
|
### 4.2.4恢复上传
|
|
|
|
```
|
|
|
|
[uploader resume];
|
|
|
|
```
|
|
|
|
### 4.2.5视频压缩
|
|
|
|
```
|
|
|
|
//初始化 DWVideoCompressController
|
|
|
|
DWVideoCompressController *imagePicker = [[DWVideoCompressController alloc] initWithQuality:DWUIImagePickerControllerQualityTypeMediumandSourceType:DWUIImagePickerControllerSourceTypePhotoLibraryandMediaType:DWUIImagePickerControllerMediaTypeMovie];
|
|
|
|
|
|
|
|
//设置delegate
|
|
|
|
imagePicker.delegate = self;
|
|
|
|
注:CC视频的压缩是继承UIImagePickerController,你需要实现UIImagePickerControllerDelegate的回调来处理媒体压缩的后续功能。如果设置相关属性时可以直接用DWVideoCompressController对象修改。
|
|
|
|
|
|
|
|
//设置媒体压缩质量
|
|
|
|
typedef NS_ENUM(NSInteger, DWUIImagePickerControllerQualityType) {
|
|
|
|
DWUIImagePickerControllerQualityTypeHigh = 0,
|
|
|
|
DWUIImagePickerControllerQualityTypeMedium = 1,
|
|
|
|
DWUIImagePickerControllerQualityTypeLow = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
//设置媒体来源
|
|
|
|
typedef NS_ENUM(NSInteger, DWUIImagePickerControllerSourceType) {
|
|
|
|
DWUIImagePickerControllerSourceTypePhotoLibrary, DWUIImagePickerControllerSourceTypeCamera, DWUIImagePickerControllerSourceTypeSavedPhotosAlbum
|
|
|
|
};
|
|
|
|
|
|
|
|
//设置媒体类型
|
|
|
|
typedef NS_ENUM(NSInteger, DWUIImagePickerControllerMediaType) {
|
|
|
|
DWUIImagePickerControllerMediaTypeMovieAndImage,
|
|
|
|
DWUIImagePickerControllerMediaTypeMovie,
|
|
|
|
DWUIImagePickerControllerMediaTypeImage
|
|
|
|
};
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
## 4.3下载功能具体使用
|
|
|
|
注:在项目TARGETS-Build Settings-Other linker Flags添加-ObjC 或者-all_load。-ObjC:链接静态库中所有的Objective-C代码到项目中,-all_load:链接静态库中所有的代码到项目中。
|
|
|
|
### 4.3.1获取下载地址
|
|
|
|
|
|
|
|
```
|
|
|
|
//hlsSupport必须传 @“0”
|
|
|
|
DWPlayInfo *playinfo = [[DWPlayInfo alloc] initWithUserId:DWACCOUNT_USERID andVideoId:videoid key:DWACCOUNT_APIKEY hlsSupport:@"0"];
|
|
|
|
//1为视频 2为音频 0为视频+音频 若不传该参数默认为视频
|
|
|
|
playinfo.mediatype =@"1";
|
|
|
|
[playinfo start];
|
|
|
|
//设置下载HTTP通信超时时间,默认超时时间为10秒,下载过程中HTTP通信超时时,会调用errorBlock下载失败的block,告知你请求资源超时。playinfo.timeoutSeconds = 20;
|
|
|
|
//回调的block
|
|
|
|
@property (copy, nonatomic)DWErrorBlock errorBlock;
|
|
|
|
@property (copy, nonatomic)DWPlayInfoFinishBlock finishBlock;
|
|
|
|
|
|
|
|
请求下载资源成功 返回下载信息 调用DWUtils解析数据
|
|
|
|
playinfo.finishBlock = ^(NSDictionary *response){
|
|
|
|
|
|
|
|
NSDictionary *playUrls =[DWUtils parsePlayInfoResponse:response];
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
得到的playurls如下
|
|
|
|
{
|
|
|
|
defaultdefinition = 10;
|
|
|
|
definitionDescription = (
|
|
|
|
"\U6e05\U6670",
|
|
|
|
"\U9ad8\U6e05"
|
|
|
|
);
|
|
|
|
definitions = (
|
|
|
|
{
|
|
|
|
definition = 10;
|
|
|
|
desp = "\U6e05\U6670";
|
|
|
|
playurl = "http://d1-33.play.bokecc.com/flvs/cb/QxhEr/hKboX7hTIY-10.pcm?t=1493352053&key=11BFE2077FC9D38787957E49128E4E1C&upid=8342481493344853732";
|
|
|
|
},
|
|
|
|
{
|
|
|
|
definition = 20;
|
|
|
|
desp = "\U9ad8\U6e05";
|
|
|
|
playurl = "http://d1-33.play.bokecc.com/flvs/cb/QxhEr/hKboX7hTIY-20.pcm?t=1493352053&key=AB2A50D26D0ADDBF01FB5DD0AE8611BF&upid=8342481493344853732";
|
|
|
|
}
|
|
|
|
);
|
|
|
|
status = 0;
|
|
|
|
statusinfo = "\U6b63\U5e38";
|
|
|
|
token = "122,125,10,120,127,14,10,8,1,120,123,124,123,10,122,14,125,120,11,123,1,11,11,120,127,0,14,0,14,0,8,15";
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
### 4.3.2开始下载
|
|
|
|
|
|
|
|
```
|
|
|
|
//在Appdelegate中进行后台下载设置
|
|
|
|
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
|
|
|
{
|
|
|
|
//是否允许移动流量下载
|
|
|
|
[DWDownloadSessionManager manager].allowsCellular =YES;
|
|
|
|
//后台下载设置
|
|
|
|
[[DWDownloadSessionManager manager] configureBackroundSession];//必须设置
|
|
|
|
}
|
|
|
|
|
|
|
|
//初始化DWDownloadSessionManager manager是个单例
|
|
|
|
DWDownloadSessionManager *manager =[DWDownloadSessionManager manager];
|
|
|
|
//设置 DWDownloadModel 注:若你所下载的 videoId 未启用视频加密功能,则保存的文件扩展名[必须]是 mp4,responseToken userId videoId均为nil 否则无法播放。 若你所下载的 videoId 启用了视频加密功能,则保存的文件扩展名[必须]是 pcm,responseToken userId videoId必须有值 否则无法播放。详情参见Demo。
|
|
|
|
DWDownloadModel *loadModel =[[DWDownloadModel alloc]initWithURLString:urlString filePath:videoPath responseToken:nil userId:nil videoId:nil];
|
|
|
|
//开始下载
|
|
|
|
[manager startWithDownloadModel:loadModel progress:^(DWDownloadProgress *progress,DWDownloadModel *downloadModel) {
|
|
|
|
progress下载的进度 调用DWDownloadUtility 解析相关进度的信息
|
|
|
|
downloadModel 本次下载的downloadModel
|
|
|
|
|
|
|
|
} state:^(DWDownloadModel *downloadModel,DWDownloadState state, NSString *filePath, NSError *error) {
|
|
|
|
state 下载状态 如下几种
|
|
|
|
DWDownloadStateNone, // 未下载 或 下载删除了
|
|
|
|
DWDownloadStateReadying, // 等待下载
|
|
|
|
DWDownloadStateRunning, // 正在下载
|
|
|
|
DWDownloadStateSuspended, // 下载暂停
|
|
|
|
DWDownloadStateCompleted, // 下载完成
|
|
|
|
DWDownloadStateFailed // 下载失败
|
|
|
|
|
|
|
|
}];
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
### 4.3.3DWDownloadSessionManager中开放的API 具体详情参见demo。也可使用代理方法更新下载的进度和状态。注:如无特殊需要 maxDownloadCount resumeDownloadFIFO isBatchDownload 均不需要设置。
|
|
|
|
|
|
|
|
```
|
|
|
|
// 下载代理
|
|
|
|
@protocol DWDownloadDelegate <NSObject>
|
|
|
|
|
|
|
|
// 更新下载进度
|
|
|
|
- (void)downloadModel:(DWDownloadModel *)downloadModel didUpdateProgress:(DWDownloadProgress *)progress;
|
|
|
|
|
|
|
|
// 更新下载状态
|
|
|
|
- (void)downloadModel:(DWDownloadModel *)downloadModel didChangeState:(DWDownloadState)state filePath:(NSString *)filePath error:(NSError *)error;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 下载管理类 封装NSURLSessionDownloadTask
|
|
|
|
*/
|
|
|
|
@interface DWDownloadSessionManager : NSObject<NSURLSessionDownloadDelegate>
|
|
|
|
|
|
|
|
// 下载代理
|
|
|
|
@property (nonatomic,weak) id<DWDownloadDelegate> delegate;
|
|
|
|
|
|
|
|
// 等待中的模型 只读
|
|
|
|
@property (nonatomic, strong,readonly) NSMutableArray *waitingDownloadModels;
|
|
|
|
|
|
|
|
// 下载中的模型 只读
|
|
|
|
@property (nonatomic, strong,readonly) NSMutableArray *downloadingModels;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* maxDownloadCount resumeDownloadFIFO起作用的前提是设置 isBatchDownload =NO
|
|
|
|
* 设置maxDownloadCount 是为了处理 譬如网络不好的时候 设置一次只下载一个视频 而不是必须要求有多个视频并发下载
|
|
|
|
* 注意 最大下载数的概念 是少于或等于
|
|
|
|
*/
|
|
|
|
|
|
|
|
// 最大下载数
|
|
|
|
@property (nonatomic, assign) NSInteger maxDownloadCount;
|
|
|
|
|
|
|
|
// 等待下载队列 先进先出 默认YES, 当NO时,先进后出
|
|
|
|
@property (nonatomic, assign) BOOL resumeDownloadFIFO;
|
|
|
|
|
|
|
|
// 全部并发 默认YES, 当YES时,忽略maxDownloadCount
|
|
|
|
@property (nonatomic, assign) BOOL isBatchDownload;
|
|
|
|
|
|
|
|
// 后台session configure
|
|
|
|
@property (nonatomic, strong) NSString *backgroundConfigure;
|
|
|
|
@property (nonatomic, copy) void (^backgroundSessionCompletionHandler)();
|
|
|
|
|
|
|
|
// 后台下载完成后调用 返回文件保存路径filePath
|
|
|
|
@property (nonatomic, copy) NSString *(^backgroundSessionDownloadCompleteBlock)(NSString *downloadURL);
|
|
|
|
|
|
|
|
// 单例
|
|
|
|
+ (DWDownloadSessionManager *)manager;
|
|
|
|
|
|
|
|
// 配置后台session
|
|
|
|
- (void)configureBackroundSession;
|
|
|
|
|
|
|
|
// 获取正在下载模型
|
|
|
|
- (DWDownloadModel *)downLoadingModelForURLString:(NSString *)URLString;
|
|
|
|
|
|
|
|
// 获取后台运行task
|
|
|
|
- (NSURLSessionDownloadTask *)backgroundSessionTasksWithDownloadModel:(DWDownloadModel *)downloadModel;
|
|
|
|
|
|
|
|
// 是否已经下载
|
|
|
|
- (BOOL)isDownloadCompletedWithDownloadModel:(DWDownloadModel *)downloadModel;
|
|
|
|
|
|
|
|
// 取消所有完成或失败后台task
|
|
|
|
- (void)cancleAllBackgroundSessionTasks;
|
|
|
|
|
|
|
|
// 开始下载
|
|
|
|
- (DWDownloadModel *)startDownloadURLString:(NSString *)URLString toDestinationPath:(NSString *)destinationPath progress:(DWDownloadProgressBlock)progress state:(DWDownloadStateBlock)state;
|
|
|
|
|
|
|
|
// 开始下载
|
|
|
|
- (void)startWithDownloadModel:(DWDownloadModel *)downloadModel;
|
|
|
|
|
|
|
|
// 开始下载
|
|
|
|
- (void)startWithDownloadModel:(DWDownloadModel *)downloadModel progress:(DWDownloadProgressBlock)progress state:(DWDownloadStateBlock)state;
|
|
|
|
|
|
|
|
// 恢复下载(除非确定对这个model进行了suspend,否则使用start)
|
|
|
|
- (void)resumeWithDownloadModel:(DWDownloadModel *)downloadModel;
|
|
|
|
|
|
|
|
// 暂停下载
|
|
|
|
- (void)suspendWithDownloadModel:(DWDownloadModel *)downloadModel;
|
|
|
|
|
|
|
|
// 取消下载 YES清除已下载的数据 NO不清除
|
|
|
|
- (void)cancleWithDownloadModel:(DWDownloadModel *)downloadModel isClear:(BOOL )isClear;
|
|
|
|
|
|
|
|
// 删除下载文件
|
|
|
|
- (void)deleteFileWithDownloadModel:(DWDownloadModel *)downloadModel;
|
|
|
|
|
|
|
|
// 删除所有的下载文件 downloadDirectory:对应的文件路径videoPath
|
|
|
|
- (void)deleteAllFileWithDownloadDirectory:(NSString *)downloadDirectory;
|
|
|
|
|
|
|
|
//根据路径获取resumeData path:传原先的下载URL字符串
|
|
|
|
- (NSData *)resumeDataFromFileWithFilePath:(NSString *)path;
|
|
|
|
|
|
|
|
//根据新的URL生成新的resumeData resumeData:原先下载的data urlString:新的下载URL字符串
|
|
|
|
- (NSData *)newResumeDataFromOldResumeData:(NSData *)resumeData withURLString:(NSString *)urlString;
|
|
|
|
|
|
|
|
@end
|
|
|
|
注:下载的URL的时效是两小时。两小时后URL失效,可根据开放的API做断点续传。因为iOS11.3后的系统bug,目前在11.3后的系统中无法做URL失效后的断点续传功能,代码中也要相应增加系统版本判断,详情参见demo。
|
|
|
|
|
|
|
|
```
|
|
|
|
## 4.4Demo具体使用
|
|
|
|
Demo是使用SDK对接CC视频云的示例源码,Demo的设计旨在展示SDK各项功能的使用方法,如果希望应用获得更好的使用体验,要根据需求自行更改。Demo使用流程如下:
|
|
|
|
|
|
|
|
## 4.4.1设置账户信息
|
|
|
|
首先将你userId和API KEY填写在Demo工程下的Demo-Prefix.pch 中:
|
|
|
|
```
|
|
|
|
#define USERID @"****************"
|
|
|
|
#define APIKEY @"********************************"
|
|
|
|
```
|
|
|
|
## 4.4.2设置播放使用的videoId
|
|
|
|
在DWPlayerViewController.m中修改generateTestData函数:
|
|
|
|
```
|
|
|
|
- (void)generateTestData
|
|
|
|
{
|
|
|
|
// 将@"..."替换成你要播放的videoId,可以添加多个。
|
|
|
|
self.videoIds = @[];
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
## 4.4.3设置下载使用的videoId
|
|
|
|
需要在DWDownloadViewController.m中修改generateTestData函数:
|
|
|
|
|
|
|
|
```
|
|
|
|
- (void)generateTestData
|
|
|
|
{
|
|
|
|
// 将@"..."替换成你要下载的videoId,可以添加多个。
|
|
|
|
self.videoIds = @[];
|
|
|
|
}
|
|
|
|
|
|
|
|
```
|
|
|
|
Demo配置完毕,可以使用Demo测试你的账号。
|
|
|
|
|
|
|
|
## 4.4.4如何调试和反馈问题
|
|
|
|
SDK提供了DWLog模块用来打印HTTP通信日志,可以在App的任意位置开启或关闭 打印HTTP通信日志等功能。下面是DWLog的使用方法:
|
|
|
|
|
|
|
|
```
|
|
|
|
// 开启 打印HTTP通信日志 功能
|
|
|
|
[DWLog setIsDebugHttpLog:YES];
|
|
|
|
// 关闭 打印HTTP通信日志 功能
|
|
|
|
[DWLog setIsDebugHttpLog:NO];
|
|
|
|
```
|
|
|
|
当遇到无法播放、上传或下载时,首先要排除userId和API KEY是否有效,其次判断网络是否正常、是否已经连接、 videoId是否是userId和API KEY名下的视频。除此之外还可以通过 HTTP通信日志排查问题。
|
|
|
|
|
|
|
|
## 4.4.5关于错误码
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
/*
|
|
|
|
error code
|
|
|
|
播放相关的 100 +
|
|
|
|
下载相关的 200 +
|
|
|
|
上传相关的 300 +
|
|
|
|
网络相关的 400 +
|
|
|
|
*/
|
|
|
|
|
|
|
|
代码 说明
|
|
|
|
100 playinfo接口返回请求失败
|
|
|
|
101 视频不可用
|
|
|
|
102 视频处理中
|
|
|
|
103 视频已删除
|
|
|
|
104 视频转码失败
|
|
|
|
105 视频状态未知错误
|
|
|
|
130 创建AVPlayer 失败
|
|
|
|
131 未知播放错误
|
|
|
|
300 xml解析失败
|
|
|
|
301 断电续传参数错误
|
|
|
|
302 用户剩余空间不足
|
|
|
|
303 用户服务终止
|
|
|
|
304 服务器处理错误
|
|
|
|
305 访问过于频繁
|
|
|
|
306 用户服务无权限
|
|
|
|
399 上传失败
|
|
|
|
400 网络资源暂时不可用
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
更多信息请参考[CC视频开发者支持网站](http://doc.bokecc.com/),如果在使用SDK过程中遇到其他问题请联系CC客服进行反馈。
|
|
|
|
|
|
|
|
# 5.API查询
|
|
|
|
[https://github.com/CCVideo/VOD_iOS_DRM_SDK/tree/master/doc/api](https://github.com/CCVideo/VOD_iOS_DRM_SDK/tree/master/doc/api)
|
|
|
|
|
|
|
|
|
|
|
|
# 6.Q&A |