-
Notifications
You must be signed in to change notification settings - Fork 0
/
16791192499571.html
446 lines (327 loc) · 17 KB
/
16791192499571.html
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=0.8,minimum-scale=0.8, maximum-scale=0.8,user-scalable=no,viewport-fit=cover">
<title>
直播 (三) : RTMP直播应用与延时分析 - 宋明的博客
</title>
<link href="atom.xml" rel="alternate" title="宋明的博客" type="application/atom+xml">
<link rel="stylesheet" href="asset/css/style.min.css">
<link rel="stylesheet" href="asset/css/doc.css">
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/[email protected]/css/font-awesome.min.css">
<!-- Global site tag (gtag.js) - Google Analytics -->
<!-- 百度分析 -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/L2Dwidget.min.js"></script>
<script src="asset/app.js"></script>
</head>
<body style="overflow-x: hidden;">
<section class="hero">
<div class="hero-head">
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="container">
<div class="navbar-brand">
<a target="self" class="navbar-item " href="index.html">Home</a>
<a target="_self" class="navbar-item " href="archives.html">Archives</a>
<a role="button" id="navbarSNSRssSwitchBtn" class="navbar-burger burger" aria-label="menu" aria-expanded="false" data-target="navbarSNSRssButtons">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="navbarSNSRssButtons" class="navbar-menu">
<div class="navbar-start">
</div>
<div class="navbar-end">
<div class="navbar-item">
<!--buttons start-->
<div class="buttons">
<a href="mailto: [email protected]" target="_blank" title="email">
<span class="icon is-large has-text-grey-darker">
<svg class="svg-inline--fa fa-email fa-w-14 fa-lg" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1208" width="200" height="200"><path fill="currentColor" d="M935.335233 153.62202h-846.666656a84.666666 84.666666 0 0 0-84.666666 84.666666v550.333327a84.666666 84.666666 0 0 0 84.666666 84.666665h846.666656a84.666666 84.666666 0 0 0 84.666666-84.666665v-550.333327a84.666666 84.666666 0 0 0-84.666666-84.666666z m-27.293711 213.952665L557.558216 549.672927a94.993177 94.993177 0 0 1-87.065555 0.197555l-354.612218-182.202664a42.333333 42.333333 0 0 1 38.698311-75.308177l354.606573 182.202664a10.196689 10.196689 0 0 0 9.341556-0.022577l350.477662-182.089776a42.333333 42.333333 0 1 1 39.034155 75.127555z" fill="#2c2c2c" p-id="1209"></path></svg>
</span>
</a>
<a href="atom.xml" target="_blank" title="RSS">
<span class="icon is-large has-text-black-bis">
<svg class="svg-inline--fa fa-rss fa-w-14 fa-lg" aria-hidden="true" focusable="false" data-prefix="fas" data-icon="rss" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" data-fa-i2svg=""><path fill="currentColor" d="M128.081 415.959c0 35.369-28.672 64.041-64.041 64.041S0 451.328 0 415.959s28.672-64.041 64.041-64.041 64.04 28.673 64.04 64.041zm175.66 47.25c-8.354-154.6-132.185-278.587-286.95-286.95C7.656 175.765 0 183.105 0 192.253v48.069c0 8.415 6.49 15.472 14.887 16.018 111.832 7.284 201.473 96.702 208.772 208.772.547 8.397 7.604 14.887 16.018 14.887h48.069c9.149.001 16.489-7.655 15.995-16.79zm144.249.288C439.596 229.677 251.465 40.445 16.503 32.01 7.473 31.686 0 38.981 0 48.016v48.068c0 8.625 6.835 15.645 15.453 15.999 191.179 7.839 344.627 161.316 352.465 352.465.353 8.618 7.373 15.453 15.999 15.453h48.068c9.034-.001 16.329-7.474 16.005-16.504z"></path></svg><!-- <i class="fas fa-rss fa-lg"></i> -->
</span>
</a>
</div>
<!--buttons end-->
</div>
</div>
</div>
</div>
</nav>
</div>
<div class="hero-body ct-body"></div>
</section>
<section class="ct-body">
<div class="container">
<div class="columns is-variable bd-klmn-columns is-4">
<div class="column is-two-thirds">
<div class="post-body single-content">
<div class="card-image">
<figure class="random-img">
</figure>
</div>
<h1 class="title">
直播 (三) : RTMP直播应用与延时分析
</h1>
<div class="media">
<figure class="media-left">
<p class="image is-48x48">
<img class="is-rounded" src="">
</p>
</figure>
<div class="media-content">
<div class="content">
<p style="line-height: 30px; font-size: 12px;">
<a href="http://apolla.cc">宋明</a>
<span style="color: #ccc;">|</span>
<span class="date"><i class="fa fa-calendar-check-o" aria-hidden="true"></i> 2023/03/18</span>
<span class="tran-posted-in">posted in</span>
<span class="posted-in"><a href='%E7%9B%B4%E6%92%AD.html'><i class="fa fa-folder" aria-hidden="true"></i> 直播</a></span>
</p>
</div>
</div>
</div>
</div>
<article class="markdown-body single-content">
<p>直播应用中,RTMP和HLS基本上可以覆盖所有客户端观看<br />
HLS主要是延时比较大,RTMP主要优势在于延时低。</p>
<p>一、应用场景<br />
◊ 低延时应用场景包括:<br />
◊ 互动式直播:譬如2013年大行其道的美女主播,游戏直播等等<br />
◊ 各种主播,流媒体分发给用户观看。用户可以文字聊天和主播互动。<br />
◊ 视频会议:我们要是有同事出差在外地,就用视频会议开内部会议。<br />
◊ 其实会议1秒延时无所谓,因为人家讲完话后,其他人需要思考,<br />
◊ 思考的延时也会在1秒左右。当然如果用视频会议吵架就不行。<br />
◊ 其他:监控,直播也有些地方需要对延迟有要求,<br />
◊ 互联网上RTMP协议的延迟基本上能够满足要求。</p>
<p>二、RTMP和延时</p>
<ol>
<li>
<p>RTMP的特点如下:</p>
</li>
<li>
<p>Adobe支持得很好:<br />
RTMP实际上是现在编码器输出的工业标准协议,基本上所有的编码器(摄像头之类)都支持RTMP输出。<br />
原因在于PC市场巨大,PC主要是Windows,Windows的浏览器基本上都支持flash,<br />
Flash又支持RTMP支持得非常好。</p>
</li>
<li>
<p>适合长时间播放:<br />
因为RTMP支持的很完善,所以能做到flash播放RTMP流长时间不断流,<br />
当时测试是100万秒,即10天多可以连续播放。<br />
对于商用流媒体应用,客户端的稳定性当然也是必须的,否则最终用户看不了还怎么玩?<br />
我就知道有个教育客户,最初使用播放器播放http流,需要播放不同的文件,结果就总出问题,<br />
如果换成服务器端将不同的文件转换成RTMP流,客户端就可以一直播放;<br />
该客户走RTMP方案后,经过CDN分发,没听说客户端出问题了。</p>
</li>
</ol>
<p>3)延迟较低:<br />
比起YY的那种UDP私有协议,RTMP算延迟大的(延迟在1-3秒),<br />
比起HTTP流的延时(一般在10秒以上)RTMP算低延时。<br />
一般的直播应用,只要不是电话类对话的那种要求,RTMP延迟是可以接受的。<br />
在一般的视频会议应用中,RTMP延时也能接受,原因是别人在说话的时候我们一般在听,<br />
实际上1秒延时没有关系,我们也要思考(话说有些人的CPU处理速度还没有这么快)。</p>
<ol start="4">
<li>
<p>有累积延迟:<br />
技术一定要知道弱点,RTMP有个弱点就是累积误差,原因是RTMP基于TCP不会丢包。<br />
所以当网络状态差时,服务器会将包缓存起来,导致累积的延迟;<br />
待网络状况好了,就一起发给客户端。<br />
这个的对策就是,当客户端的缓冲区很大,就断开重连。</p>
</li>
<li>
<p>HLS低延时<br />
主要有人老是问这个问题,如何降低HLS延迟。<br />
HLS解决延时,就像是爬到枫树上去捉鱼,奇怪的是还有人喊,看那,有鱼。<br />
你说是怎么回事?</p>
</li>
</ol>
<p>我只能说你在参与谦哥的魔术表演,错觉罢了。<br />
如果你真的确信有,请用实际测量的图片来展示出来,参考下面延迟的测量。</p>
<ol start="3">
<li>RTMP延迟的测量<br />
如何测量延时,是个很难的问题,<br />
不过有个行之有效的方法,就是用手机的秒表,可以比较精确的对比延时。</li>
</ol>
<p>经过测量发现,在网络状况良好时:<br />
. RTMP延时可以做到0.8秒左右。<br />
. 多级边缘节点不会影响延迟(和SRS同源的某CDN的边缘服务器可以做到)<br />
. Nginx-Rtmp延迟有点大,估计是缓存的处理,多进程通信导致?<br />
. GOP是个硬指标,不过SRS可以关闭GOP的cache来避免这个影响.<br />
. 服务器性能太低,也会导致延迟变大,服务器来不及发送数据。<br />
. 客户端的缓冲区长度也影响延迟。<br />
. 譬如flash客户端的NetStream.bufferTime设置为10秒,那么延迟至少10秒以上。</p>
<ol start="4">
<li>GOP-Cache<br />
什么是GOP?就是视频流中两个I帧的时间距离。<br />
GOP有什么影响?<br />
Flash(解码器)只有拿到GOP才能开始解码播放。<br />
也就是说,服务器一般先给一个I帧给Flash。<br />
可惜问题来了,假设GOP是10秒,也就是每隔10秒才有关键帧,<br />
如果用户在第5秒时开始播放,会怎么样?<br />
第一种方案:等待下一个I帧,<br />
也就是说,再等5秒才开始给客户端数据。<br />
这样延迟就很低了,总是实时的流。<br />
问题是:等待的这5秒,会黑屏,现象就是播放器卡在那里,什么也没有,<br />
有些用户可能以为死掉了,就会刷新页面。<br />
总之,某些客户会认为等待关键帧是个不可饶恕的错误,延时有什么关系?<br />
我就希望能快速启动和播放视频,最好打开就能放!</li>
</ol>
<p>第二种方案:马上开始放<br />
放什么呢?<br />
你肯定知道了,放前一个I帧。<br />
也就是说,服务器需要总是cache一个gop,<br />
这样客户端上来就从前一个I帧开始播放,就可以快速启动了。<br />
问题是:延迟自然就大了。</p>
<p>有没有好的方案?<br />
有!至少有两种:<br />
编码器调低GOP,譬如0.5秒一个GOP,这样延迟也很低,也不用等待。<br />
坏处是编码器压缩率会降低,图像质量没有那么好。</p>
<ol start="5">
<li>累积延迟<br />
除了GOP-Cache,还有一个有关系,就是累积延迟。<br />
服务器可以配置直播队列的长度,服务器会将数据放在直播队列中,<br />
如果超过这个长度就清空到最后一个I帧:</li>
</ol>
<p>当然这个不能配置太小,<br />
譬如GOP是1秒,queue_length是1秒,这样会导致有1秒数据就清空,会导致跳跃。</p>
<p>有更好的方法?有的。<br />
延迟基本上就等于客户端的缓冲区长度,因为延迟大多由于网络带宽低,<br />
服务器缓存后一起发给客户端,现象就是客户端的缓冲区变大了,<br />
譬如NetStream.BufferLength=5秒,那么说明缓冲区中至少有5秒数据。</p>
<p>处理累积延迟的最好方法,是客户端检测到缓冲区有很多数据了,如果可以的话,就重连服务器。<br />
当然如果网络一直不好,那就没有办法了。</p>
</article>
<div class="comments-wrap">
<div class="share-comments">
<script src="https://utteranc.es/client.js"
repo="Apolla/gtalk"
issue-term="title"
theme="github-dark"
crossorigin="anonymous"
id="github-comment"
async>
</script>
</div>
</div><!-- end comments wrap -->
</div>
<div class="column">
<div class="card">
<header class="card-header">
<p class="card-header-title">
<i class="fa fa-commenting" aria-hidden="true"></i>
<span class="tran-notice">Notice</span>
</p>
</header>
<div class="card-content site-notice">
<div class="content">
</div>
</div>
</div>
<div class="card">
<header class="card-header">
<p class="card-header-title">
<i class="fa fa-folder-open" aria-hidden="true"></i>
<span class="tran-site-categories">Categories</span>
</p>
</header>
<div class="card-content site-categories">
<div class="content">
<ul>
<li><a href="%E7%BB%84%E4%BB%B6%E5%8C%96.html">组件化</a>
</li>
<li><a href="%E7%A2%8E%E7%89%87%E8%8A%9D%E5%A3%AB%E6%94%B6%E8%97%8F.html">碎片芝士收藏</a>
</li>
<li><a href="%E7%9B%B4%E6%92%AD.html">直播</a>
</li>
<li><a href="coreBluetooth.html">coreBluetooth</a>
</li>
<li><a href="%E4%B8%80%E9%98%85%E9%98%85%E8%AF%BB.html">一阅阅读</a>
</li>
<li><a href="SwiftUI.html">SwiftUI</a>
</li>
<li><a href="%E8%91%B5%E8%8A%B1%E5%AE%9D%E5%85%B8.html">葵花宝典</a>
</li>
</ul>
</div>
</div>
</div>
<div class="card">
<header class="card-header">
<p class="card-header-title">
<i class="fa fa-tags" aria-hidden="true"></i>
<span class="tran-site-tags">Tags</span>
</p>
</header>
<div class="card-content site-tags">
<div class="content">
<div class="tags">
</div>
</div>
</div>
</div>
</div>
</div><!-- end columns -->
</div><!-- end container -->
</section>
<footer class="footer">
<div id="plt"></div>
<div class="content has-text-centered">
<p>
Copyright © 2019
<span id="tran-author" class="tran-author">Author: </span><a target="_blank" href="http://apolla.cc">宋明</a>,
<span class="tran-theme">Theme: </span><a target="_blank" href="https://github.com/AlanAlbert/atheme">Atheme</a> (Based on BulmaCSS).
</p>
</div>
</footer>
<script type="text/javascript">
var imgApi = "https://source.unsplash.com/random/1024x";
var imgContainers = document.getElementsByClassName('random-img');
for (var i = 0; i <= imgContainers.length - 1; i++) {
// https://picsum.photos/1024/
var img = document.createElement('img');
img.src = imgApi + (400 + i);
imgContainers[i].appendChild(img);
}
</script>
<script type="text/javascript">
var modelJson = "asset/plt/model.json";
var pluginRootPath = 'asset/plt';
var pluginModelPath = 'asset/plt';
var config = {
pluginRootPath: pluginRootPath,
pluginJsPath: "lib/",
pluginModelPath: pluginModelPath,
tagMode:false,
debug:false,
model: {
jsonPath: modelJson, // xxx.model.json 的路径
},
display: {
width: 325, // canvas的宽度
height: 300, // canvas的高度
position: 'right', // 显示位置:左或右
hOffset: -75, // canvas水平偏移
vOffset: 0, // canvas垂直偏移
},
dialog:{
enable: true
},
mobile: {
show: false, // 是否在移动设备上显示
},
react: {
opacity: 1, // 透明度
},
log: false,
};
L2Dwidget.init(config);
</script>
</body>
</html>