更新配置

This commit is contained in:
chenyukun 2023-01-16 16:44:30 +08:00
parent a64819b66f
commit ec12171542
34 changed files with 1105 additions and 0 deletions

25
airport_application.yml Normal file
View File

@ -0,0 +1,25 @@
video:
pullUrl: "rtsp://127.0.0.1:8554/video"
pushUrl: ["rtmp://192.168.10.101:19350/rlive/stream_9?sign=f8a15b6n"]
# 日志设置
log:
# 是否开启文件输出 True开启 False关闭
enable_file_log: True
# 是否开启控制台日志输出 True开启 False关闭
enable_stderr: True
# 日志打印文件夹
base_path: ./logs/
# 日志文件名称
log_name: airport.log
# 日志打印格式
log_fmt: "{time:YYYY-MM-DD HH:mm:ss.SSS} [{level}][{process.name}-{process.id}-{thread.name}-{thread.id}][{line}] {module}-{function} - {message}"
# 日志隔离级别
level: INFO
# 日志每天0点创建新文件
rotation: 00:00
# 日志保存时间1天
retention: 1 days
# 线程安全
enqueue: True
# 编码格式
encoding: utf8

11
airport_master.py Normal file
View File

@ -0,0 +1,11 @@
# -*- coding: utf-8 -*-
from alg_airport_ffmpeg.service.PushStreamService import PushStreamService
"""
airport主程序入口
"""
if __name__ == '__main__':
print("(♥◠‿◠)ノ゙ AIRPORT【推流服务】开始启动 ლ(´ڡ`ლ)゙")
PushStreamService().start_service()

20
common/Constant.py Normal file
View File

@ -0,0 +1,20 @@
from enum import Enum, unique
# 常量枚举
@unique
class ConstantEnum(Enum):
APPLICATION_CONFIG = ("airport_application.yml", "配置文件名称")
UTF_8 = ("utf-8", "utf-8")
R = ("r", "可读")
START_LOG = ("""
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
""", "启动服务LOG")

0
common/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,22 @@
import time
from threading import Thread
from loguru import logger
class Common(Thread):
def __init__(self, timeout, func, args=()):
super(Common, self).__init__()
self.__timeout = timeout
self.__func = func
self.__args = args
self.__result = None
def get_result(self):
self.join(self.__timeout)
return self.__result
def run(self):
# logger.info("开始执行线程!")
self.__result = self.__func(self.__args)
# logger.info("线程停止完成!")

0
concurrency/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

13
enums/ExceptionEnum.py Normal file
View File

@ -0,0 +1,13 @@
from enum import Enum, unique
# 异常枚举
@unique
class ExceptionType(Enum):
PULL_STREAM_URL_EXCEPTION = ("AP000", "拉流地址不能为空!")
PUSH_STREAM_URL_EXCEPTION = ("AP001", "推流地址不能为空!")
SERVICE_INNER_EXCEPTION = ("AP999", "系统内部异常, 请联系工程师定位处理!")

0
enums/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from loguru import logger
"""
自定义异常
"""
class ServiceException(Exception):
def __init__(self, code, msg):
self.code = code
self.msg = msg
def __str__(self):
logger.error("异常编码:{}, 异常描述:{}", self.code, self.msg)

0
exception/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

203
logs/airport.log Normal file
View File

