打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
友善之臂视频监控方案源码学习(6)

【问题描述】在友善之臂视频监控方案源码学习(5) - 输入控制一文中,介绍了input_run完成的功能。本文结合input_run实现的视频采集线程对视频采集进行详细分析。

【解析】

1 涉及到的文件和目录

mjpg-streamer-mini2440-read-only/start_uvc.sh

mjpg-streamer-mini2440-read-only/mjpg_streamer.c

mjpg-streamer-mini2440-read-only/mjpg_streamer.h

mjpg-streamer-mini2440-read-only/plugins/input.h

mjpg-streamer-mini2440-read-only/plugins/input_uvc

 

2 视频设备初始化

视频设备初始化在input_init函数中完成(mjpg-streamer-mini2440-read-only/plugins/input_uvc/input_uvc.c):

  1. /* open video device and prepare data structure */  
  2.   if (init_videoIn(videoIn, dev, width, height, fps, format, 1) < 0) {  
  3.     IPRINT("init_VideoIn failed\n");  
  4.     closelog();  
  5.     exit(EXIT_FAILURE);  
  6.   }  

init_videoIn函数中调用的视频初始化代码如下(mjpg-streamer-mini2440-read-only/plugins/input_uvc/V412uvc.c):

  1. if (init_v4l2 (vd) < 0) {  
  2.     fprintf (stderr, " Init v4L2 failed !! exit fatal \n");  
  3.     goto error;;  
  4.   }  

