Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi selbstgebastelter webcam stream (https://www.delphipraxis.net/147307-selbstgebastelter-webcam-stream.html)

jokerfacehro 5. Feb 2010 12:31


selbstgebastelter webcam stream
 
Hallo,

ich programmiere gerade einen ferngesteuerten webcam client mit Delphi 7 Enterprise.

Dazu nutze ich Directx für die Webcam und IdTCPClient und Server für die Verbindung.


das ding ist eine dreieckstruktur.

ich habe ein client-server-system
und dazu einen webserver.

der server sendet die configuration an den webserver.
der client liest die config vom webserver und arbeitet dem entsprechend alles ab.

und sendet zumbeispiel den webcam stream an den server.



den webserver schalte ich zwischen aufgrund der hohen erreichbarkeit.
so kann ich indirekt den client abschalten etc. ohne dass eine direkte verbindung besteht.


die webcam greife ich über directx ab.

siehe http://www.delphipraxis.net/internal...webcam+directx



per timer grabbe ich einzelne frames und übertrage die per indy an den server.


hier die prozedur des clients zum senden.

Delphi-Quellcode:
procedure TForm1.sendStream(pic:TBitmap);
var MStream:TMemoryStream;
begin

MStream:=TMemoryStream.Create;

try
  pic.SaveToStream(MStream);
  MStream.Position:=0;
  try
    IdTCPClient1.Socket.Write(MStream,0,true);
  except
    end;
finally
  MStream.Free;
  end;
end;

das gebe ich dann einfach beim server aus.

Es funktioniert alles wunderbar.

Mein Problem:
ich will natürlich keine Bitmaps versenden, aufgrund der dateigröße.
deshalb habe ich bereits jpg und png genutzt.

das funktioniert auch.
allerdings ist dementsprechend die cpu auslastung beim client dauerhaft bei über 15%
und springt auch mal auf 40%, (bei Bitmap logischerweise 0-1%)

ich suche deshalb eine praktikable kompression zum übertragen der frames.



Hoffe da hat jemand was parat :roll:

Astat 5. Feb 2010 12:58

Re: selbstgebastelter webcam stream
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von jokerfacehro
Hoffe da hat jemand was parat

Hallo jokerfacehro, hatte dies mal in Verwendung. Errorbehandlung musst Du nachziehn, ist damals etwas dürftig ausgefallen.

Delphi-Quellcode:

uses
  ZLibEx;


procedure CompressBitmap_Slow(bmp: TBitmap; var Data: string);
var
   ms   : TMemoryStream;
   buf  : pointer;
   size : integer;
begin
  ms := TMemoryStream.Create;
  bmp.SaveToStream(ms);
  ZCompress(ms.Memory, ms.Size, buf, size);
  SetLength(Data, size);
  Move(buf^, Data[1], size);
  FreeMem(buf);
  ms.Free;
end;

procedure CompressBitmap(bmp: TBitmap; var Data: string);
var
   cs: TZCompressionStream;
   ms: TMemoryStream;
begin
  ms := TMemoryStream.Create;
  cs := TZCompressionStream.Create(ms,zcDefault); // clDefault ist schneller als clMax
  bmp.SaveToStream(cs);
  cs.Free;
  SetLength(Data, ms.Size);
  Move(ms.Memory^, Data[1], ms.Size);
  ms.Free;
end;

procedure UnCompressBitmap(const Data: string; bmp: TBitmap);
var
  ms   : TMemoryStream;
  buf  : pointer;
  size : integer;
  outsize:integer;
begin
   try
     size:=0;
     outsize:=Length(Data) * 3;
     ZDecompress(@Data[1], Length(Data), buf,outsize, size);
   except
      on E: Exception do begin
         E.Message := Format('Error Decompressing Buffer (Len = %d):'#13#10'%s', [Length(Data), e.Message]);
         raise;
      end;
   end;
   ms := TMemoryStream.Create;
   ms.Write(buf^, outSize);
   FreeMem(buf);
   ms.Position := 0;
   Assert(bmp <> nil);
   bmp.LoadFromStream(ms);
   ms.Free;
end;
lg. Astat

jokerfacehro 5. Feb 2010 13:16

Re: selbstgebastelter webcam stream
 
hab mir deinen code angeschaut, versteh ihn aber nicht ganz.

wozu ist der parameter Data da ?

kannste den quelltext bitte en bischen erläutern ?


Edit:

ich habs jetz so verstanden:

die komprimierte bmp liegt im ms
und wird dann in data geschrieben.

da kann ich ja gleich den ms per indy verschicken oder nicht ?

jokerfacehro 5. Feb 2010 13:43

Re: selbstgebastelter webcam stream
 
So ich habs ma probiert umzusetzen:

hier der client:

Delphi-Quellcode:
procedure TForm1.sendStream(pic:TBitmap);
var MStream:TMemoryStream;
    data:string;
begin

MStream:=TMemoryStream.Create;

CompressBitmap(pic,data);

try
  MStream.WriteBuffer(data,Length(Data));
  MStream.Position:=0;
  try
    IdTCPClient1.Socket.Write(MStream,0,true);
  except
    end;
finally
  MStream.Free;
  end;
end;


hier der server:

Delphi-Quellcode:
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var data:string;
    FStream:TMemoryStream;
    bmp:TBitmap;
begin
FStream:=TMemoryStream.Create;

try
  AContext.Connection.Socket.ReadStream(FStream);
  FStream.Position:=0;
finally
  try
     FStream.Read(data,1000000);
  finally
    //bmp.LoadFromStream(FStream);
    FStream.Free;
    end;
  end;

UnCompressBitmap(data,bmp);

end;

sooo der client schickt anscheinend was, zumindest ist data gefüllt

beim server kommt Connection closed Gracefully.

Astat 5. Feb 2010 13:47

Re: selbstgebastelter webcam stream
 
Zitat:

Zitat von jokerfacehro
..da kann ich ja gleich den ms per indy verschicken oder nicht ?

Hallo jokerfacehro, natürlich, aber nicht dem ms, sondern

Delphi-Quellcode:
 
ZCompress(ms.Memory, ms.Size, buf, size);
send(ASocket, buf^, size)

Da die komprimierten Daten in buf liegen.

lg. Astat

jokerfacehro 5. Feb 2010 13:53

Re: selbstgebastelter webcam stream
 
ähm ich arbeite mit CompressBitmap, nicht mit CompressBitmap_slow ;)

grizzly 5. Feb 2010 14:00

Re: selbstgebastelter webcam stream
 
Hallo!

Da existiert noch eine andere Möglichkeit, allerdings ist mein WebCam Code noch nicht 100%ig darauf vorbereitet: Unter Umständen sind Deine Bilder von der Kamera eh schon komprimiert: YUY2, MJPG etc.

Wenn Du im aktuellen Beispielcode der Unit VFrames.pas nachsiehst, findest Du dort die Routine, welche Dir die Bitmaps liefert: TVideoImage.GetBitmap(BMP: TBitmap).
Diese Routine wiederum ruft UnpackFrame(..) auf. Das heißt, falls Deine Kamera beispielsweise MJPG Daten liefert (was unterm Strich schon fertige JPG Bilder sind), dann packt diese Routine das Ding aus in ein Bitmap, und Du machst es dann wieder klein, um es zu verschicken.

Es könnte sich also lohnen, die Originaldaten zu holen (Also Pointer fImagePtr[fImagePtrIndex], welcher auf fImagePtrSize[fImagePtrIndex] Bytes zeigt), diese zu verschicken, und das Auspacken auf Empfänger-Seite zu erledigen. Da mußt Du allerdings noch ein bissl was einbauen ;)

