PAAS 点播服务 开发指南

产品介绍    

基本描述

微吼云视频点播基于微吼多年的技术和经验积累,为有点播服务需求的用户提供点播上传、音视频转码、音视频存储、CDN加速、iOS/Android/PC多终端播放的一体化解决方案。点播服务提供控制台上传,iOS、Android、Javascript端的播放器SDK,web端管理控制台及服务端API接口,帮助用户快速完成点播平台的搭建。

目前,微吼云点播服务面向微吼云注册用户开放。

核心能力

1.视频上传

支持控制台本地上传、支持直播录制转点播,适应不同场景下的上传需求;支持多种音视频格式上传。

2.极致加速体验

具备大规模全网分发能力,支持百万级并发直播观看需求,为音视频点播提供加速服务,带来更快速、更流畅的视听体验。

3.支持多平台播放

提供多终端播放器SDK,支持Android/iOS/Web平台,开发者可通过集成SDK快速接入点播服务。

4.数据统计

提供多维度的数据统计分析,用户可快速查看服务的使用量和服务访问统计的情况。

产品架构

主要功能    

类别 功能名称 详细内容
视频上传 控制台上传 进入点播控制台页面,可选择本地视频文件进行上传
视频转码 转码设置 支持转码设置,转码输出支持720P、480P、360P、音频
点播回调 回调设置 设置回调URL,主动将回放转码状态返回给用户
视频管理 管理方式 支持通过控制台和API两种方式对视频进行管理
控制台管理 支持点播视频上传、点播视频查询、点播视频预览和点播视频删除
API管理 支持生成点播文件、删除点播、获取点播视频列表、配置点播转码、指定回放文件转码
数据统计 控制台统计 查询空间、流量、观众访问数据
数据统计 API统计 查询流量

产品定价    

1、计费类型及说明

微吼云点播服务采用后付费方式,即使用服务后扣费的计费方式。您需要先在微吼云账户预先充值,系统会按照不同的功能实时或按天从您的账户余额中扣除实际消费产生的金额。

2、计费方式说明

微吼云的计费项分为以下三部分:

点播存储:直播录制的视频文件、上传到微吼云点播服务的视频文件和转码后的视频文件占用的存储空间,按存储容量计费。

点播流量:视频进行播放时,观看产生的全网下行流量,按下行流量计费。

点播转码:存储在微吼云点播服务的视频文件进行转码处理时,按照文件转码时长进行计费。

您可以通过控制台查看微吼云点播服务的实际使用量。

2.1 点播存储

价格

单价:0.02元/G/天

计费规则

计费方式:后付费计费方式

计费统计项:根据实际使用量收费,统计每天使用的存储空间量值为当天的计费值。

计费规则:统计一天内使用的存储空间,按照实际使用的存储空间乘以单价计费。

例:当天使用的存储空间为100G,则收费为100*0.02=2元

计费周期:按天扣费,按天出消费明细,每个月出账单。每个月的账单会在次月1号生成。

计费说明

1.计费点为当天使用的点播存储空间。

2.按天进行扣费,请确保账户余额充足,以免影响您的业务。

2.2 点播流量

价格

单价:1.5元/G

计费规则

计费方式:后付费计费方式

计费统计项:统计观看产生的全网下行流量。

计费规则:实时进行扣费,按照实时消耗的流量乘以单价计费。

例:当天使用的流量为100G,则收费为100*1.5=150元

计费周期:实时扣费,按小时出消费明细,每个月出账单。每个月的账单会在次月1号生成。

计费说明

1.计费点为观看过程中实际消耗的流量。

2.实时进行扣费,请确保账户余额充足,以免影响您的业务。

2.3 点播转码

价格

单价:0.08元/分钟

注意:多码率场景下,您可以添加多条线路(2~3条),例如其中有N条线路涉及转码计费,则价格为N*0.08元/分钟。

计费规则

计费方式:后付费计费方式

计费统计项:转码时长

计费规则:完成一个点播文件的转码后进行扣费,按照转码的时长乘以单价计费,时长精确到分钟,不足一分钟的不计入计费。

例:当转码时长为100分钟,则收费为100*0.08=8元

  • 有N路转码流直播:总时长 = 所有直播流的转码时长之和。

计费周期:完成一个点播文件的转码后进行扣费,按小时出消费明细,每个月出账单。每个月的账单会在次月1号生成。

计费说明

1.功能默认关闭,可在微吼云控制台手动开启。

2.使用转码功能会相应的收取转码费用。

3.完成一个点播文件的转码后进行扣费,请确保账户余额充足,以免影响您的业务

3、欠费说明

1.欠费后工作人员会与您进行联系,如还未进行充值,将会停掉您的服务。

2.开通策略:账户充值余额为正后则会自动开通服务。

控制台指南    

创建账号

申请开通微吼云账号,提供用户资料,微吼服务人员在后台为用户开通平台账号,账号开通后,用户即可登录,成为一名开发者。

创建应用

登录成功后,点击左侧或者应用管理页面中的创建应用按钮,创建一个新应用

添加服务

创建应用后,点击添加服务,弹出添加服务对话框,选择点播服务,点击确定,点播服务添加成功。

点播配置

点播服务添加成功后,可对服务进行配置,点播配置包含应用信息、转码设置两部分

应用信息

应用信息包含Appid、回调URL

回调URL:设置回调URL,填写完成,点击保存,回调URL设置成功。点播回调URL设置成功后,会主动将视频转码&点播文件生成状态通过指定的URL通知用户

转码设置

点击配置,可选择需要转码的码率,支持720P、480P、360P、音频。

转码设置还可以通过API进行控制,具体操作参考直播服务端API。

规格说明:

720P:分辨率720P 码率650kb

480P:分辨率480P 码率450kb

360P:分辨率360P 码率330kb

音频:AAC

提醒:开启转码后会产生对应费用,请根据实际情况留意相关成本支出。

视频管理

视频管理支持对视频进行上传、查询、删除、预览操作。

视频上传

点击视频上传按钮,本地选择视频文件,点击上传,视频文件上传成功。

规格说明:

上传视频:RMVB、MP4、AVI、WMV、MKV、FLV、MOV

上传音频:MP3、WAV

文件大小:5G内

提醒:上传视频时会产生对应费用,请根据实际情况留意相关成本支出。

视频查询

搜索框中输入视频ID/视频文件名称,列表中依照搜索条件将检索出的视频文件显示在列表中

视频删除

选中需要删除的视频,点击删除或批量删除按钮,视频文件被彻底删除。

视频预览

选择某个视频,点击预览,可预览该视频文件,观看视频效果

流量空间

用户可以通过菜单选择流量空间,对空间、流量信息,根据日期进行查看。

统计分析

用户可以通过菜单选择统计分析,对观众人数、观看次数、观众的地理位置分布、观看终端分布、观看浏览器分布信息,根据日期进行查看。

客户端集成

客户端SDK下载:

SDK下载

客户端SDK集成文档:

ios SDK开发集成

Android SDK开发集成

Javascript SDK开发集成

服务端集成

服务端API文档

服务端API    

接口概述    

1 请求说明

1.1 请求地址

http://api.vhallyun.com/api/v1/controller/action

  • controller/action 为每个接口单独提供

1.2 通信协议

请求支持HTTP和HTTPS两种访问方式

1.3 请求方法

同时支持POST&GET方式,GET方式查询字符串(名称/值对)是在GET请求的URL中发送的,POST方式查询字符串(名称/值对)是在POST请求的HTTP消息主体中发送的。

1.4 请求参数

每个请求都需要包含的公共请求参数

1.5 字符编码

所有接口均使用UTF-8编码

2 公共参数

2.1 公共请求参数(如无特殊说明,接口中均包含公共请求参数)

所有接口均需要放置以下公共参数在请求头中,用于标识用户和接口鉴权。后续的接口说明不再对这些参数进行说明,但每次发起请求均需要携带。

参数 类型 是否必选 含义
app_id string 应用ID
signed_at string 鉴权时间,时间戳
sign string 鉴权签名

2.2 公共响应参数(如无特殊说明,接口中的响应参数均为data中的数据)

参数 类型 是否必选 含义
code int 请求状态码 (200 成功)
msg string 失败原因(默认空字符串)
data json 请求数据

2.3 公共错误码

参数 类型 含义
10001 int 应用ID不能为空
10002 int 鉴权时间不能为空
10003 int 鉴权签名不能为空
20001 int 应用查询为空
20003 int 开发者不存在
30004 int 接口鉴权失败
30003 int 当前开发者尚未通过认证

3 API鉴权方案

使用业界通用方案。

  • 我们为客户的每个应用,分配一个app_id和一个secret_key。
  • app_id和一个secret_key获取地址 : http://yun.vhall.com/console/app/index (应用->设置->应用信息)
  • 客户的所有API请求中,需携带app_id。用于识别应用。
  • 同时,客户对请求中所有参数(包括app_id)进行字典序排序,并拼接成字符串。
  • 在此字符串首尾各拼接secret_key。
  • 对拼接后的字符串进行md5,得到sign。
  • 将得到的sign作为请求参数之一传递。
  • VOP服务器收到所有参数后,根据app_id取得对应的secret_key,然后依照同样的算法计算sign。验证与传递的sign是否一致。

例如:

