我正在尝试使用 UDP 将摄像头从 Raspberry pi 直播到 PC。我按照Picamera2库提供的示例代码使用python发送直播数据,并使用C# WinForms
PictureBox
在PC上显示直播。
C# 应用程序收到数据字节数组后,我将使用内存流和
Image.FromStream()
将字节数组转换为图像。但是,这会引发“参数无效”异常。
Python代码(服务器):
host = #IP Address
port = 24325
with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as server_socket:
# Initial connection
server_socket.bind((host, port))
print("UDP Server is listening...")
while True:
data, addr = server_socket.recvfrom(1024)
rx = data.decode()
## Protocol Code...
# if...
# Stream code
elif rx == "STREAM":
tx = "STREAMING"
server_socket.sendto(tx.encode(), addr)
print("Starting stream")
# Note: 2 cameras are being used on the Pi but only 1 is being streamed for testing
picam1 = Picamera2(0)
picam2 = Picamera2(1)
config1 = picam1.create_preview_configuration()
config2 = picam2.create_preview_configuration()
picam1.configure(config1)
picam2.configure(config2)
picam1.controls.ExposureTime = 30000
picam2.controls.ExposureTime = 30000
encoder = H264Encoder(1000000)
server_socket.connect(addr)
stream = server_socket.makefile("wb")
picam1.start_recording(encoder, FileOutput(stream))
else:
print(f"Recieved from {addr}: {rx}")
tx = "Your message received"
server_socket.sendto(tx.encode(), addr)
C# 代码(客户端):
// Connection code...
// Protocol code...
// Receive livestream data
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Any, 0);
bool isReceiving = true;
if (rx == "STREAMING")
{
logToConsole("Stream started"); // Custom function
try
{
while (isReceiving)
{
byte[] streamData = udpClient.Receive(ref serverEndPoint);
using (MemoryStream ms = new MemoryStream(streamData))
{
Image receivedImage = Image.FromStream(ms);
if (receivedImage != null)
{
pictureBoxStream.Invoke(new Action(() => pictureBoxStream.Image = receivedImage));
}
}
}
}
catch (Exception ex)
{
logToConsole("Error receiving video stream: " + ex.Message);
}
}
我不是Python开发人员,所以我可能误解了一些东西,但在我看来,存在几个基本问题:
UDP 数据包的最大大小约为 65kb。接收方假设每个数据包都是一个完整的帧,除非图像非常小,否则无法保证这一点。通常,您会在 UDP 之上定义一个协议,该协议允许您发送和重组更大的消息,以及处理无序数据包传送等问题。
看起来python代码使用了h264压缩,但是c#上没有任何东西可以解码这样的视频流。
Image.FromStream
应该处理最常见的 图像格式,例如 jpeg 和 png,但您将需要第三方解码器来处理大多数类型的真实视频流。
您必须在图像的生命周期内保持流打开。
所以删除
using
我建议使用一些现有的协议。 实时流协议可能是一个不错的选择,它构建在UDP之上,并且应该内置处理丢失数据包、乱序交付等的功能。
另一种选择可能是一些简单的东西,例如通过 http、gRCP 或类似的发送 jpeg 帧,这应该保证可靠的传输并且应该相当容易使用。