Mjpeg-streamer源码分析(二)

来源:互联网 发布:如何查找淘宝模特名字 编辑:程序博客网 时间:2024/05/20 05:09

                                         input_uvc.c源码分析
-----------------------------------------------------------------------------------------------------------------------
重要函数解析:
 char *strtok_r(char *str, const char *delim, char **saveptr);
 
与线程相关的函数:
 线程可以安排它推出时需要调用的函数,这与进程可以用atexit函数安排进程退出时需要调用的函数是类似的.
 这样的函数称为线程清理处理程序,线程可以建立多个清理处理程序.处理程序记录在栈内,也就是说它们的调
 用顺序与它们的注册顺序相反
 #include <pthread.h>
 int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
 int pthread_detach(pthread_t thread);
 void pthread_cleanup_push(void (*routine)(void *),void *arg);
 void pthread_cleanup_pop(int execute);


 
-----------------------------------------------------------------------------------------------------------------------
分析input_uvc.c主要分析四个函数:
input_init() input_stop() input_run() input_cmd()
-----------------------------------------------------------------------------------------------------------------------
现在来分析一下input_init()函数:
 首先解析命令:将param->parameter_string字符串形式的命令转换为一个argv[MAX_ARGUMENTS]字符串数组;
 其次就是用getopt_long_only()解析命令;
 保留指向global全局变量的指针:
   pglobal = param->global;
 分配一个webcam的结构体:
  videoIn = malloc(sizeof(struct vdIn));
   struct vdIn {
                  int fd;
                  char *videodevice;
                  char *status;
                  char *pictName;
                  struct v4l2_capability cap;
                  struct v4l2_format fmt;
                  struct v4l2_buffer buf;
                  struct v4l2_requestbuffers rb;
                  void *mem[NB_BUFFER];
                  unsigned char *tmpbuffer;
                  unsigned char *framebuffer;
                  int isstreaming;
                  int grabmethod;
                  int width;
                  int height;
                  int fps;
                  int formatIn;
                  int formatOut;
                   int framesizeIn;
                  int signalquit;
                  int toggleAvi;
                  int getPict;
                  int rawFrameCapture;
                  /* raw frame capture */
                  unsigned int fileCounter;
                  /* raw frame stream capture */
                  unsigned int rfsFramesWritten;
                  unsigned int rfsBytesWritten;
                  /* raw stream capture */
                  FILE *captureFile;
                  unsigned int framesWritten;
                  unsigned int bytesWritten;
                  int framecount;
                  int recordstart;
                  int recordtime;
          };
 结构体成员清零:
   memset(videoIn, 0, sizeof(struct vdIn));
 显示我们设置的参数:
  IPRINT("Using V4L2 device.: %s\n", dev);
  IPRINT("Desired Resolution: %i x %i\n", width, height);
  IPRINT("Frames Per Second.: %i\n", fps);
  IPRINT("Format............: %s\n", (format==V4L2_PIX_FMT_YUYV)?"YUV":"MJPEG");
  if ( format == V4L2_PIX_FMT_YUYV )
   IPRINT("JPEG Quality......: %d\n", gquality);
 初始化videoIn结构体:
  init_videoIn(videoIn, dev, width, height, fps, format, 1);
   int init_videoIn(struct vdIn *vd, char *device, int width, int height, int fps, int format, int grabmethod)
    {
      if (vd == NULL || device == NULL)
        return -1;
      if (width == 0 || height == 0)
        return -1;
      if (grabmethod < 0 || grabmethod > 1)
        grabmethod = 1;  //mmap by default;
      vd->videodevice = NULL;
      vd->status = NULL;
      vd->pictName = NULL;
      vd->videodevice = (char *) calloc (1, 16 * sizeof (char)); /* calloc分配并初始化为零 */
      vd->status = (char *) calloc (1, 100 * sizeof (char));
      vd->pictName = (char *) calloc (1, 80 * sizeof (char));
      snprintf (vd->videodevice, 12, "%s", device);
      vd->toggleAvi = 0;
      vd->getPict = 0;
      vd->signalquit = 1;
      vd->width = width;
      vd->height = height;
      vd->fps = fps;
      vd->formatIn = format;
      vd->grabmethod = grabmethod;
      if (init_v4l2 (vd) < 0) {
        fprintf (stderr, " Init v4L2 failed !! exit fatal \n");
        goto error;;
      }
      /* alloc a temp buffer to reconstruct the pict */
      vd->framesizeIn = (vd->width * vd->height << 1);
      switch (vd->formatIn) {
      case V4L2_PIX_FMT_MJPEG:
        vd->tmpbuffer = (unsigned char *) calloc(1, (size_t) vd->framesizeIn);
        if (!vd->tmpbuffer)
          goto error;
        vd->framebuffer =
            (unsigned char *) calloc(1, (size_t) vd->width * (vd->height + 8) * 2);
        break;
      case V4L2_PIX_FMT_YUYV:
        vd->framebuffer = (unsigned char *) calloc(1, (size_t) vd->framesizeIn);
        break;
      default:
        fprintf(stderr, " should never arrive exit fatal !!\n");
        goto error;
        break;
      }
      if (!vd->framebuffer)
        goto error;
      return 0;
    error:
      free(vd->videodevice);
      free(vd->status);
      free(vd->pictName);
      close(vd->fd);
      return -1;
    }
 对摄像头的调整:
  if (dynctrls)
   initDynCtrls(videoIn->fd);
 最后执行input_cmd函数:
   input_cmd(led, 0);
 
