UDP传输流的问题(100分)

  • 主题发起人 主题发起人 ZS99241
  • 开始时间 开始时间
Z

ZS99241

Unregistered / Unconfirmed
GUEST, unregistred user!
发送:
var
VideoStream: TMemoryStream;
begin

VideoStream := TMemoryStream.Create;
CompressVideo(lpVhdr,AVCapturer1.VideoFormat,VideoStream);//这个过程是进行图像压缩并写入VideoStream中
IdUDPServer1.SendBuffer(Edt_Ip.Text,5027,VideoStream,VideoStream.Size);
VideoStream.Free;
end;

接收:
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject;
AData: TStream;
ABinding: TIdSocketHandle);
var
jpg:TJpegImage;
VideoStream:TMemoryStream;
begin

AData.ReadBuffer(VideoStream,AData.Size);
jpg := TJpegImage.Create;
jpg.LoadFromStream(VideoStream);
Image1.Picture.Bitmap.Assign(jpg);
VideoStream.Free;
jpg.Free;

end;

以上的代码能正常发送和接收图像,现想把存储视频流的VideoStream放入一个结构体中,然后进行发送
结构定入如下:
TVideoInfo = record
CMD: string[15];
VideoStream: TMemoryStream;
end;

发送:
var
VideoInfor: TVideoInfo;
begin

VideoInfor.VideoStream := TMemoryStream.Create;
CompressVideo(lpVhdr,AVCapturer1.VideoFormat,VideoInfor.VideoStream);//这个过程是进行图像压缩并写入VideoStream中
IdUDPServer1.SendBuffer(Edt_Ip.Text,5027,VideoInfor,SizeOf(VideoInfor));
VideoInfor.VideoStream.Free;
end;

接收:
procedure TForm1.IdUDPServer1UDPRead(Sender: TObject;
AData: TStream;
ABinding: TIdSocketHandle);
var
jpg:TJpegImage;
VideoInfor: TVideoInfo;
begin

AData.ReadBuffer(VideoInfor,AData.Size);
jpg := TJpegImage.Create;
jpg.LoadFromStream(VideoInfo.VideoStream);//这里出错,各位说下,我想要实现把视频流放在一个结构中,该怎么写才对?
Image1.Picture.Bitmap.Assign(jpg);
VideoStream.Free;
jpg.Free;

end;
我的每帧图像大小在3K左右,现就是想把图像流放在memoryStream中,因为接收时要根据结构中的CMD指令来判断接收到的是什么数据,所以需要把图像流放在VideoInfo结构中,不知该如何处理?
 
IdUDPServer1.SendBuffer(Edt_Ip.Text,5027,VideoInfor,SizeOf(VideoInfor));
改为
IdUDPServer1.SendBuffer(Edt_Ip.Text,5027,VideoInfor,15 + VideoInfor.VideoStream.Size );
 
谢谢jettop这个我试过了,接收载入JPG的时候还是出错,我刚问了另一朋友说是,网络上不能这么大的数据包,他建议我分包发送,每个包控制在1K内,不知道这种建议是否正确正确,关键是我觉得为什么我单独发送视频流没问题,把视频流放入record中就不行呢?真的不解,希望各位能给出建议
 
不可能,我收发10M的都没有问题.分包只是更保险一点.
 
因为你的record 含CMD 和 Stream ,所以发送时要加上这两者的size .
接收后, 你要对 AData 进行分解,因为它是CMD与Stream 合并的 Stream. 你的DEMO 中未见有分解它们.
 
我以为这句:
AData.ReadBuffer(VideoInfor,AData.Size);
就能直接把接收到的数据自动放入CMD和VideoInor中,因为我跟踪看到VideoInfor.CMD中的值是正确的,该如何写代码分解呢?
 
TVideoInfo = record
CMD: string[10];
VideoStream: TMemoryStream;
end;

