| 
									
										
										
										
											2025-09-03 13:43:58 +08:00
										 |  |  | import asyncio | 
					
						
							|  |  |  | import logging | 
					
						
							|  |  |  | from aiortc import RTCPeerConnection, RTCSessionDescription | 
					
						
							|  |  |  | import aiohttp | 
					
						
							| 
									
										
										
										
											2025-09-03 13:52:24 +08:00
										 |  |  | from ocr.ocr_violation_detector import OCRViolationDetector | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import logging | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | # 创建检测器实例 | 
					
						
							|  |  |  | detector = OCRViolationDetector( | 
					
						
							|  |  |  |         forbidden_words_path=r"D:\Git\bin\video\ocr\forbidden_words.txt", | 
					
						
							|  |  |  |         ocr_confidence_threshold=0.7, | 
					
						
							|  |  |  |         log_level=logging.INFO, | 
					
						
							|  |  |  |         log_file="ocr_detection.log" | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2025-09-03 13:43:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | # 配置日志 | 
					
						
							|  |  |  | logging.basicConfig(level=logging.INFO) | 
					
						
							|  |  |  | logger = logging.getLogger("whep_video_puller") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-03 13:52:24 +08:00
										 |  |  | async def whep_pull_video_stream(ip,whep_url): | 
					
						
							| 
									
										
										
										
											2025-09-03 13:43:58 +08:00
										 |  |  |     """
 | 
					
						
							|  |  |  |     通过WHEP从指定URL拉取视频流并在收到每一帧时打印消息 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Args: | 
					
						
							|  |  |  |         whep_url: WHEP端点的URL | 
					
						
							|  |  |  |     """
 | 
					
						
							|  |  |  |     pc = RTCPeerConnection() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 添加连接状态变化监听 | 
					
						
							|  |  |  |     @pc.on("connectionstatechange") | 
					
						
							|  |  |  |     async def on_connectionstatechange(): | 
					
						
							|  |  |  |         print(f"连接状态: {pc.connectionState}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 添加ICE连接状态变化监听 | 
					
						
							|  |  |  |     @pc.on("iceconnectionstatechange") | 
					
						
							|  |  |  |     async def on_iceconnectionstatechange(): | 
					
						
							|  |  |  |         print(f"ICE连接状态: {pc.iceConnectionState}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 添加视频接收器 | 
					
						
							|  |  |  |     pc.addTransceiver("video", direction="recvonly") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 处理接收到的视频轨道 | 
					
						
							|  |  |  |     @pc.on("track") | 
					
						
							|  |  |  |     def on_track(track): | 
					
						
							|  |  |  |         print(f"接收到轨道: {track.kind}") | 
					
						
							|  |  |  |         if track.kind == "video": | 
					
						
							|  |  |  |             print(f"轨道ID: {track.id}") | 
					
						
							|  |  |  |             print(f"轨道就绪状态: {track.readyState}") | 
					
						
							|  |  |  |             # 创建异步任务来处理视频帧 | 
					
						
							|  |  |  |             asyncio.ensure_future(handle_video_track(track)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async def handle_video_track(track): | 
					
						
							|  |  |  |         """处理视频轨道,接收并打印每一帧""" | 
					
						
							|  |  |  |         frame_count = 0 | 
					
						
							|  |  |  |         print("开始处理视频轨道...") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             try: | 
					
						
							|  |  |  |                 # 尝试接收帧 | 
					
						
							|  |  |  |                 frame = await track.recv() | 
					
						
							|  |  |  |                 frame_count += 1 | 
					
						
							|  |  |  |                 print(f"收到原始帧 (第{frame_count}帧)") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # 打印帧的基本信息 | 
					
						
							|  |  |  |                 if hasattr(frame, 'width') and hasattr(frame, 'height'): | 
					
						
							|  |  |  |                     print(f"  尺寸: {frame.width}x{frame.height}") | 
					
						
							|  |  |  |                 if hasattr(frame, 'time_base'): | 
					
						
							|  |  |  |                     print(f"  时间基准: {frame.time_base}") | 
					
						
							|  |  |  |                 if hasattr(frame, 'pts'): | 
					
						
							|  |  |  |                     print(f"  显示时间戳: {frame.pts}") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-09-03 13:52:24 +08:00
										 |  |  |                 has_violation, violations, confidences = OCRViolationDetector.detect(frame) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # 输出检测结果 | 
					
						
							|  |  |  |                 if has_violation: | 
					
						
							|  |  |  |                     detector.logger.info(f"在图片中检测到 {len(violations)} 个违禁词:") | 
					
						
							|  |  |  |                     for word, conf in zip(violations, confidences): | 
					
						
							|  |  |  |                         detector.logger.info(f"- {word} (置信度: {conf:.4f})") | 
					
						
							|  |  |  |                 else: | 
					
						
							|  |  |  |                     detector.logger.info("图片中未检测到违禁词") | 
					
						
							| 
									
										
										
										
											2025-09-03 13:43:58 +08:00
										 |  |  |             except Exception as e: | 
					
						
							|  |  |  |                 print(f"接收帧时出错: {e}") | 
					
						
							|  |  |  |                 # 等待一段时间后重试 | 
					
						
							|  |  |  |                 await asyncio.sleep(0.1) | 
					
						
							|  |  |  |                 continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 创建offer | 
					
						
							|  |  |  |     offer = await pc.createOffer() | 
					
						
							|  |  |  |     await pc.setLocalDescription(offer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print(f"本地SDP信息:\n{offer.sdp}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 通过HTTP POST发送offer到WHEP端点 | 
					
						
							|  |  |  |     async with aiohttp.ClientSession() as session: | 
					
						
							|  |  |  |         async with session.post( | 
					
						
							|  |  |  |                 whep_url, | 
					
						
							|  |  |  |                 data=offer.sdp, | 
					
						
							|  |  |  |                 headers={"Content-Type": "application/sdp"} | 
					
						
							|  |  |  |         ) as response: | 
					
						
							|  |  |  |             if response.status != 201: | 
					
						
							|  |  |  |                 print(f"WHEP服务器返回错误: {response.status}") | 
					
						
							|  |  |  |                 print(f"响应内容: {await response.text()}") | 
					
						
							|  |  |  |                 raise Exception(f"WHEP服务器返回错误: {response.status}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 获取answer SDP | 
					
						
							|  |  |  |             answer_sdp = await response.text() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # 创建RTCSessionDescription对象 | 
					
						
							|  |  |  |             answer = RTCSessionDescription(sdp=answer_sdp, type="answer") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             print(f"收到远程SDP:\n{answer_sdp}") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 设置远程描述 | 
					
						
							|  |  |  |     await pc.setRemoteDescription(answer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     print("连接已建立,开始接收视频流...") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 保持连接,直到用户中断 | 
					
						
							|  |  |  |     try: | 
					
						
							|  |  |  |         while True: | 
					
						
							|  |  |  |             await asyncio.sleep(1) | 
					
						
							|  |  |  |             # 检查连接状态 | 
					
						
							|  |  |  |             print(f"当前连接状态: {pc.connectionState}") | 
					
						
							|  |  |  |     except KeyboardInterrupt: | 
					
						
							|  |  |  |         print("用户中断,关闭连接...") | 
					
						
							|  |  |  |     finally: | 
					
						
							|  |  |  |         await pc.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if __name__ == "__main__": | 
					
						
							|  |  |  |     # 替换为你的WHEP端点URL | 
					
						
							|  |  |  |     WHEP_URL = "http://192.168.110.25:1985/rtc/v1/whep/?app=live&stream=473b95a47e338301cbd96809ea7ac416" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # 运行拉流任务 | 
					
						
							|  |  |  |     asyncio.run(whep_pull_video_stream(WHEP_URL)) |