到此,inpu_init()函数结束,这个函数太长了~~~~~~~~~~
-----------------------------------------------------------------------------------------------------------------------
现在开始分析input_cmd()函数:
  int input_cmd(in_cmd_type cmd, int value) {
    int res=0;
    static int pan=0, tilt=0, pan_tilt_valid=-1;
    static int focus=-1;
    const int one_degree = ONE_DEGREE;
    /* certain commands do not need the mutex */
    if ( cmd != IN_CMD_RESET_PAN_TILT_NO_MUTEX )
      pthread_mutex_lock( &controls_mutex );
    switch (cmd) {
      case IN_CMD_HELLO:
        fprintf(stderr, "Hello from input plugin\n");
        break;
      case IN_CMD_RESET:
        DBG("about to reset all image controls to defaults\n");
        res = v4l2ResetControl(videoIn, V4L2_CID_BRIGHTNESS);
        res |= v4l2ResetControl(videoIn, V4L2_CID_CONTRAST);
        res |= v4l2ResetControl(videoIn, V4L2_CID_SATURATION);
        res |= v4l2ResetControl(videoIn, V4L2_CID_GAIN);
        if ( res != 0 ) res = -1;
        break;
      case IN_CMD_RESET_PAN_TILT:
      case IN_CMD_RESET_PAN_TILT_NO_MUTEX:
        DBG("about to set pan/tilt to default position\n");
        if ( uvcPanTilt(videoIn->fd, 0, 0, 3) != 0 ) {
          res = -1;
          break;
        }
        pan_tilt_valid = 1;
        pan = tilt = 0;
        sleep(4);
        break;
      case IN_CMD_PAN_SET:
        DBG("set pan to %d degrees\n", value);
        /* in order to calculate absolute positions we must check for initialized values */
        if ( pan_tilt_valid != 1 ) {
          if ( input_cmd(IN_CMD_RESET_PAN_TILT_NO_MUTEX, 0) == -1 ) {
            res = -1;
            break;
          }
        }
        /* limit pan-value to min and max, multiply it with constant "one_degree" */
        value = MIN(MAX(value*one_degree, MIN_PAN), MAX_PAN);
        /* calculate the relative degrees to move to the desired absolute pan-value */
        if( (res = value - pan) == 0 ) {
          /* do not move if this would mean to move by 0 degrees */
          res = pan/one_degree;
          break;
        }
        /* move it */
        pan = value;
        uvcPanTilt(videoIn->fd, res, 0, 0);
        res = pan/one_degree;
        DBG("pan: %d\n", pan);
        break;
      case IN_CMD_PAN_PLUS:
        DBG("pan +\n");
        if ( pan_tilt_valid != 1 ) {
          if ( input_cmd(IN_CMD_RESET_PAN_TILT_NO_MUTEX, 0) == -1 ) {
            res = -1;
            break;
          }
        }
        if ( (MAX_PAN) >= (pan+MIN_RES) ) {
          pan += MIN_RES;
          uvcPanTilt(videoIn->fd, MIN_RES, 0, 0);
        }
        res = pan/one_degree;
        DBG("pan: %d\n", pan);
        break;
      case IN_CMD_PAN_MINUS:
        DBG("pan -\n");
        if ( pan_tilt_valid != 1 ) {
          if ( input_cmd(IN_CMD_RESET_PAN_TILT_NO_MUTEX, 0) == -1 ) {
            res = -1;
            break;
          }
        }
        if ( (MIN_PAN) <= (pan-MIN_RES) ) {
          pan -= MIN_RES;
          uvcPanTilt(videoIn->fd, -MIN_RES, 0, 0);
        }
        res = pan/one_degree;
        DBG("pan: %d\n", pan);
        break;
      case IN_CMD_TILT_SET:
        DBG("set tilt to %d degrees\n", value);
        if ( pan_tilt_valid != 1 ) {
          if ( input_cmd(IN_CMD_RESET_PAN_TILT_NO_MUTEX, 0) == -1 ) {
            res = -1;
            break;
          }
        }
        /* limit pan-value to min and max, multiply it with constant "one_degree" */
        value = MIN(MAX(value*one_degree, MIN_TILT), MAX_TILT);
        /* calculate the relative degrees to move to the desired absolute pan-value */
        if( (res = value - tilt) == 0 ) {
          /* do not move if this would mean to move by 0 degrees */
          res = tilt/one_degree;
          break;
        }
        /* move it */
        tilt = value;
        uvcPanTilt(videoIn->fd, 0, res, 0);
        res = tilt/one_degree;
        DBG("tilt: %d\n", tilt);
        break;
      case IN_CMD_TILT_PLUS:
        DBG("tilt +\n");
        if ( pan_tilt_valid != 1 ) {
          if ( input_cmd(IN_CMD_RESET_PAN_TILT_NO_MUTEX, 0) == -1 ) {
            res = -1;
            break;
          }
        }
        if ( (MAX_TILT) >= (tilt+MIN_RES) ) {
          tilt += MIN_RES;
          uvcPanTilt(videoIn->fd, 0, MIN_RES, 0);
        }
        res = tilt/one_degree;
        DBG("tilt: %d\n", tilt);
        break;
      case IN_CMD_TILT_MINUS:
        DBG("tilt -\n");
        if ( pan_tilt_valid != 1 ) {
          if ( input_cmd(IN_CMD_RESET_PAN_TILT_NO_MUTEX, 0) == -1 ) {
            res = -1;
            break;
          }
        }
        if ( (MIN_TILT) <= (tilt-MIN_RES) ) {
          tilt -= MIN_RES;
          uvcPanTilt(videoIn->fd, 0, -MIN_RES, 0);
        }
        res = tilt/one_degree;
        DBG("tilt: %d\n", tilt);
        break;
      case IN_CMD_SATURATION_PLUS:
        DBG("saturation + (%d)\n", v4l2GetControl (videoIn, V4L2_CID_SATURATION));
        res = v4l2UpControl(videoIn, V4L2_CID_SATURATION);
        break;
      case IN_CMD_SATURATION_MINUS:
        DBG("saturation - (%d)\n", v4l2GetControl (videoIn, V4L2_CID_SATURATION));
        res = v4l2DownControl(videoIn, V4L2_CID_SATURATION);
        break;
      case IN_CMD_CONTRAST_PLUS:
        DBG("contrast + (%d)\n", v4l2GetControl (videoIn, V4L2_CID_CONTRAST));
        res = v4l2UpControl(videoIn, V4L2_CID_CONTRAST);
        break;
      case IN_CMD_CONTRAST_MINUS:
        DBG("contrast - (%d)\n", v4l2GetControl (videoIn, V4L2_CID_CONTRAST));
        res = v4l2DownControl(videoIn, V4L2_CID_CONTRAST);
        break;
      case IN_CMD_BRIGHTNESS_PLUS:
        DBG("brightness + (%d)\n", v4l2GetControl (videoIn, V4L2_CID_BRIGHTNESS));
        res = v4l2UpControl(videoIn, V4L2_CID_BRIGHTNESS);
        break;
      case IN_CMD_BRIGHTNESS_MINUS:
        DBG("brightness - (%d)\n", v4l2GetControl (videoIn, V4L2_CID_BRIGHTNESS));
        res = v4l2DownControl(videoIn, V4L2_CID_BRIGHTNESS);
        break;
      case IN_CMD_GAIN_PLUS:
        DBG("gain + (%d)\n", v4l2GetControl (videoIn, V4L2_CID_GAIN));
        res = v4l2UpControl(videoIn, V4L2_CID_GAIN);
        break;
      case IN_CMD_GAIN_MINUS:
        DBG("gain - (%d)\n", v4l2GetControl (videoIn, V4L2_CID_GAIN));
        res = v4l2DownControl(videoIn, V4L2_CID_GAIN);
        break;
      case IN_CMD_FOCUS_PLUS:
        DBG("focus + (%d)\n", focus);
        value=MIN(MAX(focus+10,0),255);
        if ( (res = v4l2SetControl(videoIn, V4L2_CID_FOCUS_LOGITECH, value)) == 0) {
          focus = value;
        }
        res = focus;
        break;
      case IN_CMD_FOCUS_MINUS:
        DBG("focus - (%d)\n", focus);
        value=MIN(MAX(focus-10,0),255);
        if ( (res = v4l2SetControl(videoIn, V4L2_CID_FOCUS_LOGITECH, value)) == 0) {
          focus = value;
        }
        res = focus;
        break;
      case IN_CMD_FOCUS_SET:
        value=MIN(MAX(value,0),255);
        DBG("set focus to %d\n", value);
        if ( (res = v4l2SetControl(videoIn, V4L2_CID_FOCUS_LOGITECH, value)) == 0) {
          focus = value;
        }
        res = focus;
        break;
      /* switch the webcam LED permanently on */
      case IN_CMD_LED_ON:
        res = v4l2SetControl(videoIn, V4L2_CID_LED1_MODE_LOGITECH, 1);
      break;
      /* switch the webcam LED permanently off */
      case IN_CMD_LED_OFF:
        res = v4l2SetControl(videoIn, V4L2_CID_LED1_MODE_LOGITECH, 0);
      break;
      /* switch the webcam LED on if streaming, off if not streaming */
      case IN_CMD_LED_AUTO:
        res = v4l2SetControl(videoIn, V4L2_CID_LED1_MODE_LOGITECH, 3);
      break;
      /* let the webcam LED blink at a given hardcoded intervall */
      case IN_CMD_LED_BLINK:
        res = v4l2SetControl(videoIn, V4L2_CID_LED1_MODE_LOGITECH, 2);
        res = v4l2SetControl(videoIn, V4L2_CID_LED1_FREQUENCY_LOGITECH, 255);
      break;
      default:
        DBG("nothing matched\n");
        res = -1;
    } 
    if ( cmd != IN_CMD_RESET_PAN_TILT_NO_MUTEX )
      pthread_mutex_unlock( &controls_mutex );
    return res;
  }
  
 其中用到了v4l2ucv.c中的函数:
   int v4l2SetControl(struct vdIn *vd, int control, int value) {
     struct v4l2_control control_s;
     struct v4l2_queryctrl queryctrl;
     int min, max, step, val_def;
     int err;
   
     if (isv4l2Control(vd, control, &queryctrl) < 0)
       return -1;
   
     min = queryctrl.minimum;
     max = queryctrl.maximum;
     step = queryctrl.step;
     val_def = queryctrl.default_value;
   
     if ((value >= min) && (value <= max)) {
       control_s.id = control;
       control_s.value = value;
       if ((err = ioctl(vd->fd, VIDIOC_S_CTRL, &control_s)) < 0) {
         return -1;
       }
     }
   
     return 0;
   }
