技术研究之腾讯云直播

标签: 无 分类: 未分类 创建时间:2025-04-06 02:30:57 更新时间:2025-04-28 14:37:41

1.前言

在使用大疆机场直播的时候,本来我用了阿里云的rtmp服务,结果阿里云的rtmp服务总是非常的卡,非常的慢,多次联系阿里云之后,他们说解决不了这个东西,不支持120帧的高刷,也不支持 “大疆的无人机推流,分析推过来的流,在每个 P 帧前面都有插入 SEI ,导致播放卡顿,要在推流端把这个 SEI 和 AUD 去掉 再推流。” 这就是让我去改大疆的设备,这个让我怎么处理呢?

参考文章:
【1】.快速入门 这里是官方的文档,说明了如何配置这个东西。
【2】.标准直播服务费用 直播流量和直播带宽,不同的计费标准,基本上是 0.26 元每GB。

2.添加域名

在云直播控制台,域名管理,增加推流直播和拉流直播,根据提示进行操作,主要就是配置DNS映射。

3.获取推流地址

我这里使用Java代码获取推流和拉流地址。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
/**
* 腾讯云直播
*/
private static final char[] DIGITS_LOWER =
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

/*
* KEY+ streamName + txTime
*/
private static String getSafeUrl(String key, String streamName, long txTime) {
String input = new StringBuilder().
append(key).
append(streamName).
append(Long.toHexString(txTime).toUpperCase()).toString();

String txSecret = null;
try {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
txSecret = byteArrayToHexString(
messageDigest.digest(input.getBytes("UTF-8")));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}

return txSecret == null ? "" :
new StringBuilder().
append("txSecret=").
append(txSecret).
append("&").
append("txTime=").
append(Long.toHexString(txTime).toUpperCase()).
toString();
}

private static String byteArrayToHexString(byte[] data) {
char[] out = new char[data.length << 1];

for (int i = 0, j = 0; i < data.length; i++) {
out[j++] = DIGITS_LOWER[(0xF0 & data[i]) >>> 4];
out[j++] = DIGITS_LOWER[0x0F & data[i]];
}
return new String(out);
}

/**
* 生成腾讯云地址
* @param streamName
* @return
*/
public String generateTcPushUrl(String streamName) {
String pushUrl = "";
//推流域名未开启鉴权功能的情况下
if(tcPushKey.isEmpty()) {
pushUrl = "rtmp://"+tcPushDomain+"/"+tcAppName+"/"+streamName;
}else {
long timeStamp = System.currentTimeMillis()/1000L + tcExpireTime;
pushUrl = "rtmp://"+tcPushDomain+"/"+tcAppName+"/"+streamName+"?"+getSafeUrl(tcPushKey,streamName,timeStamp);
}
return pushUrl;
}
/**
* 生成播放地址
* @param streamName 播放streamName,播放源流时,streamName 同推流streamName;播放转码流时,streamName 为推流streamName_{转码模板ID}
*/
public String generaTcPullUrl(String streamName,String type) {
String result="";
String rtmpUrl = ""; //rtmp的拉流地址
String hlsUrl = ""; //m3u8的拉流地址
String flvUrl = ""; //flv的拉流地址
String artcUrl =""; // 超低延迟
//播放域名未配置鉴权Key的情况下
if(pullKey.isEmpty()) {
rtmpUrl = "rtmp://"+tcPullDomain+"/"+appName+"/"+streamName;
hlsUrl = "http://"+tcPullDomain+"/"+appName+"/"+streamName+".m3u8";
flvUrl = "http://"+tcPullDomain+"/"+appName+"/"+streamName+".flv";
artcUrl = "webrtc://"+tcPullDomain+"/"+appName+"/"+streamName;
}else {
long timeStamp = System.currentTimeMillis()/1000L + tcExpireTime;
rtmpUrl = "rtmp://"+tcPullDomain+"/"+appName+"/"+streamName+"?"+getSafeUrl(tcPullKey,streamName,timeStamp);
hlsUrl = "http://"+tcPullDomain+"/"+appName+"/"+streamName+".m3u8"+"?"+getSafeUrl(tcPullKey,streamName,timeStamp);
flvUrl = "http://"+tcPullDomain+"/"+appName+"/"+streamName+".flv"+"?"+getSafeUrl(tcPullKey,streamName,timeStamp);
artcUrl = "webrtc://"+tcPullDomain+"/"+appName+"/"+streamName+"?"+getSafeUrl(tcPullKey,streamName,timeStamp);
}
switch (type){
case "flv":
result=flvUrl;
break;
case "rtmp":
result=rtmpUrl;
break;
case "webrtc":
result=artcUrl;
break;
case "m3u8":
result=hlsUrl;
break;
}
return result;
}

4.直播推流

PC 端推流,建议使用 OBS WebRTC 推流。

5.获取播放地址

通过地址生成器,或者控制台,都可以获取播放地址。登录云直播控制台 > 进入常用工具 > 地址生成器 进入地址生成器页面,获取播放地址。推流成功后,选择 流管理 > 在线流,查看推流地址状态,单击预览在线播放观看。

