• 腾讯云 Web 超级播放器开发实战


    目录

    关于超级播放器

    范例运行环境

    开发前准备

    设计与实现

    初始化播放器

    播放器重要属性设置

    播放器实用事件

     一些兼容性判断

    浏览器支持

    关于华为手机

     实现代码

    小结


    关于超级播放器

    腾讯云 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)前端布局,下载我的资源后,假设放在当前应用目录下,首先我们需要引入样式单,如下代码:

    <link rel="stylesheet" href="tcplayer2021.css" />

     其次,引入核心库,如下代码:

    1. <script type="text/javascript" src="tcplayer.v4.min.js"> script>

    (3)需要引入 Jquery,以下是一组基于Jquery的自定义开发的扩展应用库,请下载我的资源:

    https://download.csdn.net/download/michaelline/88615565

    进行引用,本库用于调用服务器静态方法等功能使用。

    设计与实现

    初始化播放器

    播放器需要引入与结合 H5 的 Video 控件,假设有如下引用:

    1. "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;">
    2. <video id="realcoplayer" autoplay="autoplay" controls="controls" webkit-playsinline playsinline x5-playsinline x-webkit-airplay="allow" runat="server" >video>
    3. <a id="b_rate" onclick="rate(this);" style=" float:right; line-height:25px; margin-right:10px; color:#fff;display:none;">1xa>
  • 其中

    1、coplayer 为外围容器层,控制一些样式和位置输出  

    2、realcoplayer 为 h5 video 控件,用于结合腾讯 web 超级播放器使用

    其关键属性说明如下:

    序号属性与设置说明
    1autoplay="autoplay" 设置是否自动播放,在移动端或IOS系统可能无法实现
    2controls="controls"是否显示控制工具栏,这里设置为需要显示
    3webkit-playsinline playsinline

    兼容性属性:webkit-playsinline使ios 10中设置可以让视频在小窗内播放,即不全屏播放。  playsinline 可使用IOS/微信浏览器支持小窗内播放

    4x5-playsinlineH5 移动是否禁用全屏,这里为允许,为空则不允许
    5x-webkit-airplay="allow"使此视频支持ios的AirPlay(隔空播放)功能,隔空播放能将各种 Apple 设备中的音乐流传输到家中的多个扬声器上,并让这些扬声器中播放的旋律始终保持合拍, 让音乐荡漾在每个房间。

    3、b_rate 为用于改造及引入超级播放器的快进组件,配合其使用。

    客户端播放器的初始化代码如下:

    1. var player = new TCPlayer('realcoplayer', {
    2. fileID: 111,
    3. appID: '125407',
    4. playbackRates: [0.5, 1, 1.25, 1.5, 2],
    5. autoplay: false,
    6. live: false,
    7. x5_player: true,
    8. volume: 0.5,
    9. flash: true,
    10. x5_player: true,
    11. systemFullscreen: false,
    12. playsinline: true,
    13. x5_orientation: 0,
    14. x5_type: 'h5',
    15. allowFullScreen: false,
    16. width:_w,
    17. height:_h,
    18. });

    播放器重要属性设置

    在实际使用中,为保证良好的可用性和兼容性,还需要设置如下属性,说明见下表:

    序号参数类型说明
    1fileID string云点播平台可播放视频文件的 fileID
    2appIDstring云点播平台申请的 appID
    3playbackRatesfloat[]快进倍速设置,如此数组 [0.5, 1, 1.25, 1.5, 2]
    4autoplaybool是否设置为自动播放,false 为不自动
    5livebool是否直播功能,默认为 false
    6x5_playerbool设为 true 。是否启用 TBS 的播放 flv 或 hls 。启用时播放器将在 TBS 模式下(例如 Android 的微信、QQ 浏览器),将 flv 或 hls 播放地址直接赋给
    7volumefloat默认音量,0-1,0.5为居中
    8flashbool一个兼容的重要属性,设为 true
    9systemFullscreenbool开启后(true),在不支持 Fullscreen API 的浏览器环境下,尝试使用浏览器提供的 webkitEnterFullScreen 方法进行全屏,如果支持,将进入系统全屏,控件为系统控件
    10playsinlinebool兼容性属性,设为 true
    11x5_orientationint

    通过 video 属性 “x5-video-orientation” 声明 TBS 播放器支持的方向,可选值:

    0:landscape 横屏

    1:portraint 竖屏

    2:landscape | portrait 跟随手机自动旋转。

    (备注:该属性为 TBS 内核实验性属性,非 TBS 内核不支持)

    12x5_typestring通过 video 属性 “x5-video-player-type” 声明启用同层 H5 播放器,支持的值:h5-page (该属性为 TBS 内核实验性属性,非 TBS 内核不支持)
    13allowFullScreenbool兼容性写法,是否允许全屏播放
    14widthint设置播放器宽度,单位为像素。
    15heightint设置播放器高度,单位为像素。

    播放器实用事件

    通过跟踪超级播放器提供的监听事件,实现我们的开发需求,其关键事件说明如下:

    序号事件说明
    1timeupdate

    播放时间更新事件,可记录播放时间,其结构体如下:

    player.on('timeupdate',function(){  }) 

    2play

    开始播放时事件,其结构体如下:

    player.on('play',function(){ })

    3fullscreenchange

    切换全屏状态事件,其结构体如下:

    player.on('fullscreenchange',function(){    })

    4seeked

    拖动播放进度结束事件,其结构体如下:

    player.on('seeked',function(){    })

    5pause

    播放暂停时事件,其结构体如下:

    player.on('pause',function(){    })

    6ended

    播放结束时事件,其结构体如下:

    player.on('ended',function(){    })

    7canplay

    播放能力执行成功事件,其结构体如下:

    player.on('canplay',function(){    })

    8loadeddata

    音视频数据加载完毕时事件,其结构体如下:

    player.on('loadeddata',function(){    })

    9ratechange

    改变快进倍速完成时事件,其结构体如下:

    player.on('ratechange',function(){    })

    类实现代码如下:

    1. public class QR_LIMIT_STR_SCENE
    2. {
    3. public string AccessToken { get; set; }
    4. public string ticket { get; set; }
    5. public string url { get; set; }
    6. public string ResultJson = "";
    7. public QR_LIMIT_STR_SCENE()
    8. {
    9. }
    10. public string getUrl(string scene_str)
    11. {
    12. string PostJson = "{\"action_name\": \"QR_LIMIT_STR_SCENE\", \"action_info\": {\"scene\": {\"scene_str\": \"" + scene_str + "\"}}}";
    13. String action = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=" + AccessToken;
    14. WebService ws = new WebService();
    15. string rs = ws.GetResponseResult(action, Encoding.UTF8, "POST", PostJson);
    16. Newtonsoft.Json.Linq.JObject jsonObj = Newtonsoft.Json.Linq.JObject.Parse(rs);
    17. ticket = jsonObj["ticket"] != null ? jsonObj["ticket"].ToString() : "";
    18. url = jsonObj["url"] != null ? jsonObj["url"].ToString() : "";
    19. ResultJson = rs;
    20. return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=" + ticket;
    21. }
    22. }

     一些兼容性判断

    浏览器支持

    编写浏览器是否支持终端H5播放的判断,实现代码如下:

    1. function checkVideo() {
    2. if (!!document.createElement('video').canPlayType) {
    3. var vidTest = document.createElement("video");
    4. oggTest = vidTest.canPlayType('video/ogg; codecs="theora, vorbis"');
    5. if (!oggTest) {
    6. h264Test = vidTest.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
    7. if (!h264Test) {
    8. return false;
    9. }
    10. else {
    11. if (h264Test == "probably") {
    12. return true;
    13. }
    14. else {
    15. return false;
    16. }
    17. }
    18. }
    19. else {
    20. if (oggTest == "probably") {
    21. return true;
    22. }
    23. else {
    24. return false;
    25. }
    26. }
    27. }
    28. else {
    29. return false;
    30. }
    31. return true;
    32. }
    33. if (!checkVideo()) {
    34. alert('您的浏览器不支持Video播放,请使用支持H5技术的浏览器!');
    35. }
    关于华为手机

    在某些华为手机我们发现倍速快进组件样式显示异常,因此引入 JS 函数,对机型增加了一些判断 ,代码如下:

    1. function judgeBrand(sUserAgent) {
    2. var isIphone = sUserAgent.match(/iphone/i) == "iphone";
    3. var isHuawei = sUserAgent.match(/huawei/i) == "huawei";
    4. var isHonor = sUserAgent.match(/honor/i) == "honor";
    5. var isOppo = sUserAgent.match(/oppo/i) == "oppo";
    6. var isOppoR15 = sUserAgent.match(/pacm00/i) == "pacm00";
    7. var isVivo = sUserAgent.match(/vivo/i) == "vivo";
    8. var isXiaomi = sUserAgent.match(/mi\s/i) == "mi ";
    9. var isXiaomi2s = sUserAgent.match(/mix\s/i) == "mix ";
    10. var isRedmi = sUserAgent.match(/redmi/i) == "redmi";
    11. var isSamsung = sUserAgent.match(/sm-/i) == "sm-";
    12. if (isIphone) {
    13. return 'iphone';
    14. } else if (isHuawei || isHonor) {
    15. return 'huawei';
    16. } else if (isOppo || isOppoR15) {
    17. return 'oppo';
    18. } else if (isVivo) {
    19. return 'vivo';
    20. } else if (isXiaomi || isRedmi || isXiaomi2s) {
    21. return 'xiaomi';
    22. } else if (isSamsung) {
    23. return 'samsung';
    24. } else {
    25. return 'default';
    26. }
    27. }

    对华为手机的判断处理代码如下:

    1. if(judgeBrand(navigator.userAgent.toLowerCase())=='huawei'){
    2. $("#b_rate").html="1x";
    3. $("#b_rate").css("display","");
    4. }else{
    5. $("#b_rate").css("display","none");
    6. }

     实现代码

    相对完整的实现代码(包括样式引入、前端控件和JS控制)如下:

    1. "stylesheet" href="tcplayer2021.css" />
    2. <asp:TextBox ID="x_roomid" checkSchema="" runat="server" style="display:none">asp:TextBox>
    3. <script type="text/javascript" src="hls.min.0.12.4.js"> script>
    4. <script type="text/javascript" src="tcplayer.v4.min.js"> script>
    5. <script type="text/javascript" language="javascript" src="jquery.js" >script>
    6. <div id="h5panel" runat="server" >
    7. <asp:TextBox ID="x_fileid" style="display:none;" runat="server">asp:TextBox>
    8. <asp:TextBox ID="current" Text="0" style="display:none;" runat="server">asp:TextBox>
    9. <asp:TextBox ID="duration" Text="0" style="display:none;" runat="server">asp:TextBox>
    10. <asp:TextBox ID="mname" style="display:none;" runat="server">asp:TextBox>
    11. <asp:TextBox ID="x_mp4url" style="display:none;" runat="server">asp:TextBox>
    12. <asp:TextBox ID="x_CoverUrl" style="display:none;" runat="server">asp:TextBox>
    13. <asp:TextBox ID="x_playMark" style="display:none;" runat="server">asp:TextBox>
    14. <asp:TextBox ID="x_lasttime" style="display:none;" runat="server">asp:TextBox>
    15. <asp:TextBox ID="confirmflag" Text="0" runat="server" style="display:none;" >asp:TextBox>
    16. <asp:TextBox ID="playMarkflag" Text="0" runat="server" style="display:none;" >asp:TextBox>
    17. <asp:TextBox ID="x_videocount" Text="0" style="display:none;" runat="server">asp:TextBox>
    18. <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;">
    19. <video id="realcoplayer" autoplay="autoplay" controls="controls" webkit-playsinline playsinline x5-playsinline x-webkit-airplay="allow" runat="server" >video>
    20. <a id="b_rate" onclick="rate(this);" style=" float:right; line-height:25px; margin-right:10px; color:#fff;display:none;">1xa>
    21. div>
    22. <script language="javascript">
    23. var windowheight=$(window).height();
    24. form = document.forms[0];
    25. function checkVideo() {
    26. if (!!document.createElement('video').canPlayType) {
    27. var vidTest = document.createElement("video");
    28. oggTest = vidTest.canPlayType('video/ogg; codecs="theora, vorbis"');
    29. if (!oggTest) {
    30. h264Test = vidTest.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"');
    31. if (!h264Test) {
    32. return false;
    33. }
    34. else {
    35. if (h264Test == "probably") {
    36. return true;
    37. }
    38. else {
    39. return false;
    40. }
    41. }
    42. }
    43. else {
    44. if (oggTest == "probably") {
    45. return true;
    46. }
    47. else {
    48. return false;
    49. }
    50. }
    51. }
    52. else {
    53. return false;
    54. }
    55. return true;
    56. }
    57. if (!checkVideo()) {
    58. alert('您的浏览器不支持Video播放,请使用支持H5技术的浏览器!');
    59. }
    60. var timer=null;
    61. var curtime=0;
    62. function stimer(){
    63. timer=window.setInterval("setpmark()",1000);
    64. }
    65. function etimer(){
    66. window.clearInterval(timer);
    67. }
    68. function secondToDate(result) {
    69. var h = Math.floor(result / 3600) < 10 ? '0'+Math.floor(result / 3600) : Math.floor(result / 3600);
    70. var m = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60));
    71. var s = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60));
    72. if(h=="00"){
    73. return result = m + ":" + s;
    74. }else{
    75. return result = h + ":" + m + ":" + s;
    76. }
    77. }
    78. var _w = $(document).width();
    79. if(_w>=1200){
    80. _w=640;
    81. }
    82. _h=_w/16*9;
    83. function resizeAll(){
    84. var _w = $(document).width();
    85. if(_w>=1200){
    86. _w=640;
    87. }
    88. _h=_w/16*9;
    89. if(player.isFullscreen()==true){
    90. }
    91. document.getElementById('coplayer').style.left=($(document).width()-_w)/2+'px';
    92. document.getElementById('coplayer').style.width=_w+'px';
    93. document.getElementById('coplayer').style.height=_h+'px';
    94. function aiplaymark(curtime){
    95. player.currentTime(curtime);
    96. player.play();
    97. }
    98. var debug=document.getElementById('debug');
    99. var curtime=0;
    100. var seeked=false;
    101. var player = new TCPlayer('realcoplayer', { fileID: document.getElementById('x_fileid').value, appID: '12540',
    102. playbackRates: [0.5, 1, 1.25, 1.5, 2],
    103. autoplay: false,
    104. live: false,
    105. x5_player: true,
    106. volume: 0.5,
    107. flash: true,
    108. x5_player: true,
    109. systemFullscreen: false,
    110. playsinline: true,
    111. x5_orientation: 0,
    112. x5_type: 'h5',
    113. allowFullScreen: false,
    114. width:_w,
    115. height:_h,
    116. });
    117. player.on('timeupdate',function(){
    118. document.getElementById("current").value=player.currentTime();
    119. })
    120. player.on('play',function(){
    121. stimer();
    122. updcountinfo('play',0);
    123. })
    124. player.on('fullscreenchange',function(){
    125. })
    126. player.on('seeked',function(){
    127. })
    128. player.on('pause',function(){
    129. etimer();
    130. })
    131. player.on('ended',function(){
    132. etimer();
    133. })
    134. player.on('canplay',function(){
    135. })
    136. player.on('loadeddata',function(){
    137. player.poster(document.getElementById('x_CoverUrl').value);
    138. if(judgeBrand(navigator.userAgent.toLowerCase())=='huawei'){
    139. $("#b_rate").html="1x";
    140. $("#b_rate").css("display","");
    141. }else{
    142. $("#b_rate").css("display","none");
    143. }
    144. this.currentTime(document.getElementById("current").value);
    145. })
    146. player.on('ratechange',function(){
    147. $('#b_rate').html($('.vjs-playback-rate-value').html());
    148. })
    149. function rate(o) {
    150. document.querySelectorAll('.vjs-playback-rate')[1].click();
    151. }
    152. function judgeBrand(sUserAgent) {
    153. var isIphone = sUserAgent.match(/iphone/i) == "iphone";
    154. var isHuawei = sUserAgent.match(/huawei/i) == "huawei";
    155. var isHonor = sUserAgent.match(/honor/i) == "honor";
    156. var isOppo = sUserAgent.match(/oppo/i) == "oppo";
    157. var isOppoR15 = sUserAgent.match(/pacm00/i) == "pacm00";
    158. var isVivo = sUserAgent.match(/vivo/i) == "vivo";
    159. var isXiaomi = sUserAgent.match(/mi\s/i) == "mi ";
    160. var isXiaomi2s = sUserAgent.match(/mix\s/i) == "mix ";
    161. var isRedmi = sUserAgent.match(/redmi/i) == "redmi";
    162. var isSamsung = sUserAgent.match(/sm-/i) == "sm-";
    163. if (isIphone) {
    164. return 'iphone';
    165. } else if (isHuawei || isHonor) {
    166. return 'huawei';
    167. } else if (isOppo || isOppoR15) {
    168. return 'oppo';
    169. } else if (isVivo) {
    170. return 'vivo';
    171. } else if (isXiaomi || isRedmi || isXiaomi2s) {
    172. return 'xiaomi';
    173. } else if (isSamsung) {
    174. return 'samsung';
    175. } else {
    176. return 'default';
    177. }
    178. }
    179. function updcountinfo(ctype,counts){
    180. if(ctype=='play'){
    181. if(document.getElementById('x_videocount').value=='0'){
    182. document.getElementById('x_videocount').value='1';
    183. }else{
    184. return;
    185. }
    186. }
    187. callServerFunction("", "updateCountInfo","{cid:'"+$("#x_cid").val()+"',ctype:'"+ctype+"',counts:'"+counts+"'}", sscount);
    188. }
    189. function setpmark(){
    190. curtime++;
    191. callServerFunction("", "updatePersonLearnInfo","{cid:'"+$("#x_cid").val()+"',uid:'"+$("#x_uid").val()+"',pid:'"+$("#x_pid").val()+"',playmark:'"+$('#current').val()+"',steptime:'1'}", ss);
    192. }
    193. var sTime;
    194. script>

    小结

    (1)关于更多的超级播放器 SDK 开发介绍,请参照如下链接:

    https://cloud.tencent.com/document/product/881/30818

    (2)实现代码中事件代码仅供参考,对于服务器静态方法实现需要根据我们实际的应用需求进行开发。

    (3)实现代码中的前端控件,只为演示实例使用,可根据需要改造符合自己的开发规范。

    感谢您的阅读,希望本文能够对您有所帮助。

  • 相关阅读:
    180页100+题15W+字解析的《Java高级面试指南》,果断收下
    基于函数计算自定义运行时快速部署一个 Springboot 项目
    leetcode 热题 100_环形链表
    系统移植--前言
    重要通知 | 3月31日前小程序未完成备案,将予清退!
    代码随想录算法训练营第二天 | 242. 有效的字母异位词、349. 两个数组的交集、1. 两数之和
    notification控件 通知栏
    【1620. 网络信号最好的坐标】
    基于JSP的智能道路交通信息管理系统
    SQL教程之SQL 中数据透视表的不同方法
  • 原文地址:https://blog.csdn.net/michaelline/article/details/139253919