<?php
$secret_key = "f145b675f441cc00dd3e55746a0f4780";
$params = [
    "room_id"=> "123456789",
    "app_id"=> "3eb7261",
    "signed_at"=> "1484620708"
];
// 按参数名升序排列
ksort($params);
// 将键值组合
array_walk($params,function(&$value,$key){
    $value = $key . $value;
});
// 拼接,在首尾各加上$secret_key,计算MD5值
$sign = md5($secret_key . implode('',$params) . $secret_key);

AccessToken    

生成AccessToken

API 名称

base/create-access-token,用于SDK权限校验,针对点播服务。如果您同时集成多个服务,可在入参时传入相应服务的权限值,具体权限值可参考个服务的参数描述。

入参

参数 类型 是否必选 含义
third_party_user_id string 第三方用户ID
expire_time string 过期时间 默认为一天,最大为一天 格式为 2017/01/01 00:00:00

参数示例

{
	third_party_user_id : "vhall_user_nelsonking", // 第三方用户ID
	expire_time : 2017/01/01 00:00:00, // 过期时间
}

出参

参数 类型 是否必选 含义
access_token string token 令牌

错误码

错误码 类型 含义
10012 int 第三方用户ID不能为空
40004 int 时间类型不正确

响应格式

{
    "code": 200,
    "msg": "",
    "data": {
        "access_token": ""
    }
}

销毁AccessToken

API 名称

base/destroy-access-token

入参

参数 类型 是否必选 含义
access_token string 访问令牌

出参

参数 类型 是否必选 含义
destory_token string 销毁的AccessToken

错误码

错误码 类型 含义

响应格式

{
    "code": 200,
    "msg": "",
    "data": [
		"destory_token" : "access:app_id_1:jfalsiecnm"
	]
}

生成点播文件    

描述

record/create,将直播录制文件生成点播文件

请求参数

参数 类型 是否必选 含义
room_id string 房间ID
start_time string 点播生成时间 格式 2017/01/01 00:00:00
end_time string 点播结束时间 格式 2017/01/01 00:00:00

响应参数

参数 类型 是否必选 含义
record_id string 回放ID

错误码

错误码 类型 含义
10013 int 创建点播开始时间不能为空
10014 int 创建点播结束时间不能为空
20002 int 房间查询为空
30001 int 不是当前房间拥有者
40004 int 时间类型不正确
60001 int 录制功能未开启

响应示例

{
    "code": 200,
    "msg": "",
    "data": {
        "record_id": "6e5692bb"
    }
}

再裁剪生成回放    

描述

record/create-more,对已有的回放m3u8操作裁剪,并生成新的最终回放.

请求参数

参数 类型 是否必选 含义
record_id string 回放ID
room_id string 房间ID
point json 文字打点信息 秒/单位 格式:[{"timePoint": 12,"msg": "abc"}, {"timePoint": 38,"msg": "abc"}]
cut json 裁剪片段信息 秒/单位 格式:[ { "start": 1,"end": 5}, {"start": 10,"end": 20}]

响应参数

参数 类型 是否必选 含义
record_id string 回放ID

错误码

错误码 类型 含义
10008 int 房间ID不能为空
20002 int 房间查询为空
20006 int 当前回放查询为空
30001 int 不是当前房间拥有者
40004 int 时间类型不正确
50003 int 生成回放失败

响应示例

{
    "code": 200,
    "msg": "",
    "data": {
        "record_id": "6e5692bb"
    }
}

删除点播    

描述

record/delete,删除点播文件

请求参数

参数 类型 是否必选 含义
record_id string 房间ID

响应参数

参数 类型 是否必选 含义
delete_record_id int 删除的点播ID

错误码

错误码 类型 含义
10015 int 点播ID不能为空
20006 int '当前点播查询为空

响应示例

{
    "code": 200,
    "msg": "",
    "data": {
        "delete_record_id": "ead7e8e1"
    }
}

点播列表    

描述

record/lists,获取点播文件列表

请求参数

参数 类型 是否必选 含义
pos int 当前获取条目节点 eg : 10 从第10条开始查询
limit int 获取条目数量

响应参数

参数 类型 是否必选 含义
record_id string 点播ID
app_id string app_id
name string 点播名称
created_at string 创建时间

错误码

错误码 类型 含义
40008 int 分页起始提条目不正确
40009 int 分页条目不正确
20006 int 当前回放查询为空

响应示例

{
    "code": 200,
    "msg": "",
    "data": [
        {
            "record_id": "bfd60d4e",
            "app_id": "9320432d",
            "name": "lss_24316d41",
            "created_at": "2017-12-12 16:00:07"
        },
        {
            "record_id": "f7d363e7",
            "app_id": "9320432d",
            "name": "",
            "created_at": "2017-12-13 15:28:39"
        }
    ]
}

配置点播转码    

描述

record/set-trans-code-info,配置点播文件转码,支持360P/480P/720P

请求参数

参数 类型 是否必选 含义
rate string 转换清晰度 多个清晰度以英文逗号分开,清晰度见下面列表 eg : 360P,720P

清晰度列表

参数 类型 含义
360P string 360P
480P string 480P
720P string 720P

响应参数

参数 类型 是否必选 含义
rate string 配置的清晰度

错误码

错误码 类型 含义
10024 int 转码配置不能为空
40010 int 转码类型不正确

响应示例

{
    "code": 200,
    "msg": "",
    "data": {
        "rate": "360P,720P"
    }
}

指定点播文件转码    

描述

record/trans-record,指定点播文件转码

请求参数

参数 类型 是否必选 含义
record_id string 点播ID

错误码

错误码 类型 含义
10015 int 点播ID不能为空
20006 int 当前回放查询为空
30010 int 不是当前点播拥有者

响应示例

{
    "code": 200,
    "msg": "",
    "data": []
}

回调管理    

回调概述    

回调说明

  • 如需回调服务需要在控制台添加回调接口
  • 添加回调域后,该服务下回调服务会自动往回调接口上推送数据

回调失败判定

  • 当在控制台填写固定回调接口地址后,需要在接口中返回 success 字符串

以PHP为例

exit("success");
  • 当回调接口未返回success字符串时,回调服务会被认定为失败,并重试
  • 当重试次数达到3次时,该回调信息会被记录到数据库中,请使用接口查询

回调格式

  • 通知信息是以 JSON 格式进行组织的,注意这里的 POST 格式的 ContentType 是 application/json。

公共头信息

以下的字段每种类型的回调都一定会携带:

参数名 类型 含义
User-Agent string 回调代理信息
Content-Type string application-json 数据格式
Content-Length int 数据长度
User-Agent: vhall
Content-Type: application/json
Content-Length: content length

回调签名

使用请求参数构造规范化的请求字符串(Canonicalized Query String)

a) 按照参数名称的字典顺序对请求中所有的请求参数(包括文档中描述的“公共请求参数”和给定了的请求接口的自定义参数,但不能包括“公共请求参数”中提到signature参数本身)进行排序。

注:当使用GET方法提交请求时,这些参数就是请求URI中的参数部分(即URI中“?”之后由“&”连接的部分)。

b) 对每个请求参数的名称和值进行编码。名称和值要使用UTF-8字符集进行URL编码,URL编码的编码规则是:

  • 对于字符 A-Z、a-z、0-9以及字符“-”、“_”、“.”、“~”不编码;

c) 对编码后的参数名称、私钥和值使用英文等号(|)进行连接。

d) 再把英文竖线连接得到的字符串按参数名称的字典顺序依次连接,即得到规范化字符串。

使用上一步构造的规范化字符MD5计算,即得到签名的字符串:

签名方法示例

//PHP版本代码
$privateKey = 'abcdefg';    // app secret_key
data = $_POST;
$sign = $data['signature'];
unset($data['signature']);
$sign_new = makeSignature($data , $privateKey);//调用签名生成函数

if($sign == $sign_new){
    echo 'success';
}else{
    echo 'fail';
}

//$privateKey为回调接口私钥
//$data为回传的POST数据数组,剔除掉signature键值
//签名生成函数
function makeSignature(array $data, $privateKey){
    ksort($data);
    $str = '';
    $privateKey = md5($privateKey);
    foreach ($data as $k => $v){
        $str .= $k.'|'.$privateKey.'|'.$v;
    }
    return md5($str);
}

点播文件生成回调    

事件 event

record/created-success,点播文件生成回调

回调信息

参数 类型 是否必选 含义
event string record/created-success
refer string vhall
time string 回调时间戳
record_id string 回放ID
status int 1 点播生成成功 2 点播生成失败
signature string 回调签名

响应示例

{
    event : "record/created-success", // 事件
    refer: "vhall", // 来源
    time: "1505095994", // 当前时间戳
    record_id: "56b345",  // 回放ID
    signature: "7ffa066561d280d0d51f8fdaad29f4a4", // 签名
}

回放转码回调    

事件 event

record/trans-over,回放转码回调

回调信息

参数 类型 是否必选 含义
event string record/trans-over
refer string vhall
time string 回调时间戳
record_id string 回放ID
status int 1 转码成功 2 转码失败
signature string 回调签名

响应示例

{
    event : "record/trans-over", // 事件
    refer: "vhall", // 来源
    time: "1505095994", // 当前时间戳
    record_id: "56b345",  // 回放ID
    signature: "7ffa066561d280d0d51f8fdaad29f4a4", // 签名
}

查询失败回调记录    

描述

callback/fail-list,查询失败回调记录

请求参数

参数 类型 是否必选 含义
event int 回调事件
start_time timestamp 查询开始时间 格式为 2017/01/01 00:00:00
end_time timestamp 查询结束时间 默认为当前时间 格式为 2017/01/01 00:00:00

