一. 用SDL显示camera图像
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;
-
}
2.2 Makefile
-
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$
3.源码打包
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$
3. 代码打包
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)
最后发现原来是#include
<libv4l2
.h
>没有加入头文件,我说这个warning怎么提示v4l2_mmap返回的是integer呢?
看来有些warning也是需要重视的.
阅读(2541) | 评论(0) | 转发(0) |