2025-09-03 13:43:58 +08:00
|
|
|
|
import asyncio
|
|
|
|
|
import logging
|
|
|
|
|
import cv2
|
|
|
|
|
import time
|
2025-09-03 16:22:21 +08:00
|
|
|
|
from ocr.model_violation_detector import MultiModelViolationDetector
|
2025-09-03 13:52:24 +08:00
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
|
|
|
|
|
# 配置文件相对路径(根据实际目录结构调整)
|
|
|
|
|
YOLO_MODEL_PATH = "../ocr/models/best.pt" # 关键修正:从core目录向上一级找ocr文件夹
|
|
|
|
|
FORBIDDEN_WORDS_PATH = "../ocr/forbidden_words.txt"
|
|
|
|
|
OCR_CONFIG_PATH = "../ocr/config/1.yaml"
|
|
|
|
|
KNOWN_FACES_DIR = "../ocr/known_faces"
|
2025-09-03 13:52:24 +08:00
|
|
|
|
|
|
|
|
|
# 创建检测器实例
|
2025-09-03 16:22:21 +08:00
|
|
|
|
detector = MultiModelViolationDetector(
|
|
|
|
|
forbidden_words_path=FORBIDDEN_WORDS_PATH,
|
|
|
|
|
ocr_config_path=OCR_CONFIG_PATH,
|
|
|
|
|
yolo_model_path=YOLO_MODEL_PATH,
|
|
|
|
|
known_faces_dir=KNOWN_FACES_DIR,
|
|
|
|
|
ocr_confidence_threshold=0.5
|
2025-09-03 13:52:24 +08:00
|
|
|
|
)
|
2025-09-03 13:43:58 +08:00
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 配置日志
|
2025-09-03 13:43:58 +08:00
|
|
|
|
logging.basicConfig(level=logging.INFO)
|
|
|
|
|
logger = logging.getLogger("rtmp_video_puller")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async def rtmp_pull_video_stream(rtmp_url):
|
|
|
|
|
"""
|
2025-09-03 16:22:21 +08:00
|
|
|
|
通过RTMP从指定URL拉取视频流并进行违规检测
|
2025-09-03 13:43:58 +08:00
|
|
|
|
"""
|
|
|
|
|
cap = None # 初始化视频捕获对象
|
|
|
|
|
try:
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 异步打开RTMP流
|
2025-09-03 13:43:58 +08:00
|
|
|
|
cap = await asyncio.to_thread(
|
|
|
|
|
cv2.VideoCapture,
|
|
|
|
|
rtmp_url,
|
2025-09-03 16:22:21 +08:00
|
|
|
|
cv2.CAP_FFMPEG # 指定FFmpeg后端确保RTMP兼容性
|
2025-09-03 13:43:58 +08:00
|
|
|
|
)
|
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 检查RTMP流是否成功打开
|
2025-09-03 13:43:58 +08:00
|
|
|
|
is_opened = await asyncio.to_thread(cap.isOpened)
|
|
|
|
|
if not is_opened:
|
|
|
|
|
raise Exception(f"RTMP流打开失败: {rtmp_url}(请检查URL有效性和FFmpeg环境)")
|
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 获取RTMP流基础信息
|
2025-09-03 13:43:58 +08:00
|
|
|
|
width = await asyncio.to_thread(cap.get, cv2.CAP_PROP_FRAME_WIDTH)
|
|
|
|
|
height = await asyncio.to_thread(cap.get, cv2.CAP_PROP_FRAME_HEIGHT)
|
|
|
|
|
fps = await asyncio.to_thread(cap.get, cv2.CAP_PROP_FPS)
|
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 处理异常情况
|
2025-09-03 13:43:58 +08:00
|
|
|
|
fps = fps if fps > 0 else 30.0
|
|
|
|
|
width, height = int(width), int(height)
|
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 打印流初始化成功信息
|
2025-09-03 13:43:58 +08:00
|
|
|
|
print(f"RTMP流状态: 已成功连接")
|
|
|
|
|
print(f"流基础信息: 分辨率 {width}x{height} | 配置帧率 {fps:.2f} FPS")
|
|
|
|
|
print("开始接收视频帧...(按 Ctrl+C 中断)")
|
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 初始化帧统计参数
|
|
|
|
|
frame_count = 0
|
|
|
|
|
start_time = time.time()
|
2025-09-03 13:43:58 +08:00
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 循环读取视频帧
|
2025-09-03 13:43:58 +08:00
|
|
|
|
while True:
|
|
|
|
|
ret, frame = await asyncio.to_thread(cap.read)
|
|
|
|
|
|
|
|
|
|
if not ret:
|
|
|
|
|
print(f"RTMP流状态: 帧读取失败(可能流已中断或结束)")
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
frame_count += 1
|
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
# 打印当前帧信息
|
2025-09-03 13:43:58 +08:00
|
|
|
|
print(f"收到帧 (第{frame_count}帧)")
|
|
|
|
|
print(f" 帧尺寸: {width}x{height}")
|
|
|
|
|
print(f" 配置帧率: {fps:.2f} FPS")
|
|
|
|
|
|
2025-09-03 16:22:21 +08:00
|
|
|
|
if frame is not None:
|
|
|
|
|
has_violation, violation_type, details = detector.detect_violations(frame)
|
|
|
|
|
if has_violation:
|
|
|
|
|
print(f"检测到违规 - 类型: {violation_type}, 详情: {details}")
|
|
|
|
|
else:
|
|
|
|
|
print("未检测到任何违规内容")
|
2025-09-03 13:52:24 +08:00
|
|
|
|
else:
|
2025-09-03 16:22:21 +08:00
|
|
|
|
print(f"无法读取测试图像")
|
|
|
|
|
|
|
|
|
|
# 每100帧统计一次实际接收帧率
|
2025-09-03 13:43:58 +08:00
|
|
|
|
if frame_count % 100 == 0:
|
|
|
|
|
elapsed_time = time.time() - start_time
|
2025-09-03 16:22:21 +08:00
|
|
|
|
actual_fps = frame_count / elapsed_time
|
2025-09-03 13:43:58 +08:00
|
|
|
|
print(f"---- 帧统计: 累计{frame_count}帧 | 实际平均帧率 {actual_fps:.2f} FPS ----")
|
|
|
|
|
|
|
|
|
|
except KeyboardInterrupt:
|
|
|
|
|
print(f"\n用户操作: 已通过 Ctrl+C 中断程序")
|
|
|
|
|
except Exception as e:
|
|
|
|
|
logger.error(f"RTMP流处理异常: {str(e)}", exc_info=True)
|
|
|
|
|
print(f"错误信息: {str(e)}")
|
|
|
|
|
finally:
|
|
|
|
|
if cap is not None:
|
|
|
|
|
await asyncio.to_thread(cap.release)
|
|
|
|
|
print(f"\n资源释放: RTMP流已关闭")
|
|
|
|
|
print(f"最终统计: 共接收 {frame_count if 'frame_count' in locals() else 0} 帧")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
|
RTMP_URL = "rtmp://192.168.110.25:1935/live/473b95a47e338301cbd96809ea7ac416"
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
asyncio.run(rtmp_pull_video_stream(RTMP_URL))
|
|
|
|
|
except Exception as e:
|
2025-09-03 16:22:21 +08:00
|
|
|
|
print(f"程序启动失败: {str(e)}")
|