init_v412代码如下(mjpg-streamer-mini2440-read-only/plugins/input_uvc/V412uvc.c):

  1. static int init_v4l2(struct vdIn *vd)  
  2. {  
  3.   int i;  
  4.   int ret = 0;  
  5.   
  6.   if ((vd->fd = open(vd->videodevice, O_RDWR)) == -1) {  
  7.     perror("ERROR opening V4L interface");  
  8.     return -1;  
  9.   }  
  10.   
  11.   memset(&vd->cap, 0, sizeof(struct v4l2_capability));  
  12.   ret = ioctl(vd->fd, VIDIOC_QUERYCAP, &vd->cap);  
  13.   if (ret < 0) {  
  14.     fprintf(stderr, "Error opening device %s: unable to query device.\n", vd->videodevice);  
  15.     goto fatal;  
  16.   }  
  17.   
  18.   if ((vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {  
  19.     fprintf(stderr, "Error opening device %s: video capture not supported.\n",  
  20.            vd->videodevice);  
  21.     goto fatal;;  
  22.   }  
  23.   
  24.   if (vd->grabmethod) {  
  25.     if (!(vd->cap.capabilities & V4L2_CAP_STREAMING)) {  
  26.       fprintf(stderr, "%s does not support streaming i/o\n", vd->videodevice);  
  27.       goto fatal;  
  28.     }  
  29.   } else {  
  30.     if (!(vd->cap.capabilities & V4L2_CAP_READWRITE)) {  
  31.       fprintf(stderr, "%s does not support read i/o\n", vd->videodevice);  
  32.       goto fatal;  
  33.     }  
  34.   }  
  35.   
  36.   /*  
  37.    * set format in  
  38.    */  
  39.   memset(&vd->fmt, 0, sizeof(struct v4l2_format));  
  40.   vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  41.   vd->fmt.fmt.pix.width = vd->width;  
  42.   vd->fmt.fmt.pix.height = vd->height;  
  43.   vd->fmt.fmt.pix.pixelformat = vd->formatIn;  
  44.   vd->fmt.fmt.pix.field = V4L2_FIELD_ANY;  
  45.   ret = ioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt);  
  46.   if (ret < 0) {  
  47.     perror("Unable to set format");  
  48.     goto fatal;  
  49.   }  
  50.   
  51.   if ((vd->fmt.fmt.pix.width != vd->width) ||  
  52.       (vd->fmt.fmt.pix.height != vd->height)) {  
  53.     fprintf(stderr, " format asked unavailable get width %d height %d \n", vd->fmt.fmt.pix.width, vd->fmt.fmt.pix.height);  
  54.     vd->width = vd->fmt.fmt.pix.width;  
  55.     vd->height = vd->fmt.fmt.pix.height;  
  56.     /*  
  57.      * look the format is not part of the deal ???  
  58.      */  
  59.   }  
  60.     if(vd->fmt.fmt.pix.pixelformat!=vd->formatIn)  
  61.     {  
  62.         char fourcc1[5]={0,0,0,0,0};  
  63.         char fourcc2[5]={0,0,0,0,0};  
  64.         memmove(fourcc1,(char*)&vd->formatIn,4);  
  65.         memmove(fourcc2,(char*)&vd->fmt.fmt.pix.pixelformat,4);  
  66.         fprintf(stderr, " requested %s but got %s format instead\n",fourcc1,fourcc2);  
  67.     vd->formatIn = vd->fmt.fmt.pix.pixelformat;  
  68.     }  
  69.   
  70.   /*  
  71.    * set framerate  
  72.    */  
  73.   struct v4l2_streamparm *setfps;  
  74.   setfps = (struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm));  
  75.   memset(setfps, 0, sizeof(struct v4l2_streamparm));  
  76.   setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  77.   setfps->parm.capture.timeperframe.numerator = 1;  
  78.   setfps->parm.capture.timeperframe.denominator = vd->fps;  
  79.   ret = ioctl(vd->fd, VIDIOC_S_PARM, setfps);  
  80.   
  81.   /*  
  82.    * request buffers  
  83.    */  
  84.   memset(&vd->rb, 0, sizeof(struct v4l2_requestbuffers));  
  85.   vd->rb.count = NB_BUFFER;  
  86.   vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  87.   vd->rb.memory = V4L2_MEMORY_MMAP;  
  88.   
  89.   ret = ioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb);  
  90.   if (ret < 0) {  
  91.     perror("Unable to allocate buffers");  
  92.     goto fatal;  
  93.   }  
  94.   
  95.   /*  
  96.    * map the buffers  
  97.    */  
  98.   for (i = 0; i < NB_BUFFER; i++) {  
  99.     memset(&vd->buf, 0, sizeof(struct v4l2_buffer));  
  100.     vd->buf.index = i;  
  101.     vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  102.     vd->buf.memory = V4L2_MEMORY_MMAP;  
  103.     ret = ioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf);  
  104.     if (ret < 0) {  
  105.       perror("Unable to query buffer");  
  106.       goto fatal;  
  107.     }  
  108.   
  109.     if (debug)  
  110.       fprintf(stderr, "length: %u offset: %u\n", vd->buf.length, vd->buf.m.offset);  
  111.   
  112.     vd->mem[i] = mmap(0 /* start anywhere */ ,  
  113.                       vd->buf.length, PROT_READ, MAP_SHARED, vd->fd,  
  114.                       vd->buf.m.offset);  
  115.     if (vd->mem[i] == MAP_FAILED) {  
  116.       perror("Unable to map buffer");  
  117.       goto fatal;  
  118.     }  
  119.     if (debug)  
  120.       fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]);  
  121.   }  
  122.   
  123.   /*  
  124.    * Queue the buffers.  
  125.    */  
  126.   for (i = 0; i < NB_BUFFER; ++i) {  
  127.     memset(&vd->buf, 0, sizeof(struct v4l2_buffer));  
  128.     vd->buf.index = i;  
  129.     vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  130.     vd->buf.memory = V4L2_MEMORY_MMAP;  
  131.     ret = ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);  
  132.     if (ret < 0) {  
  133.       perror("Unable to queue buffer");  
  134.       goto fatal;;  
  135.     }  
  136.   }  
  137.   return 0;  
  138. fatal:  
  139.   return -1;  
  140.   
  141. }  

该部分主要完成了下述功能:

(1) 打开视频设备

  1. if ((vd->fd = open(vd->videodevice, O_RDWR)) == -1) {  
  2.     perror("ERROR opening V4L interface");  
  3.     return -1;  
  4.   }  