Allerding: Das hilft natürlich nur, wenn Deine Kamera schon eine solche Datenkompression anbietet. Ist es von vorneherein entpackt, dann hilft mein Vorschlag hier nicht weiter...

Gruß
Michael

jokerfacehro 5. Feb 2010 14:07

Re: selbstgebastelter webcam stream
 
du hast recht, ich mach das so :D

ich gehe über getBitmap();

allerdings habe ich mit dem hintergrund noch nicht beschäftigt ^^

muss mir dat erstma anschaun oder du hast noch paar anhaltspunkte

Astat 5. Feb 2010 14:10

Re: selbstgebastelter webcam stream
 
Zitat:

Zitat von jokerfacehro
ähm ich arbeite mit CompressBitmap, nicht mit CompressBitmap_slow ;)

Hallo jokerfacehro, da war ich wohl mit meinen Gedanken schneller als im Code stand, sorry, meinte dies in etwa so.

Delphi-Quellcode:

procedure TForm1.sendStream(pic: TBitmap);
var
  MStream:TMemoryStream;
  pOutBuf  : pointer;
  cbOutSize:integer;
begin
  pOutBuf := nil;
  cbOutSize := 0;

  MStream := TMemoryStream.Create;
  try
    pic.SaveToStream(MStream);
    ZCompress(MStream.memory, MStream.size, pOutBuf, cbOutSize, zcMax);
  finally
    MStream.Free;
  end;

  if (pOutBuf <> nil) and (cbOutSize > 0) then begin
    IdTCPClient1.Socket.Write(pOutBuf, cbOutSize, 0);
    FreeMem(pOutBuf);
  end else
    raise exception.Create('u should never see this.');
