servfox源碼分析

一.文件目錄結構如下圖:

二.視頻設備自定義的數據結構
------------------------------------------
struct vdIn {
    int fd;
    char *videodevice ;                 //視頻設備文件路徑,如/dev/video0
    struct video_mmap vmmap;//內存映射
    struct video_capability videocap;
    int mmapsize;
    struct video_mbuf videombuf;
    struct video_picture videopict;
    struct video_window videowin;
    struct video_channel videochan;
    struct video_param videoparam;        
    int cameratype ;
    char *cameraname;
    char bridge[9];
    int sizenative; // available size in jpeg
    int sizeothers;    // others palette
    int palette; // available palette
    int norme ; // set spca506 usb video grabber
    int channel ; // set spca506 usb video grabber
    int grabMethod ;                      //抓圖方法
    unsigned char *pFramebuffer; //內存映射後指向數據指針
    unsigned char *ptframe[4]; //frameconverse以後指向將要發送到網絡的數據指針
    int framelock[4];//佔用與否標識
    pthread_mutex_t grabmutex;
    int framesizeIn ;//在init中確定
    volatile int frame_cour; //目前要傳輸到網絡的frame
    int bppIn;//depth
    int hdrwidth;                //圖像寬的高度
    int hdrheight;
    int formatIn; //palette  //圖像格式
    int signalquit;    
    };
------------------------------------------
三.在linux內核源代碼中的/include/linux/videodev.h中定義了各個format格式的值
從main函數出發,跟蹤int format
-------------------------
1在server.c中的main 函數中:
int format = VIDEO_PALETTE_JPEG;
-------------------------
2 根據輸入的參數識別用戶要求的format
-------------------------
for (i = 1; i < argc; i++)
{
/* skip bad arguments */
if (argv[i] == NULL || *argv[i] == 0 || *argv[i] != '-')
    {
     continue;
    }
if (strcmp (argv[i], "-d") == 0)
    {
     if (i + 1 >= argc)
     {
     if(debug) printf ("No parameter specified with -d, aborting./n");
     exit (1);
     }
     videodevice = strdup (argv[i + 1]);
    }
if (strcmp (argv[i], "-g") == 0)
    {
     /* Ask for read instead default mmap */
     grabmethod = 0;
    }

    if (strcmp (argv[i], "-s") == 0) {
            if (i + 1 >= argc) {
                if(debug) printf ("No parameter specified with -s, aborting./n");
                exit (1);
            }

            sizestring = strdup (argv[i + 1]);

            width = strtoul (sizestring, &separateur, 10);
            if (*separateur != 'x') {
                if(debug) printf ("Error in size use -s widthxheight /n");
                exit (1);
            } else {
                ++separateur;
                height =
                    strtoul (separateur, &separateur, 10);
                if (*separateur != 0)
                    if(debug) printf ("hmm.. dont like that!! trying this height /n");
                if(debug) printf (" size width: %d height: %d /n",
                    width, height);
            }
    }
    if (strcmp (argv[i], "-w") == 0) {
            if (i + 1 >= argc) {
                if(debug) printf ("No parameter specified with -w, aborting./n");
                exit (1);
            }
            serverport = (unsigned short) atoi (argv[i + 1]);
            if (serverport < 1024 ){
            if(debug) printf ("Port should be between 1024 to 65536 set default 7070 !./n");
            serverport = 7070;
            }
    }

if (strcmp (argv[i], "-h") == 0)
    {
     printf ("usage: cdse [-h -d -g ] /n");
     printf ("-h    print this message /n");
     printf ("-d    /dev/videoX use videoX device/n");
     printf ("-g    use read method for grab instead mmap /n");

     printf ("-s    widthxheight use specified input size /n");
     printf ("-w    port server port /n");

     exit (0);
    }
}
三. 初始化設備的時候

1.init_videoIn (&videoIn, videodevice, width, height, format,grabmethod)

代碼如下:
***********************************************
/****************************************************************************
*            Public
****************************************************************************/
int
init_videoIn (struct vdIn *vd, char *device, int width, int height,
     int format, int grabmethod)
{
int err = -1;
int i;
if (vd == NULL || device == NULL)
return -1;
if (width == 0 || height == 0)
return -1;
if(grabmethod < 0 || grabmethod > 1)
    grabmethod = 1; //read by default;
    // check format
vd->videodevice = NULL;
vd->cameraname = NULL;
vd->videodevice = NULL;
vd->videodevice = (char *) realloc (vd->videodevice, 16);
vd->cameraname = (char *) realloc (vd->cameraname, 32);
snprintf (vd->videodevice, 12, "%s", device);
if(debug) printf("video %s /n",vd->videodevice);
memset (vd->cameraname, 0, sizeof (vd->cameraname));
memset(vd->bridge, 0, sizeof(vd->bridge));
vd->signalquit = 1;
vd->hdrwidth = width;
vd->hdrheight = height;
/* compute the max frame size */
vd->formatIn = format;
vd->bppIn = GetDepth (vd->formatIn);//根據format值確定vd.depth
vd->grabMethod = grabmethod;        //mmap or read
vd->pFramebuffer = NULL;
/* init and check all setting */
err = init_v4l (vd);
/* allocate the 4 frames output buffer */

for (i = 0; i < OUTFRMNUMB; i++)
{
vd->ptframe[i] = NULL;
vd->ptframe[i] =
    (unsigned char *) realloc (vd->ptframe[i], sizeof(struct frame_t) + (size_t) vd->framesizeIn );
vd->framelock[i] = 0;
}
vd->frame_cour = 0;


pthread_mutex_init (&vd->grabmutex, NULL);
return err;
}