响应参数

参数 类型 是否必选 含义
list obj 回调数据信息(数据同个回调接口产生的回调数据)

错误码

错误码 类型 含义
10020 int 开始时间不能为空
40004 int 时间类型不正确
40007 int 回调事件类型不正确

响应示例

{
    "code": 200,
    "msg": "",
    "data": [
        {
            "id": 0,
            "record_id": "70545e9f",
            "status": 1
        }
    ]
}

上传SDK    

Java上传SDK    

功能简介:

  • 录播上传服务提供服务端上传视频生成录播支持,目前仅支持java语言

集成过程:

  • 复制commons-codec-1.9.jar到工程lib目录下
  • 复制commons-logging-1.2.jar到工程lib目录下
  • 复制hamcrest-core-1.1.jar到工程lib目录下
  • 复制httpclient-4.4.1.jar到工程lib目录下
  • 复制httpcore-4.4.1.jar到工程lib目录下
  • 复制jdom-1.1.jar到工程lib目录下
  • 复制json-20170516.jar到工程lib目录下
  • 复制vhalluploadkit_pass-1.0-release.jar到工程lib目录下

调用流程:

util = VhallUploadKit.getInstance();
util.initData(APP_ID, SECRET_KEY);
util.uploadAndBuildVideo(file, videoName,Callback, PutObjectProgressListener);

API简介:

  • 初始化
 void initData(String APPID, String SecretKey)
  • 是否可用
 boolean isEnable()
  • 上传视频并自动生成录播
/**
	 * 
	 * @param file
	 *            需要上传的文件
	 * @param videoName
	 *            录播名称
	 * @param callback
	 *            服务器回调
	 * @param listener
	 *            上传过程监听
	 * @return 文件对应OSS路径
	 */
 String uploadAndBuildVideo(File file, String videoName,Callback callback, ProgressListener listener)
  • 停止上传
/**
	 * 中断上传
	 * 
	 * @param fileKey
	 *            上传返回的文件ID
	 * @return 是否成功
	 */
boolean stopUpload(String fileKey)

-取消上传

/**
	 * 取消上传(取消本次上传操作,删除本地及服务器上传纪录和服务器上的文件碎片)
	 * 
	 * @param fileKey
	 *            上传返回的文件ID
	 * @return 是否成功
	 */
boolean abortUpload(String fileKey)
Java上传SDK简介    

简介

点播上传服务提供服务端上传视频生成录播支持。

功能特性

  • 支持断点续传
  • 支持修改文件名称
  • 支持显示上传进度条和百分比
  • 支持不同文件的上传格式 ('rmvb', 'mp4', 'avi', 'wmv', 'mkv', 'flv', 'mp3', 'wav', 'mov')
  • 支持Demo的下载,开发者可在此基础上开发样式
Java上传SDK开发指南    

1 成为开发者

申请开通微吼云账号,提供用户资料,微吼服务人员在后台为用户开通平台账号,用户也可在微吼云网站自行注册账号,账号开通后,用户即可登录,成为一名开发者。

2 创建应用

登录微吼云平台后,控制台选择应用管理,进入应用管理页面点击创建应用,根据页面提示信息,完成应用创建。应用创建完成,您可以在控制台界面找到在应用管理界面您可以找到 AppID。

3 添加服务

应用创建完成后,选择添加服务,添加点播服务,添加成功后可在点播服务下点播管理的【点播配置】页面查看AppID

4 集成过程

  • 复制commons-codec-1.9.jar到工程lib目录下
  • 复制commons-logging-1.2.jar到工程lib目录下
  • 复制hamcrest-core-1.1.jar到工程lib目录下
  • 复制httpclient-4.4.1.jar到工程lib目录下
  • 复制httpcore-4.4.1.jar到工程lib目录下
  • 复制jdom-1.1.jar到工程lib目录下
  • 复制json-20170516.jar到工程lib目录下
  • 复制vhalluploadkit_pass-1.0-release.jar到工程lib目录下

5 调用流程

一、获取上传实例:VhallUploadKit
util = VhallUploadKit.getInstance();
二、使用在微吼PAAS平台注册应用时分配的APPID和SECRETKEY初始化
util.initData(APP_ID, SECRET_KEY);
三、初始化成功后,就可以上传视频生成录播
util.uploadAndBuildVideo(file, videoName,Callback, PutObjectProgressListener);

6 API简介

  • 初始化 使用在微吼PAAS平台注册应用时分配的APPID和SECRETKEY初始化,重要!
 void initData(String APPID, String SecretKey)
  • 是否可用

初始化成功后,VhallUploadKit才会处于可用状态,才能上传录播

 boolean isEnable()
  • 上传视频并自动生成录播
/**
	 * 
	 * @param file
	 *            需要上传的文件
	 * @param videoName
	 *            录播名称
	 * @param callback
	 *            服务器回调
	 * @param listener
	 *            上传过程监听,返回当前上传状态及上传进度
	 * @return 文件对应OSS路径
	 */
 String uploadAndBuildVideo(File file, String videoName,Callback callback, ProgressListener listener)
  • 停止上传
/**
	 * 中断上传
	 *
	 * @param fileKey
	 *            上传返回的文件ID
	 * @return 是否成功
	 */
boolean stopUpload(String fileKey)
  • 断点续传

录播上传服务支持断点续传,上传过程中,本地会生成一个ucp文件,保存当前上传进度,如果上传操作被异常或手动中断,下次上传会自动定位到最后一次的上传位置继续上传。

  • 取消上传

取消本次上传操作,取消操作会删除本地及服务器上传纪录和服务器上的文件碎片,重新从0开始上传

/**
	 * 取消上传
	 * 
	 * @param fileKey
	 *            上传返回的文件ID
	 * @return 是否成功
	 */
boolean abortUpload(String fileKey)
Java上传SDK版本更新    
日期 版本 内容 SDK演示
2018.01.12 v1.0 提供点播上传功能 演示
Javascript 上传SDK    
Javascript上传SDK简介    

简介

微吼JSSDK,是微吼开放平台面向web开发者提供的基于微吼直播服务的开发工具包,面向开发者提供直播推流、直播观看、点播上传、点播观看、聊天、文档等功能。此部分用于点播上传。

功能特性

  • 支持断点续传
  • 支持修改文件名称
  • 支持显示上传进度条和百分比
  • 支持不同文件的上传格式 ('rmvb', 'mp4', 'avi', 'wmv', 'mkv', 'flv', 'mp3', 'wav', 'mov')
  • 支持Demo的预览,开发者可在此基础上开发样式
Javascript上传SDK开发指南    

1 成为开发者

申请开通微吼云账号,提供用户资料,微吼服务人员在后台为用户开通平台账号,用户也可在微吼云网站自行注册账号,账号开通后,用户即可登录,成为一名开发者。

2 创建应用

登录微吼云平台后,控制台选择应用管理,进入应用管理页面点击创建应用,根据页面提示信息,完成应用创建。应用创建完成,您可以在控制台界面找到在应用管理界面您可以找到 AppID。

3 添加服务

应用创建完成后,选择添加服务,添加点播服务,添加成功后可在点播服务下点播管理的【点播配置】页面查看AppID

4 开发准备

开发者若要将点播上传SDK集成到应用中,需要在html或者相关页面模板中引入JS脚本。

  • 本SDK依赖于JQuery库,请在需要引入JQuery的页面按以下代码示例进行引入,对JQuery版本没有要求
<script src="http://cnstatic01.e.vhall.com/3rdlibs/jquery/1.11.2/jquery.min.js" type="text/javascript"></script>
  • 在需要调用jssdk的页面插入以下代码,引入JS文件
<script src="https://static.vhallyun.com/demand-upload-jssdk-vhallcloud/dist/1.0.0/vhallDemandSDK-vhallcloud.js"></script>

5 注意

  • 为保证本SDK能够正常使用请尽量在高版本浏览器下使用本SDK产品(Chrome58及以上版本)
API文档    

1.初始化DOM

  • 为了承载相关功能需要在html或者相关页面模板中准备一系列dom元素 具体如下
<input type="file" id="upload"/> <!--文件上传域 -->
<input type="text" id='rename'> <!--用于承载文件名称的input 可用于修改上传文件标题 若用不到可设置为隐藏 -->
<button id="confirm" class="saveBtn">保存</button>  <!--上传成功后用于保存文件的按钮 -->

2.生成鉴权信息

  • 调用具体的方法之前首先需要开发者在服务端采用规定的方法生成鉴权信息 具体生产方法请参照

API鉴权方案

3.初始化配置

  • 调用 vhallCloudDemandSDK() 方法实例化上传功能
vhallCloudDemandSDK('#upload',{
            params: {
                confirmBtn:'#confirm', //保存按钮
                name:'#rename',//用于修改文件名称的input
                sign:signTag.str, //生成的鉴权信息
                signed_at:signTag.time, //鉴权信息生成的时间戳
                app_id:appId //用户的appid
            },
            ready: function() {
                /**
                  * 初始化完成的回调函数
                **/
            },
            beforeUpload:function() {
                /**
                  * 准备中...(文件进行MD5转换过程)
				  * 可以已loader形式展现该过程
                **/
            },
            progress:function(percent, file){
                /**
                 * 上传中...'
                 * 'percent 上传进度百分比'
                 * 'file 上传文档具体信息
               **/
            },
            uploadSuccess: function(res){
                /**
                 * 上传成功!'
               **/
            },
            saveSuccess:function(res) {
               /**
                 * 点击保存按钮后保存成功'
				 * res返回record_id
               **/
            },
            error: function(msg,file,e){
                /**
                  * 上传出错'
                  * 'msg 错误返回的状态码信息'
                **/
            }
        })

