V4L2拍照程序

由于毕设中用到了摄像头拍照功能,然后网上查了一下,最后自己稍微修改,以当前时间保存为.jpeg格式的图片,最后稍微添加了自己的一些小理解,与大家分享一下。

-----------------------------------------------------------------------------------------------------------------------------------

用的摄像头是ZC301P,已经加载进内核,输出格式是JPEG,大小是640*480,所以后面的图片大小计算的时候是640*480*3。

cam.c:

#include <fcntl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <time.h>
#include <stdio.h>
#include <string.h>

int main(){
  //////add by liuzj
  time_t t;
  struct tm *tmp;
  t = time(NULL);
  tmp = localtime(&t);
  char buffer1[30];
  char path[30];
  /////end
  int fd = open("/dev/video0",O_RDWR);
  printf("lzj------->>>fd is %d\n",fd);
  //////
  struct v4l2_capability cap;
  ioctl(fd,VIDIOC_QUERYCAP,&cap);
  printf("lzj---------->>>>>Driver Name:%s\nCard Name:%s\nBus info:%s\n",cap.driver,cap.card,cap.bus_info);
  //////
  struct v4l2_fmtdesc fmtdesc;
  fmtdesc.index = 0;
  fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc) != -1){
   printf("lzj-------->>>>>fmtdesc.description is %s\n",fmtdesc.description);
   fmtdesc.index ++;
  }
  //////
  struct v4l2_format fmt;
  fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  ioctl(fd,VIDIOC_G_FMT,&fmt);
  printf("lzj----------->>>>>fmt.fmt.width is %d\nfmt.fmt.pix.height is %d\nfmt.fmt.pix.colorspace is %d\n",fmt.fmt.pix.width,fmt.fmt.pix.height,fmt.fmt.pix.colorspace);
  //////
  struct v4l2_requestbuffers req;
  req.count = 4;
  req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  req.memory = V4L2_MEMORY_MMAP;
  ioctl(fd,VIDIOC_REQBUFS,&req);
  struct buffer
  {
    void *start;
    unsigned int length;
  }*buffers;
  buffers = (struct buffer*)calloc (req.count, sizeof(*buffers));
  unsigned int n_buffers = 0;
  for(n_buffers = 0; n_buffers < req.count; ++n_buffers)
 {
    struct v4l2_buffer buf;
    memset(&buf,0,sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = n_buffers;
    if(ioctl(fd,VIDIOC_QUERYBUF,&buf) == -1)
	{
      printf("lzj---------_>>>>>>error\n");
      close(fd);
      exit(-1);
    }
    buffers[n_buffers].length = buf.length;
    buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);
    if(MAP_FAILED == buffers[n_buffers].start)
	{
      printf("lzj--------__>>>>>error 2\n");
      close(fd);
      exit(-1);
    }
  }
  ////
  unsigned int i;
  enum v4l2_buf_type type;
  for(i = 0; i < 4; i++)
  {
    struct v4l2_buffer buf;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    ioctl(fd,VIDIOC_QBUF,&buf);
  }
  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  ioctl(fd,VIDIOC_STREAMON,&type);
  ////
  struct v4l2_buffer buf;
  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  buf.memory = V4L2_MEMORY_MMAP;
  ioctl(fd,VIDIOC_DQBUF,&buf);
  //add by liuzj
  strftime(buffer1, sizeof(buffer1), "%Y-%m-%d_%H-%M.jpeg", tmp);
  snprintf(path,sizeof(path),"/data/%s",buffer1); //modify by liuzj
  int fdyuyv = open(path,O_WRONLY|O_CREAT,00700);
  printf("\nlzj--------->>>>fdyuyv is %d\n",fdyuyv);
  int resultyuyv = write(fdyuyv,buffers[buf.index].start,640*480*3);
  printf("lzj--------->>>resultyuyv is %d\n",resultyuyv);
  close(fdyuyv);
  ////
  close(fd);
  return 0;
}

交叉编译好了之后,可以移到开发板上直接运行。

/apps >: pic