-----------------------------------------------------------------------------------------------------------------------
好,现在来分析input_run()函数:  哈哈,这个函数最简单~~~~~~~~~
 int input_run(void) {
   pglobal->buf = malloc(videoIn->framesizeIn);  /* 为帧缓存分配内存 */
   if (pglobal->buf == NULL) {
     fprintf(stderr, "could not allocate memory\n");
     exit(EXIT_FAILURE);
   }
   pthread_create(&cam, 0, cam_thread, NULL);  /* 创建cam线程 */
   pthread_detach(cam);     /* 将线程与父线程分离 */
   return 0;
 }
-----------------------------------------------------------------------------------------------------------------------
cma_thread()函数中用到的几个函数:
 int uvcGrab(struct vdIn *vd)    /* 抓取函数 */
 {
 #define HEADERFRAME1 0xaf
   int ret;
   if (!vd->isstreaming)
     if (video_enable(vd))
       goto err;
   memset(&vd->buf, 0, sizeof(struct v4l2_buffer));
   vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
   vd->buf.memory = V4L2_MEMORY_MMAP;
   ret = ioctl(vd->fd, VIDIOC_DQBUF, &vd->buf);  /* 清除缓冲区的内容 */
   switch (vd->formatIn) {
     case V4L2_PIX_FMT_MJPEG:
       if (vd->buf.bytesused <= HEADERFRAME1) {     /* Prevent crashon empty image */
         fprintf(stderr, "Ignoring empty buffer ...\n");
         return 0;
       }
       memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);
       if (debug)
         fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);
       break;
     case V4L2_PIX_FMT_YUYV:
       if (vd->buf.bytesused > vd->framesizeIn)
         memcpy (vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->framesizeIn);
       else
         memcpy (vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->buf.bytesused);
       break;
     default:
       goto err;
     break;
   }
   ret = ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);
   if (ret < 0) {
     perror("Unable to requeue buffer");
     goto err;
   }
   return 0;
 err:
   vd->signalquit = 0;
   return -1;
 }
 
 
 
 int memcpy_picture(unsigned char *out, unsigned char *buf, int size) /* 复制jpeg格式的图片到pglobal->buf */
 {
   unsigned char *ptdeb, *ptlimit, *ptcur = buf;
   int sizein, pos=0;
   if (!is_huffman(buf)) {
     ptdeb = ptcur = buf;
     ptlimit = buf + size;
     while ((((ptcur[0] << 8) | ptcur[1]) != 0xffc0) && (ptcur < ptlimit))
       ptcur++;
     if (ptcur >= ptlimit)
         return pos;
     sizein = ptcur - ptdeb;
     memcpy(out+pos, buf, sizein); pos += sizein;
     memcpy(out+pos, dht_data, sizeof(dht_data)); pos += sizeof(dht_data);
     memcpy(out+pos, ptcur, size - sizein); pos += size-sizein;
   } else {
     memcpy(out+pos, ptcur, size); pos += size;
   }
   return pos;
 }
