搞了一段时间的嵌入式网络视频采集与传输,基本上在服务器端采集视频用的是servfox程序包,它可以用arm-linux-gcc编译后移植到开发板上,我现在一直在做这方面的工作,用的是S3C2410的板子,这个开源程序十分不错,觉得有必要深入理解和学习一下它的源程序,网上一般没有对它的详细说明,只是简单介绍了它怎么用的,就如我当初刚开始学习嵌入式时一样看不懂这个程序,现在对其各个代码作个详细的解释,以备后忘,也希望对新手有所帮助。

       servfox主要有server.c,spcav4l.c ,spcav4l.h,utils.c ,utils.h,tcputils.c ,tcputils.h,spcaframe.h,Makefile,Makefile.fox这几个文件, arm-linux-gcc编译后可以生成servfox可执行文件,可以移植到ARM板上作为服务器端视频采集程序用。我们从server.c代码开始。


1. server.c

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <errno.h>
#include<netdb.h>
#include<sys/types.h>
#include<sys/fcntl.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include <net/if_arp.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <netinet/ether.h>
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
//#include <signal.h>

#include "spcaframe.h"
#include "spcav4l.h"
#include "utils.h"
#include "tcputils.h"   
#include "version.h"
 
static int debug = 0;
void grab (void);
void service (void *ir);
void sigchld_handler(int s);
struct vdIn videoIn;

int main (int argc, char *argv[])
{

  char *videodevice = NULL;
  int grabmethod = 1;
  int format = VIDEO_PALETTE_JPEG;
  int width = 352;
  int height = 288;

  char *separateur;
  char *sizestring = NULL;

  int i;
  int serv_sock,new_sock;
  pthread_t w1;
  pthread_t server_th;
  int sin_size;
  unsigned short serverport = 7070;
  struct sockaddr_in their_addr;
  struct sigaction sa;

    int ret;
  
/*********************************************命令行输入参数设置************************************************/

        /********************************************************************************************

          命令行参数应该这个样子的:./servfox -g -d /dev/video0 -s 640x480 -w 7070

         *********************************************************************************************/
  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)

       /********************************************************************************************

          -d 参数用于设置输入视频采集设备。

       *********************************************************************************************/


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

      /********************************************************************************************

             

            函数原型:extern char *strdup(char *str)

         参数说明:str待复制的字符串。 
         所在库名:#include <string.h>
         函数功能:实现复制字符串str。
         返回说明:返回复制的新字符串的指针,复制失败返回NULL,
所需空间由malloc()分配且可以由free()释放。

          strdup()主要是拷贝字符串 str 的一个副本,由函数返回值返回, 函数返回值是一个字符型指针,它指向 字符串 str 副本的地址空间, 这个副本有自己的内存空间, 是由malloc()自动分配的, str 不相干。

       执行完这句后, char *videodevice就指向 argv[i + 1]所表示的字符串,即 /dev/video0

        与 strcpy 区别:
        
strdup不是标准的c函数, strcpy是标准的c函数

         strdup可以直接把要复制的内容复制给没有初始化的指针,因为它会自动分配空间给目的指针
         strcpy的目的指针一定是已经分配内存的指针
        

	   strcpy
原型:
extern char *strcpy(char *dest,char *src);
用法:#include <string.h>
功能:把src所指由NULL结束的字符串复制到dest所指的数组中。
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。
    

        *********************************************************************************************/


    }
      if (strcmp (argv[i], "-g") == 0)
    {
      /* Ask for read instead default  mmap */
      grabmethod = 0;
    }
      
/********************************************************************************************

          -g 参数用于读取采集到的视频的方式,用read方式而非mmap方式。

       *********************************************************************************************/

 


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

          -s 参数用于设置视频图像帧的大小,如 640x480

       *********************************************************************************************/


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

            width = strtoul (sizestring, &separateur, 10);
       
/********************************************************************************************

             strtoul(将字符串转换成无符号长整型数)

             头文件:#include<stdlib.h>

 

            unsigned long strtoul( const char *nptr, char **endptr, int base )

      把输入的字符串转换成数字。
      参数一 字符串的起始地址。
      参数二 返回字符串有效数字的结尾地址。如 123456ff789 则返回数字6的地址。实际上返回的应该是第一个f的地址
      参数三 转化基数.

 

             函数说明: strtol ()会将参数nptr字符串根据参数base来转换成长整型数。参数base范围从2至36,或0。参数base代表采用的进制方式 ,如base值为10则采用10进制(字符串以10进制表示) ,若base值为16则采用16进制(字符串以16进制表示)。当base值为0时则是采用10进制做转换,但遇到如''0x''前置字符则会使用16进制做转换。一开始strtol ()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串时(''/0'')结束转换,并将结果返回若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。
返回值:    返回转换后的长整型数,否则返回ERANGE并将错误代码存入errno中。

           若参数endptr不为NULL,则会将遇到不合条件而终止的nptr中的字符指针由endptr返回。
           参数二 返回字符串有效数字的结尾地址。如 123456ff789 则返回数字6的地址。实际上返回的应该是第一个f的地址

          char *sizestring 指向 argv[i + 1]所表示的字符串,即 640x480

          strtoul (sizestring, &separateur, 10)中遇到x结束转换,并返回结果 640给width

       *********************************************************************************************/

            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);
            }

      /********************************************************************************************

          -w参数用于设置端口。

       *********************************************************************************************/


            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);
    }
    }

 

/********************************* main code主程序开始位置*************************************************/      
  printf(" %s /n",version);
  if (videodevice == NULL || *videodevice == 0)
    {
      videodevice = "/dev/video0";
    }

  memset (&videoIn, 0, sizeof (struct vdIn));

 if (init_videoIn(&videoIn, videodevice, width, height, format,grabmethod) != 0)  跟踪进入 init_videoIn()
    
    if(debug) printf (" damned encore rate !!/n");   
         /*****************************************************************************************
                  spcav4l.c中:
                  int init_videoIn (struct vdIn *vd, char *device, int width, int height,
                  int format, int grabmethod)
                  struct vdIn videoIn;  //在spcav4l.h中定义
                  videodevice = "/dev/video0";
                 int width = 352;
                 int height = 288;
                 int format = VIDEO_PALETTE_JPEG;
                 int grabmethod = 1;

                请进入下面的 跟踪进入 init_videoIn() ,对其进 行详细说明,我们来看看它里面做了些什么事情。
        ***********************************************************************************************/
        main()函数还没有完,请看嵌入式网络视频采集源程序servfox解析02

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