end;
lg. Astat

jokerfacehro 5. Feb 2010 14:15

Re: selbstgebastelter webcam stream
 
ich schaue mir beide ansätze an, da erster flexibler ist.

ich bin gespannt wie nacher die unterschiede bei cpu last und speicherverbrauch sind.

aber schreibt ruhig mehr :D

gsh 5. Feb 2010 14:20

Re: selbstgebastelter webcam stream
 
Ich möchte noch etwas kurz einwerfen:
Es ist nicht intelligent Webcam Livebilder über TCP (wegen Handshake, FlowControl, ..) zu übertragen. Besser geeignet ist in diesem Fall UDP.

Astat 5. Feb 2010 14:24

Re: selbstgebastelter webcam stream
 
Zitat:

Zitat von jokerfacehro
..aber schreibt ruhig mehr

Naja!

1. UDP verwenden, ist bedeutend schneller. EDIT: zu spät! :cry:
2. Nur die Pixel übertragen, die sich geändert haben (Different Screening)
3. Andere Kompression verwenden, wenn Bitmap Kompression notwendig,
das wesentlich performantere paszlib anstatt ZLib*.obj Files verwenden.

lg. Astat

jokerfacehro 5. Feb 2010 14:24

Re: selbstgebastelter webcam stream
 
da
Zitat:

Zitat von gsh
Ich möchte noch etwas kurz einwerfen:
Es ist nicht intelligent Webcam Livebilder über TCP (wegen Handshake, FlowControl, ..) zu übertragen. Besser geeignet ist in diesem Fall UDP.

geb ich dir recht :D

jokerfacehro 5. Feb 2010 14:41

Re: selbstgebastelter webcam stream
 
ich hab mir grad ma ne to do list geschrieben :D

grizzly 5. Feb 2010 14:54

Re: selbstgebastelter webcam stream
 
Nu, vielleicht aktiviert Du ja alle Methoden!

Zu den Web-Cam Kompressionen:
In dem Dialog, in dem Du die Größe deiner Videos auswählen kannst, bietet Dir der Treiber in der Regel noch unterschiedliche Kompressionen: RGB 24 beispielsweise ist der unkomprimierte Datenstrom, 3 Bytes pro Pixel, das wären dann bei 640x480 Pixel großen Bilder schon 921600 Bytes. Andere wären YUY2 (2 Bytes pro Pixel, 33% Ersparnis), MJPEG (Jedes Bild als JPG), I420 (eineinhalb Bytes pro Pixel, 50% Ersparnis).
Die so komprimierten Bilder kann man mit DirectX zu normalen Bitmaps auspacken. Das war mir aber etwas zu kompliziert, deshalb habe ich für einige Kompressionen eigene Entpacker in den Code eingebaut (sind natürlich nicht so performant wie die DirectX Dinger). Wenn man ein Bild mit GetBitmap() abholt, entpacke ich den Datenstrom (UnpackFrame). Mein Code sollte YUY2 (=YUYV, YUNV), MJPG, I420 (=YV12, IYUV) unterstützen.

Falls also Deine Webcam einige der Kompressionsformate beherrscht, könntest Du neben GetBitmap() ja noch eine andere Funktion basteln ala GetFrameData(), welche Dir einen Zeiger auf die Originaldaten (samt deren Größe und den FourCC code) zurückliefert. Maximal simpel so:
Delphi-Quellcode:
procedure TVideoImage.GetFrameData(VAR FrameData: pointer; VAR FrameDataSize: integer; VAR FourCC : cardinal);
begin
  FrameData := fImagePtr[fImagePtrIndex];
  FrameDataSize := fImagePtrSize[fImagePtrIndex];
  FourCC := fFourCC;
