使用 Image.FromStream() 时出现“参数无效”异常 - UDP 视频直播
我正在尝试将树莓派的摄像头直播到电脑上,使用的是UDP协议。我参考了Picamera2库提供的示例代码,用Python发送直播数据,并在电脑上使用C#的WinForms中的PictureBox
来显示这个直播。
当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);
}
}
1 个回答
1
我不是Python开发者,可能有些地方理解错了,但我觉得这里有几个基本问题:
没有消息重组
一个UDP数据包的最大大小大约是65KB。接收方假设每个数据包都是一个完整的帧,但除非图像非常小,否则根本无法保证这一点。
通常,你会在UDP之上定义一个协议,这样可以发送和重组更大的消息,还能处理数据包乱序到达的问题。同时,它还需要考虑丢失的数据包,可以通过某种重发机制或者内置冗余来解决。
没有解压缩
看起来Python代码使用了h264压缩,但在C#中没有解码这种视频流的东西。Image.FromStream
可以处理大多数常见的图像格式,比如jpeg和png,但对于大多数真实的视频流,你需要一个第三方解码器。
过早关闭流
根据Image.FromStream的文档:
你必须在图像的生命周期内保持流的打开状态。
所以要去掉using
。
建议
我建议使用一些现有的协议。实时流协议可能是个不错的选择,它建立在UDP之上,并且应该内置处理丢失数据包、乱序传输等问题。
另一个选择可能是像通过http、gRPC或类似方式发送jpeg帧,这样可以保证可靠传输,而且使用起来相对简单。