-----------------------------------------------------------------------------------------------------------------------
现在分析一下cma_thread()函数,这个线程很重要哦!!!!!!该函数的作用是抓取一帧的图像,并复制到全局缓冲区
 void *cam_thread( void *arg ) {
   /* set cleanup handler to cleanup allocated ressources */
   pthread_cleanup_push(cam_cleanup, NULL);  /* 注册清除处理函数cam_cleanup() */
   while( !pglobal->stop ) {
     /* grab a frame */
     if( uvcGrab(videoIn) < 0 ) {   /* 在videoIn结构体中抓取一个帧图像 */
       IPRINT("Error grabbing frames\n");
       exit(EXIT_FAILURE);
     }
     DBG("received frame of size: %d\n", videoIn->buf.bytesused);
     /*
      * Workaround for broken, corrupted frames:
      * Under low light conditions corrupted frames may get captured.
      * The good thing is such frames are quite small compared to the regular pictures.
      * For example a VGA (640x480) webcam picture is normally >= 8kByte large,
      * corrupted frames are smaller.
      */
     if ( videoIn->buf.bytesused < minimum_size ) {
       DBG("dropping too small frame, assuming it as broken\n");
       continue;
     }
     /* copy JPG picture to global buffer */
     pthread_mutex_lock( &pglobal->db );
     /*
      * If capturing in YUV mode convert to JPEG now.
      * This compression requires many CPU cycles, so try to avoid YUV format.
      * Getting JPEGs straight from the webcam, is one of the major advantages of
      * Linux-UVC compatible devices.
      */
     if (videoIn->formatIn == V4L2_PIX_FMT_YUYV) {
       DBG("compressing frame\n");
       pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality);
     }
     else {
       DBG("copying frame\n");
       pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);
     }
 #if 0
     /* motion detection can be done just by comparing the picture size, but it is not very accurate!! */
     if ( (prev_size - global->size)*(prev_size - global->size) > 4*1024*1024 ) {
         DBG("motion detected (delta: %d kB)\n", (prev_size - global->size) / 1024);
     }
     prev_size = global->size;
 #endif
     /* signal fresh_frame */
     pthread_cond_broadcast(&pglobal->db_update);
     pthread_mutex_unlock( &pglobal->db );
     DBG("waiting for next frame\n");
     /* only use usleep if the fps is below 5, otherwise the overhead is too long */
     if ( videoIn->fps < 5 ) {
       usleep(1000*1000/videoIn->fps);
     }
   }
   DBG("leaving input thread, calling cleanup function now\n");
   pthread_cleanup_pop(1);
   return NULL;
 }
