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一直对摄像头转码,也即无论机顶盒端看或不看,转码一直在进行,浪费网络带宽,同时耗费服务器资源,理想状态是当机顶盒端点播播放时才进行转码;其次,脚本虽然对摄像头地址通不通进行了判断,但不灵活,无法及时检测到通后立马去执行转码,而且对转码进程没有监听,一旦断开,无法及时从新执行,当然,这个问题可以通过后期去完善脚本;最后,当数据库里摄像头数量比较多时,执行转码耗费时间比较长,其中判断摄像头通不通耗费的最长,这一点可以通过多线程去解决。