![]() |
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. |
Re: selbstgebastelter webcam stream
Zitat:
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 |
Re: selbstgebastelter webcam stream
da
Zitat:
|
Re: selbstgebastelter webcam stream
ich hab mir grad ma ne to do list geschrieben :D
|
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:
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).
procedure TVideoImage.GetFrameData(VAR FrameData: pointer; VAR FrameDataSize: integer; VAR FourCC : cardinal);
begin FrameData := fImagePtr[fImagePtrIndex]; FrameDataSize := fImagePtrSize[fImagePtrIndex]; FourCC := fFourCC; end; 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 |
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 |
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 ? |
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 |
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:
und versuche diesem pointer jetzt einen string zu zuweisen
TFour = ARRAY[0..3] OF byte;
weiß aber nicht genau weiter ^^ |
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: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 17:30 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz