python操作ffmpeg对摄像头rtsp流进行自动转码-
- 格式:docx
- 大小:2.37 MB
- 文档页数:6
1、 背景
最近公司有个项目,需要将几个景点的监控摄像头在安卓机顶盒和avb中间件机顶盒上做网络直播播放,如果不通过设备中继,让机顶盒和摄像头直接交互,存在如下几个问题:
(1) 景点摄像头均是景点自建,地址和机顶盒地址不互通,打通路由较为麻烦。
(2) 安卓机顶盒和dvb机顶盒均无法直接播放网络摄像头的rtsp流。
(3) 机顶盒和摄像头直接数据交互对机顶盒城域网安全存在一定的威胁。
综合考虑以上问题,想到用中间服务器配置开源ffmpeg来解决这个问题,其中服务器即能ping通景点硬盘录像机,也能ping通机顶盒地址。
2、 项目流程
项目整体流程如下:
图1 项目流程图
首先提前将摄像头rtsp流信息录入数据库,然后python读数据库取出所有的流地址信息,包括位置、ip地址、rtsp地址等,然后遍历每一条信息,判断服务器能否ping通摄像头地址,如果不通就继续遍历,如果通就去执行转码操作,依次直至遍历完所有摄像头。 3、 具体实施
(1)运行环境
操作系统:CentOS Linux release 7.7.1908
Python:Python 3.6.8
Mysql:Server version: 10.4.6-MariaDB
Ffmpeg:ffmpeg-3.3.3
(2)ffmpeg简介
FFmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec,具有非常好的高可移植性和编解码质量等特点。
Ffmpeg功能非常强大,可以对视频或直播流进行转码、剪切、合并、播放速调整等,可以输出单播、组播,当前很多商业推流软件、播放软件都是基于ffmpeg开发的,具体参考/。
(3)python操作数据库
数据库表主要有三个字段,如下图:
图2 数据库字段图
其中,FName是监控位置字段,表示监控摄像头的具体位置,FAddr是摄像头的ip地址,FSsrcURL是摄像头的rtsp流地址。
读数据库代码如下:
1. import pymysql
2. def conn_mysql():
3. conn=pymysql.connect(host='172.17.1.11',user='emspapp',password='emspapp',db='easydms')
4. cursor=conn.cursor()
5. sql='select FName,FAddr,FSsrcURL from c4sm_ssrc' 6. cursor.execute(sql)
7. results=cursor.fetchall()
8. conn.close()
9. return results
返回的results 是一个包含多个监控点元组信息的大元组,每个小元组格式如下:
('景点1', '192.168.1.10', 'rtsp://admin:admin@192.168.1.10:554/cam/realmonitor?channel=1&subtype=1')
(4)python遍历元组,并执行转码
已经获取到数据库里的监控信息,下一步需要遍历信息,先检查地址是否ping通,如下:
1. def check_ip(ipaddr):
2. command='ping -s 1000 -c 3 '+ipaddr
3. a,b=subprocess.getstatusoutput(command)
4. if '100% packet loss' in b:
5. return False
6. else:
7. return True
如果地址是通的,则把通的地址以ip地址作为键,rtsp地址作为值存在字典中,如下:
1. ipaddress={}
2. for row in conn_mysql():
3. ipaddr=row[1]
4. rtspaddr=row[2]
5. if check_ip(ipaddr):
6. ipaddress[ipaddr]=rtspaddr
7.
else:
8. print(ipaddr+"不通")
下面遍历字典,利用多线程执行转码,如下:
1. threads=[]
2. for ip in ipaddress.items():
3. t=threading.Thread(target=transcode,args=(ip[0],ip[1]))
4. threads.append(t)
5. for t in threads:
6. t.setDaemon(True) 7. t.start()
8. def transcode(ipaddr,rtspaddr):
9. if check_dir(ipaddr)==False:
10. mkdircmd='mkdir '+ipaddr
11. subprocess.getstatusoutput(mkdircmd)
12. command='nohup ffmpeg -re -rtsp_transport tcp -i '+rtspaddr+' -codec:v copy -codec:a aac -f hls -hls_list_size 6 -hls_wrap 10 -hls_time 5 '+ipaddr+'/live.m3u8&'
13. code,message=subprocess.getstatusoutput(command)
14. if code==0:
15. print(ipaddr+"开启转码成功")
其中ffmpeg命令参数解释如下:
-re:按视频帧率的速度读取输入
-rtsp_transport:传输协议
-i:输入源
-codec:v :视频编码,copy表示用默认编码
-codec:a :音频编码
-f: 指定输出流封装格式
-hls_list_size:HLS播放的列表
-hls_wrap:最大的TS循环数,也就是每10个一个循环
live.m3u8指的切片的索引文件
下面在服务器上执行转码脚本,如下:
1. chmod +x transcode.py
2. nohup python transcode.py &
执行效果如下:
图3 执行脚本
图4 转码进程已启动
图5 ip目录已生成
图6 摄像头切片已生成
然后在服务器上部署web服务,在web根目录下创建软连接指向切片目录所在的目录,然后用vlc去拉流,如下:
图7 拉流效果
既然在服务器上转码已完成,那么下一步就可以通过H5在机顶盒上去播放地址串,项目完成。
4、 总结
本文通过利用python操控ffmpeg对监控摄像头进行批量转码,虽然解决了机顶盒无法直接播放rtsp等问题,但也存在一定的问题,首先ffmpeg一直对摄像头转码,也即无论机顶盒端看或不看,转码一直在进行,浪费网络带宽,同时耗费服务器资源,理想状态是当机顶盒端点播播放时才进行转码;其次,脚本虽然对摄像头地址通不通进行了判断,但不灵活,无法及时检测到通后立马去执行转码,而且对转码进程没有监听,一旦断开,无法及时从新执行,当然,这个问题可以通过后期去完善脚本;最后,当数据库里摄像头数量比较多时,执行转码耗费时间比较长,其中判断摄像头通不通耗费的最长,这一点可以通过多线程去解决。