如何通过Python实现松下DC-FZ82相机WLAN实时画面预览(已解决)
解决松下DC-FZ82相机UDP实时流的Python解析与显示问题
我有一台松下DC-FZ82相机,支持通过自带WLAN传输实时画面。已经能通过Python发送HTTP请求控制相机——比如用http://192.168.54.1/cam.cgi?mode=getstate获取状态,发送http://192.168.54.1/cam.cgi?mode=startstream&value=49152就能启动实时流。启动后,相机从端口65428通过UDP把画面数据发到我的49152端口,但我不知道怎么处理sock.recvfrom(max_length)接收到的数据,没法把它显示成实时视频。
初始代码
这是我一开始写的接收UDP数据的代码:
import socket UDP_IP = "0.0.0.0" UDP_PORT = 49152 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((UDP_IP, UDP_PORT)) print(f"Listening for UDP stream on port {UDP_PORT}...") while True: data, addr = sock.recvfrom(65535) # 最大UDP包长度 print(f"Received {len(data)} bytes from {addr}") # 这里不知道怎么处理data来显示视频
接收数据示例
接收到的UDP包数据是类似这样的分片(十六进制片段):
FF D8 FF E0 00 10 4A 46 49 46 00 01 01 00 00 01 00 01 00 00 FF DB 00 43 00 03 02 02 03 02 02 03 03 03 03 04 03 03 04 05 08 05 05 04 04 05 0A 07 07 06 08 0C 0A 0C 0C 0B 0A 0B 0B 0D 12 0F 0D 11 0E 0F 11 11 10 12 14 15 15 15 0C 0E 17 18 16 14 18 12 14 15 14 FF D9
能看到开头的FF D8和结尾的FF D9——这是JPEG帧的起始和结束标记,但UDP包是分片传输的,单个包可能只包含帧的一部分。
最终解决代码
核心思路:把UDP分片的数据拼接起来,直到凑出完整的JPEG帧(从FF D8开始到FF D9结束),然后用OpenCV解码并显示。
import socket import cv2 import numpy as np UDP_IP = "0.0.0.0" UDP_PORT = 49152 # 初始化UDP套接字 sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) sock.bind((UDP_IP, UDP_PORT)) # 用于缓存拼接中的JPEG数据 frame_buffer = b"" print(f"Listening for UDP stream on port {UDP_PORT}...") while True: data, addr = sock.recvfrom(65535) frame_buffer += data # 查找完整的JPEG帧:从FF D8开始,到FF D9结束 start_idx = frame_buffer.find(b"\xff\xd8") end_idx = frame_buffer.find(b"\xff\xd9") if start_idx != -1 and end_idx != -1: # 提取完整的JPEG帧 jpeg_frame = frame_buffer[start_idx:end_idx+2] # 更新缓存,保留当前帧之后的数据(可能包含下一帧的部分数据) frame_buffer = frame_buffer[end_idx+2:] # 解码JPEG帧并显示 try: np_frame = np.frombuffer(jpeg_frame, dtype=np.uint8) cv_frame = cv2.imdecode(np_frame, cv2.IMREAD_COLOR) if cv_frame is not None: cv2.imshow("Panasonic FZ82 Live Stream", cv_frame) # 按Q键退出 if cv2.waitKey(1) & 0xFF == ord('q'): break except Exception as e: print(f"Failed to decode frame: {e}") # 清理资源 cv2.destroyAllWindows() sock.close()
代码说明
- 缓存拼接:用
frame_buffer持续累加UDP接收到的数据,因为单个UDP包不一定包含完整的JPEG帧。 - 帧提取:通过查找JPEG的起始(
FF D8)和结束(FF D9)标记,提取完整的帧数据,同时更新缓存,避免重复处理。 - 解码显示:用
numpy把字节数据转成数组,再通过OpenCV的imdecode解码为图像,最后用imshow实时显示。 - 退出逻辑:按下Q键时关闭窗口并终止程序。
内容的提问来源于stack exchange,提问作者Tobias
相关产品推荐
相关产品推荐

