Linux 下V4l2摄像头采集图片,实现yuyv转RGB,RGB转BMP,RGB伸缩,jpeglib 库实现压缩RGB到内存中,JPEG经UDP发送功(转)
./configure CC=arm-linux-gnueabihf-gcc LD=arm-linux-gnueabihf-ld --host=arm-linux --prefix=/usr/local/jpeg --exec-prefix=/usr/local/jpeg --enable-shared --enable-static
make ; sudo make install
将此函数插入 v4l2grab.c 中,long rgb_to_jpeg(const char *rgb, char *jpeg)
arm-linux-gnueabihf-gcc v4l2grab.c -ljpeg -I/usr/local/jpeg/include -L/usr/local/jpeg/lib
正常生成a.out文件。
以下为转发内容:
http://blog.csdn.net/xuyangwyw/article/details/40476653
最近自己所在小组做了一个智能家居系统,本人主要负责摄像头图像采集部分,需要完成的功能是实现摄像头数据采集,而且图片需要在LCD上显示,需要经过网络远程发送,自己小白一个,做之前什么都不懂,经历各种查资料请教过后总算出效果了,感触颇深。这期间CSDN上各位大神的各种博客对自己帮助很大,在此一并谢过!!!!!同时也发现很多博客都只包含一个小部分,感觉如果有一个篇完整的介绍可能对新手会有帮助,因此在此简单介绍摄像头采集整个流程。第一次发博客,恳请各位大神多多指教,如有不妥之处,还请见谅。
废话少说,直接进正题。首先要说明的是我们的摄像头是在ARM Cortex-A8要下运行的,出来的图像结果与PC机上会有一定的不同,请各位注意。
1、驱动支持
在那位法国牙医的无私奉献下,Linux内核几乎支持所有的USB摄像头,不过要想自己的Linux内核支持USB免驱摄像头,还需要先配置内核,
Device Drivers ---> <*> Multimedia support ---> <*> Video For Linux [ ] Enable Video For Linux API 1 (DEPRECATED) [*] Video capture adapters ---> [*] V4L USB devices ---> <*> USB Video Class (UVC) [*] UVC input events device support
这样在板子上插入摄像头后终端就会有显示:
[root@farsight /]# usb 1-1.1: new full speed USB device using s3c2410-ohci and a ddress 4 uvcvideo: Found UVC 1.00 device Webcam C110 (046d:0829) input: Webcam C110 as /class/input/input2
同时输入命令:lsusb 也会有相应信息,在此不就不详细展开了,网上有很多资料。最主要的是此时进入/dev 目录下,ls 会新增加一个设备,我的是video0,不同情况下需自己确认,这个设备名很重要。至此,Linux内核对摄像头的驱动支持就没问题了。
2、开始操作摄像头
经典操作v4l2的方法一共也就那么步,大致为:打开设备->查看设备功能->设置图片格式->申请帧缓冲->内存映射->帧缓冲入列->开始采集->读数据(包括处理数据)->帧缓冲重新入列->关闭设备。看着名字挺霸气的,其实每一步都是调用内核驱动提供的出来的接口就可以了。
2.1 打开设备
fd = open(dev_name, O_RDWR, 0 );//打开设备文件,阻塞模式
if (fd < 0){
perror("open /dev/video0 fialed! ");
return -1;
}
打开一个open就OK了,注意此处用的是阻塞模式,如果是非阻塞模式(O_NONBLOCK)的话,即使摄像头尚未捕获到信息,驱动依旧会把缓存(DQBUFF)里的东西返回给应用程序,感觉这样有点不合理,也懂内核为何要这样设计。
2.2 查看设备功能
<span style="font-size:14px;">struct v4l2_capability cap;
ret = ioctl(fd, VIDIOC_QUERYCAP, &cap);//查看设备功能
if (ret < 0){
perror("requre VIDIOC_QUERYCAP fialed! \n");
return -1;
}
printf("driver:\t\t%s\n",cap.driver);
printf("card:\t\t%s\n",cap.card);
printf("bus_info:\t%s\n",cap.bus_info);
printf("version:\t%d\n",cap.version);
printf("capabilities:\t%x\n",cap.capabilities); if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE){
printf("Device %s: supports capture.\n",dev_name);
}
if ((cap.capabilities & V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING){
printf("Device %s: supports streaming.\n",dev_name);
}</span>
查看设备功能也没什么好说的,看代码就OK啦。
2.3 设置图片格式
struct v4l2_format fmt;
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = WIDTH;
fmt.fmt.pix.height = HEIGHT;
fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
if(-1 == ioctl(fd, VIDIOC_S_FMT, &fmt)){//设置图片格式
perror("set format failed!");
return -1;
}
if(-1 == ioctl(fd, VIDIOC_G_FMT, &fmt)){//得到图片格式
perror("set format failed!");
return -1;
} printf("fmt.type:\t\t%d\n",fmt.type);
printf("pix.pixelformat:\t%c%c%c%c\n", \
fmt.fmt.pix.pixelformat & 0xFF,\
(fmt.fmt.pix.pixelformat >> 8) & 0xFF, \
(fmt.fmt.pix.pixelformat >> 16) & 0xFF,\
(fmt.fmt.pix.pixelformat >> 24) & 0xFF);
printf("pix.width:\t\t%d\n",fmt.fmt.pix.width);
printf("pix.height:\t\t%d\n",fmt.fmt.pix.height);
printf("pix.field:\t\t%d\n",fmt.fmt.pix.field);
也是一个命令就完成:VIDIOC_S_FMT,其中WIDTH,HEGHT 是定义的宏,后面很多地方都要用这两个参数,定义成宏比传参方便。V4L2_PIX_FMT_YUYV 指定输出格式为YUYV,关于YUYV,RGB等等什么什么格式,网上也有很详细的介绍,比如这篇:谈谈RGB、YUY2、YUYV、YVYU、UYVY、AYUV。 当然,图片格式设置也不只这3个,还有像帧率什么的也是可以设置的。 需要注意的是,对于不用的摄像头,内核有不一样的支持,并不是你设置了就一定能用,如果内核中该视频设备驱动不支持你所设定的图像格式,视频驱动会重新修改struct v4l2_format结构体变量的值为该视频设备所支持的图像格式,所以在程序设计中,设定完所有的视频格式后,要获取实际的视频格式,要重新读取 struct v4l2_format结构体变量。
2.3.1 查看图片格式
if(-1 == ioctl(fd, VIDIOC_G_FMT, &fmt)){//得到图片格式
perror("set format failed!");
return -1;
} printf("fmt.type:\t\t%d\n",fmt.type);
printf("pix.pixelformat:\t%c%c%c%c\n", \
fmt.fmt.pix.pixelformat & 0xFF,\
(fmt.fmt.pix.pixelformat >> 8) & 0xFF, \
(fmt.fmt.pix.pixelformat >> 16) & 0xFF,\
(fmt.fmt.pix.pixelformat >> 24) & 0xFF);
printf("pix.width:\t\t%d\n",fmt.fmt.pix.width);
printf("pix.height:\t\t%d\n",fmt.fmt.pix.height);
printf("pix.field:\t\t%d\n",fmt.fmt.pix.field); <span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"> </span>
2.4 申请帧缓冲
<span style="font-size:14px;">req.count = 5;//申请缓冲数量
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ioctl(fd, VIDIOC_REQBUFS, &req);//申请缓冲,
if (req.count < 2){
perror("buffer memory is Insufficient! \n");
return -1;
}</span>
2.5 映射用户空间
<span style="font-size:14px;"> yuyv_buffers0 = calloc(req.count, sizeof(*yuyv_buffers0));//内存中建立对应空间
for (n_buffers = 0; n_buffers < req.count; ++n_buffers){
struct v4l2_buffer buf;//驱动中的一帧
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = n_buffers; if (-1 == ioctl(fd, VIDIOC_QUERYBUF, &buf)){//映射用户空间
perror("VIDIOC_QUERYBUF error!\n");
return -1;
} yuyv_buffers0[n_buffers].length = buf.length;
yuyv_buffers0[n_buffers].start =(char*) mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (MAP_FAILED == yuyv_buffers0[n_buffers].start){
close(fd);
perror("mmap faild! \n");
return -1;
} printf("Frame buffer %d: address = 0x%x, length = %d \n",req.count, (unsigned int)yuyv_buffers0[n_buffers].start, yuyv_buffers0[n_buffers].length);
}</span>
好像也没什么好说的..........不过这篇博客说得挺详细的,直接引用了,博主勿怪.....和菜鸟一起学linux之V4L2摄像头应用流程
2.6 申请到的缓冲进入队列
<span style="font-size:14px;"> </span><span style="font-size:14px;"> for (i=0; i<n_buffers; ++i){
struct v4l2_buffer buf;
CLEAR(buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
if ( -1 == ioctl(fd, VIDIOC_QBUF, &buf)){//申请到的缓冲进入队列
close(fd);
perror("VIDIOC_QBUF failed! \n");
return -1;
}
}</span>
直接看代码......
2.7 开始捕捉图像数据
<span style="font-size:14px;"> type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if (-1 == ioctl(fd, VIDIOC_STREAMON, &type)){//开始捕捉图像数据
close(fd);
perror("VIDIOC_STREAMON failed! ");
exit(-1);
} </span>
函数执行成功后,摄像头开始采数据,一般来说可以用一个select判断一帧视频数据是否采集完成,当视频设备驱动完成一帧视频数据采集并保存到视频缓冲区中时,select函数返回,应用程序接着可以读取视频数据;否则select函数阻塞直到视频数据采集完成。
<span style="font-size:14px;"> </span><span style="font-size:14px;"> enum v4l2_buf_type type;
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fd_set fds;
struct timeval tv;
int r; FD_ZERO(&fds);//将指定文件描述符集清空
FD_SET(fd, &fds);//在文件描述符集合中增加一个新的文件描述符
tv.tv_sec = 2;//time out
tv.tv_usec = 0;
r = select(fd+1, &fds, NULL, NULL, &tv);//判断摄像头是否准备好,tv是定时 if(-1 == r){
if(EINTR == errno){
printf("select erro! \n");
}
}
else if(0 == r){
printf("select timeout! \n");//超时
return 1;
//exit(EXIT_FAILURE);
} read_frame(); //处理一帧数据</span>
2.8 读数据
<span style="font-size:14px;"> file_fd = fopen(path1, "w");//yuyv图片
if (file_fd < 0){
perror("open test_mmap.jpg fialed! \n");
exit(-1);
} CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(fd, VIDIOC_DQBUF, &buf);//出列采集的帧缓冲,成功返回0
if(0 != ret){
printf("VIDIOC_DQBUF failed!\n");
exit(-1);<pre name="code" class="objc"> }<pre name="code" class="objc"> ret = fwrite(yuyv_buffers0[buf.index].start, yuyv_buffers0[buf.index].length, 1, file_fd);//将摄像头采集得到的yuyv数据写入文件中<pre name="code" class="objc"> if(ret <= 0){
printf("write yuyv failed!\n");
exit(-1);
}</span><span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"> </span><span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"> </span>
这里有个帧缓冲出列的概念,也就是读取里面的数据并保存置文件中,不过保存的文件是yuyv图片,直接打开自然是不行的,需要用工具YUVViewer.exe,并且工具软件里面的参数配置也必须符合你设定的图片格式,这样才能看到真正的效果。到此为止,恭喜你,已经成功的迈出第一步了。是的,你没听错,才第一步,一张图片要直接在LCD上显示,要远程发送,是不能直接用yuyv数据的,还得经过一系列转换。
2.9 帧缓冲入列
<span style="font-size:14px;"> ret = ioctl(fd, VIDIOC_QBUF,&buf);//帧缓冲入列
if(0 != ret){
printf("VIDIOC_QBUF failed!\n");
exit(-1);
}</span>
读取完帧缓冲里面的数据,别忘了将其入列,方便下次使用。
2.10 关闭设备
<span style="font-size:14px;">static void v4l2_close(void)
{
int i=0;
unmap:
for(i=0; i<n_buffers; ++i){
if(-1 == munmap(yuyv_buffers0[i].start, yuyv_buffers0[i].length)){
printf("munmap error! \n");
exit(-1);
}
}
close(fd);
exit(EXIT_SUCCESS);
}</span>
关闭设备一个close就可以了,不过需要注意的是还有一个解除内存映射的工作需要完成。
3.1 yuyv 转RGB
<span style="font-size:14px;">void yuyv_to_rgb(unsigned char* yuv,unsigned char* rgb)
{
unsigned int i;
unsigned char* y0 = yuv + 0;
unsigned char* u0 = yuv + 1;
unsigned char* y1 = yuv + 2;
unsigned char* v0 = yuv + 3; unsigned char* r0 = rgb + 0;
unsigned char* g0 = rgb + 1;
unsigned char* b0 = rgb + 2;
unsigned char* r1 = rgb + 3;
unsigned char* g1 = rgb + 4;
unsigned char* b1 = rgb + 5; float rt0 = 0, gt0 = 0, bt0 = 0, rt1 = 0, gt1 = 0, bt1 = 0; for(i = 0; i <= (WIDTH * HEIGHT) / 2 ;i++)
{
bt0 = 1.164 * (*y0 - 16) + 2.018 * (*u0 - 128);
gt0 = 1.164 * (*y0 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
rt0 = 1.164 * (*y0 - 16) + 1.596 * (*v0 - 128); bt1 = 1.164 * (*y1 - 16) + 2.018 * (*u0 - 128);
gt1 = 1.164 * (*y1 - 16) - 0.813 * (*v0 - 128) - 0.394 * (*u0 - 128);
rt1 = 1.164 * (*y1 - 16) + 1.596 * (*v0 - 128); if(rt0 > 250) rt0 = 255;
if(rt0< 0) rt0 = 0; if(gt0 > 250) gt0 = 255;
if(gt0 < 0) gt0 = 0; if(bt0 > 250) bt0 = 255;
if(bt0 < 0) bt0 = 0; if(rt1 > 250) rt1 = 255;
if(rt1 < 0) rt1 = 0; if(gt1 > 250) gt1 = 255;
if(gt1 < 0) gt1 = 0; if(bt1 > 250) bt1 = 255;
if(bt1 < 0) bt1 = 0; *r0 = (unsigned char)rt0;
*g0 = (unsigned char)gt0;
*b0 = (unsigned char)bt0; *r1 = (unsigned char)rt1;
*g1 = (unsigned char)gt1;
*b1 = (unsigned char)bt1; yuv = yuv + 4;
rgb = rgb + 6;
if(yuv == NULL)
break; y0 = yuv;
u0 = yuv + 1;
y1 = yuv + 2;
v0 = yuv + 3; r0 = rgb + 0;
g0 = rgb + 1;
b0 = rgb + 2;
r1 = rgb + 3;
g1 = rgb + 4;
b1 = rgb + 5;
}
}</span>
出列帧缓冲后就可以调用该函数,rgb 需要先开辟大小为WIDTH * HEIGTH * 3的空间,因为我们用的RGB是24位格式,3个字节分别代表一个像素点的R、G、B,根据公式转换就好了。
3.2 RGB 转BMP
<span style="font-size:14px;">void rgb_to_bmp(unsigned char* pdata, FILE* bmp_fd)
{
//分别为rgb数据,要保存的bmp文件名
int size = WIDTH * HEIGHT * 3 * sizeof(char); // 每个像素点3个字节
// 位图第一部分,文件信息
BMPFILEHEADER_T bfh;
bfh.bfType = (unsigned short)0x4d42; //bm
bfh.bfSize = size // data size
+ sizeof( BMPFILEHEADER_T ) // first section size
+ sizeof( BMPINFOHEADER_T ) // second section size
;
bfh.bfReserved1 = 0; // reserved
bfh.bfReserved2 = 0; // reserved
bfh.bfOffBits = sizeof( BMPFILEHEADER_T )+ sizeof( BMPINFOHEADER_T );//真正的数据的位置
// printf("bmp_head== %ld\n", bfh.bfOffBits);
// 位图第二部分,数据信息
BMPINFOHEADER_T bih;
bih.biSize = sizeof(BMPINFOHEADER_T);
bih.biWidth = WIDTH;
bih.biHeight = -HEIGHT;//BMP图片从最后一个点开始扫描,显示时图片是倒着的,所以用-height,这样图片就正了
bih.biPlanes = 1;//为1,不用改
bih.biBitCount = 24;
bih.biCompression = 0;//不压缩
bih.biSizeImage = size; bih.biXPelsPerMeter = 0;//像素每米 bih.biYPelsPerMeter = 0;
bih.biClrUsed = 0;//已用过的颜色,为0,与bitcount相同
bih.biClrImportant = 0;//每个像素都重要 fwrite( &bfh, 8, 1, bmp_fd);
fwrite(&bfh.bfReserved2, sizeof(bfh.bfReserved2), 1, bmp_fd);
fwrite(&bfh.bfOffBits, sizeof(bfh.bfOffBits), 1, bmp_fd);
fwrite(&bih, sizeof(BMPINFOHEADER_T), 1, bmp_fd);
fwrite(pdata, size, 1, bmp_fd);
} </span>
说是转,其实就是一个另存为,只是加个格式头而已,需要注意的也只有size, biWidth, biHeight 这几个参数而已,如果你发现你生成的BMP图是倒立的,改下bih.biHeight = -HEIGHT就OK了。
3.3 RGB放缩算法
void rgb_stretch(char* src_buf, char* dest_buf, int des_width, int des_hight)
{
//最临近插值算法
//双线性内插值算法放大后马赛克很严重 而且帧率下降严重
printf("des_width = %d, des_hight = %d \n ",des_width, des_hight);
double rate_w = (double) WIDTH / des_width;//横向放大比
double rate_h = (double) HEIGHT / des_hight;//轴向放大比 int dest_line_size = ((des_width * BITCOUNT +31) / 32) * 4;
int src_line_size = BITCOUNT * WIDTH / 8;
int i = 0, j = 0, k = 0;
for (i = 0; i < des_hight; i++)//desH 目标高度
{
//选取最邻近的点
int t_src_h = (int)(rate_h * i + 0.5);//rateH (double)srcH / desH;
for (j = 0; j < des_width; j++)//desW 目标宽度
{
int t_src_w = (int)(rate_w * j + 0.5);
memcpy(&dest_buf[i * dest_line_size] + j * BITCOUNT / 8, \
&src_buf[t_src_h * src_line_size] + t_src_w * BITCOUNT / 8,\
BITCOUNT / 8);
}
}
}
也尝试了双线性内插值算法,从原理上分析,应该是双线性内插值算法效果更好,结果却不是这样,为什么是这样,我这种菜鸟也弄不明白......
int numb = 0;
static int read_frame(char *rgb_buffers)
{
struct v4l2_buffer buf;
int ret =0;
static char path1[30];
static char path2[30];
FILE *file_fd;//yuyv 图片文件流
FILE *bmp_fd;//bmp 图片文件流 numb ++; sprintf(path1, "./test_mmap%d.jpg", numb);//文件名
sprintf(path2, "./image%d.bmp", numb);
printf("path1=%s, path2=%s %d\n", path1, path2, numb); file_fd = fopen(path1, "w");//yuyv图片
if (file_fd < 0){
perror("open test_mmap.jpg fialed! \n");
exit(-1);
}
bmp_fd = fopen(path2, "w");//bmp图片
if (bmp_fd < 0){
perror("open image.bmp failed!");
exit(-1);
}
CLEAR(buf);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ret = ioctl(fd, VIDIOC_DQBUF, &buf);//出列采集的帧缓冲,成功返回0
if(0 != ret){
printf("VIDIOC_DQBUF failed!\n");
exit(-1);
} yuyv_to_rgb(yuyv_buffers0[buf.index].start, rgb_buffers);//yuyv -> rgb24 rgb_stretch(rgb_buffers, dest_buffers, DEST_WIDTH, DEST_HEIGHT);//176 X 144 -> 320 X 240 rgb24_to_rgb565(dest_buffers, rgb565_buffers);//rgb24 -> rgb565 ret = fwrite(yuyv_buffers0[buf.index].start, yuyv_buffers0[buf.index].length, 1, file_fd);//将摄像头采集得到的yuyv数据写入文件中
if(ret <= 0){
printf("write yuyv failed!\n");
exit(-1);
} rgb_to_bmp(rgb565_buffers, bmp_fd);//rgb -> bmp ret = ioctl(fd, VIDIOC_QBUF,&buf);//帧缓冲入列
if(0 != ret){
printf("VIDIOC_QBUF failed!\n");
exit(-1);
}
fclose(file_fd);
fclose(bmp_fd);
return 1;
}
这个函数,调用了以上3.1 - 3.3 列举出来的所有函数,当然了,是先放大还是先保存怎样怎样的,大家都可以自己调整。
3.4 RGB 转JPEG
long rgb_to_jpeg(const char *rgb, char *jpeg)
{
long jpeg_size;
struct jpeg_compress_struct jcs;
struct jpeg_error_mgr jem;
JSAMPROW row_pointer[1];
int row_stride; jcs.err = jpeg_std_error(&jem);
jpeg_create_compress(&jcs); jpeg_mem_dest(&jcs, jpeg, &jpeg_size);//就是这个函数!!!!!!! jcs.image_width = WIDTH;
jcs.image_height = HEIGHT; jcs.input_components = 3;//1;
jcs.in_color_space = JCS_RGB;//JCS_GRAYSCALE; jpeg_set_defaults(&jcs);
jpeg_set_quality(&jcs, 180, TRUE); jpeg_start_compress(&jcs, TRUE);
row_stride =jcs.image_width * 3; while(jcs.next_scanline < jcs.image_height){//对每一行进行压缩
row_pointer[0] = &rgb[jcs.next_scanline * row_stride];
(void)jpeg_write_scanlines(&jcs, row_pointer, 1);
}
jpeg_finish_compress(&jcs);
jpeg_destroy_compress(&jcs); #ifdef JPEG //jpeg 保存,测试用
FILE *jpeg_fd; sprintf(path3, "./jpeg%d.jpg", numb);
jpeg_fd = fopen(path3,"w");
if(jpeg_fd < 0 ){
perror("open jpeg.jpg failed!\n");
exit(-1);
} fwrite(jpeg, jpeg_size, 1, jpeg_fd);
close(jpeg_fd);
#endif
return jpeg_size;
}
上面的代码注释不是很详细,jpeglib 详细使用方法看这篇博客就OK:利用jpeglib压缩图像为jpg格式,想必大家也发现了,是的,如果你用的是jpeg_stdio_dest()函数,那么就是文件操作,最后压缩完成的结果直接保存在文件中,反之,如果你用的是jpeg_mem_dest()函数,那么压缩完成的结果就保存在内存中。
Linux 下V4l2摄像头采集图片,实现yuyv转RGB,RGB转BMP,RGB伸缩,jpeglib 库实现压缩RGB到内存中,JPEG经UDP发送功(转)的更多相关文章
- C语言高级应用---操作linux下V4L2摄像头应用程序
我们都知道,想要驱动linux下的摄像头,其实很简单,照着V4L2的手册一步步来写,很快就可以写出来,但是在写之前我们要注意改变系统的一些配置,使系统支持framebuffer,在dev下产生fb0这 ...
- C语言高级应用---操作linux下V4L2摄像头应用程序【转】
转自:http://blog.csdn.net/morixinguan/article/details/51001713 版权声明:本文为博主原创文章,如有需要,请注明转载地址:http://blog ...
- 基于V4L2摄像头采集图片程序设计
#ifndef __COMMON_H #define __COMMON_H //该头文件定义的是摄像头在屏幕上显示的宽度和高度 #include<stdio.h> #include< ...
- Linux下用FFMPEG采集usb摄像头到RTMP
Linux下用 FFMPEG 采集 usb摄像头视频 和 摄像头内置麦克风音频 到RTMP服务 ffmpeg -f video4linux2 -qscale 10 -r 12 -s 640x480 ...
- linux下tomcat6无法显示图片验证码 少了图形插件
linux下tomcat6无法显示图片验证码(windows下显示正常) 原创 2015年10月20日 10:31:47 3526 linux下tomcat6无法显示图片验证码(windows下显示正 ...
- 网络采集软件核心技术剖析系列(5)---将任意博主的全部博文下载到内存中并通过Webbrower显示(将之前的内容综合到一起)
一 本系列随笔概览及产生的背景 自己开发的豆约翰博客备份专家软件工具问世3年多以来,深受广大博客写作和阅读爱好者的喜爱.同时也不乏一些技术爱好者咨询我,这个软件里面各种实用的功能是如何实现的. 该软件 ...
- VC++使用CImage在内存中Jpeg转换Bmp图片
VC++中Jpeg与Bmp图片格式互转应该是会经常遇到,Jpeg相比Bmp在图片大小上有很大优势. 本文重点介绍使用现有的CImage类在内存中进行转换,不需要保存为文件,也不需要引入第三方库. Li ...
- linux之V4L2摄像头应用流程【转】
本文转载自:http://blog.csdn.net/tommy_wxie/article/details/11486907 对于v4l2,上次是在调试收音机驱动的时候用过,其他也就只是用i2c配置一 ...
- Linux之V4L2视频采集编程详解
V4L2(Video For Linux Two) 是内核提供给应用程序访问音.视频驱动的统一接口. Linux系统中,视频设备被当作一个设备文件来看待,设备文件存放在 /dev目录下,完整路径的设 ...
随机推荐
- 项目构建工具gradle
1.安装 https://gradle.org/install 2.构建一个项目 https://guides.gradle.org/creating-new-gradle-builds/ 3.bui ...
- 使用路径arc-奥运五环
<!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head> < ...
- zuul网关源码解析
zuul网关源码解析 zuul请求的生命周期 ZuulServlet ZuulServlet定义了对zuul整个过程的处理,如下: public void service(javax.servlet. ...
- Object是个什么鬼
引言 老人常说,在js中,一切皆对象,那对象又是什么涅,最常用的我们都知道,对象有方法和属性.由一些键值对构成的集合,然后随便用个大括号括起来就形成了一个对象.看起来蛮简单的,但是真是这么简单么,当我 ...
- oracle 产生一个任意大小的随机数
SELECT DBMS_RANDOM.RANDOM FROM DUAL; 产生一个任意大小的随机数 SELECT ABS(MOD(DBMS_RANDOM.RANDOM,100)) F ...
- 微信小程序绑定数据(微信小程序交流群:604788754)
在小程序开发中,用js绑定数据时,明明没报错,但页面没有显示绑定的数据内容.这有可能是相对应的js绑定数据的一些变量名字的问题.遇到这种情况.可以从新建立一个新的demo页面.把问题页面相对应的js. ...
- MinGW安装教程——著名C/C++编译器GCC的Windows版本
前言本文主要讲述如何安装 C语言 编译器——MinGW,特点是文章附有完整详细的实际安装过程截图,文字反而起说明提示作用. 编写本文的原因始于我的一个观点:图片可以比文字传达更多的信息,也能让其他人更 ...
- ansible with_subelements
with_subelements 循环列表中的子元素 (意想不到的地方会用到) --- - hosts: web tasks: - authorized_key: "user={{ item ...
- bjui的ajax form不使用validate的表单验证
当form使用data-toggle为ajaxform或者是validate的时候,表单的onSubmit()和submit按钮的click()事件明明return false:还是会提交. 如果将d ...
- IntelliJ IDEA 2017.01配置jdk和tomcat
之前开发Web项目都是用myeclipse或者eclipse,最近想用IDEA这个编辑器去配置一个Web项目,因为是新手,加上对界面的操作不熟练,所以在配置的过程中遇到了一些难题.最后配置成功,并且可 ...