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

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sfrysh/article/details/5623247
个人分类: V4L
上一篇linux socket 详解
下一篇snprintf函数用法
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