![]() |
WebCam via Stream senden
Moin DP,
ich habe mir mal ![]() Client:
Delphi-Quellcode:
procedure TFormMain.FormActivate(Sender: TObject);
var DeviceList: TStringList; begin if fActivated then Exit; fActivated := true; DeviceList := TStringList.Create; fVideoImage.GetListOfDevices(DeviceList); if not DeviceList.Count < 1 then begin fVideoImage.VideoStart(DeviceList[0]); Timer1.Enabled := true; end; end; procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction); begin fVideoImage.VideoStop; end; procedure TFormMain.FormCreate(Sender: TObject); begin fActivated := false; fVideoImage := TVideoImage.Create; fVideoImage.SetDisplayCanvas(PaintBox1.Canvas); //Brauche ich das überhaupt? Oder wie kriege ich das Bild dann in die SendStream Prcedure rein? end; procedure TFormMain.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; end; procedure TFormMain.Timer1Timer(Sender: TObject); begin //via Timer Einzelbilder senden (1-2 Sek. Intervall) SendStream(); //Hier komm ihch nicht weiter! Das soll ja ein Bild in Form von TBitmap übergeben werden, aber wie, bzw. wo nehme ich es her? end; Server:
Delphi-Quellcode:
Also in der PaintBox bekomme ich ein Bild, also funktioeniert das schonmal, jetzt weiß ich aber nicht was das mit TBitmap bei der SendStream-Procedure auf sich hat :cry:// Kompression 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); 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; {------ MAIN ------} procedure TForm1.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); PaintBox1.Canvas.Create(bmp); //Bin mir da nicht sicher, was ist mit data? end; Danke, Lukas |
AW: WebCam via Stream senden
Das Bild musst du natürlich erst von der Webcam bekommen. Dazu gibt es hier im Forum auch eine schöne Demoanwendung, wie das über DirectX funktioniert. Wenn du allerdings mit deinem Code einen Stream wie z.b. bei Skype erwartest, muss ich dich enttäuschen.
Deine Kompression ist sehr langsam und wird trotzdem nicht ausreichen, um ein flüssiges Video zu erzeugen. Je nach Verbindungsgeschwindigkeit kannst du mit ca. 1 Frame pro Sekunde rechnen. Hab das vor einiger Zeit auch mal ausprobiert gehabt. Normale Differenzbildverfahren kannst du hier auch nicht ohne weiteres verwenden, da jede Webcam ein normales Bildrauschen erzeugt. Dadurch werden klassische Differenzbildverfahren ohne Toleranz praktisch nutzlos. Optimalerweise solltest du auf erprobte Verfahren, wie z.b. MPEG Kompression setzen. Ich selbst habe leider keine passende Implementation dafür in Delphi gefunden. |
AW: WebCam via Stream senden
Das Problem ist garnicht das auslesen, das funktioniert wunderbar. Das mit der KOmpression lasse ich erstmal außen vor, habe da aber auch schon was passendes gefunden (steht sogar beim Client-Code dabei). Mir reicht auch erstmal ein Bild pro Sekunde, auf Skype möchte ich die Messlatte noch nicht setzen :D Aber bei mir hackts daran, wie ich das Bild, was ich aus der Cam bekomme jetzt in diese Prodedure packe:
Delphi-Quellcode:
procedure TFormMain.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; end; //Aufruf SendStream(); //Was muss jetzt aber in die "()"? Etwas vom Typ TBitmap, aber wo bekomme ich das nun her, bzw. wie bekomme ich eine Bitmap aus dem Video? |
AW: WebCam via Stream senden
Delphi-Quellcode:
wobei ich hier
var
bmp:TBitmap; begin bmp:=TBitmap.Create; try bmp.Width := 600; bmp.Height := 450; BitBlt(bmp.Canvas.Handle,0,0,panel1.Width,panel1.Height,Panel1.canvas.handle,0,0,SRCCOPY); image1.Picture.Assign(bmp); finally bmp.Free; end;
Delphi-Quellcode:
verwende, bei Deiner Komponente kannst Du gegf. direkt
connect := capCreateCaptureWindow('Kamera',ws_child+ws_visible, 0,
0, 600, 450, Panel1.Handle, 1);
Delphi-Quellcode:
verwenden ....
fVideoImage.SetDisplayCanvas(MyBitmap.Canvas);
ansonsten BITBLT auf Panintbox1.canvas.handle ... |
AW: WebCam via Stream senden
Hallo!
Mir scheint, Du verwendest meinen ![]() Definiere eine Callback-Routine wie folgt:
Delphi-Quellcode:
Statt Deinem Code hier:
procedure TForm1.OnNewVideoFrame(Sender : TObject; Width, Height: integer; DataPtr: pointer);
begin // Denkbar wäre, hier ein Busy-Flag zu testen und zu setzen. // So holst Du das Bitmap direkt ab: fVideoImage.GetBitmap(fVideoBitmap); // fVideoBitmap mußt Du Dir halt noch als TBitmap zuvor erzeugen // Alternativ kannst Du gleich den übergebenen Pointer verwenden: // Der zeigt auf die Bilddaten (in 24bit RGB oder 8bit Grau, falls "Gray8Bit" gesetzt war // Die Speichergröße ergibt sich aus Width*Height*3 (bzw. beim Graustufenbild ohne das *3) // (Da die Breiten der Videos meist durch 4 teilbar sind, muß man sich nicht darum kümmern, // dass bei Bildern die Scanlines auf ein Vielfaches von 4 Bytes aufgefüllt wird) // Hier kommt Dein Code rein zum Packen und verschicken... // z.B.: (ohne ZCompress zu kennen): ZCompress(MStream.memory, MStream.size, DataPtr^, Width*Height*3, ... end;
Delphi-Quellcode:
meldest Du diesen Callback wie folgt an:
fVideoImage.SetDisplayCanvas(PaintBox1.Canvas); //Brauche ich das überhaupt? Oder wie kriege ich das Bild dann in die SendStream Prcedure rein?
Delphi-Quellcode:
(Du kannst natürlich die Zuweisung an die Paintbox drinlassen, dann sparst Du Dir das selber-zeichnen.)
fVideoImage.OnNewVideoFrame := OnNewVideoFrame;
Nebenbei: Der Foreneintrag, auf den Du in Deinem ersten Post verweist, hatte auch das Problem mit dem Packen der Daten. Ich hatte damals schon darauf hingewiesen, dass viele WebCams ihre Daten sowieso schon gepackt schicken, und in meinem Code-Misthaufen entpackt werden, bevor sie als Bitmap weitergereicht werden. Das wäre natürlich ein Zwischenschritt, den Du rauslassen könntest, und das Entpacken des Videoframes erst auf der Zielseite machst. Aber natürlich: Die Packqualität ist halt wieder abhängig vom Codec, und Du müßtest in meinem Code-Durcheinander eingreifen... Gruß Michael |
AW: WebCam via Stream senden
Danke an euch, ich versuche es so, das sieht schonmal ganz gut aus ;)
|
AW: WebCam via Stream senden
Okay, etwas geht dennoch nicht :( Hier etwas Code:
Client:
Delphi-Quellcode:
Server:
procedure TFormMain.FormActivate(Sender: TObject);
var DeviceList: TStringList; begin if fActivated then Exit; fActivated := true; DeviceList := TStringList.Create; fVideoImage.GetListOfDevices(DeviceList); if not DeviceList.Count < 1 then begin fVideoImage.VideoStart(DeviceList[0]); Timer1.Enabled := true; end; end; procedure TFormMain.FormClose(Sender: TObject; var Action: TCloseAction); begin fVideoImage.VideoStop; end; procedure TFormMain.FormCreate(Sender: TObject); begin TCPClient.Connect; fActivated := false; fVideoImage := TVideoImage.Create; fVideoBitmap := TBitmap.Create; PaintBox1.Align := alClient; fVideoImage.SetDisplayCanvas(PaintBox1.Canvas); fVideoImage.OnNewVideoFrame := OnNewVideoFrame; end; procedure TFormMain.SendStream(pic: TBitmap); var MStream: TMemoryStream; begin MStream := TMemoryStream.Create; try pic.SaveToStream(MStream); MStream.Position := 0; try TCPClient.Socket.Write(MStream, 0, true); except end; finally MStream.Free; end; end; procedure TFormMain.OnNewVideoFrame(Sender: TObject; Width: integer; Height: integer; DataPtr: pointer); begin fVideoImage.GetBitmap(fVideoBitmap); SendStream(fVideoBitmap); fVideoImage.VideoStop; //Erstmal fehlerfrei nur ein Einzelbild erhalten. end; procedure TFormMain.Timer1Timer(Sender: TObject); begin //SendStream(fVideoBitmap); end;
Delphi-Quellcode:
Irgendwo schimmelt der Server immer ab, sobald ein Stream gesendet wird, bleibt das Ding hängen :( Also da steht dann: "CamServer.exe funktioniert nicht mehr", eine dieser Windows-Fehlermeldungen, also keine Exception im Programm oder so. Und ich weiß nicht genau, wie ich die Bitmap die ich bekomme enzeigen lassen soll, oben ist der Code ohne komprimieren, ich will erstmal ein Bild sehen.
procedure TForm1.TCPServerExecute(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); JvImage1.LoadFromStream(FStream); FStream.Free; end; end; end; Danke |
AW: WebCam via Stream senden
Darf ich es vllt. doch noch mal Pushen :( :oops:
|
AW: WebCam via Stream senden
Hi!
Ist das jetzt ein reines Problem der Kommunikation, oder spuckt die WebCam Geschichte mit rein in die Suppe? Falls der WebCam Zugriff verdächtig ist: Hast Du die Übertragung mal nur mit einem Bitmap versucht, so ganz ohne WebCam etc.? Gruß Michael |
AW: WebCam via Stream senden
Nein, irgendeine Bitmap klappt auch nicht, es muss am Server-Code liegen, aber ich weiß nicht wo. Da ich erstmal nur ein Frame übertragen wollte, habe ich natürlich viel kopiert :oops: Der Autor des Originalthreads (siehe
![]()
Delphi-Quellcode:
procedure TForm1.TCPServerExecute(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); //Hier tritt der Fehler auf. Ich weiß nicht genau, was hier rein muss, //der Code ist aus dem oben genanntem Thema abgeleitet, an dem Punkt //ging es aber schon um Kompression, was ich ja erstmal nicht will. finally //bmp.LoadFromStream(FStream); JvImage1.LoadFromStream(FStream); FStream.Free; end; end; end; |
AW: WebCam via Stream senden
Irgendwie scheinen mir Server und Client vertauscht zu sein.
Das lesen in Data scheint mir keinen sinn zu machen zumal etwas in der wie
Delphi-Quellcode:
da stehen müsste, wenn man denn wüsste dass der Stream 1000000 Bytes enthält.
SetLength(Data,1000000);
FStream.Read(Data[1], 1000000); bmp.LoadFromStream(FStream); wäre richtig wenn der Stream komplett gelesen würde |
AW: WebCam via Stream senden
Liste der Anhänge anzeigen (Anzahl: 1)
Hmm... Also irgendetwas läuft bei mir schief. Im Anhang befindet sich mal mein gesamtes Projekt, es ist etwas unordentlich, ist ja auch nur ein kleier Test, um es später, wenn es funktioniert, in ein anderes Projekt zu übernehmen. Das mit dem Read verstehe ich einfahc nicht. Wenn einer Lust und Zeit hat, kann er sich das ja mal anschauen. Aber ich verstehe nicht, wie ich den gesendeten Stream
Delphi-Quellcode:
vollständig lesen soll
TCPClient.Socket.Write(MStream, 0, true);
Delphi-Quellcode:
. Genau das ist mein Problem. Sorry für mein Unverständnis :oops:
FStream.Read(???); //Was muss hier rein?
Danke |
AW: WebCam via Stream senden
Liste der Anhänge anzeigen (Anzahl: 1)
Aus dem Stream wird solange gelesen bis die Gegenseite die Connection abbricht.
Ich habe mal den ganzen Videokram rausgelassen ud mich auf die Bildübertragung gestürzt ... Ich habe versucht Deine Strukturen beizubehalten, damit Du im Vergleich siehst was ich ändern musste. Irgendwie sind für mich Gedanklich Client und Server immer noch vertauscht, aber das überlasse ich Dir, vielleicht soll es ja so sein. |
AW: WebCam via Stream senden
@Bummi: Danke für die Antwort, ich war unter der Woche weg, kann mir das jetzt erst anschauen. Und ich weiß jetzt was du mit "Vertauscht" meinst. Normalerweiße schickt ja ein Server ein (empfangenes) Bild an einen Clienten. Ich mach es andersherum, ich will mit einem Kumpel das ganze testen. Er führt immer meinen Client aus, der sich dann mit meinem Server (bei mir am Laptop) verbindet.
|
AW: WebCam via Stream senden
Liste der Anhänge anzeigen (Anzahl: 1)
Einen Zwischenstand Server und Client in einem Projekt kann ich Dir anbieten ...
Die komplette Dienstlösung würde ich dann doch lieber erst mal closed Source lassen wollen. |
AW: WebCam via Stream senden
Schau ich mir auch an :) Aber ich habe an deiner ersten Lösung etwas rumgewerkelt und jetzt kann ich Timer-gesteuert Bilder meiner Webcam versenden. Jetzt fang ich mit Kompression an. Mal eine Frage: Da du ja die Indy KOmponenten verwendet hast, kann ich dann auch die ganzen Indy-Kompressoren und verwenden?
Und eine Frage bleibt noch offen: Das ganze soll in ein Chat-Programm integriert werder, d.h. ich kann während dem schreiben per Button ein Video-Chatfenster öffnen. Allerdings läuft mein Shat mit den Sockets. Um das ganze erstmal auszuprobieren, möchte ich ganz unkompiliziert einen 2. Server in meiner Anwendung laufen lassen, eben nur für die Cam, den IndyTCP-Server. Kann es aber sein, das sich die beiden trotz unterschiedlicher Ports in die Quere kommen? Z.B. im lokalen Netzwerk, wo die Ports ja irrelevant sind? Danke |
AW: WebCam via Stream senden
wieso irrelevant?
Ports sind die eindeutigen "Türen" über die zugegriffen werden. In meinem 2. Beispiel werden die Kamerabilder vor dem Versand in JPG's umgewandelt, IMHO dürfte die Kompressionsrate hier besser sein. Du kannst auch alles über einen Socket laufen lassen, dann wird halt das Protokoll etwas umfangreicher. Die Indy habe ich eigentlich nur verwendet weil Dein erster Post damit gearbeitet hat, persönlich verwende ich lieber die altmodische Methode mit TTcpServer.GetThread mit eigenen Threads. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:37 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