关于超级播放器
腾讯云 Web 超级播放器 TCPlayer 可实现在手机浏览器和 PC 浏览器上播放音视频流的问题,功能强劲,兼容性好,可以不依赖用户安装 App,就能进行播放。
在实际的应用中,我们仍然根据需求直接改造了混淆代码,主要解决了以下问题:
1、增加、集成了播放快进组件
2、更改了一些样式
3、增强了一些旧版手机的兼容性
范例运行环境
操作系统: Windows Server 2019 DataCenter
.net版本: .netFramework4.0 或以上
开发工具:VS2019 C#
浏览器需要支持 H5 技术。
开发前准备
(1)我们需要引入腾讯云 Web 超级播放器的 JS 库,以下是我改造后的资源,可点击如下链接进行下载:
https://download.csdn.net/download/michaelline/89367455
(2)前端布局,下载我的资源后,假设放在当前应用目录下,首先我们需要引入样式单,如下代码:
代码语言:javascript复制<link rel="stylesheet" href="tcplayer2021.css" />
其次,引入核心库,如下代码:
代码语言:javascript复制 <script type="text/javascript" src="hls.min.0.12.4.js"> </script>
<script type="text/javascript" src="tcplayer.v4.min.js"> </script>
(3)需要引入 Jquery,以下是一组基于Jquery的自定义开发的扩展应用库,请下载我的资源:
https://download.csdn.net/download/michaelline/88615565
进行引用,本库用于调用服务器静态方法等功能使用。
设计与实现
初始化播放器
播放器需要引入与结合 H5 的 Video 控件,假设有如下引用:
代码语言:javascript复制<div id="coplayer" style="box-shadow:2px 0px 35px #000; -webkit-box-shadow:2px 0px 35px #000; background-color:rgb(69,69,69); position:fixed;top:40px;left:0px;width:80%;height:100px; margin: 0px auto;">
<video id="realcoplayer" autoplay="autoplay" controls="controls" webkit-playsinline playsinline x5-playsinline x-webkit-airplay="allow" runat="server" ></video>
<a id="b_rate" onclick="rate(this);" style=" float:right; line-height:25px; margin-right:10px; color:#fff;display:none;">1x</a>
</div>
其中
1、coplayer 为外围容器层,控制一些样式和位置输出
2、realcoplayer 为 h5 video 控件,用于结合腾讯 web 超级播放器使用
其关键属性说明如下:
序号 | 属性与设置 | 说明 |
---|---|---|
1 | autoplay="autoplay" | 设置是否自动播放,在移动端或IOS系统可能无法实现 |
2 | controls="controls" | 是否显示控制工具栏,这里设置为需要显示 |
3 | webkit-playsinline playsinline | 兼容性属性:webkit-playsinline使ios 10中设置可以让视频在小窗内播放,即不全屏播放。 playsinline 可使用IOS/微信浏览器支持小窗内播放 |
4 | x5-playsinline | H5 移动是否禁用全屏,这里为允许,为空则不允许 |
5 | x-webkit-airplay="allow" | 使此视频支持ios的AirPlay(隔空播放)功能,隔空播放能将各种 Apple 设备中的音乐流传输到家中的多个扬声器上,并让这些扬声器中播放的旋律始终保持合拍, 让音乐荡漾在每个房间。 |
3、b_rate 为用于改造及引入超级播放器的快进组件,配合其使用。
客户端播放器的初始化代码如下:
代码语言:javascript复制var player = new TCPlayer('realcoplayer', {
fileID: 111,
appID: '125407',
playbackRates: [0.5, 1, 1.25, 1.5, 2],
autoplay: false,
live: false,
x5_player: true,
volume: 0.5,
flash: true,
x5_player: true,
systemFullscreen: false,
playsinline: true,
x5_orientation: 0,
x5_type: 'h5',
allowFullScreen: false,
width:_w,
height:_h,
});
播放器重要属性设置
在实际使用中,为保证良好的可用性和兼容性,还需要设置如下属性,说明见下表:
序号 | 参数 | 类型 | 说明 |
---|---|---|---|
1 | fileID | string | 云点播平台可播放视频文件的 fileID |
2 | appID | string | 云点播平台申请的 appID |
3 | playbackRates | float[] | 快进倍速设置,如此数组 [0.5, 1, 1.25, 1.5, 2] |
4 | autoplay | bool | 是否设置为自动播放,false 为不自动 |
5 | live | bool | 是否直播功能,默认为 false |
6 | x5_player | bool | 设为 true 。是否启用 TBS 的播放 flv 或 hls 。启用时播放器将在 TBS 模式下(例如 Android 的微信、QQ 浏览器),将 flv 或 hls 播放地址直接赋给 <video> 播放。 |
7 | volume | float | 默认音量,0-1,0.5为居中 |
8 | flash | bool | 一个兼容的重要属性,设为 true |
9 | systemFullscreen | bool | 开启后(true),在不支持 Fullscreen API 的浏览器环境下,尝试使用浏览器提供的 webkitEnterFullScreen 方法进行全屏,如果支持,将进入系统全屏,控件为系统控件 |
10 | playsinline | bool | 兼容性属性,设为 true |
11 | x5_orientation | int | 通过 video 属性 “x5-video-orientation” 声明 TBS 播放器支持的方向,可选值: 0:landscape 横屏 1:portraint 竖屏 2:landscape | portrait 跟随手机自动旋转。 (备注:该属性为 TBS 内核实验性属性,非 TBS 内核不支持) |
12 | x5_type | string | 通过 video 属性 “x5-video-player-type” 声明启用同层 H5 播放器,支持的值:h5-page (该属性为 TBS 内核实验性属性,非 TBS 内核不支持) |
13 | allowFullScreen | bool | 兼容性写法,是否允许全屏播放 |
14 | width | int | 设置播放器宽度,单位为像素。 |
15 | height | int | 设置播放器高度,单位为像素。 |
播放器实用事件
通过跟踪超级播放器提供的监听事件,实现我们的开发需求,其关键事件说明如下:
序号 | 事件 | 说明 |
---|---|---|
1 | timeupdate | 播放时间更新事件,可记录播放时间,其结构体如下: player.on('timeupdate',function(){ }) |
2 | play | 开始播放时事件,其结构体如下: player.on('play',function(){ }) |
3 | fullscreenchange | 切换全屏状态事件,其结构体如下: player.on('fullscreenchange',function(){ }) |
4 | seeked | 拖动播放进度结束事件,其结构体如下: player.on('seeked',function(){ }) |
5 | pause | 播放暂停时事件,其结构体如下: player.on('pause',function(){ }) |
6 | ended | 播放结束时事件,其结构体如下: player.on('ended',function(){ }) |
7 | canplay | 播放能力执行成功事件,其结构体如下: player.on('canplay',function(){ }) |
8 | loadeddata | 音视频数据加载完毕时事件,其结构体如下: player.on('loadeddata',function(){ }) |
9 | ratechange | 改变快进倍速完成时事件,其结构体如下: player.on('ratechange',function(){ }) |
类实现代码如下:
代码语言:javascript复制public class QR_LIMIT_STR_SCENE
{
public string AccessToken { get; set; }
public string ticket { get; set; }
public string url { get; set; }
public string ResultJson = "";
public QR_LIMIT_STR_SCENE()
{
}
public string getUrl(string scene_str)
{
string PostJson = "{"action_name": "QR_LIMIT_STR_SCENE", "action_info": {"scene": {"scene_str": "" scene_str ""}}}";
String action = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" AccessToken;
WebService ws = new WebService();
string rs = ws.GetResponseResult(action, Encoding.UTF8, "POST", PostJson);
Newtonsoft.Json.Linq.JObject jsonObj = Newtonsoft.Json.Linq.JObject.Parse(rs);
ticket = jsonObj["ticket"] != null ? jsonObj["ticket"].ToString() : "";
url = jsonObj["url"] != null ? jsonObj["url"].ToString() : "";
ResultJson = rs;
return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" ticket;
}
}
一些兼容性判断
浏览器支持
编写浏览器是否支持终端H5播放的判断,实现代码如下:
代码语言:javascript复制 function checkVideo() {
if (!!document.createElement('video').canPlayType) {
var vidTest = document.createElement("video");
oggTest = vidTest.canPlayType('video/ogg; codecs="theora, vorbis"');
if (!oggTest) {
h264Test = vidTest.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
if (!h264Test) {
return false;
}
else {
if (h264Test == "probably") {
return true;
}
else {
return false;
}
}
}
else {
if (oggTest == "probably") {
return true;
}
else {
return false;
}
}
}
else {
return false;
}
return true;
}
if (!checkVideo()) {
alert('您的浏览器不支持Video播放,请使用支持H5技术的浏览器!');
}
关于华为手机
在某些华为手机我们发现倍速快进组件样式显示异常,因此引入 JS 函数,对机型增加了一些判断 ,代码如下:
代码语言:javascript复制 function judgeBrand(sUserAgent) {
var isIphone = sUserAgent.match(/iphone/i) == "iphone";
var isHuawei = sUserAgent.match(/huawei/i) == "huawei";
var isHonor = sUserAgent.match(/honor/i) == "honor";
var isOppo = sUserAgent.match(/oppo/i) == "oppo";
var isOppoR15 = sUserAgent.match(/pacm00/i) == "pacm00";
var isVivo = sUserAgent.match(/vivo/i) == "vivo";
var isXiaomi = sUserAgent.match(/mis/i) == "mi ";
var isXiaomi2s = sUserAgent.match(/mixs/i) == "mix ";
var isRedmi = sUserAgent.match(/redmi/i) == "redmi";
var isSamsung = sUserAgent.match(/sm-/i) == "sm-";
if (isIphone) {
return 'iphone';
} else if (isHuawei || isHonor) {
return 'huawei';
} else if (isOppo || isOppoR15) {
return 'oppo';
} else if (isVivo) {
return 'vivo';
} else if (isXiaomi || isRedmi || isXiaomi2s) {
return 'xiaomi';
} else if (isSamsung) {
return 'samsung';
} else {
return 'default';
}
}
对华为手机的判断处理代码如下:
代码语言:javascript复制if(judgeBrand(navigator.userAgent.toLowerCase())=='huawei'){
$("#b_rate").html="1x";
$("#b_rate").css("display","");
}else{
$("#b_rate").css("display","none");
}
实现代码
相对完整的实现代码(包括样式引入、前端控件和JS控制)如下:
代码语言:javascript复制<link rel="stylesheet" href="tcplayer2021.css" />
<asp:TextBox ID="x_roomid" checkSchema="" runat="server" style="display:none"></asp:TextBox>
<script type="text/javascript" src="hls.min.0.12.4.js"> </script>
<script type="text/javascript" src="tcplayer.v4.min.js"> </script>
<script type="text/javascript" language="javascript" src="jquery.js" ></script>
<div id="h5panel" runat="server" >
<asp:TextBox ID="x_fileid" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="current" Text="0" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="duration" Text="0" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="mname" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="x_mp4url" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="x_CoverUrl" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="x_playMark" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="x_lasttime" style="display:none;" runat="server"></asp:TextBox>
<asp:TextBox ID="confirmflag" Text="0" runat="server" style="display:none;" ></asp:TextBox>
<asp:TextBox ID="playMarkflag" Text="0" runat="server" style="display:none;" ></asp:TextBox>
<asp:TextBox ID="x_videocount" Text="0" style="display:none;" runat="server"></asp:TextBox>
<div id="coplayer" style="box-shadow:2px 0px 35px #000; -webkit-box-shadow:2px 0px 35px #000; background-color:rgb(69,69,69); position:fixed;top:40px;left:0px;width:80%;height:100px; margin: 0px auto;">
<video id="realcoplayer" autoplay="autoplay" controls="controls" webkit-playsinline playsinline x5-playsinline x-webkit-airplay="allow" runat="server" ></video>
<a id="b_rate" onclick="rate(this);" style=" float:right; line-height:25px; margin-right:10px; color:#fff;display:none;">1x</a>
</div>
<script language="javascript">
var windowheight=$(window).height();
form = document.forms[0];
function checkVideo() {
if (!!document.createElement('video').canPlayType) {
var vidTest = document.createElement("video");
oggTest = vidTest.canPlayType('video/ogg; codecs="theora, vorbis"');
if (!oggTest) {
h264Test = vidTest.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
if (!h264Test) {
return false;
}
else {
if (h264Test == "probably") {
return true;
}
else {
return false;
}
}
}
else {
if (oggTest == "probably") {
return true;
}
else {
return false;
}
}
}
else {
return false;
}
return true;
}
if (!checkVideo()) {
alert('您的浏览器不支持Video播放,请使用支持H5技术的浏览器!');
}
var timer=null;
var curtime=0;
function stimer(){
timer=window.setInterval("setpmark()",1000);
}
function etimer(){
window.clearInterval(timer);
}
function secondToDate(result) {
var h = Math.floor(result / 3600) < 10 ? '0' Math.floor(result / 3600) : Math.floor(result / 3600);
var m = Math.floor((result / 60 % 60)) < 10 ? '0' Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60));
var s = Math.floor((result % 60)) < 10 ? '0' Math.floor((result % 60)) : Math.floor((result % 60));
if(h=="00"){
return result = m ":" s;
}else{
return result = h ":" m ":" s;
}
}
var _w = $(document).width();
if(_w>=1200){
_w=640;
}
_h=_w/16*9;
function resizeAll(){
var _w = $(document).width();
if(_w>=1200){
_w=640;
}
_h=_w/16*9;
if(player.isFullscreen()==true){
}
document.getElementById('coplayer').style.left=($(document).width()-_w)/2 'px';
document.getElementById('coplayer').style.width=_w 'px';
document.getElementById('coplayer').style.height=_h 'px';
function aiplaymark(curtime){
player.currentTime(curtime);
player.play();
}
var debug=document.getElementById('debug');
var curtime=0;
var seeked=false;
var player = new TCPlayer('realcoplayer', { fileID: document.getElementById('x_fileid').value, appID: '12540',
playbackRates: [0.5, 1, 1.25, 1.5, 2],
autoplay: false,
live: false,
x5_player: true,
volume: 0.5,
flash: true,
x5_player: true,
systemFullscreen: false,
playsinline: true,
x5_orientation: 0,
x5_type: 'h5',
allowFullScreen: false,
width:_w,
height:_h,
});
player.on('timeupdate',function(){
document.getElementById("current").value=player.currentTime();
})
player.on('play',function(){
stimer();
updcountinfo('play',0);
})
player.on('fullscreenchange',function(){
})
player.on('seeked',function(){
})
player.on('pause',function(){
etimer();
})
player.on('ended',function(){
etimer();
})
player.on('canplay',function(){
})
player.on('loadeddata',function(){
player.poster(document.getElementById('x_CoverUrl').value);
if(judgeBrand(navigator.userAgent.toLowerCase())=='huawei'){
$("#b_rate").html="1x";
$("#b_rate").css("display","");
}else{
$("#b_rate").css("display","none");
}
this.currentTime(document.getElementById("current").value);
})
player.on('ratechange',function(){
$('#b_rate').html($('.vjs-playback-rate-value').html());
})
function rate(o) {
document.querySelectorAll('.vjs-playback-rate')[1].click();
}
function judgeBrand(sUserAgent) {
var isIphone = sUserAgent.match(/iphone/i) == "iphone";
var isHuawei = sUserAgent.match(/huawei/i) == "huawei";
var isHonor = sUserAgent.match(/honor/i) == "honor";
var isOppo = sUserAgent.match(/oppo/i) == "oppo";
var isOppoR15 = sUserAgent.match(/pacm00/i) == "pacm00";
var isVivo = sUserAgent.match(/vivo/i) == "vivo";
var isXiaomi = sUserAgent.match(/mis/i) == "mi ";
var isXiaomi2s = sUserAgent.match(/mixs/i) == "mix ";
var isRedmi = sUserAgent.match(/redmi/i) == "redmi";
var isSamsung = sUserAgent.match(/sm-/i) == "sm-";
if (isIphone) {
return 'iphone';
} else if (isHuawei || isHonor) {
return 'huawei';
} else if (isOppo || isOppoR15) {
return 'oppo';
} else if (isVivo) {
return 'vivo';
} else if (isXiaomi || isRedmi || isXiaomi2s) {
return 'xiaomi';
} else if (isSamsung) {
return 'samsung';
} else {
return 'default';
}
}
function updcountinfo(ctype,counts){
if(ctype=='play'){
if(document.getElementById('x_videocount').value=='0'){
document.getElementById('x_videocount').value='1';
}else{
return;
}
}
callServerFunction("", "updateCountInfo","{cid:'" $("#x_cid").val() "',ctype:'" ctype "',counts:'" counts "'}", sscount);
}
function setpmark(){
curtime ;
callServerFunction("", "updatePersonLearnInfo","{cid:'" $("#x_cid").val() "',uid:'" $("#x_uid").val() "',pid:'" $("#x_pid").val() "',playmark:'" $('#current').val() "',steptime:'1'}", ss);
}
var sTime;
</script>
小结
(1)关于更多的超级播放器 SDK 开发介绍,请参照如下链接:
https://cloud.tencent.com/document/product/881/30818
(2)实现代码中事件代码仅供参考,对于服务器静态方法实现需要根据我们实际的应用需求进行开发。
(3)实现代码中的前端控件,只为演示实例使用,可根据需要改造符合自己的开发规范。
感谢您的阅读,希望本文能够对您有所帮助。