4.文件上传

  • 完成上述步骤后,即完成所有的上传接口调用。当用户选择上传文件后,将通过相关事件触发相关回调并完成文件的上传。

5. 断点续传

  • 当文件上传中断后,用户只需重新选择文件提交即可恢复上传。

6. 其他

  • 参数说明
参数 含义
confirmBtn 保存按钮的ID名以#开头
name 用于重命名的input的ID名以#开头
sign 按照规则生成的鉴权信息
signed_at 鉴权信息生成的时间戳
app_id 用户的appId
  • 初始化配置错误状态码对应信息参见消息体
错误码 含义
10000 当前浏览器不支持断点上传
10001 初始化元素请传入类似于"#id"选择器
10002 确认按钮请传入类似于"#id"选择器
10003 重命名元素请传入类似于"#id"选择器
10004 options参数应该为对象类型
10005 当前传入的初始化dom不是input file
10006 不支持该文件格式
10007 上传文件大于5GB
10008 获取上传临时授权失败
10009 当前账号无上传权限
10010 请确认确认按钮dom是否存在
10011 视频名称不符合规范
10012 请选择需要上传的文件
Javascript 上传SDK版本更新    
日期 版本 内容 SDK演示
2018.01.12 v1.0 提供点播上传功能 SDK演示

播放器SDK    

iOS SDK开发集成    
iOS SDK简介    

简介

微吼点播视频播放器 iOS SDK 是微吼云官方推出的软件开发工具包,提供简单,便捷的开发接口,帮助开发者在iOS平台上快速开发播放器应用。

功能特性

  • 支持常见的音视频文件播放(MP4、HLS)
  • 支持iOS 8.0及以上系统
  • 支持的CPU架构:armv7、arm64、i386、x86_64
  • 可高度定制化播放器UI控件
  • 支持多种画面预览模式(填充,拉伸,裁剪)
  • 支持硬件解码(iOS 8.0及以上)
iOS SDK开发指南    

1 概念说明

点播的视频源是存储在微吼云的一个视频文件,只要视频未被移除,就可以随时播放, 播放中您可以通过进度条控制播放位置。

2 接入准备

2.1 成为开发者

申请开通微吼云账号,提供用户资料,微吼服务人员在后台为用户开通平台账号,账号开通后,用户即可登录,成为一名开发者。

2.2 创建应用

登录微吼云平台后,控制台选择应用管理,进入应用管理页面点击创建应用,根据页面提示信息,完成应用创建。应用创建完成,您可以在控制台界面找到在应用管理界面您可以找到 AppID。

2.3 添加服务

应用创建完成后,选择添加服务,添加点播服务,添加成功后可在点播服务下点播管理的【点播配置】页面查看AppID

2.4 SDK下载

SDK下载

3 工程配置

3.1 支持平台

  • SDK支持iOS 8.0以上系统

3.2 开发环境

  • Xcode 8或更高版本
  • OS X 10.10或更高版本

3.3 Xcode工程设置

下面通过一个简单的iOS Application工程,说明如和在Xcode工程中配置SDK。

3.3.1 拷贝SDK文件

在本例中,新建一个名字叫做VHSDKDemo的iOS工程,将下载下来的文件夹拷贝至工程目录。目录结构如下图所示:

3.3.2 添加库和Framework

libc++.tbd
libz2.1.0.tbd
libicucore.tbd
libz.tbd
libiconv.tbd
CoreTelephony.framework
MediaPlayer.framework
AVFoundation.framework
VideoToolbox.framework
AssetsLibrary.framework
OpenAL.framework
OpenGLES.framework
QuartzCore.framework
CoreMedia.framework
Security.framework

3.3.3 工程设置修改

  • AppDelegate.m 文件名修改为AppDelegate.mm
  • Build Setting 中 Enable Bitcode 设置为NO
  • 设置Info.plist中 App Transport Security Settings -> Allow Arbitrary Loads 设置为 YES
  • 设置Info.pplist中 Privacy - Camera Usage Description 是否允许使用相机
  • 设置Info.pplist中 Privacy - Microphone Usage Description 是否允许使用麦克风

3.4 验证

下面在VHSDKDemo的代码中,调用SDK的接口,设置appID 获取SDK版本信息,以验证工程设置是否正确。

3.4.1 引用头文件

在AppDelegate.mm开头引用SDK的头文件:

#import "VHLiveBase.h"

3.4.2 添加调用代码

在application: didFinishLaunchingWithOptions:方法中添加代码:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [VHLiveBase registerApp:@"xxxxxxxxx"];//AppID:xxxxxxxxx
    [VHLiveBase setThirdPartyUserId:@"xxxxxxxx"];//第三方账号id:xxxxxxxx
    NSLog(@"SDK Version: %@",[VHLiveBase getSDKVersion]);
    return YES;
}

3.4.3 编译运行

如果前面各个步骤都操作正确的话,VHSDKDemo工程应该可以顺利编译通过。在Debug模式下运行APP,Xcode的Console窗格会打印出SDK的版本信息。

至此,工程配置完成。

4 注册APP

[VHLiveBase registerApp:@"xxxxxxxxx"];//AppID:xxxxxxxxx

5 设置第三方ID

[VHLiveBase setThirdPartyUserId:@"xxxxxxxx"];//第三方账号id:xxxxxxxx

6 LOG打印

在 VHLiveBase 中可以设置 log的级别,具体代码如下:

[VHLiveBase setLogLevel:VHLogLevelDebug];

7 获取roomID、access_token

获取roomIDaccess_token

8 代码接入

8.1 创建VodPlayer

SDK 中的 VHVodPlayer 模块负责实现直播播放功能。

VHVodPlayer _vodPlayer = [[VHVodPlayer alloc] init];

8.2 设置 渲染View、delegate

  • delegate 设置播放器代理
  • 接下来我们要给播放器的视频画面找个地方来显示,iOS系统中使用 view 作为基本的界面渲染单位,所以您只需要准备一个 view 并调整好布局就可以了。
    _vodPlayer.delegate = self;
    _vodPlayer.view.frame = self.view.bounds;
    [self.view insertSubview:_vodPlayer.view atIndex:0];

8.3 开始播放

  • recordId 点播id 可以通过调用 api 创建
  • accessToken 可以通过调用 api 获得
    NSString* recordId = @"lss_xxxxxx";
    NSString* accessToken = @"xxxxxxxxxx";
    [_vodPlayer startPlay:recordId accessToken:accessToken];

8.4 画面调整

_vodPlayer.scalingMode = VHPlayerScalingModeAspectFit;

可选值 含义
VHPlayerScalingModeFill 将图像拉伸填充
VHPlayerScalingModeAspectFit 将图像等比例缩放,适配最长边,缩放后的宽和高都不会超过显示区域,居中显示,画面可能会留有黑边
VHVPlayerScalingModeAspectFill 将图像等比例铺满整个屏幕,多余部分裁剪掉,此模式下画面不会留黑边,但可能因为部分区域被裁剪而显示不全

8.5 清晰度切换

_vodPlayer.curDefinition = VHDefinitionOrigin;

可选值 含义
VHDefinitionOrigin 原画
VHDefinitionUHD 超高清
VHDefinitionHD 高清
VHDefinitionSD 标清
VHDefinitionAudio 纯音频

8.6 暂停/恢复播放

// 暂停
[_vodPlayer pause];
// 恢复
[_vodPlayer resume];

8.7 结束播放

结束当前直播,播放器资源并未释放

[_vodPlayer stopPlay];

8.8 销毁播放器

释放播放器资源

[_vodPlayer destroyPlayer];

9 事件处理

  • 推流状态监听

SDK 通过 VHPlayerDelegate 代理来监听推流相关的事件

状态 含义
VHPlayerStatusLoading 加载中
VHPlayerStatusPlaying 播放中
VHPlayerStatusStop 停止播放
VHPlayerStatusPause 播放暂停
iOS SDK版本更新    
日期 版本 内容 SDK下载
2017.12.29 v1.0 提供iOS平台基本的点播功能 下载
Android SDK开发集成    
Android SDK简介    

简介

微吼点播视频播放器 Android SDK 是微吼云官方推出的软件开发工具包,提供简单,便捷的开发接口,帮助开发者在Android平台上快速开发播放器应用。

功能特性

  • 支持常见的音视频文件播放(MP4、flv、MP3 等)
  • 支持 MediaCodec 硬件解码
  • 支持多种画面预览模式(填充,拉伸,裁剪)
  • 支持 ARM, ARMv7a, ARM64v8a 架构
  • 支持 Android 4.0及以上系统
  • 可高度定制化播放器UI控件
Android SDK开发指南    

1 概念说明

点播的视频源是存储在微吼云的一个视频文件,只要视频未被移除,就可以随时播放, 播放中您可以通过进度条控制播放位置。

2 接入准备

2.1 成为开发者

申请开通微吼云账号,提供用户资料,微吼服务人员在后台为用户开通平台账号,账号开通后,用户即可登录,成为一名开发者。

2.2 创建应用

登录微吼云平台后,控制台选择应用管理,进入应用管理页面点击创建应用,根据页面提示信息,完成应用创建。应用创建完成,您可以在控制台界面找到在应用管理界面您可以找到 AppID。