***********************************************
2. static int init_v4l (struct vdIn *vd);
***********************************************
init_v4l (struct vdIn *vd)
{
int f;
int erreur = 0;
if ((vd->fd = open (vd->videodevice, O_RDWR)) == -1)
exit_fatal ("ERROR opening V4L interface");

if (ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap)) == -1)
exit_fatal ("Couldn't get videodevice capability");

if(debug) printf ("Camera found: %s /n", vd->videocap.name);
snprintf (vd->cameraname, 32, "%s", vd->videocap.name);

erreur = GetVideoPict (vd);
if (ioctl (vd->fd, VIDIOCGCHAN, &vd->videochan) == -1)
{
if(debug) printf ("Hmm did not support Video_channel/n");
vd->cameratype = UNOW;
}
else
{
if (vd->videochan.name){
if(debug) printf ("Bridge found: %s /n", vd->videochan.name);
snprintf (vd->bridge, 9, "%s", vd->videochan.name);
vd->cameratype = GetStreamId (vd->videochan.name);
spcaPrintParam (vd->fd,&vd->videoparam);
}
else
{
if(debug) printf ("Bridge not found not a spca5xx Webcam Probing the hardware !!/n");
vd->cameratype = UNOW;
}
}
/* Only jpeg webcam allowed */
if(vd->cameratype != JPEG) {
    exit_fatal ("Not a JPEG webcam sorry Abort !");
}
if(debug) printf ("StreamId: %d Camera/n", vd->cameratype);
/* probe all available palette and size Not need on the FOX always jpeg
if (probePalette(vd ) < 0) {
     exit_fatal ("could't probe video palette Abort !");
     }
if (probeSize(vd ) < 0) {
     exit_fatal ("could't probe video size Abort !");
     }

     err = check_palettesize(vd);
     if(debug) printf (" Format asked %d check %d/n",vd->formatIn, err);
*/         
vd->videopict.palette = vd->formatIn;
vd->videopict.depth = GetDepth (vd->formatIn);
vd->bppIn = GetDepth (vd->formatIn);

//vd->framesizeIn = (vd->hdrwidth * vd->hdrheight * vd->bppIn) >> 3; // here alloc the output ringbuffer
vd->framesizeIn = (vd->hdrwidth * vd->hdrheight >> 2 ); // here alloc the output ringbuffer jpeg only
erreur = SetVideoPict (vd);
erreur = GetVideoPict (vd);
if (vd->formatIn != vd->videopict.palette ||
vd->bppIn != vd->videopict.depth)
exit_fatal ("could't set video palette Abort !");
if (erreur < 0)
exit_fatal ("could't set video palette Abort !");

if (vd->grabMethod)
{
if(debug) printf (" grabbing method default MMAP asked /n");
// MMAP VIDEO acquisition
memset (&(vd->videombuf), 0, sizeof (vd->videombuf));
if (ioctl (vd->fd, VIDIOCGMBUF, &(vd->videombuf)) < 0)
    {
     perror (" init VIDIOCGMBUF FAILED/n");
    }
if(debug) printf ("VIDIOCGMBUF size %d frames %d offets[0]=%d offsets[1]=%d/n",
     vd->videombuf.size, vd->videombuf.frames,
     vd->videombuf.offsets[0], vd->videombuf.offsets[1]);
vd->pFramebuffer =
    (unsigned char *) mmap (0, vd->videombuf.size, PROT_READ | PROT_WRITE,
                MAP_SHARED, vd->fd, 0);
vd->mmapsize = vd->videombuf.size;
vd->vmmap.height = vd->hdrheight;
vd->vmmap.width = vd->hdrwidth;
vd->vmmap.format = vd->formatIn;
for (f = 0; f < vd->videombuf.frames; f++)
    {
     vd->vmmap.frame = f;
     if (ioctl (vd->fd, VIDIOCMCAPTURE, &(vd->vmmap)))
     {
     perror ("cmcapture");
     }
    }
vd->vmmap.frame = 0;
}
else
{
/* read method */
/* allocate the read buffer */
vd->pFramebuffer =
    (unsigned char *) realloc (vd->pFramebuffer, (size_t) vd->framesizeIn);
if(debug) printf (" grabbing method READ asked /n");
if (ioctl (vd->fd, VIDIOCGWIN, &(vd->videowin)) < 0)
    perror ("VIDIOCGWIN failed /n");
vd->videowin.height = vd->hdrheight;
vd->videowin.width = vd->hdrwidth;
if (ioctl (vd->fd, VIDIOCSWIN, &(vd->videowin)) < 0)
    perror ("VIDIOCSWIN failed /n");
if(debug) printf ("VIDIOCSWIN height %d width %d /n",
     vd->videowin.height, vd->videowin.width);
}
vd->frame_cour = 0;
return erreur;
}

