最近在研究热力图,发现了一篇可能有用的Python
模拟疫情扩散的文章,可以部分模拟热力图,整篇文章原文内容如下:
年度归档: 2018 年
RTSP回放时如何通过RTP的timestamp计算NPT时间(Normal Play Time)
客户端通过RTSP
的PLAY
方法开始播放、定位播放、快速/慢速播放(Scale
)某非实时视频时,客户端会通过Range
头字段指定NPT
时间,即让服务器开始从NPT
指定时刻开始播放视频(NPT
(Normal Play Time---正常播放时间
)即播放位置离文件开始部分的相对时间)。
播放开始后,下一次发送PLAY
命令前,客户端需要根据服务器发来的RTP timestamp
计算当前收到的帧的NPT
时间。
客户端与服务器同步NPT
时间
客户端可以在每次收到PLAY
响应消息时与服务器同步NPT
时间,响应消息里可带RTP-Info:rtptime
和Range:npt
参数。
客户端发往服务器RTSP
消息例子:
1 2 3 4 5 |
PLAY rtsp://foo.com/test.wav RTSP/1.0 CSeq: 3 Session: 2034820394 Range: npt=30.6-3508 Scale: 2 |
服务器响应消息的例子:
1 2 3 4 5 6 7 |
RTSP/1.0 200 OK CSeq: 3 Session: 2034820394 Range: npt=30.6-3508 Scale: 2 RTP-Info: url=rtsp://foo.com/test.wav/streamid=0; seq=981888;rtptime=3781123 |
其中响应消息中Range:npt
的第一个参数表示客户端紧接着收到的timestamp
为RTP-Info:rtptime
指定的RTP
包时的NPT
时间。
当前NPT
时间计算公式
1 |
current_npt = begin_npt + ((timestamp_len * reset_counter + current_timestamp - start_timestamp) / clock_rate) * scale |
其中各项含义:
begin_npt
:PLAY
返回消息里Range: npt=18.8-3600
中的开始时间(秒)timestamp_len
:RTP timestamp
的最大表示个数,4
个字节,所以是2^32
即0x100000000
reset_counter
:RTP timestamp
的归零次数current_timestamp
: 当前收到的RTP
的timestamp
值start_timestamp
:PLAY
返回消息里的RTP-Info
里的rtptime
(指明此后第一个收到的RTP
包的timestamp
值)clock_rate
: 时钟频率,即SDP a=rtpmap:96 H264/90000
里的90000
scale
:PLAY
里请求和返回中的Scale
值(以返回为准)
NPT
与RTP timestamp
的进一步讨论
RTP
的timestamp
里的wallclock
应该是表示RTP
会话开始到当前的绝对elapsed
时间,与NPT
不是对应的。(比如PAUSE
以后,重新PLAY
时NPT
是影片开始的相对时间,而RTP timestamp
是RTP
会话开始的相对时间)
加速播放时(RTSP scale=2
),在PLAY
返回让npt
与rtptime
映射后,npt
计算时要加倍计算,而rtptime
间隔保持不变。
另外,关于RTP timestamp
与帧率等关系可参考RTP timestamp与帧率及时钟频率的关系。
参考资料
[1] RFC2326 (Appendix B: Interaction with RTP):
For scaling (see Section 12.34), RTP timestamps should correspond to
the playback timing. For example, when playing video recorded at 30
frames/second at a scale of two and speed (Section 12.35) of one, the
server would drop every second frame to maintain and deliver video
packets with the normal timestamp spacing of 3,000 per frame, but NPT
would increase by 1/15 second for each video frame.The client can maintain a correct display of NPT by noting the RTP
timestamp value of the first packet arriving after repositioning. The
sequence parameter of the RTP-Info (Section 12.33) header provides
the first sequence number of the next segment.[2] 3GPP 26.234 (A.3.2.4 Timestamp handling after PAUSE/PLAY requests):
The description below intends to clarify how RTP timestamps are specified within the 3GPP PSS when a client sends a PLAY request following a PAUSE request. The RTP timestamp space must be continuous along time during a session and then reflect the actual time elapsed since the beginning of the session. A server must reflect the actual time interval elapsed between the last RTP packets sent before the reception of the PAUSE request and the first RTP packets sent after the reception of the PLAY request in the RTP timestamp. A client will need to compute the mapping between NPT time and RTP timestamp each time it receives a PLAY response for on-demand content. This means that a client must be able to cope with any gap in RTP timestamps after a PLAY request.
The PLAY request can include a Range header if the client wants to seek backward or forward in the media, or without a Range header if the client only wants to resume the paused session.
Example:
In this example Client C plays a media file from Server S. RTP timestamp rate in this example is 1000Hz for clarity.
C -> S: PLAY rtsp://example.com/mediastream RTSP/1.0
CSeq: 2
Session: 123456
Range: npt=1.125-
S -> C: RTSP/1.0 200 OK
CSeq: 2
Session: 123456
Range: npt=1.120-
RTP-Info: url=rtsp://example.com/mediastream;seq=1000;rtptime=5000
S -> C: RTP packet - seq = 1000 - rtptime = 5000 - corresponding media time (NPT time) = 1120ms
S -> C: RTP packet - seq = 1001 - rtptime = 5040 - corresponding media time (NPT time) = 1160ms
S -> C: RTP packet - seq = 1002 - rtptime = 5080 - corresponding media time (NPT time) = 1200ms
S -> C: RTP packet - seq = 1003 - rtptime = 5120 - corresponding media time (NPT time) = 1240ms
C -> S: PAUSE rtsp://example.com/mediastream RTSP/1.0
CSeq: 3
Session: 123456
S -> C: RTSP/1.0 200 OK
CSeq: 3
Session: 123456
[10 seconds elapsed]
C -> S: PLAY rtsp://example.com/mediastream RTSP/1.0
CSeq: 4
Session: 123456
S -> C: RTSP/1.0 200 OK
CSeq: 4
Session: 123456
Range: npt=1.280-
RTP-Info: url=rtsp://example.com/mediastream;seq=1004;rtptime=15160
S -> C: RTP packet - seq = 1004 - rtptime = 15160 - corresponding media time (NPT time) = 1280ms
S -> C: RTP packet - seq = 1005 - rtptime = 15200 - corresponding media time (NPT time) = 1320ms
S -> C: RTP packet - seq = 1006 - rtptime = 15240 - corresponding media time (NPT time) = 1360ms
C -> S: PAUSE rtsp://example.com/mediastream RTSP/1.0
CSeq: 5
Session: 123456
S -> C: RTSP/1.0 200 OK
CSeq: 5
Session: 123456
C -> S: PLAY rtsp://example.com/mediastream RTSP/1.0
CSeq: 6
Session: 123456
Range: npt=0.5-
[55 milliseconds elapsed during request processing]
S -> C: RTSP/1.0 200 OK
CSeq: 6
Session: 123456
Range: npt=0.480-
RTP-Info: url=rtsp://example.com/mediastream;seq=1007;rtptime=15295
S -> C: RTP packet - seq = 1007 - rtptime = 15295 - corresponding media time (NPT time) = 480ms
S -> C: RTP packet - seq = 1008 - rtptime = 15335 - corresponding media time (NPT time) = 520ms
S -> C: RTP packet - seq = 1009 - rtptime = 15375 - corresponding media time (NPT time) = 560ms
参考链接
RTP时间映射及同步
RTP
包中的时间戳字段是说明数据包时间的同步信息,是数据能以正确的时间顺序恢复的关键。时间戳的值给出了分组中数据的第一个字节的采样时间。为了计算各个数据流的播放时间以及同步处理,仅有RTP
包中的时间戳信息是不够的。
在整个播放过程中,包括这样几种时间:
RTP
包中的rtptime
PLAY
请求的Response
中的rtp time
和npt
RTCP
的SR
(Sender Report
)中的rtp
和ntp
时间戳对
一、时间戳映射关系
首先介绍PLAY
请求的Response
里的两个域:
(1)npt
npt
顾名思义Normal PLay Time
,正常播放时间,指出了流相对与播放开始时的绝对位置。播放开始时的之间定义为0.0s
。这个特殊的常量now
被定义为现场事件的当前时刻。"now
"常数允许客户端请求接收实时反馈而不是存储或者延时的版本。因为对于这种情况而言,既没有绝对时间,也没有0
时间,所以需要该参数。
(2)rtptime
rtptime
是发送PLAY
请求后将收到的第一个RTP
包的时间戳值。
npt
和rtptime
的区别在于npt
是影片开始的相对时间,而rtptime
是会话开始的相对时间。因此在client
端,需要对这两者进行map
处理。
在client
端计算播放时间戳的公式如下:
1 |
nptUs = (current_rtpTime - start_rtptime) / scale + srart_npt |
其中:
start_rtptime
与start_npt
分别是PLAY
请求的Response
中的rtptime
和npt
。
current_rtpTime
是当前收到的RTP
包头中的rtptime
。
scale
为PLAY
请求的Response
中的scale
值。在正常播放的情况下为1
,快速播放时大于1
,当处于反向扫描模式时小于-1
.
二、媒体间同步方法(不同设备的同步)
上面的处理仅仅实现了媒体内的同步,在实现媒体间同步时,还需要进行其他的处理工作。这就需要用到RTCP
的SR
(Sender Report
)。在SR
中包含一个<rtp
,ntp
>时间戳对,通过这个时间戳对可以将音频和视频准确的定位到一个绝对时间轴上。
<rtp
,ntp
>时间戳对的必要性在于不同流的RTP
时间戳有不同的随机偏移量,因此无法直接进行同步。
<rtp
,ntp
>中的ntp
是网络时间协议格式表示的绝对时间值。
<rtp
,ntp
>中的RTP
与数据包中的RTP
时间戳具有相同的单位和偏移量,但在大多数情况下此时间戳不等于任何临近的RTP
包中的时间戳。
根据不同stream
中的<rtp
,ntp
>时间戳对,可以将一个stream
中的时间戳值映射为另一个stream
的时间戳值,从而实现媒体间的同步。
参考链接
ubuntu 14.04.5桌面版与服务器版~/.bashrc,~/.bash_profile的差异
对于ubuntu 14.04.5
服务器版,当前用户目录下存在.bash_profile
的时候,会忽略.bashrc
文件。
对于ubuntu 14.04.5
桌面版,当前用户目录下的.bash_profile
会被忽略。
Ubuntu 17.10将于1月11日“重新”发布,修复“变砖”问题
Ubuntu 17.10
将于1
月11
日“重新”发布,表示不会再让本本变砖~
Canonical
上个月从Ubuntu
的官方网站临时关闭了Ubuntu 17.10
的下载通道,并留下通知:
由于在 某些笔记本电脑(主要为联想)上出现BIOS
固件问题,导致笔记本电脑无法启动,目前不推荐下载Ubuntu 17.10
。待问题解决后,再重新开放。
关闭Safari英文矫正功能
在macOS High Sierra
系统上使用Safari
进行搜索的时候,总是莫名其妙的被修改搜索词,导致搜索结果驴唇不对马嘴。搜索了一下,这个锅应该是输入法导致的,最可恶的是不能拒绝输入法的推荐词汇,可以使用如下方式关闭输入法的自动英文矫正功能。
Ubuntu 14.04.5安装开源跳板机 Jumpserver 开发版(2018.01.08)
参照ubuntu 14.04.5下安装多版本Python(2.7.6/3.4.3/3.6.4),安装配置最新版本的Python 3.6.4
。Jumpserver
需要Python 3.5
以上的版本才能正常运行。
目前我们安装的是2018.01.08
的开发版Jumpserver
,此时的版本信息如下:
1 2 3 4 5 |
commit dfaf029a68f3e3a327a0f22c470306e9bf64aedb Author: ibuler <ibuler@qq.com> Date: Mon Jan 8 15:51:08 2018 +0800 [Bugfix] 资产导入bugfix |
安装流程:
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 |
$ sudo apt-get update $ sudo apt-get upgrade $ pip3 install --upgrade pip # c/_cffi_backend.c:15:17: fatal error: ffi.h: 没有那个文件或目录 $ sudo apt-get install libffi-dev # Modules/LDAPObject.c:17:18: fatal error: sasl.h: 没有那个文件或目录 $ sudo apt-get install libsasl2-dev $ sudo apt-get install slapd ldap-utils # 需要的数据库 $ sudo apt-get install redis-server $ cd ~ $ git clone https://github.com/jumpserver/jumpserver.git $ cd ~/jumpserver $ git checkout dev # 取消可能影响到我们安装路径的环境变量 $ unset PYTHONPATH $ cd requirements && sudo apt-get install -y $(cat deb_requirements.txt) && pip3 install -r requirements.txt $ cd ~/jumpserver $ cp config_example.py config.py $ cd apps && python3 manage.py makemigrations && python3 manage.py migrate $ cd ~/jumpserver # 安装配置coco,coco被配置用来支持远程登陆 $ git clone https://github.com/jumpserver/coco.git $ cd coco $ cd requirements $ pip3 install -r requirements.txt $ cd ~/jumpserver/coco $ cp conf_example.py conf.py $ cd ~/jumpserver $ python3 run_server.py all & #如果提示 “[service ERROR] Access key is not valid”,则需要执行如下操作 #$ rm -rf coco/keys/.access_key $ python3 coco/run_server.py |
如果代码下载失败,可以从本站下载一份代码拷贝。点击这里下载jumpserver,点击这里下载coco
浏览器通过http://127.0.0.1:8080进行访问,默认的用户名密码都是admin
。
上面都启动成功之后,通过如下命令访问jumpserver
1 2 3 |
#$jumpserver_ip为跳板机的访问IP ,$login_user 为跳板机上为登陆用户分配的用户名 $ ssh $jumpserver_ip -p2222 -l $login_user |
ubuntu 14.04.5下安装多版本Python(2.7.6/3.4.3/3.6.4)
系统环境:ubuntu14.04.5 LTS
,系统默认的python
版本为2.7.4/3.4.3
。
但是实际工作中,某些通过pip
安装的开发包需要不低于某个版本的python
才能正常工作,比如ansible-2.4.2.0
,明确只支持python-3.5
以上的版本。在低版本的python
上,无法正常运行。
而如果我们贸然更新系统python
版本的话,会导致系统异常。因此我们借助pyenv
实现基于用户的python
版本定制。
安装pyenv
:
1 2 3 4 5 6 7 8 9 |
$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv $ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bashrc $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bashrc $ echo 'eval "$(pyenv init -)"' >> ~/.bashrc $ exec $SHELL -l |
查看可以安装的python
版本:
1 |
$ pyenv install --list |
这里以安装python-3.6.4
为例,首先安装依赖:
1 |
$ sudo apt-get install -y make build-essential |
安装python
:
1 2 3 4 |
# 要求开启Python动态库的支持(默认是全部静态编译),否则在安装某些插件的时候会出现无法正常链接的情况,比如 mod_wsgi $ export PYTHON_CONFIGURE_OPTS="--enable-shared" $ pyenv install 3.6.4 -vvv |
该命令会从github
上下载python
的源代码,并解压到/tmp
目录下,然后在/tmp
中执行编译工作。若依赖包没有安装,则会出现编译错误,需要在安装依赖包之后重新执行该命令。
安装完成之后,需要使用如下命令对数据库进行更新:
1 |
$ pyenv rehash |
查看当前已经安装的python
版本
1 2 3 |
$ pyenv versions * system (set by /home/xxx/.pyenv/version) 3.6.4 |
其中星号代表是当前系统正在使用的python
版本是系统自带的。
设置全局的python
版本
1 2 3 4 5 |
$ pyenv global 3.6.4 $ pyenv versions system * 3.6.4 (set by /home/xxx/.pyenv/version) |
从上面,我们可以看出来当前的python
版本已经变为了3.6.4
。也可以使用pyenv local
或pyenv shell
临时改变python
的版本。
如果需要还原设定的python
版本为系统自带的版本,则执行如下命令:
1 |
$ pyenv global system |
确认python
版本
1 2 3 4 |
$ python Python 3.6.4 (default, Jan 9 2018, 11:21:57) [GCC 4.8.4] on linux Type "help", "copyright", "credits" or "license" for more information. |
上面的操作会导致在当前用户下,执行python
或者python3
命令的时候都会被定向到python-3.6.4
,如果只想执行python3
命令的时候被定向到python-3.6.4
,则可以直接删除python
这个链接:
1 2 3 |
# 注意,这个链接删除后,可能导致ros indigo的初始化异常,因此,这部分的改动要慎重 $ rm -rf ~/.pyenv/versions/3.6.4/bin/python |
安装pip
:
1 2 3 4 5 6 7 |
$ wget https://bootstrap.pypa.io/get-pip.py $ python3 get-pip.py $ rm -rf get-pip.py $ pip3 install --upgrade pip |
安装完成之后,需要使用如下命令对数据库进行更新:
1 |
$ pyenv rehash |
注意事项:
- 输入
python
即可使用新版的python
- 系统自带的脚本会以
/usr/bin/python
的方式直接调用老版本的python
,因而不会对系统脚本产生影响 - 使用
pip
安装第三方模块时会安装到~/.pyenv/versions/3.6.4
下,不会和系统模块发生冲突 - 使用
pip
安装模块后,可能需要执行pyenv rehash
更新数据库
参考链接
Ubuntu 16.04.3系统VirtualBox-5.0.40使用USB设备
Ubuntu
版本:16.04.3
Oracle VirtualBox
版本:5.0.40
问题:
1 |
USB 2.0 is currently enabled for this virtual machine. However, this requires the Oracle VM VirtualBox Extension Pack to be installed.Please install the Extension Pack from the VirtualBox download site. After this you will be able to re- enable USB 2.0. It will be disabled in the meantime unless you cancel the current settings changes. |
这是在设置启用USB
时提示的错误。关于如何启用Ubuntu
下Oracle VM VirtualBox
的USB
功能 (Oracle VM VirtualBox
-设置
-USB
-启用USB控制器
-启用USB 2.0 ECHI控制器
)--如果你没有安 装Oracle VM VirtualBox Extension Pack
的话,那么这时就会弹出一个提示框,提示上面给出的那段英文提示。
ROS国内镜像
从国外下载ROS
安装包,有时候会非常耗时。国内镜像的地址参考如下:
1 2 |
#中科大源 $ sudo sh -c 'echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list' |