一. 用SDL显示camera图像
1. SDL
虽然把图像写到文件中去己经很好很强大了,但进一步实时的显示图片是不是更好?
这就需要用到SDL了
2. 源码
2.1 display.c
2.2 Makefile
3.源码打包
3display.rar (下载后改名为3display.tar.gz)
二. 改进
1. 有图像显示出来了,但是还有几个问题
a. 程序结束不了,只能用kill强制杀死,
这样做后,下次必需插拔usb摄像头才能正常使用
b. 关于v4l2_mmap这一直有个疑问
为什么在luvcview的源码中没有问题,而我这儿一用就segment fault呢?
2.1 代码
3. 代码打包
3display_1.rar (下载后改名为3display_1.tar.gz)
4. 说明
a. 为了让程序退出,这儿加入了SDL线程来监听退出事件,有退出事件触发时就通知主while退出
b. 在主while退出时需要把camera的视频关闭,这样下次才可以打开
c.关于为什么老是会出现下面的warning?
最后发现原来是#include
<
libv4l2
.
h
>
没有加入头文件,我说这个warning怎么提示v4l2_mmap返回的是integer呢?
看来有些warning也是需要重视的.
1. SDL
虽然把图像写到文件中去己经很好很强大了,但进一步实时的显示图片是不是更好?
这就需要用到SDL了
2. 源码
2.1 display.c
- cong@msi:/work/test/uvcview/3display$ cat display.c
- #include "utils.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <linux/videodev2.h>
- #include <sys/mman.h>
- #include <SDL/SDL.h>
- #define VIDEO_DEVICE "/dev/video0"
- #define NB_BUFFER 4
- int fd;
- int ret = 0;
- struct v4l2_capability cap;
- struct v4l2_format fmt;
- struct v4l2_requestbuffers rb;
- struct v4l2_buffer vbuf;
- void* vmem[NB_BUFFER];
- unsigned char* tempbuffer;
- unsigned char* framebuffer;
- int type;
- int framesize;
- int width = 640; //1280; //640;
- int height= 480; // 720; // 480;
- float fps = 30.0;
- int format = V4L2_PIX_FMT_YUYV;
-
- init_camera()
- {
- int i;
- if( (fd = v4l2_open(VIDEO_DEVICE,O_RDWR)) == -1)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- //check format is valid
- //fix me
-
- //set format and frame size
- memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = width;
- fmt.fmt.pix.height = height;
- fmt.fmt.pix.field = V4L2_FIELD_ANY;
- if( (ret = v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
-
- //mmap buffer: reqbufs-> querybuf -> mmap -> QBUF
- memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
- rb.count = NB_BUFFER;
- rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rb.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_REQBUFS, &rb)) < 0 )
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- for(i=0; i<NB_BUFFER; i++)
- {
- memset(&vbuf, 0, sizeof(struct v4l2_buffer));
- vbuf.index = i;
- vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vbuf.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_QUERYBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- dbmsg("len=%d, offset=%d", vbuf.length, vbuf.m.offset);
- //if( (vmem[i] = v4l2_mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)
- if( (vmem[i] = mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- dbmsg("Buffer mapped at address %p", vmem[i]);
- }
- for(i=0; i<NB_BUFFER; i++)
- {
- memset(&vbuf, 0, sizeof(struct v4l2_buffer));
- vbuf.index = i;
- vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vbuf.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- }
-
- //alloc framebuffer
- framesize = ((width*height)<<1);
- if( !(tempbuffer = malloc(framesize)))
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- if( !(framebuffer = malloc(width*height*8)))
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if( (ret = v4l2_ioctl(fd, VIDIOC_STREAMON, &type)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- }
-
- int main ( int argc, char *argv[] )
- {
- int i;
- SDL_Surface* psscreen;
- SDL_Overlay* overlay;
- SDL_Rect drect;
- unsigned char* p;
- SDL_Init(SDL_INIT_EVERYTHING);
- psscreen = SDL_SetVideoMode(width, height, 0, SDL_SWSURFACE);
- SDL_WM_SetCaption( "YUV Window", NULL);
- /* Create a YUV overlay */
- overlay = SDL_CreateYUVOverlay(width, height, SDL_YUY2_OVERLAY, psscreen);
- p = (unsigned char*) overlay->pixels[0];
- drect.x = 0;
- drect.y = 0;
- drect.w = width;
- drect.h = height;
-
- init_camera();
-
- while(1)
- {
- memset(&vbuf, 0, sizeof(struct v4l2_buffer));
- vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vbuf.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_DQBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- if(vbuf.bytesused > framesize)
- {
- memcpy(framebuffer, vmem[vbuf.index], (size_t)framesize);
- }else {
- memcpy(framebuffer, vmem[vbuf.index], (size_t)vbuf.bytesused);
- if( (ret=v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- }
- SDL_LockYUVOverlay(overlay);
- memcpy(p, framebuffer, width*height*2);
- SDL_UnlockYUVOverlay(overlay);
- SDL_DisplayYUVOverlay(overlay, &drect);
- SDL_Delay(10);
- }
-
- return EXIT_SUCCESS;
- }
- cong@msi:/work/test/uvcview/3display$ cat Makefile
- EXE=display
- CC=gcc
- SRC=$(wildcard *.c)
- #OBJ=$(SRC:.c=.o)
- OBJ=$(patsubst %.c,%.o,$(SRC))
- DEP=$(patsubst %.c,.%.d,$(SRC))
- 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
- #V4L2LIBS = $(shell pkg-config --libs libv4l2) -lSDL
- V4L2LIBS = -L/work/test/uvcview/libv4l2/libv4l-0.6.1/libv4l2 -lv4l2 \
- -L/work/test/uvcview/libv4l2/libv4l-0.6.1/libv4lconvert/ -lv4lconvert \
- -lrt -lm -lSDL -->链接库中加入了SDL
- $(EXE):$(OBJ)
- $(CC) $(CFLAGS) $^ -o $@ $(V4L2LIBS)
-
- $(DEP):.%.d:%.c
- @set -e; rm -f $@; \
- $(CC) -MM $< > $@.$$$$; \
- sed 's,/($*/)/.o[ :]*,/1.o $@ : ,g' < $@.$$$$ > $@; \
- rm -f $@.$$$$
-
- -include $(DEP)
- clean:
- @rm $(EXE) $(OBJ) $(DEP) -f
- cong@msi:/work/test/uvcview/3display$
3display.rar (下载后改名为3display.tar.gz)
二. 改进
1. 有图像显示出来了,但是还有几个问题
a. 程序结束不了,只能用kill强制杀死,
这样做后,下次必需插拔usb摄像头才能正常使用
b. 关于v4l2_mmap这一直有个疑问
为什么在luvcview的源码中没有问题,而我这儿一用就segment fault呢?
2.1 代码
- cong@msi:/work/test/uvcview/3display_1$ cat display.c
- #include "utils.h"
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <linux/videodev2.h>
- #include <sys/mman.h>
- #include <SDL/SDL.h>
- #include <libv4l2.h> //少了一个头文件,带来的问题看下面
- #define VIDEO_DEVICE "/dev/video0"
- #define NB_BUFFER 4
- int fd;
- int ret = 0;
- struct v4l2_capability cap;
- struct v4l2_format fmt;
- struct v4l2_requestbuffers rb;
- struct v4l2_buffer vbuf;
- void* vmem[NB_BUFFER];
- unsigned char* tempbuffer;
- unsigned char* framebuffer;
- int type;
- int framesize;
- int width = 640; //1280; //640;
- int height= 480; // 720; // 480;
- float fps = 30.0;
- //int format = V4L2_PIX_FMT_MJPEG;
- int format = V4L2_PIX_FMT_YUYV;
-
- SDL_mutex *affmutex;
- SDL_Event sdlevent;
- int signal_quit = 1;
-
- static int eventThread(void* data) //b.SDL的线程,用来检测事件
- { //b.当有退出事件时,把signal_quit置空
- while(signal_quit) //b.这时主线程监测到signal_quit为空就退出主线程
- {
- SDL_LockMutex(affmutex);
- while(SDL_PollEvent(&sdlevent))
- {
- switch(sdlevent.type)
- {
- case SDL_QUIT:
- {
- dbmsg("recv quit");
- signal_quit = 0;
- }
- break;
- default:
- dbmsg("sdl event");
- break;
-
- }
- }
- SDL_UnlockMutex(affmutex);
- }
- }
- init_camera()
- {
- int i;
- if( (fd = v4l2_open(VIDEO_DEVICE,O_RDWR)) == -1)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- //check format is valid
- //fix me
-
- //set format and frame size
- memset(&fmt, 0, sizeof(struct v4l2_fmtdesc));
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = width;
- fmt.fmt.pix.height = height;
- fmt.fmt.pix.field = V4L2_FIELD_ANY;
- if( (ret = v4l2_ioctl(fd, VIDIOC_S_FMT, &fmt)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
-
- //mmap buffer: reqbufs-> querybuf -> mmap -> QBUF
- memset(&rb, 0, sizeof(struct v4l2_requestbuffers));
- rb.count = NB_BUFFER;
- rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rb.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_REQBUFS, &rb)) < 0 )
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- for(i=0; i<NB_BUFFER; i++)
- {
- memset(&vbuf, 0, sizeof(struct v4l2_buffer));
- vbuf.index = i;
- vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vbuf.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_QUERYBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- dbmsg("len=%d, offset=%d", vbuf.length, vbuf.m.offset);
- if( (vmem[i] = v4l2_mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- dbmsg("Buffer mapped at address %p", vmem[i]);
- }
- for(i=0; i<NB_BUFFER; i++)
- {
- memset(&vbuf, 0, sizeof(struct v4l2_buffer));
- vbuf.index = i;
- vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vbuf.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- }
-
- //alloc framebuffer
- framesize = ((width*height)<<1);
- if( !(tempbuffer = malloc(framesize)))
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- if( !(framebuffer = malloc(width*height*8)))
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if( (ret = v4l2_ioctl(fd, VIDIOC_STREAMON, &type)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- }
-
-
- int main ( int argc, char *argv[] )
- {
- int i;
- SDL_Surface* psscreen;
- SDL_Overlay* overlay;
- SDL_Rect drect;
- SDL_Thread* sdl_thread;
- unsigned char* p;
- SDL_Init(SDL_INIT_EVERYTHING);
- psscreen = SDL_SetVideoMode(width, height, 0, SDL_SWSURFACE);
- SDL_WM_SetCaption( "YUV Window", NULL);
- /* Create a YUV overlay */
- overlay = SDL_CreateYUVOverlay(width, height, SDL_YUY2_OVERLAY, psscreen);
- p = (unsigned char*) overlay->pixels[0];
- drect.x = 0;
- drect.y = 0;
- drect.w = width;
- drect.h = height;
-
- init_camera();
-
- //sdl get signal quit
- affmutex = SDL_CreateMutex();
- sdl_thread = SDL_CreateThread(eventThread, NULL); //a.SDL创建线程
-
- while(signal_quit) //c.当主线程监测到signal_quit为空时,就退出主线程
- {
- memset(&vbuf, 0, sizeof(struct v4l2_buffer));
- vbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- vbuf.memory = V4L2_MEMORY_MMAP;
- if( (ret = v4l2_ioctl(fd, VIDIOC_DQBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- if(vbuf.bytesused > framesize)
- {
- memcpy(framebuffer, vmem[vbuf.index], (size_t)framesize);
- }else {
- memcpy(framebuffer, vmem[vbuf.index], (size_t)vbuf.bytesused);
- if( (ret=v4l2_ioctl(fd, VIDIOC_QBUF, &vbuf)) < 0)
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- }
- SDL_LockYUVOverlay(overlay);
- memcpy(p, framebuffer, width*height*2);
- SDL_UnlockYUVOverlay(overlay);
- SDL_DisplayYUVOverlay(overlay, &drect);
- SDL_Delay(10);
- }
- SDL_WaitThread(sdl_thread, &ret); //d.当线程退出时干清理的事
- SDL_DestroyMutex(affmutex);
- //close_v4l2
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if( (ret=v4l2_ioctl(fd, VIDIOC_STREAMOFF, &type)) < 0) //d.将STREAM关闭,这样下次还可以打开
- {
- dbmsg("error: %s", strerror(errno));
- return 0;
- }
- if(NULL != framebuffer)
- free(framebuffer);
- framebuffer = NULL;
-
- return EXIT_SUCCESS;
- }
- cong@msi:/work/test/uvcview/3display_1$
3display_1.rar (下载后改名为3display_1.tar.gz)
4. 说明
a. 为了让程序退出,这儿加入了SDL线程来监听退出事件,有退出事件触发时就通知主while退出
b. 在主while退出时需要把camera的视频关闭,这样下次才可以打开
c.关于为什么老是会出现下面的warning?
- display.c:102:19: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
- if( (vmem[i] = v4l2_mmap(0, vbuf.length, PROT_READ, MAP_SHARED, fd, vbuf.m.offset)) == MAP_FAILED)
看来有些warning也是需要重视的.