(2) 开启捕获功能

  1. memset(&vd->cap, 0, sizeof(struct v4l2_capability));  
  2.   ret = ioctl(vd->fd, VIDIOC_QUERYCAP, &vd->cap);  
  3.   if (ret < 0) {  
  4.     fprintf(stderr, "Error opening device %s: unable to query device.\n", vd->videodevice);  
  5.     goto fatal;  
  6.   }  
  7.   
  8.   if ((vd->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) {  
  9.     fprintf(stderr, "Error opening device %s: video capture not supported.\n",  
  10.            vd->videodevice);  
  11.     goto fatal;;  
  12.   }  
  13.   
  14.   if (vd->grabmethod) {  
  15.     if (!(vd->cap.capabilities & V4L2_CAP_STREAMING)) {  
  16.       fprintf(stderr, "%s does not support streaming i/o\n", vd->videodevice);  
  17.       goto fatal;  
  18.     }  
  19.   } else {  
  20.     if (!(vd->cap.capabilities & V4L2_CAP_READWRITE)) {  
  21.       fprintf(stderr, "%s does not support read i/o\n", vd->videodevice);  
  22.       goto fatal;  
  23.     }  
  24.   }  


(3)  设置视频格式

  1. /*  
  2.    * set format in  
  3.    */  
  4.   memset(&vd->fmt, 0, sizeof(struct v4l2_format));  
  5.   vd->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  6.   vd->fmt.fmt.pix.width = vd->width;  
  7.   vd->fmt.fmt.pix.height = vd->height;  
  8.   vd->fmt.fmt.pix.pixelformat = vd->formatIn;  
  9.   vd->fmt.fmt.pix.field = V4L2_FIELD_ANY;  
  10.   ret = ioctl(vd->fd, VIDIOC_S_FMT, &vd->fmt);  
  11.   if (ret < 0) {  
  12.     perror("Unable to set format");  
  13.     goto fatal;  
  14.   }  
  15.   
  16.   if ((vd->fmt.fmt.pix.width != vd->width) ||  
  17.       (vd->fmt.fmt.pix.height != vd->height)) {  
  18.     fprintf(stderr, " format asked unavailable get width %d height %d \n", vd->fmt.fmt.pix.width, vd->fmt.fmt.pix.height);  
  19.     vd->width = vd->fmt.fmt.pix.width;  
  20.     vd->height = vd->fmt.fmt.pix.height;  
  21.     /*  
  22.      * look the format is not part of the deal ???  
  23.      */  
  24.   }  
  25.     if(vd->fmt.fmt.pix.pixelformat!=vd->formatIn)  
  26.     {  
  27.         char fourcc1[5]={0,0,0,0,0};  
  28.         char fourcc2[5]={0,0,0,0,0};  
  29.         memmove(fourcc1,(char*)&vd->formatIn,4);  
  30.         memmove(fourcc2,(char*)&vd->fmt.fmt.pix.pixelformat,4);  
  31.         fprintf(stderr, " requested %s but got %s format instead\n",fourcc1,fourcc2);  
  32.     vd->formatIn = vd->fmt.fmt.pix.pixelformat;  
  33.     }  


(4) 设置帧速率

  1. /*  
  2.   * set framerate  
  3.   */  
  4.  struct v4l2_streamparm *setfps;  
  5.  setfps = (struct v4l2_streamparm *) calloc(1, sizeof(struct v4l2_streamparm));  
  6.  memset(setfps, 0, sizeof(struct v4l2_streamparm));  
  7.  setfps->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  8.  setfps->parm.capture.timeperframe.numerator = 1;  
  9.  setfps->parm.capture.timeperframe.denominator = vd->fps;  
  10.  ret = ioctl(vd->fd, VIDIOC_S_PARM, setfps);  


(5) 设置缓存

  1. /*  
  2.    * request buffers  
  3.    */  
  4.   memset(&vd->rb, 0, sizeof(struct v4l2_requestbuffers));  
  5.   vd->rb.count = NB_BUFFER;  
  6.   vd->rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  7.   vd->rb.memory = V4L2_MEMORY_MMAP;  
  8.   
  9.   ret = ioctl(vd->fd, VIDIOC_REQBUFS, &vd->rb);  
  10.   if (ret < 0) {  
  11.     perror("Unable to allocate buffers");  
  12.     goto fatal;  
  13.   }  
  14.   
  15.   /*  
  16.    * map the buffers  
  17.    */  
  18.   for (i = 0; i < NB_BUFFER; i++) {  
  19.     memset(&vd->buf, 0, sizeof(struct v4l2_buffer));  
  20.     vd->buf.index = i;  
  21.     vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  22.     vd->buf.memory = V4L2_MEMORY_MMAP;  
  23.     ret = ioctl(vd->fd, VIDIOC_QUERYBUF, &vd->buf);  
  24.     if (ret < 0) {  
  25.       perror("Unable to query buffer");  
  26.       goto fatal;  
  27.     }  
  28.   
  29.     if (debug)  
  30.       fprintf(stderr, "length: %u offset: %u\n", vd->buf.length, vd->buf.m.offset);  
  31.   
  32.     vd->mem[i] = mmap(0 /* start anywhere */ ,  
  33.                       vd->buf.length, PROT_READ, MAP_SHARED, vd->fd,  
  34.                       vd->buf.m.offset);  
  35.     if (vd->mem[i] == MAP_FAILED) {  
  36.       perror("Unable to map buffer");  
  37.       goto fatal;  
  38.     }  
  39.     if (debug)  
  40.       fprintf(stderr, "Buffer mapped at address %p.\n", vd->mem[i]);  
  41.   }  
  42.   
  43.   /*  
  44.    * Queue the buffers.  
  45.    */  
  46.   for (i = 0; i < NB_BUFFER; ++i) {  
  47.     memset(&vd->buf, 0, sizeof(struct v4l2_buffer));  
  48.     vd->buf.index = i;  
  49.     vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  50.     vd->buf.memory = V4L2_MEMORY_MMAP;  
  51.     ret = ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);  
  52.     if (ret < 0) {  
  53.       perror("Unable to queue buffer");  
  54.       goto fatal;;  
  55.     }  


3 视频采集

在input_run中调用了视频采集的线程函数,如下所示:

  1. int input_run(void) {  
  2.   pglobal->buf = malloc(videoIn->framesizeIn);  
  3.   if (pglobal->buf == NULL) {  
  4.     fprintf(stderr, "could not allocate memory\n");  
  5.     exit(EXIT_FAILURE);  
  6.   }  
  7.   
  8.   pthread_create(&cam, 0, cam_thread, NULL);  
  9.   pthread_detach(cam);  
  10.   
  11.   return 0;  
  12. }  

cam_thread定义如下:

  1. void *cam_thread( void *arg ) {  
  2.   /* set cleanup handler to cleanup allocated ressources */  
  3.   pthread_cleanup_push(cam_cleanup, NULL);  
  4.   
  5.   while( !pglobal->stop ) {  
  6.   
  7.     /* grab a frame */  
  8.     if( uvcGrab(videoIn) < 0 ) {  
  9.       IPRINT("Error grabbing frames\n");  
  10.       exit(EXIT_FAILURE);  
  11.     }  
  12.     
  13.     DBG("received frame of size: %d\n", videoIn->buf.bytesused);  
  14.   
  15.     /*  
  16.      * Workaround for broken, corrupted frames:  
  17.      * Under low light conditions corrupted frames may get captured.  
  18.      * The good thing is such frames are quite small compared to the regular pictures.  
  19.      * For example a VGA (640x480) webcam picture is normally >= 8kByte large,  
  20.      * corrupted frames are smaller.  
  21.      */  
  22.     if ( videoIn->buf.bytesused < minimum_size ) {  
  23.       DBG("dropping too small frame, assuming it as broken\n");  
  24.       continue;  
  25.     }  
  26.   
  27.     /* copy JPG picture to global buffer */  
  28.     pthread_mutex_lock( &pglobal->db );  
  29.   
  30.     /*  
  31.      * If capturing in YUV mode convert to JPEG now.  
  32.      * This compression requires many CPU cycles, so try to avoid YUV format.  
  33.      * Getting JPEGs straight from the webcam, is one of the major advantages of  
  34.      * Linux-UVC compatible devices.  
  35.      */  
  36.     if (videoIn->formatIn != V4L2_PIX_FMT_MJPEG) {   
  37.       DBG("compressing frame\n");   
  38.       pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality, videoIn->formatIn);  
  39.     }  
  40.     else {  
  41.       DBG("copying frame\n");  
  42.       pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);  
  43.     }  
  44.   
  45. #if 0  
  46.     /* motion detection can be done just by comparing the picture size, but it is not very accurate!! */  
  47.     if ( (prev_size - global->size)*(prev_size - global->size) > 4*1024*1024 ) {  
  48.         DBG("motion detected (delta: %d kB)\n", (prev_size - global->size) / 1024);  
  49.     }  
  50.     prev_size = global->size;  
  51. #endif  
  52.   
  53.     /* signal fresh_frame */  
  54.     pthread_cond_broadcast(&pglobal->db_update);  
  55.     pthread_mutex_unlock( &pglobal->db );  
  56.   
  57.     DBG("waiting for next frame\n");  
  58.   
  59.     /* only use usleep if the fps is below 5, otherwise the overhead is too long */  
  60.     if ( videoIn->fps < 5 ) {  
  61.       usleep(1000*1000/videoIn->fps);  
  62.     }  
  63.   }  
  64.   
  65.   DBG("leaving input thread, calling cleanup function now\n");  
  66.   pthread_cleanup_pop(1);  
  67.   
  68.   return NULL;  
  69. }  

