Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2112552
  • 博文数量: 438
  • 博客积分: 3871
  • 博客等级: 中校
  • 技术积分: 6075
  • 用 户 组: 普通用户
  • 注册时间: 2011-09-10 00:11
个人简介

邮箱: wangcong02345@163.com

文章分类

全部博文(438)

文章存档

2017年(15)

2016年(119)

2015年(91)

2014年(62)

2013年(56)

2012年(79)

2011年(16)

分类: LINUX

2015-08-10 17:42:21

一. 用SDL显示camera图像
1. SDL
虽然把图像写到文件中去己经很好很强大了,但进一步实时的显示图片是不是更好?
这就需要用到SDL了
2. 源码
2.1 display.c
  1. cong@msi:/work/test/uvcview/3display$ cat display.c
  2. #include "utils.h"
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. #include <linux/videodev2.h>
  7. #include <sys/mman.h>
  8. #include <SDL/SDL.h>
  9. #define VIDEO_DEVICE "/dev/video0"
  10. #define NB_BUFFER 4
  11. int fd;
  12. int ret = 0;
  13. struct v4l2_capability cap;
  14. struct v4l2_format fmt;
  15. struct v4l2_requestbuffers rb;
  16. struct v4l2_buffer vbuf;
  17. void* vmem[NB_BUFFER];
  18. unsigned char* tempbuffer;
  19. unsigned char* framebuffer;
  20. int type;
  21. int framesize;
  22. int width = 640; //1280; //640;
  23. int height= 480; // 720; // 480;
  24. float fps = 30.0;
  25. int format = V4L2_PIX_FMT_YUYV;

  26. init_camera()
  27. {
  28.     int i;
  29.     if( (fd = v4l2_open(VIDEO_DEVICE,O_RDWR)) == -1)
  30.     {
  31.         dbmsg("error: %s", strerror(errno));
  32.         return 0;
  33.     }
  34.     //check format is valid
  35.     //fix me

  36.     //set format and frame size
  37.     memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
  38.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  39.     fmt.fmt.pix.width = width;
  40.     fmt.fmt.pix.height = height;
  41.     fmt.fmt.pix.field = V4L2_FIELD_ANY;
  42.     if( (ret = v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt)) < 0)
  43.     {
  44.         dbmsg("error: %s", strerror(errno));
  45.         return 0;
  46.     }

  47.     //mmap buffer: reqbufs-> querybuf -> mmap -> QBUF
  48.     memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
  49.     rb.count = NB_BUFFER;
  50.     rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  51.     rb.memory = V4L2_MEMORY_MMAP;
  52.     if( (ret = v4l2_ioctl(fd, VIDIOC_REQBUFS, &rb)) < 0 )
  53.     {
  54.         dbmsg("error: %s", strerror(errno));
  55.         return 0;
  56.     }
  57.     for(i=0; i<NB_BUFFER; i++)
  58.     {
  59.         memset(&vbuf, 0, sizeof(struct v4l2_buffer));
  60.         vbuf.index = i;
  61.         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  62.         vbuf.memory = V4L2_MEMORY_MMAP;
  63.         if( (ret = v4l2_ioctl(fd, VIDIOC_QUERYBUF, &vbuf)) < 0)
  64.         {
  65.             dbmsg("error: %s", strerror(errno));
  66.             return 0;
  67.         }
  68.         dbmsg("len=%d, offset=%d", vbuf.length, vbuf.m.offset);
  69.         //if( (vmem[i] = v4l2_mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)
  70.         if( (vmem[i] = mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)    
  71.         {
  72.             dbmsg("error: %s", strerror(errno));
  73.             return 0;
  74.         }
  75.         dbmsg("Buffer mapped at address %p", vmem[i]);
  76.     }
  77.     for(i=0; i<NB_BUFFER; i++)
  78.     {
  79.         memset(&vbuf, 0, sizeof(struct v4l2_buffer));
  80.         vbuf.index = i;
  81.         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  82.         vbuf.memory = V4L2_MEMORY_MMAP;
  83.         if( (ret = v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
  84.         {
  85.             dbmsg("error: %s", strerror(errno));
  86.             return 0;
  87.         }
  88.     }

  89.     //alloc framebuffer
  90.     framesize = ((width*height)<<1);
  91.     if( !(tempbuffer = malloc(framesize)))
  92.     {
  93.         dbmsg("error: %s", strerror(errno));
  94.         return 0;
  95.     }
  96.     if( !(framebuffer = malloc(width*height*8)))
  97.     {
  98.         dbmsg("error: %s", strerror(errno));
  99.         return 0;
  100.     }
  101.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  102.     if( (ret = v4l2_ioctl(fd, VIDIOC_STREAMON, &type)) < 0)
  103.     {
  104.         dbmsg("error: %s", strerror(errno));
  105.         return 0;
  106.     }
  107. }

  108. int main ( int argc, char *argv[] )
  109. {
  110.     int i;
  111.     SDL_Surface* psscreen;
  112.     SDL_Overlay* overlay;
  113.     SDL_Rect drect;
  114.     unsigned char* p;
  115.     SDL_Init(SDL_INIT_EVERYTHING);
  116.     psscreen = SDL_SetVideoMode(width, height, 0, SDL_SWSURFACE);
  117.     SDL_WM_SetCaption( "YUV Window", NULL);
  118.     /* Create a YUV overlay */
  119.     overlay = SDL_CreateYUVOverlay(width, height, SDL_YUY2_OVERLAY, psscreen);
  120.     p = (unsigned char*) overlay->pixels[0];
  121.     drect.x = 0;
  122.     drect.y = 0;
  123.     drect.w = width;
  124.     drect.h = height;

  125.     init_camera();

  126.     while(1)
  127.     {
  128.         memset(&vbuf, 0, sizeof(struct v4l2_buffer));
  129.         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  130.         vbuf.memory = V4L2_MEMORY_MMAP;
  131.         if( (ret = v4l2_ioctl(fd, VIDIOC_DQBUF, &vbuf)) < 0)
  132.         {
  133.             dbmsg("error: %s", strerror(errno));
  134.             return 0;
  135.         }
  136.         if(vbuf.bytesused > framesize)
  137.         {
  138.             memcpy(framebuffer, vmem[vbuf.index], (size_t)framesize);
  139.         }else {
  140.             memcpy(framebuffer, vmem[vbuf.index], (size_t)vbuf.bytesused);
  141.             if( (ret=v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
  142.             {
  143.                 dbmsg("error: %s", strerror(errno));
  144.                 return 0;
  145.             }
  146.         }
  147.         SDL_LockYUVOverlay(overlay);
  148.         memcpy(p, framebuffer, width*height*2);
  149.         SDL_UnlockYUVOverlay(overlay);
  150.         SDL_DisplayYUVOverlay(overlay, &drect);
  151.         SDL_Delay(10);
  152.     }

  153.     return EXIT_SUCCESS;
  154. }
2.2 Makefile
  1. cong@msi:/work/test/uvcview/3display$ cat Makefile
  2. EXE=display
  3. CC=gcc
  4. SRC=$(wildcard *.c)
  5. #OBJ=$(SRC:.c=.o)
  6. OBJ=$(patsubst %.c,%.o,$(SRC))
  7. DEP=$(patsubst %.c,.%.d,$(SRC))
  8. CFLAGS=-g -O0 -I/work/test/uvcview/libv4l2/libv4l-0.6.1/include -DUSE_SDL -O2 -DLINUX -DVERSION=\"0.2.6\" -D_GNU_SOURCE=1 -D_REENTRANT
  9. #V4L2LIBS = $(shell pkg-config --libs libv4l2) -lSDL
  10. V4L2LIBS = -L/work/test/uvcview/libv4l2/libv4l-0.6.1/libv4l2 -lv4l2 \
  11.          -L/work/test/uvcview/libv4l2/libv4l-0.6.1/libv4lconvert/ -lv4lconvert \
  12.             -lrt -lm -lSDL                       -->链接库中加入了SDL
  13. $(EXE):$(OBJ)
  14.     $(CC) $(CFLAGS) $^ -o $@ $(V4L2LIBS)

  15. $(DEP):.%.d:%.c
  16.     @set -e; rm -f $@; \
  17.     $(CC) -MM $< > $@.$$$$; \
  18.     sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; \
  19.     rm -f $@.$$$$

  20. -include $(DEP)
  21. clean:
  22.     @rm $(EXE) $(OBJ) $(DEP) -f
  23. cong@msi:/work/test/uvcview/3display$
3.源码打包
3display.rar (下载后改名为3display.tar.gz)

二. 改进
1. 有图像显示出来了,但是还有几个问题
a. 程序结束不了,只能用kill强制杀死,
    这样做后,下次必需插拔usb摄像头才能正常使用
b. 关于v4l2_mmap这一直有个疑问
    为什么在luvcview的源码中没有问题,而我这儿一用就segment fault呢?
2.1 代码
  1. cong@msi:/work/test/uvcview/3display_1$ cat display.c
  2. #include "utils.h"
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #include <fcntl.h>
  6. #include <linux/videodev2.h>
  7. #include <sys/mman.h>
  8. #include <SDL/SDL.h>
  9. #include <libv4l2.h>                      //少了一个头文件,带来的问题看下面
  10. #define VIDEO_DEVICE "/dev/video0"
  11. #define NB_BUFFER 4
  12. int fd;
  13. int ret = 0;
  14. struct v4l2_capability cap;
  15. struct v4l2_format fmt;
  16. struct v4l2_requestbuffers rb;
  17. struct v4l2_buffer vbuf;
  18. void* vmem[NB_BUFFER];
  19. unsigned char* tempbuffer;
  20. unsigned char* framebuffer;
  21. int type;
  22. int framesize;
  23. int width = 640; //1280; //640;
  24. int height= 480; // 720; // 480;
  25. float fps = 30.0;
  26. //int format = V4L2_PIX_FMT_MJPEG;
  27. int format = V4L2_PIX_FMT_YUYV;

  28. SDL_mutex *affmutex;
  29. SDL_Event sdlevent;
  30. int signal_quit = 1;

  31. static int eventThread(void* data)               //b.SDL的线程,用来检测事件
  32. {                                                //b.当有退出事件时,把signal_quit置空
  33.     while(signal_quit)                           //b.这时主线程监测到signal_quit为空就退出主线程
  34.     {
  35.         SDL_LockMutex(affmutex);
  36.         while(SDL_PollEvent(&sdlevent))
  37.         {
  38.             switch(sdlevent.type)
  39.             {
  40.                 case SDL_QUIT:
  41.                     {
  42.                         dbmsg("recv quit");
  43.                         signal_quit = 0;
  44.                     }
  45.                     break;
  46.                 default:
  47.                     dbmsg("sdl event");
  48.                     break;

  49.             }
  50.         }
  51.         SDL_UnlockMutex(affmutex);
  52.     }
  53. }
  54. init_camera()
  55. {
  56.     int i;
  57.     if( (fd = v4l2_open(VIDEO_DEVICE,O_RDWR)) == -1)
  58.     {
  59.         dbmsg("error: %s", strerror(errno));
  60.         return 0;
  61.     }
  62.     //check format is valid
  63.     //fix me

  64.     //set format and frame size
  65.     memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
  66.     fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  67.     fmt.fmt.pix.width = width;
  68.     fmt.fmt.pix.height = height;
  69.     fmt.fmt.pix.field = V4L2_FIELD_ANY;
  70.     if( (ret = v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt)) < 0)
  71.     {
  72.         dbmsg("error: %s", strerror(errno));
  73.         return 0;
  74.     }

  75.     //mmap buffer: reqbufs-> querybuf -> mmap -> QBUF
  76.     memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
  77.     rb.count = NB_BUFFER;
  78.     rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  79.     rb.memory = V4L2_MEMORY_MMAP;
  80.     if( (ret = v4l2_ioctl(fd, VIDIOC_REQBUFS, &rb)) < 0 )
  81.     {
  82.         dbmsg("error: %s", strerror(errno));
  83.         return 0;
  84.     }
  85.     for(i=0; i<NB_BUFFER; i++)
  86.     {
  87.         memset(&vbuf, 0, sizeof(struct v4l2_buffer));
  88.         vbuf.index = i;
  89.         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  90.         vbuf.memory = V4L2_MEMORY_MMAP;
  91.         if( (ret = v4l2_ioctl(fd, VIDIOC_QUERYBUF, &vbuf)) < 0)
  92.         {
  93.             dbmsg("error: %s", strerror(errno));
  94.             return 0;
  95.         }
  96.         dbmsg("len=%d, offset=%d", vbuf.length, vbuf.m.offset);
  97.         if( (vmem[i] = v4l2_mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)
  98.         {
  99.             dbmsg("error: %s", strerror(errno));
  100.             return 0;
  101.         }
  102.         dbmsg("Buffer mapped at address %p", vmem[i]);
  103.     }
  104.     for(i=0; i<NB_BUFFER; i++)
  105.     {
  106.         memset(&vbuf, 0, sizeof(struct v4l2_buffer));
  107.         vbuf.index = i;
  108.         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  109.         vbuf.memory = V4L2_MEMORY_MMAP;
  110.         if( (ret = v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
  111.         {
  112.             dbmsg("error: %s", strerror(errno));
  113.             return 0;
  114.         }
  115.     }

  116.     //alloc framebuffer
  117.     framesize = ((width*height)<<1);
  118.     if( !(tempbuffer = malloc(framesize)))
  119.     {
  120.         dbmsg("error: %s", strerror(errno));
  121.         return 0;
  122.     }
  123.     if( !(framebuffer = malloc(width*height*8)))
  124.     {
  125.         dbmsg("error: %s", strerror(errno));
  126.         return 0;
  127.     }
  128.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  129.     if( (ret = v4l2_ioctl(fd, VIDIOC_STREAMON, &type)) < 0)
  130.     {
  131.         dbmsg("error: %s", strerror(errno));
  132.         return 0;
  133.     }
  134. }


  135. int main ( int argc, char *argv[] )
  136. {
  137.     int i;
  138.     SDL_Surface* psscreen;
  139.     SDL_Overlay* overlay;
  140.     SDL_Rect drect;
  141.     SDL_Thread* sdl_thread;
  142.     unsigned char* p;
  143.     SDL_Init(SDL_INIT_EVERYTHING);
  144.     psscreen = SDL_SetVideoMode(width, height, 0, SDL_SWSURFACE);
  145.     SDL_WM_SetCaption( "YUV Window", NULL);
  146.     /* Create a YUV overlay */
  147.     overlay = SDL_CreateYUVOverlay(width, height, SDL_YUY2_OVERLAY, psscreen);
  148.     p = (unsigned char*) overlay->pixels[0];
  149.     drect.x = 0;
  150.     drect.y = 0;
  151.     drect.w = width;
  152.     drect.h = height;

  153.     init_camera();

  154.     //sdl get signal quit
  155.     affmutex = SDL_CreateMutex();
  156.     sdl_thread = SDL_CreateThread(eventThread, NULL);            //a.SDL创建线程

  157.     while(signal_quit)                                           //c.当主线程监测到signal_quit为空时,就退出主线程
  158.     {
  159.         memset(&vbuf, 0, sizeof(struct v4l2_buffer));
  160.         vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  161.         vbuf.memory = V4L2_MEMORY_MMAP;
  162.         if( (ret = v4l2_ioctl(fd, VIDIOC_DQBUF, &vbuf)) < 0)
  163.         {
  164.             dbmsg("error: %s", strerror(errno));
  165.             return 0;
  166.         }
  167.         if(vbuf.bytesused > framesize)
  168.         {
  169.             memcpy(framebuffer, vmem[vbuf.index], (size_t)framesize);
  170.         }else {
  171.             memcpy(framebuffer, vmem[vbuf.index], (size_t)vbuf.bytesused);
  172.             if( (ret=v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
  173.             {
  174.                 dbmsg("error: %s", strerror(errno));
  175.                 return 0;
  176.             }
  177.         }
  178.         SDL_LockYUVOverlay(overlay);
  179.         memcpy(p, framebuffer, width*height*2);
  180.         SDL_UnlockYUVOverlay(overlay);
  181.         SDL_DisplayYUVOverlay(overlay, &drect);
  182.         SDL_Delay(10);
  183.     }
  184.     SDL_WaitThread(sdl_thread, &ret);                          //d.当线程退出时干清理的事
  185.     SDL_DestroyMutex(affmutex);
  186.     //close_v4l2
  187.     type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  188.     if( (ret=v4l2_ioctl(fd, VIDIOC_STREAMOFF, &type)) < 0)     //d.将STREAM关闭,这样下次还可以打开
  189.     {
  190.         dbmsg("error: %s", strerror(errno));
  191.         return 0;
  192.     }
  193.     if(NULL != framebuffer)
  194.         free(framebuffer);
  195.     framebuffer = NULL;

  196.     return EXIT_SUCCESS;
  197. }
  198. cong@msi:/work/test/uvcview/3display_1$
3. 代码打包
3display_1.rar (下载后改名为3display_1.tar.gz)
4. 说明
a. 为了让程序退出,这儿加入了SDL线程来监听退出事件,有退出事件触发时就通知主while退出
b. 在主while退出时需要把camera的视频关闭,这样下次才可以打开
c.关于为什么老是会出现下面的warning?
  1. display.c:102:19: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
  2.          if( (vmem[i] = v4l2_mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)
最后发现原来是#include <libv4l2.h>没有加入头文件,我说这个warning怎么提示v4l2_mmap返回的是integer呢?
看来有些warning也是需要重视的.



阅读(2431) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~