发送:
var
VideoInfor: TVideoInfo;
begin
VideoInfor.CMD := '1';
VideoInfor.VideoStream := TMemoryStream.Create;
CompressVideo(lpVhdr,AVCapturer1.VideoFormat,VideoInfor.VideoStream);//写入视频数据VideoInfor.VideoStream
IdUDPServer1.SendBuffer(Edt_Ip.Text,5027,VideoInfor,SizeOf(VideoInfor.CMD)+VideoInfor.VideoStream.Size);
VideoInfor.VideoStream.Free;
end;

接收:
var
jpg:TJpegImage;
VideoInfor: TVideoInfo;
begin
if adata.Size>0 then
begin
adata.ReadBuffer(VideoInfor.CMD,SizeOf(VideoInfor.CMD));
aData.Seek(SizeOf(VideoInfor.CMD),SoFrombegin
ning );
VideoInfor.VideoStream.CopyFrom(adata,adata.Size-SizeOf(VideoInfor.CMD));//这里出错,我该怎么样把视频流读入VideoInfor.VideoStream中?
jpg := TJpegImage.Create;
jpg.LoadFromStream(Adata);
Image1.Picture.Bitmap.Assign(jpg);
jpg.Free;
end;
end;
 
我觉得这不是UDP问题,是你的流处理问题
 
嗯,关键是这流该怎么处理才能实现我想要的功能呢?
 
你的问题应该是,如何 结构与流的转换问题。我自己写的一段代码给你参考吧,效率很高的。(一幅图像显示3000次)
procedure TViewMain.Button2Click(Sender: TObject);
var
start : DWORD ;
i : Integer ;
begin
start := GetTickCount ;
DirectDisplay('e:/1.bmp',image1.Canvas.Handle);
Caption := IntToStr(GetTickCount - start) ;
end;


procedure TViewMain.DirectDisplay(BmpFile: String;
Handle: HDC);
var
Bmf: TBitmapFileHeader;
BitmapInfo: PBitmapInfo;
HeaderSize: Integer;
ImageSize: LongWord;
BitsMem: Pointer;
Stream: TFileStream;
i : Integer ;
begin
try
Stream := TFileStream.Create(BmpFile, fmOpenRead or fmShareDenyWrite);
Stream.ReadBuffer(Bmf, sizeof(Bmf));
//读文件头
ImageSize := Stream.Size - sizeof(Bmf) ;
Stream.ReadBuffer(HeaderSize, sizeof(HeaderSize));
GetMem(BitmapInfo, HeaderSize + 12 + 256 * sizeof(TRGBQuad));
Stream.ReadBuffer(Pointer(Longint(BitmapInfo) + sizeof(HeaderSize))^,
HeaderSize - sizeof(HeaderSize));
//读位图信息
BitmapInfo^.bmiHeader.biSize := HeaderSize ;
Dec(ImageSize, HeaderSize);
GetMem(BitsMem,ImageSize);
Stream.ReadBuffer(BitsMem^, ImageSize);
for i := 0 to 3000do
begin
StretchDIBits( Handle,
0, 0,BitmapInfo^.bmiHeader.biWidth , BitmapInfo^.bmiHeader.biHeight,
0, 0, BitmapInfo^.bmiHeader.biWidth, BitmapInfo^.bmiHeader.biHeight,
BitsMem, BitmapInfo^, 0, SRCCOPY);
image1.Canvas.TextOut(10,10,inttostr(i));
Image1.Refresh ;
end;

finally
FreeMem(BitsMem);
Stream.Free ;
end;

end;
 
再给你一点建议,位图头信息一般只是开始时传输一次。最好改成MP4压缩方式。(会有惊喜的),每个包控制在1.5K以下。呵呵这样又要对包进行排序了。
 
mp4压缩?你有这个压缩算法的单元吗?有的话共享下,中妹水平有限,看了你的代码俺的问题还是没懂咋解决[:(]我现在用的是JPG自带的压缩,压缩后每帧在3K左右
 
mp4压缩方法已经开源了。你可以搜 XVID。是个开源的项目。不过是C++的。但是你用它来生成DLL,调用它的DLL,(它已经给你做好了)来实现解压缩。DELPHIBOX中就有DELPHI使用这个DLL的例子。
 
多人接受答案了。
 
后退
顶部