@ -0,0 +1,203 @@
2023-01-13 13:12:40.886 [INFO][MainProcess-10664-MainThread-19964][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 13:12:41.894 [INFO][MainProcess-10664-MainThread-19964][38] PushStreamService-start_service - 开始重新获取视频信息: 0次
2023-01-13 13:12:49.945 [INFO][MainProcess-10664-MainThread-19964][38] PushStreamService-start_service - 开始重新获取视频信息: 1次
2023-01-13 13:12:57.999 [INFO][MainProcess-10664-MainThread-19964][38] PushStreamService-start_service - 开始重新获取视频信息: 2次
2023-01-13 15:43:43.762 [INFO][MainProcess-11488-MainThread-5440][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:43:44.777 [INFO][MainProcess-11488-MainThread-5440][38] PushStreamService-start_service - 开始重新获取视频信息: 0次
2023-01-13 15:43:46.158 [INFO][MainProcess-11488-MainThread-5440][81] Cv2Utils-get_video_info - 视频信息, width:1920|height:1080|fps:25
2023-01-13 15:44:00.788 [INFO][MainProcess-11488-MainThread-5440][224] Cv2Utils-read - 关闭拉流管道完成!
2023-01-13 15:45:16.962 [INFO][MainProcess-716-MainThread-1284][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:45:20.152 [ERROR][MainProcess-716-MainThread-1284][66] PushStreamService-start_service - 推流异常: 'int' object has no attribute 'start_push_stream'
2023-01-13 15:45:22.158 [ERROR][MainProcess-716-MainThread-1284][66] PushStreamService-start_service - 推流异常: 'int' object has no attribute 'start_push_stream'
2023-01-13 15:45:24.148 [ERROR][MainProcess-716-MainThread-1284][66] PushStreamService-start_service - 推流异常: 'int' object has no attribute 'start_push_stream'
2023-01-13 15:45:26.148 [ERROR][MainProcess-716-MainThread-1284][66] PushStreamService-start_service - 推流异常: 'int' object has no attribute 'start_push_stream'
2023-01-13 15:45:28.152 [ERROR][MainProcess-716-MainThread-1284][66] PushStreamService-start_service - 推流异常: 'int' object has no attribute 'start_push_stream'
2023-01-13 15:46:51.659 [INFO][MainProcess-28372-MainThread-8996][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:47:24.687 [INFO][MainProcess-18692-MainThread-32432][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:49:25.276 [INFO][MainProcess-28924-MainThread-3700][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:49:58.770 [INFO][MainProcess-17768-MainThread-33684][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:51:11.366 [INFO][MainProcess-26664-MainThread-22888][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:53:22.401 [INFO][MainProcess-20940-MainThread-32656][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:56:59.924 [INFO][MainProcess-11316-MainThread-10624][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 15:58:51.358 [INFO][MainProcess-12808-MainThread-30060][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 16:00:13.184 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:00:20.227 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:00:27.282 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:00:34.330 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:00:41.379 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:00:48.426 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:00:55.477 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:04:23.859 [ERROR][MainProcess-12808-MainThread-30060][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:07:51.939 [INFO][MainProcess-11556-MainThread-10732][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 16:07:58.992 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:08:06.046 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:08:13.100 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:08:35.323 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:08:42.366 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:08:49.417 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:08:56.464 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:09:54.054 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:01.103 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:08.159 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:15.207 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:22.259 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:29.304 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:36.349 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:43.406 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:50.448 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:10:57.489 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:04.534 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:11.586 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:18.630 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:25.679 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:32.727 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:39.772 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:46.822 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:11:53.870 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:00.915 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:07.973 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:15.023 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:22.065 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:29.120 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:36.174 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:43.226 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:50.270 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:12:57.321 [ERROR][MainProcess-11556-MainThread-10732][67] PushStreamService-start_service - 推流异常: Command '['ffprobe', '-show_format', '-show_streams', '-of', 'json', 'rtsp://127.0.0.1:8554/video']' timed out after 7 seconds
2023-01-13 16:13:04.146 [INFO][MainProcess-21980-MainThread-21248][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 16:13:11.200 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 0次
2023-01-13 16:13:19.269 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 1次
2023-01-13 16:13:27.331 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 2次
2023-01-13 16:13:35.365 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 3次
2023-01-13 16:13:43.424 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 4次
2023-01-13 16:13:51.475 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 5次
2023-01-13 16:13:59.527 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 6次
2023-01-13 16:14:07.583 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 7次
2023-01-13 16:14:15.629 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 8次
2023-01-13 16:14:23.684 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 9次
2023-01-13 16:14:31.743 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 10次
2023-01-13 16:14:39.801 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 11次
2023-01-13 16:14:47.855 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 12次
2023-01-13 16:14:55.915 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 13次
2023-01-13 16:15:03.975 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 14次
2023-01-13 16:15:12.030 [INFO][MainProcess-21980-MainThread-21248][39] PushStreamService-start_service - 开始重新获取视频信息: 15次
2023-01-13 16:15:18.469 [INFO][MainProcess-32128-MainThread-26468][27] PushStreamService-start_service -
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
2023-01-13 16:15:56.603 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 0次
2023-01-13 16:16:04.664 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 1次
2023-01-13 16:16:12.728 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 2次
2023-01-13 16:16:20.796 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 3次
2023-01-13 16:16:28.850 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 4次
2023-01-13 16:16:36.923 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 5次
2023-01-13 16:16:44.991 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 6次
2023-01-13 16:16:53.052 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 7次
2023-01-13 16:17:01.101 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 8次
2023-01-13 16:17:09.159 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 9次
2023-01-13 16:17:17.190 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 10次
2023-01-13 16:17:25.240 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 11次
2023-01-13 16:17:33.306 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 12次
2023-01-13 16:17:41.361 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 13次
2023-01-13 16:17:49.413 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 14次
2023-01-13 16:17:57.463 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 15次
2023-01-13 16:18:05.510 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 16次
2023-01-13 16:18:13.558 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 17次
2023-01-13 16:18:21.609 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 18次
2023-01-13 16:21:03.797 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 19次
2023-01-13 16:21:11.858 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 20次
2023-01-13 16:21:19.916 [INFO][MainProcess-32128-MainThread-26468][39] PushStreamService-start_service - 开始重新获取视频信息: 21次

View File

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
import time
from alg_airport_ffmpeg.common.Constant import ConstantEnum
from alg_airport_ffmpeg.exception.CustomerException import ServiceException
from alg_airport_ffmpeg.util import YmlUtils, LogUtils
from loguru import logger
from alg_airport_ffmpeg.util.Cv2Utils import Cv2Util
'''
推流服务
'''
class PushStreamService:
# 初始化
def __init__(self):
# 获取airport环境所需要的配置
self.__content = YmlUtils.get_configs()
# 初始化日志
LogUtils.init_log(self.__content)
# 服务调用启动方法
def start_service(self):
logger.info(ConstantEnum.START_LOG.value[0])
# 循环消息处理
pull_url = self.__content["video"]["pullUrl"]
pushUrl = self.__content["video"]["pushUrl"]
cv2_tool = Cv2Util(pull_url, pushUrl)
cv2_init_num = 0
while True:
try:
time1 = time.time()
#################################拉流推流一体###################################
# 1检查拉流通道是否有流没有流7秒后重试
if not cv2_tool.is_video_stream(pull_url):
logger.info("开始重新获取视频信息: {}", cv2_init_num)
time.sleep(1)
cv2_init_num += 1
cv2_tool.close_push_stream()
continue
cv2_init_num = 0
# 2. 推流存在跳过,不存在初始化推流
cv2_tool.start_push_stream()
# 3. 判断推流通道是否有流,进程是否存在
if cv2_tool.is_push_stream_ok():
cv2_tool.close_push_stream()
#################################先拉流再推流###################################
# if cv2_tool.check_config():
# time.sleep(1)
# logger.info("开始重新获取视频信息: {}次", cv2_init_num)
# cv2_init_num += 1
# # cv2_tool.build_cv2() # 方式1 cv2
# cv2_tool.get_video_info() # 方式2 ffmpeg
# continue
# cv2_init_num = 0
# # frame = cv2_tool.cv2_read() # 方式1 cv2
# frame = cv2_tool.read() # 方式2 ffmpeg
# if frame is None:
# continue
# cv2_tool.push_stream_write(frame)
# print(time.time()- time1)
except ServiceException as s:
logger.error("推流异常: {}", s.msg)
except Exception as e:
logger.error("推流异常: {}", e)
cv2_tool.close()

0
service/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

249
test/ffmpeg_test.py Normal file
View File

@ -0,0 +1,249 @@
# -*- coding: utf-8 -*-
import time
import cv2
import subprocess as sp
import ffmpeg
import numpy as np
from loguru import logger
'''
获取视频信息
'''
def get_video_info(pullUrl):
try:
probe = ffmpeg.probe(pullUrl)
if probe is None or probe.get("streams") is None:
return
# 视频大小
# format = probe['format']
# size = int(format['size'])/1024/1024
video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None)
if video_stream is None:
logger.error("根据拉流地址未获取到视频流")
return
width = video_stream.get('width')
height = video_stream.get('height')
nb_frames = video_stream.get('nb_frames')
fps = video_stream.get('r_frame_rate')
# duration = video_stream.get('duration')
bit_rate = video_stream.get('bit_rate')
if width:
width = int(width)
if height:
height = int(height)
if nb_frames:
all_frames = int(nb_frames)
if fps:
up, down = str(fps).split('/')
fps = int(eval(up) / eval(down))
# if duration:
# self.duration = float(video_stream['duration'])
if bit_rate:
bit_rate = int(bit_rate) / 1000
logger.info("视频信息, width:{}|height:{}|fps:{}|all_frames:{}|bit_rate:{}", width,
height, fps, all_frames, bit_rate)
except ffmpeg._run.Error as er:
logger.error("获取视频信息异常: {}", er.stderr.decode(encoding='utf-8'))
except Exception as e:
logger.exception("获取视频信息异常:{}", e)
'''
拉取视频
'''
def build_pull_p(wh, pullUrl):
try:
command = [r'E:\liumeiti\ffmpeg\ffmpeg-master-latest-win64-gpl\bin\ffmpeg',
'-re',
'-y',
'-c:v', 'h264_cuvid',
'-resize', wh,
'-i', pullUrl,
'-f', 'rawvideo',
'-an',
'-']
return sp.Popen(command, stdout=sp.PIPE)
except Exception as e:
logger.exception("构建拉流管道异常:{}", e)
return None
def read(whr, whrz, pullUrl, h, w):
result = None
try:
in_bytes = build_pull_p(whrz, pullUrl).stdout.read(whr)
if in_bytes is not None and len(in_bytes) > 0:
# result = (np.frombuffer(in_bytes, np.uint8).reshape([int(self.height), int(self.width), 3]))
try:
img = (np.frombuffer(in_bytes, np.uint8)).reshape((h, w))
except Exception as ei:
logger.exception("视频格式异常:{}", ei)
result = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12)
except Exception as e:
logger.exception("读流异常:{}", e)
return result
def close(self):
if self.pull_p:
if self.pull_p.stdout:
self.pull_p.stdout.close()
self.pull_p.terminate()
self.pull_p.wait()
logger.info("关闭拉流管道完成, requestId:{}", self.requestId)
if self.p:
if self.p.stdin:
self.p.stdin.close()
self.p.terminate()
self.p.wait()
# self.p.communicate()
# self.p.kill()
logger.info("关闭管道完成, requestId:{}", self.requestId)
if self.or_video_file:
self.or_video_file.release()
logger.info("关闭原视频写入流完成, requestId:{}", self.requestId)
if self.ai_video_file:
self.ai_video_file.release()
logger.info("关闭AI视频写入流完成, requestId:{}", self.requestId)
# async def push_stream_write(self, frame):
# self.p.stdin.write(frame.tostring())
#
# async def push_stream(self, frame):
# if self.p is None:
# self.build_p()
# try:
# await self.push_stream_write(frame)
# return True
# except Exception as ex:
# logger.exception("推流进管道异常:{}, requestId: {}", ex, self.requestId)
# current_retry_num = 0
# while True:
# try:
# time.sleep(1)
# self.p_push_retry_num += 1
# current_retry_num += 1
# if current_retry_num > 3 or self.p_push_retry_num > 600:
# return False
# self.build_p()
# await self.push_stream_write(frame)
# logger.info("构建p管道重试成功, 当前重试次数: {}, requestId: {}", current_retry_num,
# self.requestId)
# return True
# except Exception as e:
# logger.exception("构建p管道异常{}, 开始重试, 当前重试次数:{}, requestId: {}", e,
# current_retry_num, self.requestId)
# return False
# async def video_frame_write(self, or_frame, ai_frame):
# if or_frame is not None:
# self.or_video_file.write(or_frame)
# if ai_frame is not None:
# self.ai_video_file.write(ai_frame)
# async def video_write(self, or_frame, ai_frame):
# try:
# self.build_write()
# if or_frame is not None and len(or_frame) > 0:
# await self.video_frame_write(or_frame, None)
# if ai_frame is not None and len(ai_frame) > 0:
# await self.video_frame_write(None, ai_frame)
# return True
# except Exception as ex:
# ai_retry_num = 0
# while True:
# try:
# ai_retry_num += 1
# if ai_retry_num > 3:
# logger.exception("重新写入离线分析后视频到本地,重试失败:{}, requestId: {}", e, self.requestId)
# return False
# if or_frame is not None and len(or_frame) > 0:
# await self.or_video_file.write(or_frame)
# if ai_frame is not None and len(ai_frame) > 0:
# await self.ai_video_file.write(ai_frame)
# logger.info("重新写入离线分析后视频到本地, 当前重试次数: {}, requestId: {}", ai_retry_num,
# self.requestId)
# return True
# except Exception as e:
# logger.exception("重新写入离线分析后视频到本地:{}, 开始重试, 当前重试次数:{}, requestId: {}", e,
# ai_retry_num, self.requestId)
# def build_write(self):
# try:
# if self.fps is None or self.width is None or self.height is None:
# raise ServiceException(ExceptionType.VIDEO_CONFIG_EXCEPTION.value[0],
# ExceptionType.VIDEO_CONFIG_EXCEPTION.value[1])
# if self.orFilePath is not None and self.or_video_file is None:
# self.or_video_file = cv2.VideoWriter(self.orFilePath, cv2.VideoWriter_fourcc(*'mp4v'), self.fps,
# (int(self.wn), int(self.hn)))
# if self.or_video_file is None:
# raise ServiceException(ExceptionType.OR_WRITE_OBJECT_EXCEPTION.value[0],
# ExceptionType.OR_WRITE_OBJECT_EXCEPTION.value[1])
# if self.aiFilePath is not None and self.ai_video_file is None:
# self.ai_video_file = cv2.VideoWriter(self.aiFilePath, cv2.VideoWriter_fourcc(*'mp4v'), self.fps,
# (int(self.width), int(self.hn)))
# if self.ai_video_file is None:
# raise ServiceException(ExceptionType.AI_WRITE_OBJECT_EXCEPTION.value[0],
# ExceptionType.AI_WRITE_OBJECT_EXCEPTION.value[1])
# except ServiceException as s:
# logger.exception("构建文件写对象异常: {}, requestId:{}", s, self.requestId)
# raise s
# except Exception as e:
# logger.exception("构建文件写对象异常: {}, requestId:{}", e, self.requestId)
# raise e
# def video_merge(self, frame1, frame2):
# # frameLeft = cv2.resize(frame1, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR)
# # frameRight = cv2.resize(frame2, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR)
# # frame_merge = np.hstack((frameLeft, frameRight))
# frame_merge = np.hstack((frame1, frame2))
# return frame_merge
#
# def getP(self):
# if self.p is None:
# logger.error("获取管道为空, requestId:{}", self.requestId)
# raise ServiceException(ExceptionType.PULL_PIPELINE_INIT_EXCEPTION.value[0],
# ExceptionType.PULL_PIPELINE_INIT_EXCEPTION.value[1])
# return self.p
#
# def getCap(self):
# if self.cap is None:
# logger.error("获取cv2为空, requestId:{}", self.requestId)
# raise ServiceException(ExceptionType.CV2_IS_NULL_EXCEPTION.value[0],
# ExceptionType.CV2_IS_NULL_EXCEPTION.value[1])
# return self.cap
#
# def getOrVideoFile(self):
# if self.or_video_file is None:
# logger.error("获取原视频写入对象为空, requestId:{}", self.requestId)
# raise ServiceException(ExceptionType.OR_WRITE_OBJECT_EXCEPTION.value[0],
# ExceptionType.OR_WRITE_OBJECT_EXCEPTION.value[1])
# return self.or_video_file
#
# def getAiVideoFile(self):
# if self.ai_video_file is None:
# logger.error("获取AI视频写入对象为空, requestId:{}", self.requestId)
# raise ServiceException(ExceptionType.AI_WRITE_OBJECT_EXCEPTION.value[0],
# ExceptionType.AI_WRITE_OBJECT_EXCEPTION.value[1])
# return self.ai_video_file
if __name__== "__main__":
command = ['ffmpeg',
'-rtsp_transport', 'tcp',
'-i', 'rtsp://127.0.0.1:8554/video', # 指定输入文件
'-c', 'copy',
'-f', 'flv',
"rtmp://192.168.10.101:19350/rlive/stream_9?sign=f8a15b6n"]
p = sp.Popen(command, shell=False)
while True:
time.sleep(2)
print("pid", p.pid)
print("poll", p.poll())
print("returncode", p.returncode)
# p.terminate()
# p.wait()

10
test/strtest.py Normal file
View File

@ -0,0 +1,10 @@
print("""
_ ___ ____ ____ ___ ____ _____
/ \ |_ _| _ \| _ \ / _ \| _ \_ _|
/ _ \ | || |_) | |_) | | | | |_) || |
/ ___ \ | || _ <| __/| |_| | _ < | |
/_/ \_\___|_| \_\_| \___/|_| \_\|_|
:: AIRPORT SERVICE :: (1.0.0.RELEASE)
""")

394
util/Cv2Utils.py Normal file
View File

@ -0,0 +1,394 @@
# -*- coding: utf-8 -*-
import json
import subprocess as sp
import time
import cv2
import numpy as np
from loguru import logger
from alg_airport_ffmpeg.enums.ExceptionEnum import ExceptionType
from alg_airport_ffmpeg.exception.CustomerException import ServiceException
from alg_airport_ffmpeg.concurrency.CommonThread import Common
"""
推流工具
"""
class Cv2Util:
def __init__(self, pullUrl=None, pushUrl=None):
self.__pullUrl = pullUrl
self.__pushUrl = pushUrl
self.__push_stream = None
self.__pull_stream = None
self.__width = None
self.__height = None
self.__wh = None
self.__fps = None
self.__cap = None
def probe(self):
p = None
try:
args = ['ffprobe', '-show_format', '-show_streams', '-of', 'json', self.__pullUrl]
p = sp.Popen(args, stdout=sp.PIPE, stderr=sp.PIPE, close_fds=True)
out, err = p.communicate(timeout=7)
if p.returncode != 0:
# logger.error("获取视频信息异常: {}", err.stderr.decode(encoding='utf-8'))
return None
return json.loads(out.decode('utf-8'))
except Exception as e:
# logger.error("获取视频信息异常: {}", e)
return None
finally:
if p:
# if p.stdout:
# p.stdout.flush()
# p.stdout.close()
# if p.stderr:
# p.stderr.close()
p.terminate()
# parent_proc = psutil.Process(p.pid)
# for child_proc in parent_proc.children(recursive=True):
# child_proc.kill()
# parent_proc.kill()
# p.kill()
p.wait()
# logger.info("关闭获取视频管道完成!")
# 获取视频信息
def get_video_info(self):
try:
if self.__pullUrl is None or len(self.__pullUrl) == 0:
raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0],
ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1])
probe = self.probe()
if probe is None or probe.get("streams") is None:
return
video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None)
if video_stream is None:
return
width = video_stream.get('width')
height = video_stream.get('height')
fps = video_stream.get('r_frame_rate')
self.__width = int(width)
self.__height = int(height)
self.__wh = int(width * height * 3)
up, down = str(fps).split('/')
self.__fps = int(eval(up) / eval(down))
logger.info("视频信息, width:{}|height:{}|fps:{}", self.__width, self.__height, self.__fps)
except ServiceException as s:
# logger.error("获取视频信息异常: {}", s.msg)
raise s
except Exception as e:
# logger.error("获取视频信息异常:{}", e)
raise e
def build_cap(self, args):
try:
pullUrl = args[0]
return cv2.VideoCapture(pullUrl)
except Exception as e:
logger.error("初始化cap异常: {}", e)
return None
# 构建 cv2
def build_cv2(self):
try:
if self.__cap is not None:
# logger.info("重试, 关闭cap")
self.__cap.release()
self.__cap = None
self.__fps = None
self.__width = None
self.__height = None
if self.__pullUrl is None or len(self.__pullUrl) == 0:
raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0],
ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1])
cap_thread = Common(timeout=7, func=self.build_cap, args=(self.__pullUrl,))
cap_thread.setDaemon(True)
cap_thread.start()
self.__cap = cap_thread.get_result()
if self.__cap is None:
return
if self.__cap.isOpened():
if self.__fps is None or self.__fps == 0:
self.__fps = int(self.__cap.get(cv2.CAP_PROP_FPS))
if self.__width is None or self.__width == 0:
self.__width = int(self.__cap.get(cv2.CAP_PROP_FRAME_WIDTH))
if self.__height is None or self.__height == 0:
self.__height = int(self.__cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
logger.info("fps:{}|height:{}|width:{}", self.__fps, self.__height, self.__width)
except ServiceException as s:
logger.error("构建cv2异常: {}", s.msg)
raise s
except Exception as e:
logger.error("初始化cv2异常{}", e)
raise e
def cv2_read(self):
result = None
try:
if self.__cap is None:
self.build_cv2()
if self.__cap.isOpened():
ret, frame = self.__cap.read()
if ret:
result = frame
del ret
del frame
except ServiceException as s:
raise s
except Exception as e:
logger.error("读流异常:{}", e)
raise e
finally:
if result is None:
self.__fps = None
self.__height = None
self.__width = None
if self.__cap:
self.__cap.release()
self.__cap = None
logger.info("关闭cv2")
return result
# 拉取视频
def build_pull_stream(self):
try:
if self.__pullUrl is None or len(self.__pullUrl) == 0:
logger.error("拉流地址不能为空!")
raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0],
ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1])
if self.__pull_stream:
logger.info("重试, 关闭拉流管道")
if self.__pull_stream.stdout:
self.__pull_stream.stdout.close()
self.__pull_stream.terminate()
self.__pull_stream.wait()
command = ['ffmpeg',
'-rtsp_transport', 'tcp',
'-i', self.__pullUrl,
'-f', 'rawvideo',
'-pix_fmt', 'bgr24',
'-an',
'-']
# command = ['ffmpeg',
# '-re',
# '-y',
# '-c:v', 'h264_cuvid',
# '-resize', self.wah,
# '-i', self.pullUrl,
# '-f', 'rawvideo',
# '-an',
# '-']
self.__pull_stream = sp.Popen(command, stdout=sp.PIPE)
except ServiceException as s:
logger.error("构建拉流管道异常: {}", s.msg)
raise s
except Exception as e:
logger.error("构建拉流管道异常:{}", e)
raise e
def check_config(self):
if self.__fps is None or self.__width is None or self.__height is None:
return True
else:
return False
def read(self):
result = None
try:
if self.__pull_stream is None:
self.build_pull_stream()
in_bytes = self.__pull_stream.stdout.read(self.__wh)
if in_bytes is not None and len(in_bytes) > 0:
result = (np.frombuffer(in_bytes, np.uint8).reshape([int(self.__height), int(self.__width), 3]))
except ServiceException as s:
raise s
except Exception as e:
logger.error("读流异常:{}", e)
raise e
finally:
if result is None:
self.__fps = None
self.__height = None
self.__width = None
if self.__pull_stream:
if self.__pull_stream.stdout:
self.__pull_stream.stdout.close()
self.__pull_stream.terminate()
self.__pull_stream.wait()
logger.info("关闭拉流管道完成!")
self.__pull_stream = None
return result
# 关闭管道
def close(self):
if self.__pull_stream:
if self.__pull_stream.stdout:
self.__pull_stream.stdout.close()
self.__pull_stream.terminate()
self.__pull_stream.wait()
logger.info("关闭拉流管道完成!")
if self.__push_stream:
if self.__push_stream.stdin:
self.__push_stream.stdin.close()
self.__push_stream.terminate()
self.__push_stream.wait()
logger.info("关闭推流管道完成!")
if self.__cap:
self.__cap.release()
# 开始推流
def build_push_stream(self):
try:
if self.__push_stream:
logger.info("重试, 关闭管道, 重新开启新管道")
if self.__push_stream.stdin:
self.__push_stream.stdin.close()
self.__push_stream.terminate()
self.__push_stream.wait()
if self.__pushUrl is None or len(self.__pushUrl) == 0:
logger.error("推流地址不能为空!")
raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0],
ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1])
command = ['ffmpeg',
# '-loglevel', 'debug',
'-f', 'rawvideo',
'-vcodec', 'rawvideo',
'-pix_fmt', 'bgr24',
'-s', "{}x{}".format(int(self.__width), int(self.__height)),
'-r', str(self.__fps),
'-i', '-',
# '-g', str(self.__fps),
# '-maxrate', '15000k',
# '-minrate', '3000k',
# '-profile:v', 'high',
# '-level', '5.1',
# '-b:v', '4000k',
# '-crf', '26',
# '-bufsize', '4000k',
# '-c:v', 'libx264',
# '-tune', 'zerolatency',
# '-sc_threshold', '0',
# '-pix_fmt', 'yuv420p',
# "-an",
# '-preset', 'medium', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast,
# superfast, veryfast, faster, fast, medium, slow, slower, veryslow。
]
for url in self.__pushUrl:
command.extend(['-f', 'flv',
'-g', str(self.__fps),
'-maxrate', '15000k',
'-minrate', '3000k',
'-b:v', '4000k',
'-bufsize', '4000k',
'-c:v', 'libx264',
'-tune', 'zerolatency',
'-sc_threshold', '0',
'-pix_fmt', 'yuv420p',
'-preset', 'fast',
"-an", "-y", url
])
self.__push_stream = sp.Popen(command, stdin=sp.PIPE, shell=False)
except ServiceException as s:
logger.error("构建推流管道异常: {}", s.msg)
raise s
except Exception as e:
logger.error("初始化推流管道异常:{}", e)
raise e
def push_stream_write(self, frame):
try:
if self.__push_stream is None:
self.build_push_stream()
self.__push_stream.stdin.write(frame.tostring())
except Exception as ex:
logger.error("推流异常:{}", ex)
current_retry_num = 0
while True:
try:
self.build_push_stream()
self.__push_stream.stdin.write(frame.tostring())
logger.info("推流重试成功, 当前重试次数: {}", current_retry_num)
break
except Exception as e:
current_retry_num += 1
logger.error("推流异常:{}, 开始重试, 当前重试次数:{}", e, current_retry_num)
time.sleep(1)
if current_retry_num > 1:
raise Exception("推流异常,请检查通道是否被占用!")
def close_push_stream(self):
if self.__push_stream:
self.__push_stream.terminate()
self.__push_stream.wait()
self.__push_stream = None
def is_push_stream_ok(self):
if self.__push_stream:
if self.__push_stream.poll() is not None:
return True
return False
# 开始推流
def start_push_stream(self):
try:
if self.__push_stream:
return
if self.__pullUrl is None or len(self.__pullUrl) == 0:
logger.error("拉流地址不能为空!")
raise ServiceException(ExceptionType.PUll_STREAM_URL_EXCEPTION.value[0],
ExceptionType.PUll_STREAM_URL_EXCEPTION.value[1])
if self.__pushUrl is None or len(self.__pushUrl) == 0:
logger.error("推流地址不能为空!")
raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0],
ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1])
command = ['ffmpeg',
'-re',
'-rtsp_transport', 'tcp',
'-i', self.__pullUrl,
]
for url in self.__pushUrl:
command.extend(['-f', 'flv',
'-g', str(25),
'-c:v', 'copy',
"-an", "-y", url
])
self.__push_stream = sp.Popen(command, shell=False)
except ServiceException as s:
logger.error("构建推流管道异常: {}", s.msg)
raise s
except Exception as e:
logger.error("初始化推流管道异常:{}", e)
raise e
def is_video_stream(self, url):
p = None
try:
if url is None or len(url) == 0:
raise Exception("流地址不能为空!")
args = ['ffprobe', '-show_format', '-show_streams', '-of', 'json', url]
p = sp.Popen(args, stdout=sp.PIPE, stderr=sp.PIPE, close_fds=True)
out, err = p.communicate(timeout=7)
if p.returncode != 0:
return False
probe = json.loads(out.decode('utf-8'))
if probe is None or probe.get("streams") is None:
return False
video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None)
if video_stream is None:
return False
return True
except ServiceException as s:
raise s
except Exception as e:
return False
finally:
if p:
p.terminate()
p.wait()
p = None

