| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- """
- 将 JPEG 帧通过 OrangePi 的 FrameHeader(16B) 分片协议转发出去(UDP)。
- 用于 Python -> Unity 图像显示链路,便于 Unity 端复用同一套分片重组逻辑。
- Header(小端):
- uint32 magic = 0x57494649 ("WIFI")
- uint32 frame_id
- uint16 seq
- uint16 total
- uint16 data_len
- uint16 reserved
- """
- from __future__ import annotations
- import socket
- import struct
- import threading
- from dataclasses import dataclass
- MAGIC = 0x57494649
- HEADER_FMT = "<I I H H H H"
- HEADER_SIZE = struct.calcsize(HEADER_FMT)
- MAX_UDP_SIZE = 1400
- MAX_PAYLOAD = MAX_UDP_SIZE - HEADER_SIZE # 1384
- @dataclass
- class ForwardConfig:
- target_ip: str = "127.0.0.1"
- target_port: int = 12366
- class UDPFrameForwarder:
- def __init__(self, target_ip: str = "127.0.0.1", target_port: int = 12366) -> None:
- self.cfg = ForwardConfig(target_ip=target_ip, target_port=target_port)
- self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
- self._frame_id = 0
- self._lock = threading.Lock()
- def set_target(self, ip: str, port: int) -> None:
- with self._lock:
- self.cfg.target_ip = ip
- self.cfg.target_port = int(port)
- def send_jpeg(self, jpeg_bytes: bytes) -> None:
- if not jpeg_bytes:
- return
- with self._lock:
- target = (self.cfg.target_ip, self.cfg.target_port)
- frame_id = self._frame_id
- self._frame_id = (self._frame_id + 1) & 0xFFFFFFFF
- total = (len(jpeg_bytes) + MAX_PAYLOAD - 1) // MAX_PAYLOAD
- if total <= 0:
- return
- if total > 65535:
- # 单帧过大,不发送
- return
- for seq in range(total):
- start = seq * MAX_PAYLOAD
- end = min(start + MAX_PAYLOAD, len(jpeg_bytes))
- payload = jpeg_bytes[start:end]
- header = struct.pack(HEADER_FMT, MAGIC, frame_id, seq, total, len(payload), 0)
- self.sock.sendto(header + payload, target)
- def close(self) -> None:
- try:
- self.sock.close()
- except Exception:
- pass
|