lzj------->>>fd is 3

lzj---------->>>>>Driver Name:zc3xx

Card Name:PC Camera

Bus info:usb-s3c24xx-1.1

lzj-------->>>>>fmtdesc.description is JPEG

lzj----------->>>>>fmt.fmt.width is 640

fmt.fmt.pix.height is 480

fmt.fmt.pix.colorspace is 7

lzj--------->>>>fdyuyv is 4

lzj--------->>>resultyuyv is 118784

会打印出我摄像头支持的格式和采集的相关参数,然后进入我存放的目录下去寻找我的图片,再利用tftp命令来将其传到电脑上查看。

/apps >: cd /data/

/data >: ls

2016-05-09 12-47.jpeg

/date >: tftp -pr 2016-05-09 12-47.jpeg 10.228.26.4

最后贴上我的一点小注释
 1.打开摄像头
int fd = open("/dev/video0",O_RDWR);

2.捕获摄像头能力及属性

ioctl(fd,VIDIOC_QUERYCAP,&cap);
1.查看当前摄像头支持的视频格式

ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)
2.查看视频帧格式
ioctl(fd,VIDIOC_G_FMT,&fmt);//读取当前驱动的捕捉格式

5.向驱动申请缓冲帧
ioctl(fd,VIDIOC_REQBUFS,&req);//向驱动申请缓冲帧
req.count = 4;//申请4个缓冲区
req.memory = V4L2_MEMORY_MMAP;//设置使用mmap来访问内存

6.申请物理内存并进行内存映射
将申请到的帧缓冲映射到用户空间,这样就可以直接操作采集到的帧了,而不必去复制。将申请到的帧缓冲全部入队列,以便存放采集到的数据,利用mmap进行映射。
    struct buffer
   {
     void *start;
     unsigned int length;
    }*buffers;
