Board index » delphi » Help for client become server and server become client Indy9 and D7

Help for client become server and server become client Indy9 and D7


2006-02-05 12:21:53 AM
delphi102
Hy everybody
I need your help for this:
someone know the Lee Nover's application for streaming video?
ok!! Starting this, i must realize a sort of videoconfernce where a client A send video to a server that resend all to other clients: client B, client C.... Therefore i must change in the code because this realize the second side of my project (server resend other clients).
Who can help me?
Now i post the code that i believe to change
Server side--->new client that send video:
procedure TdmMain.TCPServerExecute(AThread: TIdPeerThread);
var CH: TCommHeader;
FP: TFramePacket;
bmih: TBitmapInfoHeader;
begin
// ALL messages should have a standard packet (easier coding)
AThread.Connection.ReadBuffer(CH, SizeOf(CH));
// check what the client wants
case CH.DPType of
1: // the client wants frame format and refresh rate
begin
bmih:=VideoCoDec.BIOutput.bmiHeader;
// set the size of the data part to the size of the header
CH.DPSize:=SizeOf(bmih);
CH.DPExtra:=30; // hardcoded .. find out the real RR from the source
// send the header
SendData(AThread.Connection, CH, @bmih);
end;
2: // request for frame
begin
// synch the copying of the last frame
MREWS.BeginRead;
try
FP:=CopyFrame(LastPacket);
finally
MREWS.EndRead;
end;
// send the frame
SendFrame(AThread.Connection, CH, FP);
// free the copied packet
FreeFrame(FP);
end;
end;
end;
where sendframe and senddata are two procedure to another unit that Lee has developt for this application, i post this procedure:
procedure SendData(Conn: TidTCPServerConnection; var Header: TCommHeader; Data: PByte);
var ms: TMemoryStream;
begin
ms:=TMemoryStream.Create;
try
ms.Write(Header, SizeOf(Header));
if Header.DPSize>0 then
ms.Write(Data^, Header.DPSize);
ms.Seek(0, soFromBeginning);
if Conn.Connected then
Conn.WriteStream(ms, false, false, ms.Size);
finally
ms.Free;
end;
end;
procedure SendFrame(Conn: TidTCPServerConnection; var Header: TCommHeader; Packet: TFramePacket);
begin
Header.DPCode:=Byte(Packet.KeyFrame);
Header.DPSize:=Packet.Size;
SendData(Conn, Header, Packet.Data);
end;
procedure ReceiveData(Conn: TIdTCPClient; var Header: TCommHeader; Data: PByte);
begin
ReallocMem(Data, Header.DPSize);
if Conn.Connected then
Conn.ReadBuffer(Data^, Header.DPSize);
end;
Client side---->new Server
unit ClientU;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, IdBaseComponent, IdComponent, IdTCPConnection,
IdTCPClient, StdCtrls, VideoCoDec, CommonU;
type
TClientF = class(TForm)
TCPClient: TIdTCPClient;
Label1: TLabel;
txtHost: TEdit;
Label2: TLabel;
txtPort: TEdit;
btnConnect: TButton;
btnDisconnect: TButton;
tmrDisplay: TTimer;
Panel1: TPanel;
imgDisplay: TImage;
procedure TCPClientConnected(Sender: TObject);
procedure TCPClientDisconnected(Sender: TObject);
procedure btnConnectClick(Sender: TObject);
procedure btnDisconnectClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure tmrDisplayTimer(Sender: TObject);
private
VideoCoDec: TVideoCoDec;
FFrames, FKeyFrames: Cardinal;
procedure UpdateVideoFormat(InputFormat: TBitmapInfoHeader);
public
{ Public declarations }
end;
var
ClientF: TClientF;
implementation
{$R *.dfm}
procedure TClientF.FormCreate(Sender: TObject);
begin
VideoCoDec:=TVideoCoDec.Create;
Panel1.DoubleBuffered := true;
end;
procedure TClientF.FormDestroy(Sender: TObject);
begin
FreeAndNil(VideoCoDec);
end;
procedure TClientF.TCPClientConnected(Sender: TObject);
var bmih: TBitmapInfoHeader;
CH: TCommHeader;
begin
FFrames:=0;
FKeyFrames:=0;
btnConnect.Enabled:=false;
btnDisconnect.Enabled:=true;
ZeroMemory(@CH, SizeOf(CH));
CH.DPType:=1; // request for frame format
TCPClient.WriteBuffer(CH, SizeOf(CH), true);
TCPClient.ReadBuffer(CH, SizeOf(CH));
if CH.DPType <>1 then exit; // not the right packet
if CH.DPSize <>SizeOf(bmih) then exit; // not what we expected
// read the format
TCPClient.ReadBuffer(bmih, SizeOf(bmih));
// update the format
UpdateVideoFormat(bmih);
tmrDisplay.Interval:=1000 div CH.DPExtra;
tmrDisplay.Enabled:=true;
end;
procedure TClientF.TCPClientDisconnected(Sender: TObject);
begin
tmrDisplay.Enabled:=false;
btnConnect.Enabled:=true;
btnDisconnect.Enabled:=false;
end;
procedure TClientF.btnConnectClick(Sender: TObject);
begin
TCPClient.Host:=txtHost.Text;
TCPClient.Port:=StrToIntDef(txtPort.Text, 33000);
TCPClient.Connect;
end;
procedure TClientF.btnDisconnectClick(Sender: TObject);
begin
TCPClient.Disconnect;
end;
procedure TClientF.UpdateVideoFormat(InputFormat: TBitmapInfoHeader);
var bmihOut: TBitmapInfoHeader;
FrameRate: Integer;
FCC: TFourCC;
begin
FCC.AsCardinal:=InputFormat.biCompression;
Caption:=FCC.AsString;
bmihOut:=InputFormat;
FrameRate:=30;
InputFormat.biCompression:=0; // rgb - used to decompress
InputFormat.biBitCount:=24; // decompress to 24 bit rgb
VideoCoDec.Finish;
VideoCoDec.Init(InputFormat, bmihOut, 100, 10);
VideoCoDec.SetDataRate(1024, 1000 * 1000 div FrameRate, 1);
if not VideoCoDec.StartDeCompressor then
Caption:=TranslateICError(VideoCoDec.LastError);
imgDisplay.Height:=InputFormat.biHeight;
imgDisplay.Width:=InputFormat.biWidth;
end;
procedure TClientF.tmrDisplayTimer(Sender: TObject);
var CH: TCommHeader;
Data: PByte;
begin
if not VideoCoDec.DecompressorStarted then exit;
ZeroMemory(@CH, SizeOf(CH));
CH.DPType:=2; // request the frame
TCPClient.WriteBuffer(CH, SizeOf(CH), true);
// read the frame
TCPClient.ReadBuffer(CH, SizeOf(CH));
if CH.DPType <>2 then exit; // not a frame packet
if CH.DPSize < 1 then exit;
GetMem(Data, CH.DPSize);
try
TCPClient.ReadBuffer(Data^, CH.DPSize);
if VideoCoDec.UnpackBitmap(Data, Boolean(CH.DPCode), imgDisplay.Picture.Bitmap) then
begin
Inc(FFrames);
Inc(FKeyFrames, CH.DPCode);
imgDisplay.Repaint;
Caption:=Format('Frames: %d (%d kf)', [FFrames, FKeyFrames]);
Update;
end;
finally
FreeMem(Data);
end;
end;
end.
If we read the code the exchange begins when the client connected to server that send the parameter of that it wants receive.
i hope that I am more clear
Thank you all that help me, this is my last hope :)
 
 

Re:Help for client become server and server become client Indy9 and D7

"Francesco" <XXXX@XXXXX.COM>writes
Quote

Hy everybody
I need your help for this:
someone know the Lee Nover's application for streaming video?
ok!! Starting this, i must realize a sort of videoconfernce where a client
A send video to a server that resend all to other clients: client B, client
C.... Therefore i must change in the code because this realize the second
side of my project (server resend other clients).
Quote
Who can help me?
Now i post the code that i believe to change

I do not know the full design of the system, but it seems as if the client
works in a 'one-frame-at-a-time' manner, requesting one frame on a timer,
getting it, decompressing it & then displaying it, ie. no client-side
buffering and only one thread.
I would think that a design based on a client requesting single frames from
a server would have an extremely poor performance because of link latency.
A 144 Mb/s link with a latency of 500ms. would result in a frame rate of one
per second. If the client held a buffer queue of, say, 30 frames, the
latency becomes much less relevant to overall performance and the
abovementioned fast, but high-latency, link could provide a frame rate of
30/sec with no hassle.
If the fetching of the the frames was decoupled from the displaying, eg. by
running it as a seperate thread, the 'get' thread could ask the server for
multiple frames at one, ie. 'My buffer is getting low - send me as many
frames as available to a maximum of 20'. The decompression could also
probably be best done in a thread that has a lower priority than either the
'get' or 'display' threads.
You also seem to have a lot of avoidable copying going on between allocated
data structures. This just eats up performance. Ideally, the frame buffer
that receives the data from the video producer should be the same buffer
that is used to distribute data to each consumer client, after all, the data
is not changed in the server, just distributed as-is, so there is, as I see
it, no need for copying, (use reference-counting instead to decide when the
frame buffer needs to be freed/repooled).
Rgds,
Martin