立即注册 登录
返回首页

uid:76155的个人空间

日志

摄像头的数据采集和TCP网络传送

已有 1560 次阅读2017-12-5 20:20 |个人分类:网络

具体源代码参见链接:
http://download.csdn.net/download/qq269131024/10142165
下面是视频采集的主程序:
#include <stdio.h>  
#include <string.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/types.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h> 
#include <errno.h>
#include <netinet/in.h>
#include <sys/wait.h> 
#include "camera.h"
#define     MAXLINE        1024  
#define DEBUG 1
void usage(char *command)  
{  
    printf("usage :%s portnum filename\n", command);  
    exit(0);  
}  
/*********************************************************************
* filename: tcpserver.c
*purpose: 循环tcp服务端程序
*tidied by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com)
*Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2006-07-04 22:00:00
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
*但请遵循GPL
*Thanks to: Google.com
*********************************************************************/
int main(int argc,char **argv)   
{  
    struct sockaddr_in     server_addr;  
    struct sockaddr_in     client_addr;  
    char                   buf[MAXLINE];  
    int                    server_sock_id;  
    int                    client_sock_id;  
    int                    recv_len;  
    int                    write_leng;  
    int                    client_addr_len;  
    FILE                   *fp; 
int   send_len;
//文件名
char * fileName="hello.txt";
//端口号
unsigned int serverport = 8050;
//视频大小
int width = 240;
int height = 320; 
char *separateur;
unsigned char* rgb;

/*
参数采集区
*/

/************************************************************

命令行输入参数设定命令行参数应该这个样子的:
./servfox -g -d /dev/video0 -s 640x480 -w 7070 -f fileName

***********************************************************/
int i;
for (i = 1; i < argc; i++)
    {
         /* skip bad arguments */
        if (argv[i] == NULL || *argv[i] == 0 || *argv[i] != '-')
        {
continue;
        }
/**************************************************************  /

 -d 参数用于设置输入视频采集设备。
      
****************************************************************/

        if (strcmp (argv[i], "-d") == 0)
{
if (i + 1 >= argc)
{
if(DEBUG) printf ("No parameter specified with -d, aborting./n");
exit (1);
}
//设置Parameter
            //videodevice = strdup (argv[i + 1]);
        }
/**********************************************************************

          -g 参数用于读取采集到的视频的方式,用read方式而非mmap方式。

 *********************************************************************/

        if (strcmp (argv[i], "-g") == 0)
{
            /* Ask for read instead default  mmap */
             //grabmethod = 0;
        }

 /************************************************************

          -s 参数用于设置视频图像帧的大小,如 640x480

 *********************************************************/ 
        if (strcmp (argv[i], "-s") == 0)
        {
if (i + 1 >= argc) 
{
if(DEBUG) printf ("No parameter specified with -s, aborting./n");
                   exit (1);
            }
            //sizestring = strdup (argv[i + 1]);
            //width = strtoul (sizestring, &separateur, 10);
if (*separateur != 'x') 
            {
if(DEBUG) printf ("Error in size use -s widthxheight /n");
                exit (1);
            }else {
++separateur;
                height =strtoul (separateur, &separateur, 10); 
                if (*separateur != 0)
                    if(DEBUG) printf ("hmm.. dont like that!! trying this height /n");
                if(DEBUG) printf (" size width: %d height: %d /n",
                    width, height);
            }
}
 /******************************************************

          -w参数用于设置端口。

 *********************************************************/
if (strcmp (argv[i], "-w") == 0)  
{
if (i + 1 >= argc) 
{
if(DEBUG) printf ("No parameter specified with -w, aborting./n");
exit (1);
}

 
serverport = (unsigned short) atoi (argv[i + 1]);
if (serverport < 1024  ){
if(DEBUG) printf ("Port should be between 1024 to 65536 set default 7070 !./n");
serverport = 8050;
}
}
/************************************************************
-f 用于设置文件名
*************************************************************/
if (strcmp (argv[i], "-f") == 0)  
{
if (i + 1 >= argc) 
{
if(DEBUG) printf ("No parameter specified with -f, aborting./n");
exit (1);
}
int ii;
char *str;
for(ii=0,str=argv[i + 1];str!='\0';ii++)
{
fileName[ii] = *str;
str++;
}
}
/************************************************************
-h 帮助信息
****************************************************************/
if (strcmp (argv[i], "-h") == 0)
{
printf ("usage: cdse [-h -d -g ] /n");
printf ("-h    print this message /n");
printf ("-d    /dev/videoX       use videoX device/n");
printf ("-g    use read method for grab instead mmap /n");
printf ("-s    widthxheight      use specified input size /n");
printf ("-w    port      server port /n");
exit (0);
}
}
  
/*

主代码区
*/
// printf("i am alive !");
// if ((fp = fopen(fileName, "w")) == NULL) {  
// perror("Open file failed\n");  
// exit(0);  
// }  
printf("i am alive 1!");
    if ((server_sock_id = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {  
        perror("Create socket failed\n");  
        exit(0);  
    }  
printf("i am alive 2!");
    /*fill the serverer sockaddr_in struct commented by guoqingbo*/  
    memset(&server_addr, 0, sizeof(server_addr));  
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(serverport);  
    server_addr.sin_addr.s_addr = INADDR_ANY;  
  
    if (bind(server_sock_id, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0 ) {  
        perror("Bind socket failed\n");  
        exit(0);  
    }  
printf("i am alive 3!");
    if (-1 == listen(server_sock_id, 20)) {  
        perror("Listen socket failed\n");  
        exit(0);  
    }  
    /* serverer part commented by guoqingbo*/  
    while (1) {  
        client_addr_len = sizeof(client_addr);  
/**
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd,struct sockaddr *addr,socklen_t *addrlen);

accept()系统调用:
主要用在基于连接的套接字类型,比如SOCK_STREAM和SOCK_SEQPACKET。
它提取出所监听套接字的等待连接队列中第一个连接请求,创建一个新的套接字,
并返回指向该套接字的文件描述符。新建立的套接字不在监听状态,
原来所监听的套接字也不受该系统调用的影响。

参数:
sockfd,利用系统调用socket()建立的套接字描述符,通过bind()绑定到一个本地地址
(一般为服务器的套接字),并且通过listen()一直在监听连接;
addr, 指向struct sockaddr的指针,该结构用通讯层服务器对等套接字的地址
(一般为客户端地址)填写,返回地址addr的确切格式由套接字的地址类别
(比如TCP或UDP)决定;若addr为NULL,没有有效地址填写,这种情况下,addrlen也不使用,
应该置为NULL;

备注:addr是个指向局部数据结构sockaddr_in的指针,这就是要求接入的信息本地的套接字(地址和指针)。
addrlen,    一个值结果参数,调用函数必须初始化为包含addr所指向结构大小的数值,
函数返回时包含对等地址(一般为服务器地址)的实际数值;
备注:addrlen是个局部整形变量,设置为sizeof(struct   sockaddr_in)。
///////////////////////////////////////////////////////////////////////

如果队列中没有等待的连接,套接字也没有被标记为Non-blocking,
accept()会阻塞调用函数直到连接出现;如果套接字被标记为Non-blocking,
队列中也没有等待的连接,accept()返回错误EAGAIN或EWOULDBLOCK。

成功时,返回非负整数,该整数是接收到套接字的描述符;出错时,返回-1,相应地设定全局变量errno。错误处理
**/
client_sock_id = accept(server_sock_id, (struct sockaddr *)&client_addr, &client_addr_len);  
if (-1 == client_sock_id) {  
perror("Accept socket failed\n");  
exit(0);  
camera_t* camera = camera_open("/dev/video0", height, width);
printf("open the camera success!\n");
camera_init(camera);
printf("camera init success!\n");
camera_start(camera);
printf("camera is starting!\n");
struct timeval timeout;
timeout.tv_sec = 1;
timeout.tv_usec = 0;
/* skip 5 frames for booting a cam */
for (i = 0; i < 5; i++) {
camera_frame(camera, timeout);
}
rgb = calloc(width * height * 3, sizeof (uint8_t));
while(1){
// printf("good morning!...");
camera_frame(camera, timeout);
// printf("we will capture a frame! yo\n");
yuyv2rgb888(camera->head.start,rgb,camera->width, camera->height);
// uint ii;
// uint8_t jj;
// for(ii=0;ii<height;ii++)
// for(jj=0;jj<width;jj++)
// {
// rgb[(ii*width+jj)*3+0]=jj;
// rgb[(ii*width+jj)*3+1]=jj;
// rgb[(ii*width+jj)*3+2]=jj;
// }
// printf("Sending...\n");
send_len = send(client_sock_id, rgb, width * height * 3*sizeof(uint8_t), 0); 
if ( send_len < 0 ) {  
perror("Send file failed\n");  
exit(0); 
}
// printf("I am going to sleepping good night!...\n");
// sleep(0.1);
        }
free(rgb);
camera_stop(camera);
printf("now I'm so sorry to tell you that we'l close the camera!haha\n");
camera_finish(camera);
camera_close(camera);
printf("Remeber to close the door,When you leave\n");
// printf("i am alive 4!");
        // bzero(buf, MAXLINE);  
        // while (recv_len = recv(client_sock_id, buf, MAXLINE, 0)) {  
            // /* receiver data part commented by guoqingbo*/  
            // if(recv_len < 0) {  
                // printf("Recieve Data From Server Failed!\n");  
                // break;  
            // }  
            // printf("#");  
            // write_leng = fwrite(buf, sizeof(char), recv_len, fp);  
            // if (write_leng < recv_len) {  
                // printf("Write file failed\n");  
                // break;  
            // }  
            // bzero(buf,MAXLINE);  
        // }  
        printf("\nFinish Recieve\n");  
        fclose(fp);  
        close(client_sock_id);  
    } 
printf("i am alive always yo!");
    close(server_sock_id);   
    return 0; 
}  

下面是所需的库函数
/*
 * capturing from UVC cam
 * requires: libjpeg-dev
 * build: gcc -std=c99 capture.c -ljpeg -o capture
 */

#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>

#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <asm/types.h>
#include <linux/videodev2.h>

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define FALSE  -1
#define TRUE 1
void quit(const char * msg)
{
  fprintf(stderr, "[%s] %d: %s\n", msg, errno, strerror(errno));
  exit(EXIT_FAILURE);
}

int xioctl(int fd, int request, void* arg)
{
  int i;
  for (i = 0; i < 100; i++) {
    int r = ioctl(fd, request, arg);
    if (r != -1 || errno != EINTR) return r;
  }
  return -1;
}

typedef struct {
  uint8_t* start;
  size_t length;
} buffer_t;

typedef struct {
  int fd;
  uint32_t width;
  uint32_t height;
  size_t buffer_count;
  buffer_t* buffers;
  buffer_t head;
} camera_t;


camera_t* camera_open(const char * device, uint32_t width, uint32_t height)
{
  int fd = open(device, O_RDWR | O_NONBLOCK, 0);
  if (fd == -1) 
  {
    perror("open error:"); 
    quit("open");
  }
  camera_t* camera = malloc(sizeof (camera_t));
  camera->fd = fd;
  camera->width = width;
  camera->height = height;
  camera->buffer_count = 0;
  camera->buffers = NULL;
  camera->head.length = 0;
  camera->head.start = NULL;
  return camera;
}


void camera_init(camera_t* camera) {
/**
struct v4l2_capability
{
__u8 driver[16];   //驱动名。
__u8 card[32];     // Device名
__u8 bus_info[32];  //在Bus系统中存放位置
__u32 version;      //driver 版本
__u32 capabilities;  //能力集
__u32 reserved[4];
};
**/
//第一个ioctl就是获取设备信息
  struct v4l2_capability cap;
  if (xioctl(camera->fd, VIDIOC_QUERYCAP, &cap) == -1) quit("VIDIOC_QUERYCAP");
  if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) quit("no capture");
  if (!(cap.capabilities & V4L2_CAP_STREAMING)) quit("no streaming");
  //打印信息
//  printf(“DriverName:%s/nCard Name:%s/nBus info:%s/nDriverVersion:%u.%u.%u/n”,cap.driver,cap.card,cap.bus_info,(cap.version>>16)&0XFF,(cap.version>>8)&0XFF,cap.version&OXFF);  
  /**
5. 帧格式:
VIDIOC_ENUM_FMT// 显示所有支持的格式  
int ioctl(int fd, int request, struct v4l2_fmtdesc *argp);  
struct v4l2_fmtdesc  
{  
__u32 index;   // 要查询的格式序号,应用程序设置  666
enumv4l2_buf_type type;     // 帧类型,应用程序设置 666 
__u32 flags;    // 是否为压缩格式  
__u8       description[32];      // 格式名称  
__u32pixelformat; // 格式  
__u32reserved[4]; // 保留  
};  
  
**/ 
struct v4l2_fmtdesc fmtdesc;  
fmtdesc.index=0;  
fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;  
printf("Supportformat:/n");  
while(ioctl(camera->fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1)  
{  
printf("/t%d.%s/n",fmtdesc.index+1,fmtdesc.description);  
fmtdesc.index++;  
}  
  
/**
6 图像的缩放 VIDIOC_CROPCAP
 
v4l2_cropcap 结构体用来设置摄像头的捕捉能力,
在捕捉上视频时应先先设置v4l2_cropcap 的 type 域,
再通过 VIDIO_CROPCAP 操作命令获取设备捕捉能力的参数,
保存于 v4l2_cropcap 结构体中,包括 bounds
(最大捕捉方框的左上角坐标和宽高),defrect
(默认捕捉方框的左上角坐标和宽高)等。
VIDIOC_CROPCAP  
int ioctl(int fd,int request, struct v4l2_cropcap *argp);  
structv4l2_cropcap  
{  
enum v4l2_buf_type type;// 应用程序设置  
struct v4l2_rectbounds;//     最大边界  
struct v4l2_rectdefrect;// 默认值  
structv4l2_fract pixelaspect;  
};  

V4L2_BUF_TYPE_VIDEO_CAPTURE 指定buf的类型为capture,用于视频捕获设备
V4L2_BUF_TYPE_VIDEO_OUTPUT 指定buf的类型output,用于视频输出设备
V4L2_BUF_TYPE_VIDEO_OVERLAY 指定buf的类型为overlay,用于overlay设备
V4L2_BUF_TYPE_VBI_CAPTURE 用于vbi捕获设备
V4L2_BUF_TYPE_VBI_OUTPUT 用于vbi输出设备
V4L2_BUF_TYPE_SLICED_VBI_CAPTURE 用于切片vbi捕获设备
V4L2_BUF_TYPE_SLICED_VBI_OUTPUT 用于切片vbi输出设备
V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY 用于视频输出overlay设备
V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE 用于多平面存储格式的视频捕获设备
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE用于多平面存储格式的视频输出设备
**/
  struct v4l2_cropcap cropcap;
  memset(&cropcap, 0, sizeof (cropcap));
  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  if (xioctl(camera->fd, VIDIOC_CROPCAP, &cropcap) == 0) {
    struct v4l2_crop crop;
    crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    crop.c = cropcap.defrect;
    if (xioctl(camera->fd, VIDIOC_S_CROP, &crop) == -1) {
      // cropping not supported
    }
  }
/**
// 查看或设置当前格式
VIDIOC_G_FMT,VIDIOC_S_FMT
// 检查是否支持某种格式
v4l2_format 结构体用来设置摄像头的视频制式、帧格式等,
在设置这个参数时应先填好 v4l2_format 的各个域,
如 type(传输流类型),fmt.pix.width(宽),
fmt.pix.heigth(高),fmt.pix.field(采样区域,如隔行采样),
fmt.pix.pixelformat(采样类型,如 yuyv4:2:2),
然后通过 VIDIO_S_FMT 操作命令设置视频捕捉格式。
如下图所示:
**/
  struct v4l2_format format;
  memset(&format, 0, sizeof (format));
  format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  format.fmt.pix.width = camera->width;
  format.fmt.pix.height = camera->height;
  format.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
  format.fmt.pix.field = V4L2_FIELD_NONE;
  if (xioctl(camera->fd, VIDIOC_S_FMT, &format) == -1) quit("VIDIOC_S_FMT");

  /**
9. 申请和管理缓冲区
应用程序和设备有三种交换数据的方法,直接 read/write、内存映射(memory mapping)
和用户指针。这里只讨论内存映射(memory mapping)。

9.1 向设备申请缓冲区 VIDIOC_REQBUFS
相关函数:
int ioctl(int fd, int request, struct v4l2_requestbuffers *argp);
struct v4l2_requestbuffers
{
u32 count; // 缓冲区内缓冲帧的数目
enum v4l2_buf_type type; // 缓冲帧数据格式
enum v4l2_memory memory; // 区别是内存映射还是用户指针方式
u32 reserved[2];
};
  **/
  struct v4l2_requestbuffers req;
  memset(&req, 0, sizeof (req));
  req.count = 4;
  req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  req.memory = V4L2_MEMORY_MMAP;
  if (xioctl(camera->fd, VIDIOC_REQBUFS, &req) == -1) quit("VIDIOC_REQBUFS");
  camera->buffer_count = req.count;
  camera->buffers = calloc(req.count, sizeof (buffer_t));

  size_t buf_max = 0;
  size_t i;
  for (i = 0; i < camera->buffer_count; i++) {
    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof (buf));
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;
    if (xioctl(camera->fd, VIDIOC_QUERYBUF, &buf) == -1)
      quit("VIDIOC_QUERYBUF");
/**
#include<sys/mman.h>
void *mmap(void*addr, size_t length, int prot, int flags, int fd, off_t offset);
//addr 映射起始地址,一般为NULL ,让内核自动选择
//length 被映射内存块的长度
//prot 标志映射后能否被读写,其值为PROT_EXEC,PROT_READ,PROT_WRITE,PROT_NONE
//flags 确定此内存映射能否被其他进程共享,MAP_SHARED,MAP_PRIVATE
//fd,offset, 确定被映射的内存地址
返回成功映射后的地址,不成功返回MAP_FAILED ((void*)-1);
int munmap(void*addr, size_t length);// 断开映射
//addr 为映射后的地址,length 为映射后的内存长度
**/
    if (buf.length > buf_max) buf_max = buf.length;
    camera->buffers[i].length = buf.length;
    camera->buffers[i].start =
      mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED,
           camera->fd, buf.m.offset);
printf("the image length is%d",buf.length);
    if (camera->buffers[i].start == MAP_FAILED) quit("mmap");
  }
  camera->head.start = malloc(buf_max);
}
/**
10.  缓冲区处理好之后,就可以开始获取数据了
10.1 启动 或 停止数据流 VIDIOC_STREAMON,VIDIOC_STREAMOFF
**/
void camera_start(camera_t* camera)
{
  size_t i;
  /**
  //argp 为流类型指针,如V4L2_BUF_TYPE_VIDEO_CAPTURE.
10.2 在开始之前,还应当把缓冲帧放入缓冲队列:
VIDIOC_QBUF// 把帧放入队列
VIDIOC_DQBUF// 从队列中取出帧
  **/
  for (i = 0; i < camera->buffer_count; i++) {
    struct v4l2_buffer buf;
    memset(&buf, 0, sizeof buf);
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = i;//代表放入第几个buff
    if (xioctl(camera->fd, VIDIOC_QBUF, &buf) == -1) quit("VIDIOC_QBUF");
  }
//启动 或 停止数据流 VIDIOC_STREAMON, VIDIOC_STREAMOFF
  enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  if (xioctl(camera->fd, VIDIOC_STREAMON, &type) == -1)
    quit("VIDIOC_STREAMON");
}

void camera_stop(camera_t* camera)
{
//启动 或 停止数据流 VIDIOC_STREAMON, VIDIOC_STREAMOFF
  enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  if (xioctl(camera->fd, VIDIOC_STREAMOFF, &type) == -1)
    quit("VIDIOC_STREAMOFF");
}

void camera_finish(camera_t* camera)
{
  size_t i;
  for (i = 0; i < camera->buffer_count; i++) {
    munmap(camera->buffers[i].start, camera->buffers[i].length);
  }
  free(camera->buffers);
  camera->buffer_count = 0;
  camera->buffers = NULL;
  free(camera->head.start);
  camera->head.length = 0;
  camera->head.start = NULL;
}

void camera_close(camera_t* camera)
{
  if (close(camera->fd) == -1) quit("close");
  free(camera);
}

//获取一帧并处理
int camera_capture(camera_t* camera)
{
  struct v4l2_buffer buf;
  memset(&buf, 0, sizeof buf);
  buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
  buf.memory = V4L2_MEMORY_MMAP;
  if (xioctl(camera->fd, VIDIOC_DQBUF, &buf) == -1) return FALSE;
  memcpy(camera->head.start, camera->buffers[buf.index].start, buf.bytesused);
  camera->head.length = buf.bytesused;
  if (xioctl(camera->fd, VIDIOC_QBUF, &buf) == -1) return FALSE;
  return TRUE;
}

int camera_frame(camera_t* camera, struct timeval timeout) {
/**
Select函数在Socket编程中还是比较重要的,可是对于初学Socket的人来说都不太爱用Select写程序,他们只是习惯写诸如connect、 accept、recv或recvfrom这样的阻塞程序(所谓阻塞方式block,顾名思义,就是进程或是线程执行到这些函数时必须等待某个事件的发生,如果事件没有发生,进程或线程就被阻塞,函数不能立即返回)。可是使用Select就可以完成非阻塞(所谓非阻塞方式non-block,就是进程或线程执行此函数时不必非要等待事件的发生,一旦执行肯定返回,以返回值的不同来反映函数的执行情况,如果事件发生则与阻塞方式相同,若事件没有发生则返回一个代码来告知事件未发生,而进程或线程继续执行,所以效率较高)方式工作的程序,它能够监视我们需要监视的文件描述符的变化情况——读写或是异常。下面详细介绍一下!
**/ 
  fd_set fds;
  FD_ZERO(&fds);
  FD_SET(camera->fd, &fds);
  int r = select(camera->fd + 1, &fds, 0, 0, &timeout);
  if (r == -1) quit("select");
  if (r == 0) return FALSE;
  return camera_capture(camera);
}






int minmax(int min, int v, int max)
{
  return (v < min) ? min : (max < v) ? max : v;
}

void yuyv2rgb(uint8_t* yuyv,uint8_t* rgb, uint32_t width, uint32_t height)
{
  size_t i,j;
  for (i = 0; i < height; i++) {
    for (j = 0; j < width; j += 2) {
      size_t index = i * width + j;
      int y0 = yuyv[index * 2 + 0] << 8;
      int u = yuyv[index * 2 + 1] - 128;
      int y1 = yuyv[index * 2 + 2] << 8;
      int v = yuyv[index * 2 + 3] - 128;
      rgb[index * 3 + 0] = minmax(0, (y0 + 359 * v) >> 8, 255);
      rgb[index * 3 + 1] = minmax(0, (y0 + 88 * v - 183 * u) >> 8, 255);
      rgb[index * 3 + 2] = minmax(0, (y0 + 454 * u) >> 8, 255);
      rgb[index * 3 + 3] = minmax(0, (y1 + 359 * v) >> 8, 255);
      rgb[index * 3 + 4] = minmax(0, (y1 + 88 * v - 183 * u) >> 8, 255);
      rgb[index * 3 + 5] = minmax(0, (y1 + 454 * u) >> 8, 255);
    }
  }
  
  // return rgb;
}
void yuyv2rgb888(uint8_t* yuyv,uint8_t* rgb, uint32_t width, uint32_t height)
{
 uint in, out = 0;  
 uint pixel_16;  
 uint8_t pixel_24[3];  
 uint pixel32;  
 int y0, u, y1, v;  
 for(in = 0; in < width * height * 2; in += 4) {  
 pixel_16 =  
  yuyv[in + 3] << 24 |  
  yuyv[in + 2] << 16 |  
  yuyv[in + 1] <<  8 |  
  yuyv[in + 0];//yuyv422每个像素2字节,每两个像素共用一个Cr,Cb值,即u和v,RGB24每个像素3个字节  
 y0 = (pixel_16 & 0x000000ff);  
 u  = (pixel_16 & 0x0000ff00) >>  8;  
 y1 = (pixel_16 & 0x00ff0000) >> 16;  
 v  = (pixel_16 & 0xff000000) >> 24;  
 pixel32 = convert_yuyv_to_rgb_pixel(y0, u, v);  
 pixel_24[0] = (pixel32 & 0x000000ff);  
 pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;  
 pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;  
 rgb[out++] = pixel_24[0];  
 rgb[out++] = pixel_24[1];  
 rgb[out++] = pixel_24[2];//rgb的一个像素  
 pixel32 = convert_yuyv_to_rgb_pixel(y1, u, v);  
 pixel_24[0] = (pixel32 & 0x000000ff);  
 pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;  
 pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;  
 rgb[out++] = pixel_24[0];  
 rgb[out++] = pixel_24[1];  
 rgb[out++] = pixel_24[2];  
 }  
// printf("\nthe rgb out is %d",out);
}
int convert_yuyv_to_rgb_pixel(int y, int u, int v)  
{  
 uint pixel32 = 0;  
 uint8_t *pixel = (uint8_t *)&pixel32;  
 int r, g, b;  
 r = y + (1.370705 * (v-128));  
 g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));  
 b = y + (1.732446 * (u-128));  
 if(r > 255) r = 255;  
 if(g > 255) g = 255;  
 if(b > 255) b = 255;  
 if(r < 0) r = 0;  
 if(g < 0) g = 0;  
 if(b < 0) b = 0;  
 pixel[0] = r * 220 / 256;  
 pixel[1] = g * 220 / 256;  
 pixel[2] = b * 220 / 256;  
 return pixel32;  
// int main()
// {
  // int i;
  // camera_t* camera = camera_open("/dev/video0", 352, 288);
  // printf("open the camera success!\n");
  // camera_init(camera);
  // printf("camera init success!\n");
  // camera_start(camera);
  // printf("camera is starting!\n");
  // struct timeval timeout;
  // timeout.tv_sec = 1;
  // timeout.tv_usec = 0;
  // /* skip 5 frames for booting a cam */
  // for (i = 0; i < 5; i++) {
    // camera_frame(camera, timeout);
  // }
  // camera_frame(camera, timeout);
  // printf("we will capture a frame! yo\n");
  // unsigned char* rgb =
    // yuyv2rgb(camera->head.start, camera->width, camera->height);
  // FILE* out = fopen("result.jpg", "w");

  
  // fclose(out);
  // free(rgb);
  // camera_stop(camera);
  // printf("now I'm so sorry to tell you that we'l close the camera!haha\n");
  // camera_finish(camera);
  // camera_close(camera);
  // printf("Remeber to close the door,When you leave\n");
  // return 0;
// }


路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

返回顶部