该函数完成下述任务:

(1) 视频抓取

  1. while( !pglobal->stop ) {  
  2.   
  3.     /* grab a frame */  
  4.     if( uvcGrab(videoIn) < 0 ) {  
  5.       IPRINT("Error grabbing frames\n");  
  6.       exit(EXIT_FAILURE);  
  7.     }  

uvcGrab函数实现如下:

  1. int uvcGrab(struct vdIn *vd)  
  2. {  
  3. #define HEADERFRAME1 0xaf  
  4.   int ret;  
  5.   
  6.   if (!vd->isstreaming)  
  7.     if (video_enable(vd))  
  8.       goto err;  
  9.   
  10.   memset(&vd->buf, 0, sizeof(struct v4l2_buffer));  
  11.   vd->buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  
  12.   vd->buf.memory = V4L2_MEMORY_MMAP;  
  13.   
  14.   ret = ioctl(vd->fd, VIDIOC_DQBUF, &vd->buf);  
  15.   if (ret < 0) {  
  16.     perror("Unable to dequeue buffer");  
  17.     goto err;  
  18.   }  
  19.   
  20.   switch (vd->formatIn) {  
  21.     case V4L2_PIX_FMT_MJPEG:  
  22.       if (vd->buf.bytesused <= HEADERFRAME1) {    /* Prevent crash  
  23.                                                   * on empty image */  
  24.         fprintf(stderr, "Ignoring empty buffer ...\n");  
  25.         return 0;  
  26.       }  
  27.   
  28.       /* memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);  
  29.   
  30.       memcpy (vd->tmpbuffer, vd->mem[vd->buf.index], HEADERFRAME1);  
  31.       memcpy (vd->tmpbuffer + HEADERFRAME1, dht_data, sizeof(dht_data));  
  32.       memcpy (vd->tmpbuffer + HEADERFRAME1 + sizeof(dht_data), vd->mem[vd->buf.index] + HEADERFRAME1, (vd->buf.bytesused - HEADERFRAME1));  
  33.       */  
  34.   
  35.       memcpy(vd->tmpbuffer, vd->mem[vd->buf.index], vd->buf.bytesused);  
  36.   
  37.       if (debug)  
  38.         fprintf(stderr, "bytes in used %d \n", vd->buf.bytesused);  
  39.       break;  
  40.   
  41.     case V4L2_PIX_FMT_YUYV:  
  42.     default:  
  43.       if (vd->buf.bytesused > vd->framesizeIn)  
  44.         memcpy (vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->framesizeIn);  
  45.       else  
  46.         memcpy (vd->framebuffer, vd->mem[vd->buf.index], (size_t) vd->buf.bytesused);  
  47.       break;  
  48.   
  49.       //goto err;  
  50.     break;  
  51.   }  
  52.   
  53.   ret = ioctl(vd->fd, VIDIOC_QBUF, &vd->buf);  
  54.   if (ret < 0) {  
  55.     perror("Unable to requeue buffer");  
  56.     goto err;  
  57.   }  
  58.   
  59.   return 0;  
  60.   
  61. err:  
  62.   vd->signalquit = 0;  
  63.   return -1;  
  64. }  

该函数主要完成了下述功能:

(a) 使能视频设备

  1. if (!vd->isstreaming)  
  2.     if (video_enable(vd))  
  3.       goto err;  

实质上是调用了下述方法:

  1. ret = ioctl(vd->fd, VIDIOC_STREAMON, &type);  
  2.   if (ret < 0) {  
  3.     perror("Unable to start capture");  
  4.     return ret;  
  5.   }  

(b) 视频采集

  1. ret = ioctl(vd->fd, VIDIOC_DQBUF, &vd->buf);  
  2.   if (ret < 0) {  
  3.     perror("Unable to dequeue buffer");  
  4.     goto err;  
  5.   }  

注:采集的视频信息放在vd->buf中。

(2) 视频压缩编码

  1. if (videoIn->formatIn != V4L2_PIX_FMT_MJPEG) {   
  2.       DBG("compressing frame\n");   
  3.       pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality, videoIn->formatIn);  
  4.     }  
  5.     else {  
  6.       DBG("copying frame\n");  
  7.       pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);  
  8.     }  