buffers = (struct buffer*)calloc (req.count, sizeof(*buffers));
for(n_buffers = 0; n_buffers < req.count; ++n_buffers)
 {
    struct v4l2_buffer buf;
    memset(&buf,0,sizeof(buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = n_buffers;
    if(ioctl(fd,VIDIOC_QUERYBUF,&buf) == -1)
{
      printf("lzj---------_>>>>>>error\n");
      close(fd);
      exit(-1);
    }
    buffers[n_buffers].length = buf.length;
    buffers[n_buffers].start = mmap(NULL,buf.length,PROT_READ|PROT_WRITE,MAP_SHARED,fd,buf.m.offset);
    if(MAP_FAILED == buffers[n_buffers].start)
{
      printf("lzj--------__>>>>>error 2\n");

7.开始视频传输
 for(i = 0; i < 4; i++)
  {
    struct v4l2_buffer buf;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    ioctl(fd,VIDIOC_QBUF,&buf);
  }//将4个缓冲区放入输入队列中去,VIDIOC_QBUF为其控制命令。
  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  ioctl(fd,VIDIOC_STREAMON,&type);//开始进行视频采集

8.采集图像
从视频缓冲区的输出队列中取得一个已经保存有一帧视频数据的视频缓冲区。
struct v4l2_buffer buf;
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
ioctl(fd,VIDIOC_DQBUF,&buf);
//从视频的缓冲区中取得一个缓冲区数据到buf中去,VIDIOC_DQBUF为其控制命令。

9.将采集到的图片以当前时间保存下来
strftime(buffer1, sizeof(buffer1), "%Y-%m-%d_%H-%M.jpeg", tmp);
snprintf(path,sizeof(path),"/data/%s",buffer1);
int fdyuyv = open(path,O_WRONLY|O_CREAT,00700);
int resultyuyv = write(fdyuyv,buffers[buf.index].start,640*480*3);
close(fdyuyv);
close(fd);

时间: 2024-10-28 19:24:35

V4L2拍照程序的相关文章

UWP 调用系统拍照程序

当需要用户选择照片时,一般有两种方法: 1.从本地磁盘选择 2.调用照相机拍照 这次就说一下第二种方法,毕竟第一种大家都会. 先看下效果 如图所示,点击拍照后,会弹出系统照相机界面,在手机上,会打开相机app CameraCaptureUI captureUI = new CameraCaptureUI(); captureUI.PhotoSettings.Format = CameraCaptureUIPhotoFormat.Jpeg; captureUI.PhotoSettings.Allo

Intent调用系统拍照程序,返回图片太小的问题

之前採用的方式(返回的照片会被压缩,不能达到预期效果): Intent intent = new Intent(); Intent intent_camera = getPackageManager() .getLaunchIntentForPackage("com.android.camera"); if (intent_camera != null) { intent.setPackage("com.android.camera"); } intent.setA

iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

iOS开发系列--音频播放.录音.视频播放.拍照.视频录制 转载:http://www.cnblogs.com/kenshincui/p/4186022.html#avFoundationCamera --iOS多媒体 概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操作都提供了多套API.在今天的文章中将会对这些内容进行一一介绍: 音频 音

关于android中调用系统拍照,返回图片是旋转90度..

由于项目的需要,没有自定义拍照功能,仅仅调用了系统的拍照程序..但是出现了一个问题,就是拍照完成显示图片居然是被旋转的图片.... 解决办法: /** * 获取图片的旋转角度,有些系统把拍照的图片旋转了,有的没有旋转 */ int degree = readPictureDegree(f.getAbsolutePath()); BitmapFactory.Options opts=new BitmapFactory.Options();//获取缩略图显示到屏幕上 opts.inSampleSiz

音频播放、录音、视频播放、拍照、视频录制-b

随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操作都提供了多套API.在今天的文章中将会对这些内容进行一一介绍: 音频 音效 音乐 音频会话 录音 音频队列服务 视频 MPMoviePlayerController MPMoviePlayerViewController AVPlayer 摄像头 UIImagePickerController拍照

Android实战技巧之四十七:不用预览拍照与图片缩放剪裁

副标题:Take Picture without preview Android Google出于对隐私的保护,制定了一条门槛,即在Android应用开发中编写拍照程序是必需要有图像预览的.这会对那些恶意程序比如Android中泛滥的Service在后台偷偷记录手机用户的行为与周边信息.这样的门槛还包括手机厂商自带的相机软件在拍照时必须是有声音,这样要避免一些偷拍的情况. 处于技术调研与一些特殊无害场景的使用,我们要用到不用预览的拍照.此文就是以此为背景,做的一些调研.只是用不多与五款手机测试,

Android Camera 使用小结。两种方法:一是调用系统camera app,二是自己写camera程序。

源文链接:http://www.cnblogs.com/franksunny/archive/2011/11/17/2252926.html Android Camera 使用小结 Android手机关于Camera的使用,一是拍照,二是摄像,由于Android提供了强大的组件功能,为此对于在Android手机系统上进行Camera的开发,我们可以使用两类方法:一是借助Intent和MediaStroe调用系统Camera App程序来实现拍照和摄像功能,二是根据Camera API自写Came

Android拍照,相册选择图片以及Android6.0权限管理

概述 在android开发过程中,拍照或者从相册中选择图片是很常见的功能.下面要说得这个案例比较简单,用户点击按钮选择拍照或者打开相册选择图片,然后将选中的图片显示在手机上.android6.0后,推出了动态权限管理.以往我们将涉及到的权限全部写在清单文件中,只要用户安装了该程序,程序在运行过程中都会获得相应权限.android6.0后,对于一些特别敏感的权限,开发者必须在程序中进行声明.拍照和从相册选择图片都是涉及到用户隐私的敏感权限,必须在程序中进行声明. 大概的流程 创建布局文件,这里不多

iOS开发–音频播放、录音、视频播放、拍照、视频录制

概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像头的操作都提供了多套API.在今天的文章中将会对这些内容进行一一介绍: 音频 在iOS中音频播放从形式上可以分为音效播放和音乐播放.前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度.循环等控制.后者指的是一些较长的音频,通常是主音频,对于这些音频的播放通常需要进行精确的控制