-----------------------------------------------------------------------------------------------------------------------

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 跑1000米要5分钟怎么办 孩子眼睛近视加散光怎么办 在部队混的差怎么办 2岁宝宝走路踮脚怎么办 宝宝走路膝盖弯曲不直怎么办 做了蛙跳大腿疼怎么办 跳完蛙跳腿疼怎么办 腿受凉了疼怎么办偏方 鸭子步蛙跳后腿疼怎么办 戴墨镜鼻子会红怎么办 校服黑色裙子染色了怎么办 新警培训时怀孕怎么办? 大学生欠了网贷怎么办? 车侧面底盘被刮怎么办 军人家属被打没人处理怎么办 孩子字写的难看怎么办 企业k宝锁死了怎么办 建行信用卡密码忘了怎么办 主卧对着卫生间怎么办 不会画农场的画怎么办 泰迪骨折了怎么办护理 狗狗的腿骨折了怎么办 狗狗摔了一下腿瘸了怎么办 狗狗前腿摔瘸了怎么办 狗摔跤腿瘸了怎么办 小狗的前腿弯了怎么办 两周的小狗缺钙怎么办 狗腿关节断了怎么办 五岁儿童抵抗力差怎么办 3岁儿童抵抗力差怎么办 四岁儿童抵抗力差怎么办 我孩子和我相冲怎么办 儿子不热母亲怎么办?单身呀? 大兔子吃小兔子怎么办 车窗贴膜里面有灰尘怎么办 陌陌小游戏不能玩游戏怎么办 电脑游戏里面的出现俄文怎么办 龙之谷手游转职业装备怎么办 如果函数值和类型不一致怎么办 qq提现不到账怎么办 提现的钱不到账怎么办