end;
Die kopierst du dann gleich weg und schickst sie an den anderen Rechner (oder zippst sie vorher, solange es kein MJPEG war, weil da zippt sich nicht mehr viel).
Auf dem Rechner, der die Daten empfängt, baust Du dann eine angepaßte UnpackFrame(..) Routine (siehe VFrames.pas) ein, um an Dein Bitmap zu kommen. Dieser angepaßten Routine müssen halt der FourCC code (der gibt an, welche Kompression verwendet wurde) und das Zielbitmap mit übergeben werden (momentan verwendet die ja irgendwelche Object-internen Variablen)...

Gruß
Michael

jokerfacehro 5. Feb 2010 15:08

Re: selbstgebastelter webcam stream
 
jop

ich hab mir das ma angeschaut.

ich hol mir einfach die daten vom pointer in den stream
und verschicke die.

nebenbei muss ich dem server denn sagen welche kompression etc...
und die dekompressionsfunktionen sind ja alle inner VSamples.pas vorhanden.

die kann ich ja dem server einfach hinzufügen.

die manuelle kompression ist trotzdem interessant, da ich ne funktion habe zur darstellung des desktops

jokerfacehro 11. Feb 2010 12:49

Re: selbstgebastelter webcam stream
 
sooo da bin ich mal wieder

folgendes hat sich getan:

ich hol mir jetz das komprimierte und bild und verschicke es per UDP vom Client an den Server.

Der server hat die nötige prozedur zur dekomprimierung der daten.



hier mal quelltext:

Die Client Methoden:

Holen der Daten vom VideoImage

Delphi-Quellcode:
procedure TVideoImage.GetFrameData(VAR FrameData: pointer; VAR FrameDataSize: integer; VAR FourCC : cardinal; VAR Width,Height:integer);
begin
  FrameData := fImagePtr[fImagePtrIndex];
  FrameDataSize := fImagePtrSize[fImagePtrIndex];
  FourCC := fFourCC; //codec
  Width:=fWidth;
  Height:=fHeight;
end;

Verschicken der Daten

Delphi-Quellcode:
procedure TForm1.sendStream;
var MStream:TMemoryStream;
    Data:string;
    FrPointer:Pointer;
    FrSize,fWidth,fHeight,bSize:integer;
    Codec:Cardinal;
begin

  fVideoImage.GetFrameData(FrPointer,FrSize,Codec,fWidth,fHeight);

  FrSize:=FrSize+3;
  setLength(Data,8192);  //#0#13#0



  try
    Move(FrPointer^,Data[1],8192);
  //  Data:=IntToStr(8192);
    WebcamStream.Client.Send(Data);
  except
    end;

while FrSize>8192 do begin

  try
    Data:='';
    setLength(Data,8192);
    Move(FrPointer^,Data[1],8192);
    WebcamStream.Client.Send(Data);
  except
    end;

  FrSize:=FrSize-8192;
 end;
 
Data:='';
setLength(Data,FrSize);
try
    Move(FrPointer^,Data[1],FrSize);
    Data:=Data+#0#13#0;
    WebcamStream.Client.Send(Data);
  except
    end;
end;



Server methoden:

Empfangen der Daten

Delphi-Quellcode:
procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  AData: TIdBytes; ABinding: TIdSocketHandle);
var  i:integer;
      buffer,data:string;
      MStream:TMemoryStream;
      bmp:TBitmap;
begin

//MStream:=TMemoryStream.Create;

buffer:=AThread.Server.ReceiveString(-1);
data:=buffer;