6.TCPlayer

Web 端直播流测试:建议您使用 TCPlayer Demo 工具进行播放体验。

1.申请License

参考文章:
【1】.播放器 License 这是官方申请 license 的说明。

2.通过 npm 集成

1
pnpm install tcplayer.js

3.放置 video

1
2
<video id="player-container-id" width="414" height="270" preload="auto" playsinline webkit-playsinline>
</video>

4.播放器初始化

1
2
3
4
5
6
7
8
9
10
11
12
// player-container-id 为播放器容器 ID,必须与 html 中一致
var player = TCPlayer('player-container-id', {
sources: [{
src: 'path/to/video', // 播放地址
}],
licenseUrl: 'license/url', // license 地址,必传。参考准备工作部分,在视立方控制台申请 license 后可获得 licenseUrl
});

// player.src(url); // url 播放地址

rtmp://tcpush.live.openmap.tech/drone/7CTDM1200B47P6?txSecret=eaf3c683aa35472214c281fbcd4cb35e&txTime=67F4910A
rtmp://tcpush.openmap.tech/live/7CTDM1200B47P6?txSecret=27c84aca8d434914b60b592d0316e71b&txTime=67F491A3
参考文章:
【1】.TCPlayer 集成指引
【2】.WEB 体验馆 这里可以测试相关的url是否可用。
【3】.Web 本文档是介绍适用于直播和点播播放的 Web 播放器( TCPlayer )的相关参数以及 API。本文档适合有一定 Javascript 语言基础的开发人员阅读。

5.VUE版

使用 TCPlayer 接入还是挺方便的,播放器初始化需要传入两个参数,第一个为播放器容器 ID,第二个为功能参数对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 创建 阿里云直播组件
*/
function createTcPlay(id, pullUrl) {
// 创建元素
let domId = id;
let dom = document.createElement('video');
dom.setAttribute('class', 'player video-screen-shot');
dom.setAttribute('id', domId);
dom.setAttribute('autoplay', 'autoplay');
dom.setAttribute('playsinline', 'playsinline');
dom.setAttribute('webkit-playsinline', 'webkit-playsinline');
let videoWrap = videoWrapRef.value as any;
videoWrap.appendChild(dom);

// 创建播放器
let video = new TCPlayer(id, {
sources: [
{
src: pullUrl, // 播放地址
},
],
licenseUrl: 'https://license.vod2.myqcloud.com/license/v2/1251578519_1/v_cube.license', // license 地址,必传。参考准备工作部分,在视立方控制台申请 license 后可获得 licenseUrl
controls: false,
webrtcConfig: {
receiveSEI: true,
},
});
// 监听事件
video.on('error', function () {
livePara.liveState = false;
});
video.on('webrtcevent', function (event) {
// 从回调参数 event 中获取事件状态码及相关数据
let data = event.data;
let code = data.code;
if (code == 1003) {
livePara.liveState = true;
}
});
return video;
}
参考文章:
【1】.Web 这是官方的文档说明。
【2】.WEB 体验馆 这是官方的Demo配置
【3】.vue3中TCplayer应用
【4】.tcplayer播放实时视频流 这里是通过动态创建标签的方式搞定的
【5】.标准直播服务费用

6.直播转码

配置转码需要一定的费用,按不同的功能进行收费,H.264的720P,每分钟 0.0325元。

(1)配置转码模版
可以设置帧率,gop,美颜等功能。

(2)绑定域名
设置完转码模版之后,就可以绑定域名。

(3)播放流在 StreamName 后面增加 “_模版名”

参考文章:
【1】.直播转码 官方说明
【2】.转码配置 控制台配置转码
【3】.直播转码(水印、混流、字幕、动效贴片) 这里是直播转码的费用

错误

(1)Cannot read properties of null
当我调用 dispose() 方法销毁播放器的时候,就会报这个错误。
Uncaught (in promise) TypeError: Cannot read properties of null (reading ‘trigger’)
at e.onReceiveSEI (TXLivePlayer-1.3.5.min.js:1:373508)
at TXLivePlayer-1.3.5.min.js:1:315904
at Array.forEach ()
at Object.transform (TXLivePlayer-1.3.5.min.js:1:315837)
【解决方案】
主要解决方案就是延迟销毁

1
2
3
setTimeout(() => {
  videoAiPlay.dispose();
}, 1000);

(2)直播流自动断链
在直播过程中,播放着播放着,直播流就中断了,我刷新页面,或者重建 TcPlayer ,结果又能继续的直播了,我提交了工单,工单就开始敷衍我,说我是主动断流的。我用的是大疆的无人机进行的直播推流,我开启直播之后,就一直不动,然后过一会自己就断开了,我刷新之后重新打开播放器,结果又可以继续的直播了。我确定我没有关闭直播流,而且如果我交替打开两个播放器,那么在工单中说的,说我主动断流的,但是两个播放器并不是同时断流,而是交替断流的。

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。