When I write this article, many of my friends are being asked by my boss to develop video chat software similar to QQ. Here, I will write some of my experiences and code to share with you, don't laugh at me! After reading this article, you can also create a simple network video communication software. If you have a home network, you can perform visual communication between your company and your family, it's so cool that you don't have to pay for the phone.
This example uses the old simple technology (VFW), which is relatively simple to develop. The following is the Delphi code. You need to add VFW first. if you do not have this file, you can find it online. The author started programming from delphi4. In fact, Delphi can do many things, but too many Delphi programmers do not have deep expertise and ideas, and do not surpass themselves. Delphi is just a development tool, code thinking is the essence of design.
Let's take a look at the following:
At the beginning of the program, you need to use capcreatecapturewindow to create a camera handle,
Capwnd: = capcreatecapturewindow ('preview Windows', ws_visible or ws_child, 320,240, prevwnd, 1 );
In the following parameter: prevwnd indicates the handle of the preview window. You can specify a handle of the Panel. 320 and 240 represent the length and width of the window.
If capwnd = 0 Then exit;
Capdriverconnect (capwnd, 0); // connect the camera Device
Capdlgvideoformat (capwnd); // The video Setting dialog box is displayed to configure the video size and number of digits.
Capgetvideoformat (capwnd, @ BMP ininfo, sizeof (bitmapinfo); // gets the video image data header, which must be used for subsequent compression.
Cappreviewrate (capwnd, 33); // sets the video preview frequency. 33 indicates the 30 frames in the second.
Cappreview (capwnd, true );
Capsetcallbackonframe (capwnd, framecallback );
Initcaptureparams;
The last sentence is to set the video compression parameters, which will be described later. Capsetcallbackonframe (capwnd, framecallback) is a callback function for setting the video data for each frame. We can transmit the video data during the callback over the network, this achieves the core of video chat.
The callback function format is as follows:
Function framecallback (hwnd: hwnd; lpvhdr: pvideohdr): DWORD; stdcall;
VaR
Bkeyframe: bool;
Buf: pbyte;
Videodata: tvideo_data;
Outactsize: DWORD;
I: integer;
Begin
Outactsize: = BMP ininfo. bmiheader. bisizeimage;
Buf: = icseqcompressframe (@ capvar, 0, lpvhdr. lpdata, @ bkeyframe, @ outactsize );
// Here, outactsize indicates the size of the compressed video data.
// Form1.label3. Caption: = 'compressed size: '+ inttostr (outactsize );
// I use the UDP mode. Due to the UDP packet size limit, I control the data size. If the data exceeds the limit, frame loss occurs.
If (outactsize <= sizeof (videodata. BUF) then
Begin
Zeromemory (@ videodata, sizeof (tvideo_data ));
// Whether the record is a key frame
Videodata. bkeyframe: = bkeyframe;
Copymemory (@ videodata. Buf, Buf, outactsize );
Videodata. samplenum: = samplenum; // we can record the number of frames for extension.
Videodata. bufsize: = outactsize; // record the data size, which is used for transmission
// Here, you can use your favorite network to transmit video data,
// Cc1.sendbuffer (videodata, sizeof (tvideo_data)-sendbuffersize + outactsize );
INC (samplenum );
End;
Result: = 0;
End;
The pvideohdr type is defined in VFW:
Tvideohdr = record
Lpdata: pbyte; // video data buffer
Dwbufferlength: DWORD; // data buffer Length
Dwbytesused: DWORD;
Dwtimecaptured: DWORD; // time length (MS)
Dwuser: DWORD;
Dwflags: DWORD;
Dwreserved: array [0 .. 3] of DWORD;
End;
In the callback function, only the video function icseqcompressframe is used. You can see that this function has passed in the capvar parameter. this parameter is generated by the initcaptureparams function we saw earlier. The following code is used to implement this function:
Function initcaptureparams: Boolean;
Begin
Result: = false;
// Initialize capvar
Zeromemory (@ capvar, sizeof (tcompvars ));
Capvar. cbsize: = sizeof (capvar); // you must specify the cbsize as the size of the tcompvars structure.
Capvar. dwflags: = icmf_compvars_valid;
Capvar. cbstate: = 0;
// Fcchandler indicates the compression encoding type. We use the DivX encoder.
Capvar. fcchandler: = mmiofourcc ('D', 'I', 'V', 'x ');
Capvar. fcctype: = ictype_video;
// Formally connect the Encoder
Capvar. HIC: = icopen (ictype_video, capvar. fcchandler, icmode_compress );
If (capvar. HIC> 0) then
Begin
Outformatsize: = iccompressgetformatsize (capvar. Hic, @ BMP ininfo. bmiheader );
Getmem (bmpoutinfo, outformatsize );
// We can obtain the compressed and outgoing image header bmpoutinfo through the ininfo obtained during initialization.
Iccompressgetformat (capvar. Hic, @ BMP ininfo. bmiheader, @ bmpoutinfo ^. bmiheader );
Outbuffersize: = iccompressgetsize (capvar. Hic, @ BMP ininfo. bmiheader, @ bmpoutinfo ^. bmiheader );
Icseqcompressframestart (@ capvar, @ BMP ininfo );
Result: = true;
End
Else
Begin
Showmsg ('Install the video compression encoder First ');
Exit;
End
End;
After use, if you want to disconnect the encoder, it is called as follows:
If (capvar. HIC> 0) then
Begin
Icseqcompressframeend (@ capvar );
Iccompressorfree (@ capvar );
Icclose (capvar. HIC );
End;
As a result, the server's camera data capture connection is complete, so what about extracting video data from the client? This problem is certainly solved through the IC function, but you must first transmit the bmpoutinfo and capvar on the server to the client.
Next, let's take a look at the client's image display process:
// Connect the Video Encoder with the obtained capvar.
Capvar. HIC: = icopen (capvar. fcctype, capvar. fcchandler, icmode_decompress );
// After the operation is successful, use the bmpoutinfo sent from the server as the BMP ininfo of the client to obtain the image header bmpoutinfo.
Outformatsize: = icdecompressgetformatsize (capvar. Hic, @ BMP ininfo. bmiheader );
Getmem (bmpoutinfo, outformatsize );
Zeromemory (bmpoutinfo, outformatsize );
Icdecompressgetformat (capvar. Hic, @ BMP ininfo. bmiheader, @ bmpoutinfo ^. bmiheader );
Outbuffersize: = bmpoutinfo ^. bmiheader. bisizeimage;
Getmem (outbuffer, outbuffersize );
Zeromemory (outbuffer, outbuffersize );
Icdecompressbegin (capvar. Hic, @ BMP ininfo. bmiheader, @ bmpoutinfo ^. bmiheader );
Finally, it is the decompression process of video data.
If video_data.bkeyframe then
Result: = icdecompress (capvar. Hic, 0, @ BMP ininfo, @ video_data.buf,
@ Bmpoutinfo. bmiheader, outbuffer)
Else
Result: = icdecompress (capvar. Hic, icdecompress_notkeyframe, @ BMP ininfo, @ video_data.buf,
@ Bmpoutinfo. bmiheader, outbuffer );
If (result = icerr_ OK) then
Begin
Setdibitstodevice (canvas. Handle, bmp tmp. Width, bmp tmp. Height, 0, bmpoutinfo ^. bmiheader. biheight,
Outbuffer, bmpoutinfo ^, dib_rgb_colors );
End;
In this way, the transmitted video data is directly painted on canvas. Handle.
I also forgot how to disable the camera on the server. I can call capdriverdisconnect (capwnd.
The full text is over. jasonke also needs to say that this method uses the old functions of Microsoft, but it is very easy to implement. I believe that all APIs can be developed, another method, of course, is to use DirectShow. You need to develop the filter. To understand Several Interfaces of Microsoft, you can look at the dshownetwork example. This method is also implemented by many c ++ brothers. Think about the powerful function of DirectShow. Haha.