while(Pos(#0#13#0,buffer)<1) do begin
buffer:=AThread.Server.ReceiveString(-1);
data:=data+buffer;
end;

//buffer

//MStream.Read(buffer,Length(buffer));
Decoder.DecodeFrame(data);

//Form2.Image1.Picture.Bitmap.LoadFromStream(MStream);

//if Pos(#0#13#0,buffer)>0 then Showmessage('okkk');

//MStream.Free;
end;


dekomprimieren der daten

Delphi-Quellcode:
procedure TDecoder.DecodeFrame(Bitmap:TBitmap;Data:String);
var  fp:^string;
begin
fp:=@Data;
YUY2_to_RGB(fp,Data);

end;

Delphi-Quellcode:
procedure TDecoder.YUY2_to_RGB(pData: pointer;data:string);
// [url]http://msdn.microsoft.com/en-us/library/ms893078.aspx[/url]
// [url]http://en.wikipedia.org/wiki/YCbCr[/url]
type
  TFour = ARRAY[0..3] OF byte;
VAR
  L, X, Y : integer;
  ps     : pbyte;
  pf     : ^TFour;
  FrPointer:Pointer;
      FrSize,fWidth,fHeight,i:integer;
      Codec:Cardinal;
      bmp:TBitmap;
begin
bmp:=TBitmap.Create;
bmp.PixelFormat:=pf24Bit;

pf:=pData;

//fVideoImage.GetFrameData(FrPointer,FrsIze,Codec,fWidth,fHeight);
fWidth:=640;
fHeight:=480;
bmp.Width:=fWidth;
bmp.Height:=fHeight;

Showmessage(IntToStr(Length(Data)));

  PrepareTables;
  FOR Y := 0 TO bmp.Height-1 DO
    BEGIN
      ps := bmp.ScanLine[Y];
      FOR X := 0 TO (bmp.Width div 2)-1 DO
        begin
          L := ValueY_298[pf^[0]]; // HIER KOMMT DER FEHLER
          ps^ := ValueClip[(L + ValueU_516[pf^[1]]                    ) div 256];
          Inc(ps);
          ps^ := ValueClip[(L + ValueU_100[pf^[1]] + ValueV_208[pf^[3]]) div 256];
          Inc(ps);
          ps^ := ValueClip[(L                     + ValueV_409[pf^[3]]) div 256];
          Inc(ps);
          L := ValueY_298[pf^[2]];
          ps^ := ValueClip[(L + ValueU_516[pf^[1]]                    ) div 256];
          Inc(ps);
          ps^ := ValueClip[(L + ValueU_100[pf^[1]] + ValueV_208[pf^[3]]) div 256];
          Inc(ps);
          ps^ := ValueClip[(L                     + ValueV_409[pf^[3]]) div 256];
          Inc(ps);


          Inc(pf);
        end;
    END;
    Form2.Image1.Picture.Assign(bmp);
    bmp.Free;
end;


so ich hänge jetzt an der letzten funktion.
Diese berechnet das bild zurück

Die Value Arrays enthalten umrechnungszahlen für die einzelnen pixel.

der pointer pf soll auf die Data zeigen.



Das Problem ist jetzt, dass ich bei der letzten funktion ne access violation kriege, siehe Kommentar im quelltext.
Die kommt allerdings erst nach etwa dem 20. durchlauf der For schleife mit Y.

Raised exception class C000005


hat jemand ne Idee ?

grizzly 11. Feb 2010 14:12

Re: selbstgebastelter webcam stream
 
Hallo!

Beim Zugriff auf ValueY_298 kanns ja kaum sein, denn das ist ein array von 0 bis 255. Ergo kein Rangecheck. Sieht also eher so aus, als ob es das byte "pf^[0]" nicht gibt. (access violation). Dazu hätt' ich ein paar Kandidaten:

1. Das Übergeben der Daten als string. Schlägt da nicht irgendwo vielleicht doch eine raffinierte Routine durch, die eine 0 in den Bilddaten findet und dann dort einfach den string abschneidet?

2. Die Datenübertragung läuft bis zu einem #0#13#0. Es ist natürlich schon möglich, daß dieses #0#13#0 schon in den Bilddaten selbst vorkommt! Dann würdest Du mit einem unvollständigen Bild in die Auspack-Routine gehen.

3. Hat das Übergebene Bild überhaupt 640*480 Pixel? Nicht, daß das viel kleiner ist! fWidth und fHeight werden ja explizit auf diese festen Werte gesetzt in YUY2_to_RGB.

Klappt die Übergabe für RGB24 kodierte Bilder? Da hätten alle Frames wenigstens dieselbe Größe: Width*Height*3 und Du könntest in der Routine prüfen, ob der übergebene Speicher tatsächlich so groß ist. Obwohl, YUY2 Bilder haben auch immer eine feste Größe, da könnte man also auch leicht prüfen, ob die Höhe und Breite zur Menge der übergebenen Bytes paßt.


Gruß
Michael

jokerfacehro 11. Feb 2010 14:45

Re: selbstgebastelter webcam stream
 
also
ich hab natürlich bevor ich die dekomprimierung in den server ausgelagert habe, die dekomprimierung direkt beim client getestet und hat wunderbar gefunzt.

das mit der string terminierung ist schon ne idee.

das komische ist nur: mein string ist etwa 3mal so groß wie die erwartete datenmenge und die länge von Data variiert.

die Höhe und Breite sind okay, da ich zur zeit nur meine cam nutze und die ist 100% auf 640*480



Edit:

ich sehe gerade der Pointer ist vom typ:

Delphi-Quellcode:
TFour = ARRAY[0..3] OF byte;
und versuche diesem pointer jetzt einen string zu zuweisen



weiß aber nicht genau weiter ^^

jokerfacehro 15. Feb 2010 13:03

Re: selbstgebastelter webcam stream
 
Nach ewigem rumprobieren bin ich immer noch nicht weiter.

Ich bekomme alle Daten wunderbar in meinen string eingelesen beim server.

Die Stringlänge ist auch aufs Byte genau richtig.

Ich weiß jetzt bloß nicht wie den string ins richtige format kriege damit der pointer ordentlich drauf zugreifen kann.

bzw eine möglichkeit diesen pointer zu umgehen.



Hat jemand nen Plan, bin mit Pointern nicht gerade der geschickteste



Edit: irgendwas haut nicht hin, wenn ich während des aufrufs von UDPServerRead ein Showmessage mache, ändert
sich komischer weise willkürlich die fenstergröße der dialogbox.

mal ist sie normal groß, manchmal breiter als der bildschirm... :gruebel: :wall:

jokerfacehro 15. Feb 2010 14:01

Re: selbstgebastelter webcam stream
 
Sooo

ich habs jetz hinbekommen.

allerdings schnippelt er mir das bild aufm server falsch zusammen.

bei jedem bild sieht'S anders aus.

manchmal ist es richtig. manchmal malt er was nach links gehört in die mitte, sodass sich das bild verschiebt und der überstehende teil steht dann wieder vorne

Astat 15. Feb 2010 19:49

Re: selbstgebastelter webcam stream
 
Zitat:

Zitat von jokerfacehro
allerdings schnippelt er mir das bild aufm server falsch zusammen.
bei jedem bild sieht'S anders aus.
manchmal ist es richtig. manchmal malt er was nach links gehört in die mitte, sodass sich das bild verschiebt und der überstehende teil steht dann wieder vorne

Hallo jokerfacehro, zeig mal deinen Source der die entsprechende Korrekturmaßnahmen für UDP beinhaltet!
Deutet alles auf ein nicht vorhandenes Protokoll hin.

UDP stellt einen verbindungslosen, nicht-zuverlässigen Übertragungsdienst bereit. Das bedeutet, es gibt keine Garantie, dass ein einmal gesendetes Paket auch ankommt, dass Pakete in der gleichen Reihenfolge ankommen, in der sie gesendet wurden, oder dass ein Paket nur einmal beim Empfänger eintrifft. Eine Anwendung, die UDP nutzt, muss daher gegenüber verlorengegangenen und unsortierten Paketen unempfindlich sein oder selbst entsprechende Korrekturmaßnahmen beinhalten.

Ich würde, bevor du auf die Fehlersuche nach den Ursachen gehst, vorerst mal auf TCP umstellen.
Erst wenn du da ein brauchbares TCP Protokoll entwickelt hast, solltest du dich auf den steinigen Weg zu UDP begeben.

lg. Astat

jokerfacehro 16. Feb 2010 10:02

Re: selbstgebastelter webcam stream
 
Hey Habs jetz hinbekommen :D


Client sendet:

Delphi-Quellcode:
procedure TWebcamStream.Send(Data:string);
var FrSize:integer;
begin

  Data:=Data+#255#1#2#3#4#5#6;   //terminierung
  FrSize:=Length(Data);

while FrSize>8192 do begin

  try
    Client.Send(Copy(Data,1,8192));
    Delete(Data,1,8192);
  except
    end;

  FrSize:=FrSize-8192;
 end;


try
    Client.Send(Data);
  except
    end;
end;

der server empfängt:

Delphi-Quellcode:
procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  AData: TIdBytes; ABinding: TIdSocketHandle);
var  i,size,counter:integer;
      buffer1,buffer2,data:string;
      MStream:TMemoryStream;
      bmp:TBitmap;
begin

buffer1:=BytesToString(AData);

while Pos(#255#1#2#3#4#5#6,buffer2)<1 do begin
buffer2:=AThread.Server.ReceiveString();
buffer1:=buffer1+buffer2;
end;


data:=Copy(buffer1,1,Pos(#255#1#2#3#4#5#6,buffer1)-1);

Decoder.DecodeFrame(data);

end;

funzt jetz wunderbar :D
hab auch das problem mit der dekodierung gelöst:

Delphi-Quellcode:
procedure TDecoder.YUY2_to_RGB(data:string);
// [url]http://msdn.microsoft.com/en-us/library/ms893078.aspx[/url]
// [url]http://en.wikipedia.org/wiki/YCbCr[/url]
type
  TFour = ARRAY[0..3] OF byte;
VAR
  L, X, Y : integer;
  ps     : pbyte;
  arr    :array of TFour;
  pf     : ^TFour;
  FrPointer:Pointer;
      FrSize,fWidth,fHeight,i:integer;
      Codec:Cardinal;
      bmp:TBitmap;
begin

i:=0;

bmp:=TBitmap.Create;
bmp.PixelFormat:=pf24Bit;

//pf:=pData;

//fVideoImage.GetFrameData(FrPointer,FrsIze,Codec,fWidth,fHeight);
fWidth:=640;
fHeight:=480;
bmp.Width:=fWidth;
bmp.Height:=fHeight;

//Showmessage(IntToStr(Length(Data))+'----'+IntToStr(round(640*480)));

  PrepareTables;
  FOR Y := 0 TO bmp.Height-1 DO
    BEGIN
      ps := bmp.ScanLine[Y];
      FOR X := 0 TO (bmp.Width div 2)-1 DO
        begin
          L := ValueY_298[Byte(data[i*4+1])];
          ps^ := ValueClip[(L + ValueU_516[Byte(data[i*4+2])]                    ) div 256];
          Inc(ps);
          ps^ := ValueClip[(L + ValueU_100[Byte(data[i*4+2])] + ValueV_208[Byte(data[i*4+4])]) div 256];
          Inc(ps);
          ps^ := ValueClip[(L                     + ValueV_409[Byte(data[i*4+4])]) div 256];
          Inc(ps);
          L := ValueY_298[Byte(data[i*4+3])];
          ps^ := ValueClip[(L + ValueU_516[Byte(data[i*4+2])]                    ) div 256];
          Inc(ps);
          ps^ := ValueClip[(L + ValueU_100[Byte(data[i*4+2])] + ValueV_208[Byte(data[i*4+4])]) div 256];
          Inc(ps);
          ps^ := ValueClip[(L                     + ValueV_409[Byte(data[i*4+4])]) div 256];
          Inc(ps);


          //Inc(pf);
          Inc(i);
        end;
    END;
    Form2.Image1.Picture.Assign(bmp);
    bmp.Free;
end;

4 bytes gehören immer zu einem pixel
ich lasse einfach i hochzählen und suche mir damit das richtige element des strings




habs jetz allerdings ein neues komisches problem :D

ich hab jetz die prozedur zum senden in meine klasse eingebettet, und darin läuft ein Timer
der halt das grabben und sender der frames übernimmt.

das problem ich kriege den timer nicht aktiviert.

ich kann die prozedur für das OnTimer Event manuel aufrufen aus dem hauptprogramm, aber der
Timer ruft sie nicht selber auf;

Delphi-Quellcode:
constructor Create;
begin
RunTimer:=TTimer.Create(nil);
RunTimer.Name:='RunTimer';
RunTimer.OnTimer:=Run;
RunTimer.Interval:=10;
RunTimer.Enabled:=true;
end;

procedure TWebcamStream.Run(Sender:TObject)
begin
bla
end;


Edit so nebenbei: CPU Auslastung liegt bei 8%, speicherverbrauch 20mb

Edit2: wenn nötig schreib ich mir ma nen ordentliches protokoll, aber so reichts erstma fürn Localhorst


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:30 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz