AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi selbstgebastelter webcam stream
Thema durchsuchen
Ansicht
Themen-Optionen

selbstgebastelter webcam stream

Ein Thema von jokerfacehro · begonnen am 5. Feb 2010 · letzter Beitrag vom 16. Feb 2010
Antwort Antwort
Seite 2 von 3     12 3      
Benutzerbild von gsh
gsh

Registriert seit: 24. Okt 2004
1.542 Beiträge
 
Delphi XE Architect
 
#11

Re: selbstgebastelter webcam stream

  Alt 5. Feb 2010, 15:20
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.
Alex
"Sage nicht alles, was du weißt, aber wisse alles, was du sagst!" Matthias Claudius
"Wer sich über Kritik ärgert, gibt zu, daß er sie verdient hat." Tacitus
  Mit Zitat antworten Zitat
Astat

Registriert seit: 2. Dez 2009
Ort: München
320 Beiträge
 
Lazarus
 
#12

Re: selbstgebastelter webcam stream

  Alt 5. Feb 2010, 15:24
Zitat von jokerfacehro:
..aber schreibt ruhig mehr
Naja!

1. UDP verwenden, ist bedeutend schneller. EDIT: zu spät!
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
Lanthan Astat
06810110811210410503210511511603209711003210010110 9032084097103
03211611111604403209711003210010110903210010510103 2108101116122
11610103209010110510810103206711110010103210511003 2068101108112
10410503210310111509910411410510109810111003211910 5114100046
  Mit Zitat antworten Zitat
Benutzerbild von jokerfacehro
jokerfacehro

Registriert seit: 13. Feb 2007
306 Beiträge
 
Delphi 7 Enterprise
 
#13

Re: selbstgebastelter webcam stream

  Alt 5. Feb 2010, 15:24
da
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
"Never touch a running system administrator !"
  Mit Zitat antworten Zitat
Benutzerbild von jokerfacehro
jokerfacehro

Registriert seit: 13. Feb 2007
306 Beiträge
 
Delphi 7 Enterprise
 
#14

Re: selbstgebastelter webcam stream

  Alt 5. Feb 2010, 15:41
ich hab mir grad ma ne to do list geschrieben
"Never touch a running system administrator !"
  Mit Zitat antworten Zitat
grizzly

Registriert seit: 10. Dez 2004
150 Beiträge
 
Delphi XE4 Professional
 
#15

Re: selbstgebastelter webcam stream

  Alt 5. Feb 2010, 15:54
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
  Mit Zitat antworten Zitat
Benutzerbild von jokerfacehro
jokerfacehro

Registriert seit: 13. Feb 2007
306 Beiträge
 
Delphi 7 Enterprise
 
#16

Re: selbstgebastelter webcam stream

  Alt 5. Feb 2010, 16:08
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
"Never touch a running system administrator !"
  Mit Zitat antworten Zitat
Benutzerbild von jokerfacehro
jokerfacehro

Registriert seit: 13. Feb 2007
306 Beiträge
 
Delphi 7 Enterprise
 
#17

Re: selbstgebastelter webcam stream

  Alt 11. Feb 2010, 13:49
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 ?
"Never touch a running system administrator !"
  Mit Zitat antworten Zitat
grizzly

Registriert seit: 10. Dez 2004
150 Beiträge
 
Delphi XE4 Professional
 
#18

Re: selbstgebastelter webcam stream

  Alt 11. Feb 2010, 15:12
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
  Mit Zitat antworten Zitat
Benutzerbild von jokerfacehro
jokerfacehro

Registriert seit: 13. Feb 2007
306 Beiträge
 
Delphi 7 Enterprise
 
#19

Re: selbstgebastelter webcam stream

  Alt 11. Feb 2010, 15:45
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:

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



weiß aber nicht genau weiter ^^
"Never touch a running system administrator !"
  Mit Zitat antworten Zitat
Benutzerbild von jokerfacehro
jokerfacehro

Registriert seit: 13. Feb 2007
306 Beiträge
 
Delphi 7 Enterprise
 
#20

Re: selbstgebastelter webcam stream

  Alt 15. Feb 2010, 14:03
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...
"Never touch a running system administrator !"
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:29 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