2.3 添加服务

应用创建完成后,选择添加服务,添加点播服务,添加成功后可在点播服务下点播管理的【点播配置】页面查看AppID

2.4 SDK下载

SDK下载

3 工程配置

3.1 开发环境

  • Android SDK Tools: android-sdk_22.0.|+
  • minSdkVersion: 16
  • targetSdkVersion: 22
  • Android Studio

3.2 系统要求

  • SDK 支持 在 Android 4.1(API 16)及以上系统上运行,但只有 ( Android 4.3) API 18 以上的系统才能开启硬件编码

3.3 接入流程

  • 新建gradle工程
  • 复制vhallframework1.0.jar到工程lab目录下
  • 复制jnilibs文件夹内容到appjni目录下

3.4 库简介

  • vhallframework1.0.jar:vhallsdk基础包,用户sdk基础通迅、全局配置、日志管理、权限控制等。
  • socket.io 一款公共I/O库,基础通讯功能使用,目前使用截止文档编写之日最新稳定版
   compile("io.socket:socket.io-client:0.9.0") {
        exclude group: 'org.json', module: 'json'
    }

3.5 配置权限

<uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.RECORD_VIDEO" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <uses-feature android:name="android.hardware.camera" />
    <uses-feature android:name="android.hardware.camera.autofocus" />

3.6 接口简介

3.6.1 VhallSDK初始化

appid为注册应用时配置的应用ID 初始化操作为SDK的入口,一切SDK功能都在初始化成功后才能使用,建议在应用application启动时调用

VhallSDK.getInstance().init(Context context, String appid);

3.6.2 SDK信息配置

1、配置用户ID

用户ID为客户平台用户唯一标识,建议在用户登录之后配置

VhallSDK.getInstance().setUserId(String userid);

2、配置日志显示

设置SDK日志显示(警告和错误级别日志必打印,此开关控制debug/info/verbose级别日志

VhallSDK.getInstance().setLogEnable(boolean enable);

3.6.3 获取SDK状态

SDK是否初始化成功并处于可用状态,初始化操作会校验appid对应当前包名和签名,请确保配置正确

VhallSDK.getInstance().isEnable();

3.6.4 加入频道

加入频道并接收频道信息,channelid表示当前频道号,如果是lss服务,房间号即为频道号

VhallSDK.getInstance().join(String channelid,Callback callback);

3.6.5 离开频道

VhallSDK.getInstance().leave(String channelid);

4 功能使用

4.1 获取recordID、access_token

获取recordIDaccess_token

4.2 创建 VHVodPlayer

VHVodPlayer 是SDK中负责点播的模块,需要传入上下文,和视频渲染的View,也就是播放画面的View,SDK使用的是系统自带的SurfaceView,将创建的Surface的实例传入VHVodPlayer即可创建。

  • Context 传入上下文
  • SurfaceView 传入渲染的View
  • addListener 添加监听
 mPlayer = new VHVodPlayer(this, mSurfaceView);
 mPlayer.addListener(new MyPlayer());

4.3 VHDocument

4.3.1 创建 VHDocumentView 文档

如果当前的视频文件存在文档信息, 在观看点播的过程中是可以和文档一起观看的,使用SDK中提供的VHDocumentView View 控件。 通过FindById获取View的实例。

 <com.vhall.ops.VHDocumentView
        android:id="@+id/doc"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

4.3.2 创建 VHDocument 对象

将4.3.1创建的View 设置进VHDocument,用于文档的显示。

  • recordId 点播id 可以通过调用 api 创建 (这里的recordId 必须和Start发起的recordId 一致)
 mDoc = new VHDocument(recordId);
        mDoc.setDocumentView(mDocView);
        mDoc.join();

4.4 开始观看

  • recordId 点播id 可以通过调用 api 创建
  • accessToken 可以通过调用 api 获得
 void start(String recordId,String accessToken);

4.5 设置观看清晰度

从 IVHLivePlayer.EVENT_DPI_LIST 获取当前地址可用的分辨率,确定可用的情况下在切换

清晰度 描述
IVHLivePlayer.DPI_SD 低清
IVHLivePlayer.DPI_HD 高清
IVHLivePlayer.DPI_XHD 超清
IVHLivePlayer.DPI_AUDIO 纯音频
IVHLivePlayer.DPI_SAME 原画
 void.setDPI(dpi);

4.6 暂停观看/ 恢复观看

停止拉流,而云端的视频源还在不断地更新着 , 当重新恢复时,会从最新的时间点播放

 void pause();
 void resume();

4.7 控制播放相关API

 long getDuration();  // 获取观看时长 (毫秒)
 
 long getPosition();  // 获取当前进度 (毫秒)
 
 void seek(long position); // Seek 操作

4.8 结束观看

 void stop();

4.9 销毁

销毁播放器的实例

 void release();

5 事件监听

事件监听 描述
VHVodPlayer.EVENT_STATUS_STARTING 正在运行
VHVodPlayer.EVENT_STATUS_STARTED 开始播放
VHVodPlayer.EVENT_STATUS_STOPED 停止播放
VHVodPlayer.EVENT_STATUS_END 播放结束
VHVodPlayer.EVENT_VIDEO_SIZE_CHANGED 视频的宽高发生改变
IVHLivePlayer.EVENT_DPI_LIST 可以的清晰度
IVHLivePlayer.EVENT_DPI_CHANGED 清晰度发生改变
Android SDK版本更新    
日期 版本 内容 SDK下载
2017.12.29 v1.0 提供Android平台基本的点播功能 下载
Javascript SDK开发集成    
Javascript SDK简介    

简介

微吼视频播放器 Javascript SDK 是微吼云官方推出的软件开发工具包,提供简单,便捷的开发接口,帮助开发者在web平台上快速开发播放器应用。

功能特性

  • 支持广泛的流式视频格式(MP4、M3U8、FLV)
  • 支持HTML5模式
Javascript SDK开发指南    

1 概念说明

  • 直播和点播 直播是指视频源是实时的,一旦主播停播了,这个地址就已经失去意义了,而且由于是实时直播,所以播放器在播直播视频的时候是没有进度条滴。 点播是指视频源是一个服务器上的文件,文件只要没有被提供方删除,就随时可以播放, 而且由于整个视频都在服务器上,所以播放器在播点播视频的时候是有进度条的哦。

  • 协议的支持(手机) Web播放器的视频播放能力本身不是网页代码实现的,而是靠浏览器的支持,所以其兼容性并不像我们想象的那么好,您必须要接受一个事实:不是所有的手机浏览器都能有符合预期的表现,有些手机浏览器甚至根本就不支持视频播放。>不是所有的手机浏览器都能有符合预期的表现,有些手机浏览器甚至根本就不支持视频播放。

    最常见的用于网页直播的视频源地址是以m3u8结尾的地址,我们称其为HLS (HTTP Live Streaming),这是苹果推出的标准。由于苹果的影响力,目前各手机浏览器产品对这种格式的兼容性最好,但它有个天然的问题,就是延迟比较大,一般是20-30秒左右的延迟,没有办法,在手机浏览器上我们并没有其它选择。

  • 协议的支持(PC) 在PC上情况会好很多,因为PC上的浏览器目前还没有抛弃flash控件,而flash控件的开发商 Adobe 并不追求设计上的洁癖,所以flash支持的视频源格式挺多的,而且各浏览器上的flash控件都是Adobe它家自己开发,所以兼容性非常好(也是因为这个原因,意图推广 webrtc 和 HTML5 技术的 Google 在最新版的 Chrome 浏览器里默认禁用了 Flash)

    视频协议 用途 示例地址 PC浏览器 移动浏览器
    HLS(m3u8) 可用于直播 http://live.mydomain.com/xxxx/a.m3u8 支持 支持
    HLS(m3u8) 可用于点播 http://vod.mydomain.com/xxxx/b.m3u8 支持 支持
    FLV 可用于直播 http://live.mydomain.com/xxxx/a.flv 支持 不支持
    FLV 可用于点播 http://vod.mydomain.com/xxxx/b.flv 支持 不支持
    RTMP 只适用直播 http://live.mydomain.com/xxxx 支持 不支持
    MP4 只适用点播 http://vod.mydomain.com/xxx/a.mp4 支持 支持

2 使用步骤

2.1 成为开发者

申请开通微吼云账号,提供用户资料,微吼服务人员在后台为用户开通平台账号,账号开通后,用户即可登录,成为一名开发者。

2.2 创建应用

登录微吼云平台后,控制台选择应用管理,进入应用管理页面点击创建应用,根据页面提示信息,完成应用创建。应用创建完成,您可以在控制台界面找到在应用管理界面您可以找到 AppID。

2.3 添加服务

应用创建完成后,默认开通直播服务,在直播服务下直播管理的【直播配置】页面查看AppID

2.4 页面引用SDK文件

在需要播放视频的页面(包括PC或H5)中引入初始化脚本

<link rel="stylesheet" href="https://static.vhallyun.com/jssdk/videojs.min.css?v=1.0.0"></script><!--播放器默认样式,需要引用在包含在页面的head标签里-->
<script src="https://static.vhallyun.com/jssdk/dvideo-plugin.js?v=1.0.0"></script><!--依赖的播放器资源-->
<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-player-1.0.0.js"></script>
<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-base-1.0.0.js"></script>

注意:

  1. 直接用本地网页是调试不了的
  2. 上面所有文件都需要引用,而且顺序需要保持与上面一致
  3. 建议直接复制上面代码

2.5 页面创建播放器容器

在需要web播放的页面位置加入播放器对象容器,也就是放一个div,然后给它取个名字,比如: my-video 。之后推流回显画面都会在这个容器里渲染,容器的大小控制您可以使用div的属性进行控制,示例代码如下:

	<div id="my-video" style="width:100%; height:450px;"></div>

2.6 注册ready事件

Vhall.ready(function(){
    //todo
})

注意: 初始化完成之后,会执行ready回调事件,机制同jQuery ready事件,播放器调用逻辑需要写在此事件里。

2.7 初始化SDK配置

初始化配置:

 Vhall.config({
     appId :'',//应用 ID ,必填
     accountId :'',//第三方用户唯一标识,必填
     token:'',//token必填
 })     

注意: appId获取方式:登陆微吼云>>进应用管理>>取得对应AppId token生成方式:通过API生成,生成accessToken接口说明

API 文档    

1 调用说明

所有接口通过VhallPlayer对象来调用,参数是一个对象,除了每个接口本身需要传的参数之外,还有以下通用参数:

  1. success:接口调用成功时执行的回调函数。
  2. fail:接口调用失败时执行的回调函数。
  3. complete:接口调用完成时执行的回调函数,无论成功或失败都会执行。

2 API接口

2.1 VhallPlayer.init 播放器初始化


    VhallPlayer.init({
        roomId:'', //房间ID,直播必填,点播不写
        recordId:'',//回放Id,点播必填,直播不写
        type:'live',//播放类型,必填,live 直播, vod 为点播
        videoNode:'',//推流视频回显节点id,必填
        complete:function(){

        }
    });

注意:

  1. 此方法必需写在Vhall.ready事件里。
  2. 获取roomId
  3. 获取recordId
  4. videoNode,为推流回显容器的Id,需要开发者自己在需要显示回显的地方,创建一个空div,然后给Id命名,再将id名称写入此参数。

2.2 播放

VhallPlayer.play 播放


    VhallPlayer.play();

2.3 暂停

VhallPlayer.pause;


VhallPlayer.pause();

2.4 获取视频清晰度

VhallPlayer.getQuality


/**
 * 获取视频清晰度
 * @return {Array}   清晰度数组,如: [same,720,480],same为原画
 */
VhallPlayer.getQuality();

返回清晰度数组,数组元素为清晰度值

2.5 设置视频清晰度

此方法的参数为视频清晰度,值必须来源于getQuality方法, 获取方式:调用getQuality,将返回数组中的任何一个值,传入即可。示例代码如下。 VhallPlayer.setQuality


/**
 *  @param {string} quality 视频清晰度,值来源于getQuality方法
 */
VhallPlayer.setQuality(VhallPlayer.getQuality()[0]);

2.6 设置全屏

VhallPlayer.setFullScreen


/**
 * 设置全屏
 * @param {bool}  true 或空为全屏,false为退出全屏      
 */
VhallPlayer.setFullScreen(bool);

2.7 获取当前是否全屏

VhallPlayer.isFullscreen


/**
 * 获取当前是否全屏
 * @return {bool}   是否全屏,true or false
 */
VhallPlayer.isFullscreen();

2.8 设置音量

VhallPlayer.setVolume


/**
 * 设置音量
 * @param {int} volume 0~100 的数字,0 静音
 */
VhallPlayer.setVolume(volume);

注意:默认音量为60

2.9 设置播宽度

VhallPlayer.setWidth


/**
 * 设置宽度
 * @param {int} width 整形数字
 */
VhallPlayer.setWidth(width);

注意:默认视频宽度为,step5中设置的容器的宽度。

2.10 设置高度

VhallPlayer.setHeight


/**
 * 设置宽度
 * @param {int} height 整形数字
 */
VhallPlayer.setHeight(height);

注意:默认视频高度为,step4中设置的容器的高度。

2.11 获取当前视频总时长

VhallPlayer.getDuration


/**
 * 获取当前视频总时长
 * @return {int}  单位秒
 */
VhallPlayer.getDuration();

2.12 获取当前播放的时间

VhallPlayer.getCurrentTime


/**
 * 获取当前播放的时间
 * @return {int}  单位秒
 */
VhallPlayer.getCurrentTime();

2.13 设置当前播放时间

VhallPlayer.seek


/**
 * 设置当前播放时间
 * @return {int}  单位秒
 */
VhallPlayer.seek(time);

此接口只支持点播

2.14 获取当前网络状态

VhallPlayer.getNetworkState


/**
 * 获取当前网络状态
 * @return {int}  0:音频/视频尚未初始化,1:音频/视频是活动的且已选取资源,但并未使用网络,2:浏览器正在下载数据,3:未找到音频/视频来源
 */
VhallPlayer.getNetworkState();

返回码 说明
0 音频/视频尚未初始化
1 音频/视频是活动的且已选取资源,但并未使用网络
2 浏览器正在下载数据
3 未找到音频/视频来源

2.15 推流端开始推流事件

此事件发起直播时才会触发,注册方法如下:

VhallPlayer.onPublishStart


VhallPlayer.onPublishStart(function(){
    console.log('直播开始!');
})

2.16 推流端停止推流事件

此事件停止直播时才会触发,注册方法如下:

VhallPlayer.onPublishStop


VhallPlayer.onPublishStop(function(){
    console.log('直播结束!');
})

Javascript SDK版本更新    
日期 版本 内容 SDK演示
2017.12.29 v1.0 提供web平台基本的点播功能 SDK演示
Demo使用指南    
上传Demo使用指南    
Java上传Demo    

主要功能

  • 支持断点续传
  • 支持修改文件名称
  • 支持显示上传进度条和百分比
  • 支持不同文件的上传格式 ('rmvb', 'mp4', 'avi', 'wmv', 'mkv', 'flv', 'mp3', 'wav', 'mov')
  • 支持Demo的下载,开发者可在此基础上开发样式

示例代码

public class SampleWithWindow extends JFrame {
	private static final long serialVersionUID = 560684569647135515L;
	// 编辑部分
	// TODO APPID
	public static final String APP_ID = "d0d7b081";// 微吼APPKEY
	public static final String SECRET_KEY = "98294813a6d553b2a2dadd8a5375e21f";// 微吼SECRETKEY
	public static final String callbackurl = "http://t.e.vhall.com/api/callback";
	public static final String videoName = "";

	// demo
	static Callback callback;
	static JLabel fileLabel;
	static JLabel tipsLabel;
	static JProgressBar bar;

	static VhallUploadKit util;
	static File file;
	static String fileKey = "";

	public SampleWithWindow() {
		util = VhallUploadKit.getInstance();
		callback = new Callback();
		callback.setCallbackUrl(callbackurl);
		callback.setCallbackBody("{\\\"mimeType\\\":${mimeType},\\\"size\\\":${size}}");
		callback.setCalbackBodyType(CalbackBodyType.JSON);
	}

	public static void main(String[] args) {

		SampleWithWindow window = new SampleWithWindow();
		window.setTitle("vhall upload kit");
		window.setSize(600, 300);
		window.setResizable(false);
		window.setLocationRelativeTo(null);
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setContentPane(initUI());
		window.setVisible(true);

		util.initData(APP_ID, SECRET_KEY);
		if (util.isEnable()) {
			tipsLabel.setText("初始化成功!");
		} else {
			tipsLabel.setText("初始化失败!");
		}

	}

	private static JPanel initUI() {
		final JPanel contentPanel = new JPanel();
		contentPanel.setLayout(new GridLayout(10, 1));
		fileLabel = new JLabel();
		fileLabel.setText("请选择文件!");
		fileLabel.setHorizontalAlignment(SwingConstants.CENTER);
		bar = new JProgressBar();
		bar.setMaximum(100);
		bar.setMinimum(0);
		bar.setValue(0);
		bar.setStringPainted(true);

		JButton selectBtn = new JButton("选择文件");
		selectBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				selectFile(contentPanel);
			}
		});
		JButton uploadBtn = new JButton("上传文件");
		uploadBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				startUpload();
			}
		});
		JButton stopBtn = new JButton("停止上传");
		stopBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				stopUpload();
			}
		});
		JButton cancelBtn = new JButton("取消上传");
		cancelBtn.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				abortUpload();
			}
		});
		tipsLabel = new JLabel();
		tipsLabel.setText("初始化,请稍等...");
		tipsLabel.setHorizontalAlignment(SwingConstants.CENTER);

		contentPanel.add(fileLabel);
		contentPanel.add(new JLabel());
		contentPanel.add(bar);
		contentPanel.add(selectBtn);
		contentPanel.add(uploadBtn);
		contentPanel.add(stopBtn);
		contentPanel.add(cancelBtn);
		contentPanel.add(new JLabel());
		contentPanel.add(tipsLabel);

		return contentPanel;
	}

	private static void startUpload() {
		if (file == null) {
			tipsLabel.setText("请先选择文件...");
			return;
		}
		String key = util.uploadAndBuildVideo(file, videoName,null, new PutObjectProgressListener(file.length()));
		if (!TextUtils.isEmpty(key))
			fileKey = key;
	}

	private static void stopUpload() {
		if (file == null) {
			tipsLabel.setText("请先选择文件...");
			return;
		}
		if (TextUtils.isEmpty(fileKey)) {
			tipsLabel.setText("请先上传...");
			return;
		}
		if (util.stopUpload(fileKey))
			tipsLabel.setText("上传已停止...");
	}

	private static void abortUpload() {
		if (file == null) {
			tipsLabel.setText("请先选择文件...");
			return;
		}
		if (TextUtils.isEmpty(fileKey)) {
			tipsLabel.setText("请先上传...");
			return;
		}
		if (util.abortUpload(fileKey)) {
			tipsLabel.setText("上传已取消...");
			fileKey = "";
		}

	}

	/**
	 * 获取上传进度回调
	 */
	static class PutObjectProgressListener implements ProgressListener {

		private long bytesWritten = 0;
		private long totalBytes = -1;
		private boolean succeed = false;
		private long fileLength = 0;

		public PutObjectProgressListener(long fileLength) {
			super();
			this.fileLength = fileLength;
		}

		@Override
		public void progressChanged(ProgressEvent progressEvent) {
			long bytes = progressEvent.getBytes();
			ProgressEventType eventType = progressEvent.getEventType();
			switch (eventType) {
			case TRANSFER_STARTED_EVENT:
				tipsLabel.setText("开始上传...");
				break;
			case REQUEST_CONTENT_LENGTH_EVENT:
				this.totalBytes = bytes;
				this.bytesWritten = fileLength - totalBytes;
				break;
			case REQUEST_BYTE_TRANSFER_EVENT:
				this.bytesWritten += bytes;
				if (this.totalBytes != -1) {
					int percent = (int) (this.bytesWritten * 100.0 / this.fileLength);
					bar.setValue(percent);
					System.out.println(bytes + " bytes have been written at this time, upload progress: " + percent
							+ "%(" + this.bytesWritten + "/" + this.fileLength + ")");
				} else {
					System.out.println(bytes + " bytes have been written at this time, upload ratio: unknown" + "("
							+ this.bytesWritten + "/...)");
				}
				break;

			case TRANSFER_COMPLETED_EVENT:
				this.succeed = true;
//				tipsLabel.setText("上传成功!");
				fileKey = "";
				break;

			case TRANSFER_FAILED_EVENT:
				tipsLabel.setText("上传失败!");
				break;

			default:
				break;
			}
		}

		public boolean isSucceed() {
			return succeed;
		}

		@Override
		public void webinarCreate(String fileKey, String webinarId, String recordId) {
			tipsLabel.setText("上传成功,文件ID:" + fileKey + " 生成录播成功,recordID:" + recordId);
		}
	}

	private static void selectFile(Component parent) {
		int result = 0;
		JFileChooser fileChooser = new JFileChooser();
		FileSystemView fsv = FileSystemView.getFileSystemView();
		fileChooser.setCurrentDirectory(fsv.getHomeDirectory());
		fileChooser.setDialogTitle("请选择要上传的文件...");
		fileChooser.setApproveButtonText("确定");
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		result = fileChooser.showOpenDialog(parent);
		if (JFileChooser.APPROVE_OPTION == result) {
			file = new File(fileChooser.getSelectedFile().getPath());
			fileLabel.setText("待上传文件:" + file.getAbsolutePath());
			// 停止正在上传的文件
			if (!TextUtils.isEmpty(fileKey))
				stopUpload();
			fileKey = "";
		}
	}

}

地址

https://github.com/vhall/VhalluploadkitForPaas

Javascript上传Demo    

主要功能

  • 支持断点续传
  • 支持修改文件名称
  • 支持显示上传进度条和百分比
  • 支持不同文件的上传格式 ('rmvb', 'mp4', 'avi', 'wmv', 'mkv', 'flv', 'mp3', 'wav', 'mov')
  • 支持Demo的下载,开发者可在此基础上开发样式

Demo示例

https://static.vhallyun.com/demand-upload-jssdk-vhallcloud/dist/1.0.0/index.html?appKey=appKey&secretKey=secretKey

需要将获取到的 appId 和 secretKey 以URL传参的方式拼接到URL中即可使用

播放器Demo使用指南    
iOS demo    

主要功能

点播:支持常见的音视频文件播放(MP4、HLS)

示例代码

//
//  WatchVodViewController.m
//  VHOpenSDKDemo
//
//  Created by vhall on 2017/11/24.
//  Copyright © 2017年 www.vhall.com. All rights reserved.
//

#import "WatchVodViewController.h"
#import "VHVodPlayer.h"

#define CONTROLS_SHOW_TIME  10  //底部进度条显示时间

#define DefinitionNameList  (@[@"原画",@"超清",@"高清",@"标清",@"音频"])

@interface WatchVodViewController ()<VHVodPlayerDelegate>
{
    NSTimer         *_timer;
    NSArray *_definitionBtns;
}
@property (strong, nonatomic)VHVodPlayer *player;

@property (weak, nonatomic) IBOutlet UIView *preView;


@property (weak, nonatomic) IBOutlet UIView   *bottomView;
@property (weak, nonatomic) IBOutlet UIButton *playBtn;
@property (weak, nonatomic) IBOutlet UILabel  *minLabel;
@property (weak, nonatomic) IBOutlet UISlider *curTimeSlider;
@property (weak, nonatomic) IBOutlet UILabel  *maxLabel;
@property (weak, nonatomic) IBOutlet UIButton *fullscreenBtn;


@property (weak, nonatomic) IBOutlet UIButton *definitionBtn;

@property (weak, nonatomic) IBOutlet UIView   *definitionsView;
@property (weak, nonatomic) IBOutlet UIButton *definitionBtn0;
@property (weak, nonatomic) IBOutlet UIButton *definitionBtn1;
@property (weak, nonatomic) IBOutlet UIButton *definitionBtn2;
@property (weak, nonatomic) IBOutlet UIButton *definitionBtn3;
@property (weak, nonatomic) IBOutlet UIButton *definitionBtn4;
@end

@implementation WatchVodViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view from its nib.
    
    _player = [[VHVodPlayer alloc]init];
    _player.delegate = self;
    _player.isUseDefaultControl = NO;//不适用默认UI Control
    
    [self.preView insertSubview:_player.view atIndex:0];
    _player.view.frame = _preView.bounds;
    [_player startPlay:self.recordID accessToken:self.accessToken];
    [self showProgressDialog:self.preView];
    [self startTimer];
    
    
    // 单击的_player.view
    UITapGestureRecognizer* singleRecognizer;
    singleRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(SingleTap:)];
    singleRecognizer.numberOfTapsRequired = 1; // 单击
    [self.preView addGestureRecognizer:singleRecognizer];
    
    [_definitionBtn setTitle:DefinitionNameList[0] forState:UIControlStateNormal];
    _definitionsView.hidden = YES;
    _definitionBtns = @[_definitionBtn0,_definitionBtn1,_definitionBtn2,_definitionBtn3,_definitionBtn4];
}

- (void)viewDidLayoutSubviews
{
    _player.view.frame = _preView.bounds;
    _fullscreenBtn.selected = ([UIApplication sharedApplication].statusBarOrientation != UIDeviceOrientationPortrait);
}


- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (IBAction)backBtnClicked:(id)sender {
    [_player stopPlay];
    [_player destroyPlayer];
    [self dismissViewControllerAnimated:YES completion:^{
    }];
    [self.navigationController popViewControllerAnimated:NO];
}

- (void)stopPlayer
{
    [_player stopPlay];
    [self stopTimer];
}

- (IBAction)scalingModeBtnClicked:(UIButton *)sender {
    sender.selected = !sender.selected;
    [_player setScalingMode: sender.selected?VHPlayerScalingModeAspectFill:VHPlayerScalingModeAspectFit];
}

- (IBAction)definitionsBtnClicked:(UIButton *)sender {
    _definitionsView.hidden = !_definitionsView.hidden;
}

- (IBAction)definitionBtnClicked:(UIButton *)sender {
    if(sender.selected) return;
    
    [_player setCurDefinition:sender.tag];
    _definitionsView.hidden = YES;
//    _logView.hidden = (sender.tag != VHDefinitionAudio);
}
#pragma mark - Timer
- (void)startTimer
{
    if(_timer == nil)
    {
        _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerEvent)  userInfo:nil repeats:YES];
    }
}
- (void)stopTimer
{
    if(_timer)
    {
        [_timer invalidate];
        _timer = nil;
    }
}

-(void)timerEvent
{
    if(_player.playerState == VHPlayerStatusPlaying)
    {
        _minLabel.text = [self timeFormat:_player.currentPlaybackTime];
        _maxLabel.text = [self timeFormat:_player.duration];
        if(_player.duration>0)
            _curTimeSlider.value =_player.currentPlaybackTime/_player.duration;
    }
}

- (NSString*)timeFormat:(NSTimeInterval)time
{
    NSString *str = @"00:00";
    long t = ceil(time);
    
    int hh = (int)(t/3600);
    int mm = (int)(t-hh*3660)/60;
    int ss = (int)(t%60);
    str = [NSString stringWithFormat:@"%02d:%02d:%02d",hh,mm,ss];
    return str;
}

#pragma mark - palyerControls
- (void)showControls:(BOOL)isForever
{
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideControls) object:nil];
    if(!isForever)
        [self performSelector:@selector(hideControls) withObject:nil afterDelay:CONTROLS_SHOW_TIME];
    
    _bottomView.hidden = NO;
}
- (void)hideControls
{
    _bottomView.hidden = YES;
}

-(void)SingleTap:(UITapGestureRecognizer*)recognizer
{
    if(_bottomView.hidden)
        [self showControls:(_player.playerState != VHPlayerStatusPlaying)];
    else
        [self hideControls];
}