***********************************************
分析如下:
其中,probePalette(vd )
//將五個palette類型傳到video_picture數據結構裏面,set之後在get一次,比較前後palette值,如果兩者一致,說明該palette類型爲可用

其中probeSize(vd )
//同上理,將7個width*height結構傳到video_window裏面,察看是否可用

check_palettesize(vd)
//首先轉換大小int needsize = convertsize(vd->hdrwidth,vd->hdrheight),
convertsize(),根據w*h返回7個類型:VGA,PAL,SIF,CIF,QPAL,QSIF,QCIF,上述七個宏定義在spcav4l.h中:
/* ITU-R-BT.601 PAL/NTSC */
#define MASQ 1
#define VGA MASQ
#define PAL (MASQ << 1)
#define SIF (MASQ << 2)
#define CIF (MASQ << 3)
#define QPAL (MASQ << 4)
#define QSIF (MASQ << 5)
#define QCIF (MASQ << 6)
####################################
int needsize的值應該爲這七個值之一
int needpalette=0,needpalette = checkpalette(vd),

在checkpalette(vd)中,convertpalette(vd->formatIn); see is the palette available?

根據vd->formatIn返回jpeg yuv420p rbg24 rgb565 and rgb32

#define JPG MASQ //JPEG 1
#define YUV420P (MASQ << 1)
#define RGB24 (MASQ << 2)
#define RGB565 (MASQ << 3)
#define RGB32 (MASQ << 4)

根據needpalette的值察看是否available?
將測試結果寫入函數palette = paletteconvert( needpalette),
if (palette),
對palette的返回將它賦值到vd->vmmap.height = vd->hdrheight;

vd->vmmap.width = vd->hdrwidth;
vd->vmmap.format = palette;
設置VIDIOCMCAPTURE,測試一下是否可以採集,ok的話vd->formatIn = palette;
根據needsize和vd.sizeother察看是否還有別的palettesize可以支持,
test is palette and size are available otherwhise return the next available palette and size palette is set by preference order jpeg yuv420p rbg24 rgb565 and rgb32

其中:
vd->videopict.palette = vd->formatIn; 設置video_picture數據結構
vd->videopict.depth = GetDepth (vd->formatIn);
vd->bppIn = GetDepth (vd->formatIn);

其中:
vd->framesizeIn = (vd->hdrwidth * vd->hdrheight * vd->bppIn) >> 3; 設置framesize大小
erreur = SetVideoPict (vd);
erreur = GetVideoPict (vd);
if (vd->formatIn != vd->videopict.palette ||
vd->bppIn != vd->videopict.depth)
exit_fatal ("could't set video palette Abort !");
if (erreur < 0)
exit_fatal ("could't set video palette Abort !");
其中:
開始採集兩個frame的視頻數據,指向數據的指針爲pFramebuffer

***********************************************
四.打開採集視頻線程 pthread_create (&w1, NULL, (void *) grab, NULL),進入grab函數

1 vd->vmmap.format = vd->formatIn;
VIDIOCSYNC:開始check在init時候採集的數據是否已經完成

2 採集完成,進行jpeg壓縮處理,裏面大有文章
jpegsize= convertframe(vd->ptframe[vd->frame_cour]+ sizeof(struct frame_t),
vd->pFramebuffer + vd->videombuf.offsets[vd->vmmap.frame],
vd->hdrwidth,vd->hdrheight,vd->formatIn,qualite);

在 int convertframe(unsigned char *dst,unsigned char *src, int width,int height, int formatIn, int qualite)中
switch (formatIn)根據不同的palette值做不同的數據壓縮處理,返回壓縮後的數據大小值,如果是JPEG格式,意味着硬件採集近來的數據已經做了壓縮,不需要再用軟件進行壓縮處理,而除了VIDEO_PALETTE_JPEG以外的palette,都需要進行encode,函數爲UINT32 encode_image (UINT8 * input_ptr, UINT8 * output_ptr,UINT32 quality_factor, UINT32 image_format,UINT32 image_width, UINT32 image_height),UINT32 image_format爲輸入的palette,壓縮使用huffman編碼,詳細代碼在huffman.c和encode.c中

五. 打開數據遠程網絡傳輸線程,在accept阻塞處代開線程pthread_create(&server_th, NULL, (void *)service, &new_sock),
首先在連接處讀取frame_t message數據結構的內容,read(sock,(unsigned char*)&message,sizeof(struct client_t)),
根據message的內容決定如何傳輸,下一步做循環發送,根據frame_lock和frame_cour發送沒有被佔用的compressed frame
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章