简介
PyAV是FFmpeg库的python绑定。我们的目标是提供底层库的所有功能和控制,但是尽可能多地管理细节。
PyAV用于通过容器、流、包、编解码器和帧直接而精确地访问您的媒体。它公开了该数据的一些转换,并帮助您从其他包(例如Numpy和Pillow)获取数据。
这种能力确实带来了一些责任,因为与媒体打交道非常复杂,PyAV无法将其抽象出来,也无法为您做出所有最好的决定。如果ffmpeg命令在没有您向后弯腰的情况下完成了工作,那么PyAV可能是一个障碍而不是帮助。但是如果没有它就无法工作,PyAV是一个关键的工具。
总而言之:PyAV 是 FFmpeg 的 Python 接口
window or linux 安装
- 第一步: 安装ffmpeg。下载ffmpeg shared,并将其目录下的bin目录添加到环境变量。安装方法:windows | linux
- 第二步:安装PyAV。然后有两种方式安装PyAV:
T2、到GitHub下载PyAV源码,解压后进入其目录执行
python setup.py build --ffmpeg-dir=D:/Program Files/ffmpeg
python setup.py install
注意
其中D:\Program Files\ffmpeg\bin是你的ffmpeg目录,一定要对!
或者
进入setup.py代码文件内,将
FFMPEG_DIR = None
改为
FFMPEG_DIR = 'D://Program Files//ffmpeg'
arm 安装
- 第一步:ffmpeg安装同上面的linux
- 第二步:装PyAV。然后有两种方式安装PyAV:
T2、到GitHub下载PyAV源码,解压后进入其目录执行
sudo apt-get install -y python-dev python-virtualenv pkg-config
sudo sudo apt-get install -y libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libavresample-dev
pip3 install Cython
python3 setup.py build --ffmpeg-dir=/usr/local/ffmpeg
python3 setup.py install
安装错误
- ModuleNotFoundError: No module named ‘av._core’ 解决方法
- PyAV安装:段错误或者could not find libavdevice with pkg-config 解决办法
代码错误
- max delay reached. need to consume packet 解决办法
- Invalid NAL unit 17, skipping.
时间戳说明
ffmpeg中常用的几个时间戳:
- rtcp_ntp_timestamp: 真实时间, 绝对时间,在网络传输时的时间基(1 << 32),
- rtcp_timestamp: rtcp时间,一般会有一个base, 在网络传输时的时间基90000
- rtp_timestamp: rtp时间,和rtcp_timestamp类似,网络时间基90000
- Avpacket->pts: 通过如上计算得到,video一般是以90000为基
- timebase:通常为1/90000,表示时间戳的单位为1/90k秒
RTP和NTP
RTP : 相对时间,Real-time Transport Protocol(实时传输协议),RTP用来为IP网上的语音、图像、传真等多种需要实时传输的多媒体数据提供端到端的实时传输服务。RTP为Internet上端到端的实时传输提供时间信息和流同步,但并不保证服务质量,服务质量由RTCP来提供。
NTP:绝对时间,网络时间协议(Network Time Protocol),它是用来同步网络中各个计算机的时间的协议。NTP时间戳是从1900年1月1日00:00:00以来经过的秒数.
首先明确:NTP时间戳有64位,其中32位表示second,32位表示 fraction second(就是秒后面的单位)表示的秒数起点为 0h UTC on 1 January 1900 (不同于Unix时间的起始于1970),fraction的单位为2^32 second
relation:rtp时间戳和ntp时间戳表示的意义是相同的. 可以互相转换(但未找到关系),rtp=f(ntp) 类似中文名张三,英文名zhangjohn.
summary:ntp,rtp,pts表示的是同一帧的时间.ntp是绝对时间,rtp是相对时间,pts是播放时间.rtp是用频率表示,pts是用秒表示.
PTS和DTS
PTS:Presentation Time Stamp。PTS主要用于度量解码后的视频帧什么时候被显示出来
DTS:Decode Time Stamp。DTS主要是标识读入内存中的bit流在什么时候开始送入解码器中进行解码
PTS和RTP的关系
timebase往往取的1/90000
pts= rtp 时间戳 *timebase
每秒=pts*time_base
获取RTSP的各种时间戳(TCP)
如果用作视频流同步,则少不了对于时间戳的获取和同步,这里介绍了通过av和ntplib来获取我们的NTP_time、RTP_time、PTS_time、DTS_time,分别是网络时间协议(同步网络中各个计算机的时间的协议)
import av,cv2
import av.datasets
import datetime
import ntplib #这里的ntp不是海康设备的
if __name__ == '__main__':
# rtp是相对时间,ntp是绝对时间
# container = av.open('F:/epycharm/engineer/data/video/1.avi')
url='rtsp://admin:a12345678@10.16.55.149:554/h264/ch1/main/av_stream'
options = {
"rtsp_transport": "tcp",
# "buffer_size": "1024000",
}
# ****************************************************************
# url:表示海康摄像头的地址
# options:rtsp_transport表示采用什么传输方式,buffer_size表示缓冲大小
# timeout:timeout=(10, 24)限制时间
# ****************************************************************
container = av.open(url,'r',options=options)
print("format:" , container.dumps_format())
# Signal that we only want to look at keyframes.
stream = container.streams.video[0]
stream.codec_context.skip_frame = 'NONKEY'
for frame in container.decode(stream):
client = ntplib.NTPClient()
global response
try:
response = client.request('ntp.api.bz')
except:
pass
ntp_time = datetime.datetime.fromtimestamp(response.tx_time)
dt_ms = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S.%f') # 含微秒的日期时间,来源 比特量化
# ****************************************************************
# 根据pts来计算一桢在整个视频中的时间位置:
# 时间戳 = pts * (AVRational.num/AVRational.den) ,这里的pts是相对pts = 绝对PTS - 首帧PTS
# timestamp(秒) = pts * av_q2d(st->time_base)
# timestamp(毫秒) = pts * av_q2d(st->time_base) * 1000
# pts= rtp 时间戳 *timebase
# ****************************************************************
second=frame.pts*frame.time_base
rtp_time = frame.pts / frame.time_base
print('ntp_time:{} pc_time:{} rtp_time:{} pts_time:{} dts_time:{}'.format(ntp_time,dt_ms,rtp_time,float(frame.pts),float(frame.dts)))
# 我们使用frame.pts作为frame.Index '对' skip_frame '没有意义。
# frame.to_image().save(
# 'night-sky.{:04d}.jpg'.format(frame.pts),
# quality=80,
# )
img = frame.to_ndarray(format='bgr24')
img = cv2.resize(img,(668,668))
cv2.imshow("Test", img)
cv2.waitKey(1)