- (IBAction)playeBtnClicked:(UIButton *)sender {
    if(sender.selected)
    {
        [_player pause];
        sender.selected = NO;
    }
    else
    {
        if(_player.playerState == VHPlayerStatusStop)
        {
            [_player startPlay:self.recordID accessToken:self.accessToken];
            [self showProgressDialog:self.preView];
            [self startTimer];
        }
        else if(_player.playerState == VHPlayerStatusPause)
        {
            [_player resume];
        }
    }
}
- (IBAction)fullscreenBtnClicked:(UIButton *)sender {
    [self rotateScreen:!sender.selected];
}

- (void)rotateScreen:(BOOL)isLandscapeRight
{
    if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)])
    {
        NSNumber *num = [[NSNumber alloc] initWithInt:(isLandscapeRight?UIInterfaceOrientationLandscapeRight:UIInterfaceOrientationPortrait)];
        [[UIDevice currentDevice] performSelector:@selector(setOrientation:) withObject:(id)num];
        [UIViewController attemptRotationToDeviceOrientation];
        //这行代码是关键
    }
    SEL selector=NSSelectorFromString(@"setOrientation:");
    NSInvocation *invocation =[NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]];
    [invocation setSelector:selector];
    [invocation setTarget:[UIDevice currentDevice]];
    int val =isLandscapeRight?UIInterfaceOrientationLandscapeRight:UIInterfaceOrientationPortrait;
    [invocation setArgument:&val atIndex:2];
    [invocation invoke];
    [[UIApplication sharedApplication] setStatusBarHidden:isLandscapeRight withAnimation:UIStatusBarAnimationSlide];
}
- (IBAction)curTimeValueChange:(id)sender {
    _player.currentPlaybackTime = _player.duration*_curTimeSlider.value;
}


#pragma mark - VHVodPlayerDelegate
- (void)player:(VHVodPlayer *)player statusDidChange:(int)state
{
    switch (state) {
        case VHPlayerStatusLoading:
        {
            [self showProgressDialog:self.preView];
        }
            break;
        case VHPlayerStatusPlaying:
        {
            [self showControls:NO];
            _playBtn.selected = YES;
            [self hideProgressDialog:self.preView];
        }
            break;
        case VHPlayerStatusStop:
        {
            [self showControls:YES];
            _playBtn.selected = NO;
            [self hideProgressDialog:self.preView];
        }
            break;
        case VHPlayerStatusPause:
            _playBtn.selected = NO;
            break;
            
        default:
            break;
    }
}

- (void)player:(VHVodPlayer *)player validDefinitions:(NSArray*)definitions curDefinition:(VHDefinition)definition
{
    NSLog(@"curDefinition: %ld definitions:%@",(long)definition,definitions);
    
    [_definitionBtn setTitle:DefinitionNameList[definition] forState:UIControlStateNormal];
    for (UIButton* btn in _definitionBtns) {
        btn.enabled = NO;
    }
    
    for (NSNumber *idx in definitions) {
        UIButton* btn  = _definitionBtns[[idx integerValue]];
        btn.enabled = YES;
        btn.selected = (definition == [idx integerValue]);
    }
}

- (void)player:(VHVodPlayer *)player stoppedWithError:(NSError *)error
{
    [self hideProgressDialog:self.preView];
    [self stopPlayer];
    [self showMsg:[NSString stringWithFormat:@"%@",error.domain] afterDelay:2];
}

-(BOOL)shouldAutorotate
{
    return YES;
}
-(UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscape;
    
}

- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
    return UIInterfaceOrientationPortrait;
}
@end

下载地址

http://www.vhallyun.com/document/document/download

Android Demo    

主要功能

点播:支持常见的音视频文件播放(MP4、flv、MP3 等)

示例代码

public class VodPlayerActivity extends Activity {
    private static final String TAG = "LivePlayerActivity";
    private String roomId = "7a97e8c7";
    private String accessToken = "vhall";
    private SurfaceView mSurfaceView;
    private VHVodPlayer mPlayer;
    private boolean mPlaying = false;
    ImageView mPlayBtn;
    ProgressBar mLoadingPB;
    SeekBar mSeekbar;
    TextView mPosView, mMaxView;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (mPlaying) {
                int pos = (int) mPlayer.getPosition();
                mSeekbar.setProgress(pos);
                mPosView.setText(String.valueOf(pos));
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        roomId = getIntent().getStringExtra("roomid");
        accessToken = getIntent().getStringExtra("token");
        setContentView(R.layout.vod_layout);
        mPlayBtn = (ImageView) this.findViewById(R.id.btn_play);
        mLoadingPB = (ProgressBar) this.findViewById(R.id.pb_loading);
        mSeekbar = (SeekBar) this.findViewById(R.id.seekbar);
        mSurfaceView = (SurfaceView) this.findViewById(R.id.surfaceview);
        mPosView = (TextView) this.findViewById(R.id.tv_pos);
        mMaxView = (TextView) this.findViewById(R.id.tv_max);
        mPlayer = new VHVodPlayer(this, mSurfaceView);
        mPlayer.addListener(new MyPlayer());
        mSeekbar.setOnSeekBarChangeListener(new MySeekbarListener());
        handlePosition();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mPlayer != null && mPlaying)
            mPlayer.pause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mPlayer != null && mPlayer.resumeAble()) {
            mPlayer.resume();
        }
    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mPlayer != null)
            mPlayer.release();
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
    }

    public void play(View view) {
        if (mPlaying) {
            mPlayer.pause();
        } else {
            if (mPlayer.resumeAble())
                mPlayer.resume();
            else
                mPlayer.start(roomId, accessToken);
        }
    }

    class MyPlayer implements VHPlayerListener {

        @Override
        public void onEvent(int event, String msg) {
            switch (event) {
                case VHVodPlayer.EVENT_STATUS_STARTING:
                    mLoadingPB.setVisibility(View.VISIBLE);
                    break;
                case VHVodPlayer.EVENT_STATUS_STARTED:
                    int max = (int) mPlayer.getDuration();
                    mSeekbar.setMax(max);
                    mMaxView.setText(String.valueOf(max));
                    mLoadingPB.setVisibility(View.GONE);
                    mPlaying = true;
                    mPlayBtn.setImageResource(R.mipmap.icon_pause_bro);
                    break;
                case VHVodPlayer.EVENT_STATUS_STOPED:
                    mPlaying = false;
                    mPlayBtn.setImageResource(R.mipmap.icon_start_bro);
                    mLoadingPB.setVisibility(View.GONE);
                    break;
                case VHVodPlayer.EVENT_STATUS_END:
                    mPlaying = false;
                    mPlayBtn.setImageResource(R.mipmap.icon_start_bro);
                    mLoadingPB.setVisibility(View.GONE);
                    break;
                case VHVodPlayer.EVENT_STATUS_WH:
                    break;
            }
        }

        @Override
        public void onError(int errorCode, String msg) {
            mPlaying = false;
            mPlayBtn.setImageResource(R.mipmap.icon_start_bro);
            mLoadingPB.setVisibility(View.GONE);
            Toast.makeText(VodPlayerActivity.this, msg, Toast.LENGTH_SHORT).show();
        }
    }

    class MySeekbarListener implements SeekBar.OnSeekBarChangeListener {

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            mPosView.setText(String.valueOf(seekBar.getProgress()));
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
            mPlayer.seek(seekBar.getProgress());
        }
    }
    //每秒获取一下进度
    Timer timer;

    private void handlePosition() {
        if (timer != null)
            return;
        timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                handler.sendEmptyMessage(0);
            }
        }, 1000, 1000);
    }
}

下载地址

http://www.vhallyun.com/document/document/download

Javascript Demo    

主要功能

点播:支持广泛的流式视频格式(MP4、M3U8、FLV)

Demo示例

http://www.vhallyun.com/document/document/download

示例代码

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>demo  for push stream</title>
	<link rel="stylesheet" href="https://static.vhallyun.com/jssdk/videojs.min.css?v=1.0.0"></script><!--播放器默认样式,需要引用在包含在页面的head标签里-->
	<script src="https://static.vhallyun.com/jssdk/dvideo-plugin.js?v=1.0.0"></script><!--依赖的播放器资源-->
	<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-player-1.0.0.js"></script>
	<script src="https://static.vhallyun.com/jssdk/vhall-jssdk-base-1.0.0.js"></script>
	<style>
		body{
			background-color: #000;
/*			height: 800px;
			line-height: 800px;*/
		}
		.video-box{
			margin:0 auto;
			width: 854px;
			height: 480px;
		}
	</style>
</head>
<body>
	<div class="video-box" >
		<div id="myVideo" style="width:100%; height:450px;"></div>
	</div>

</body>
<script>

	Vhall.ready(function(){

	    VhallPlayer.init({
	        roomId:'lss_c063b5c9', //房间ID,直播必填,点播不写
	        recordId:'',//回放Id,点播必填,直播不写
	        type:'live',//播放类型,必填,live 直播, vod 为点播
	        videoNode:'myVideo',//推流视频回显节点id,必填
	        complete:function(){
	        	VhallPlayer.play();
	        }
    	});

	});

	 Vhall.config({
	     appId :'76043aaf',//应用 ID ,必填
	     accountId :'10000126',//第三方用户唯一标识,必填
	     token:'vhall',//token必填
	 });


</script>
</html>