27
util/LogUtils.py Normal file
View File

@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
import sys
import os
from loguru import logger
# 初始化日志配置
def init_log(content):
if not os.path.exists(content["log"]["base_path"]):
os.makedirs(content["log"]["base_path"])
# 移除日志设置
logger.remove(handler_id=None)
# 打印日志到文件
if content["log"]["enable_file_log"]:
logger.add(content["log"]["base_path"] + content["log"]["log_name"],
rotation=content["log"]["rotation"],
retention=content["log"]["retention"],
format=content["log"]["log_fmt"],
level=content["log"]["level"],
enqueue=content["log"]["enqueue"],
encoding=content["log"]["encoding"])
# 控制台输出
if content["log"]["enable_stderr"]:
logger.add(sys.stderr,
format=content["log"]["log_fmt"],
level=content["log"]["level"],
enqueue=True)

19
util/TimeUtils.py Normal file
View File

@ -0,0 +1,19 @@
import time
import datetime
YY_MM_DD_HH_MM_SS = "%Y-%m-%d %H:%M:%S"
YMDHMSF = "%Y%m%d%H%M%S%f"
def generate_timestamp():
"""根据当前时间获取时间戳,返回整数"""
return int(time.time())
def now_date_to_str(fmt=None):
if fmt is None:
fmt = YY_MM_DD_HH_MM_SS
return datetime.datetime.now().strftime(fmt)
if __name__=="__main__":
print(now_date_to_str(YMDHMSF))

21
util/YmlUtils.py Normal file
View File

@ -0,0 +1,21 @@
import os
import yaml
from alg_airport_ffmpeg.common.Constant import ConstantEnum
"""
获取配置项信息
"""
def get_configs():
print("开始读取配置文件,获取配置信息:", ConstantEnum.APPLICATION_CONFIG.value[0])
config_path = os.path.abspath(ConstantEnum.APPLICATION_CONFIG.value[0])
if not os.path.exists(config_path):
raise Exception("未找到配置文件:{}".format(ConstantEnum.APPLICATION_CONFIG.value[0]))
with open(config_path, ConstantEnum.R.value[0], encoding=ConstantEnum.UTF_8.value[0]) as f:
file_content = f.read()
content = yaml.load(file_content, yaml.FullLoader)
if not content:
raise Exception("配置项不能为空:{}".format(ConstantEnum.APPLICATION_CONFIG.value[0]))
print("读取配置文件完成!")
return content

0
util/__init__.py Normal file
View File

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.