此过程,后续文章进行详述。

 

4 视频的存储

视频采集的信息存储在vd->buf中,vd->buf怎么和global->buf联系起来的呢?

(1) input_init初始化全局指针

  1. pglobal = param->global;  

param->global指针指向mjpg-streamer-mini2440-read-only/mjpg_streamer.c主程序main中的global全局指针。

(2) input_run中分配空间

  1. pglobal->buf = malloc(videoIn->framesizeIn);  
  2.   if (pglobal->buf == NULL) {  
  3.     fprintf(stderr, "could not allocate memory\n");  
  4.     exit(EXIT_FAILURE);  
  5.   }  

(3) cam_thread抓取

  1. while( !pglobal->stop ) {  
  2.   
  3.     /* grab a frame */  
  4.     if( uvcGrab(videoIn) < 0 ) {  
  5.       IPRINT("Error grabbing frames\n");  
  6.       exit(EXIT_FAILURE);  
  7.     }  

抓取的数据存储在videoIn结构中:

  1. int uvcGrab(struct vdIn *vd)  
  2. {  
  3. ...  
  4. ret = ioctl(vd->fd, VIDIOC_DQBUF, &vd->buf);  
  5.   if (ret < 0) {  
  6.     perror("Unable to dequeue buffer");  
  7.     goto err;  
  8.   }  
  9. }  

(4) global->buf和videoIn->buf的联系

  1. if (videoIn->formatIn != V4L2_PIX_FMT_MJPEG) {   
  2.       DBG("compressing frame\n");   
  3.       pglobal->size = compress_yuyv_to_jpeg(videoIn, pglobal->buf, videoIn->framesizeIn, gquality, videoIn->formatIn);  
  4.     }  
  5.     else {  
  6.       DBG("copying frame\n");  
  7.       pglobal->size = memcpy_picture(pglobal->buf, videoIn->tmpbuffer, videoIn->buf.bytesused);  
  8.     }  

最终,通过压缩编码将videoIn->buf的数据存储在global->buf中。



 【源码下载】

http://download.csdn.net/detail/tandesir/4915905

 

 

转载请标明出处,仅供学习交流,勿用于商业目的

Copyright @ http://blog.csdn.net/tandesir

 

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
RT5350无线视频监控
嵌入式WEB视频监控小车项目指导
基于linux-2.6.35的网络视频服务器移植
Mjpeg‐stream移植(mini2440)
开源视频服务器软件MJPG-streamer的分析
openwrt挂载摄像头MJPG-streamer完全教程
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服