Linux下的视频传输

利用网线在电脑与开发板之间组成一个局域网,能够让电脑与开发板之间的网络互通,(记着要IP地址固定哟!!)
在电脑上挂载摄像头并作为服务端,开发板在显示屏上显示摄像头所拍摄的画面。

服务端

利用V4L2来采集视频
V4L2 是 Video for linux two 的简称,是 Linux 内核中视频类设备的一套驱动框架,为视频类设备驱动开发和应用层提供了一套统一的接口规范。

  1. 首先是打开摄像头设备;
/* 初始化摄像头 */
static int v4l2_dev_init(char *path)
{
    v4l2_fd = open(path, O_RDWR);
    if(v4l2_fd < 0) {
        perror("open_video error");
        exit(1);
    }
    return 1;
}
  1. 枚举出摄像头所支持的所有视频像素格式\采集分辨率\帧率
/* 枚举出摄像头所支持的所有视频像素格式\采集分辨率\帧率 */
static void v4l2_print_formats(void)
{
    struct v4l2_fmtdesc fmtdesc;
    struct v4l2_frmsizeenum frmsize;
    struct v4l2_frmivalenum frmival;

    fmtdesc.index = 0;
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频采集
    /*查看支持的像素格式*/
    while(ioctl(v4l2_fd, VIDIOC_ENUM_FMT, &fmtdesc)==0)
    {
        printf("fmt: \" %s \"  <0x%d>\n", fmtdesc.description, fmtdesc.pixelformat);
        fmtdesc.index++;

        frmsize.index = 0;
        frmsize.type =  V4L2_BUF_TYPE_VIDEO_CAPTURE;
        frmsize.pixel_format = fmtdesc.pixelformat;
        /*查看支持的分辨率*/
        while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0)
        {
            printf("frm_size<%d*%d>   ", frmsize.discrete.width, frmsize.discrete.height);
            frmsize.index++;

            frmival.index = 0;
            frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            frmival.pixel_format = fmtdesc.pixelformat;
            frmival.width = frmsize.discrete.width;
            frmival.height = frmsize.discrete.height;
            /*查看支持的帧率*/
            while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) == 0)
            {
                printf("<%dfps>\n", (frmival.discrete.denominator / frmival.discrete.numerator));
                frmival.index++;
            }
        }
        printf("\r\n");
    }
}
  1. 设置设备的参数,譬如像素格式、 帧大小
/* 设置格式 */
static int v4l2_set_format(unsigned int format, int width, int height)
{
    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 = format;//设置视频输出格式
    if(ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt) < 0){
        printf("Error: v4l2_set_format\r\n");
        return 0;
    }
    /*查询当前摄像头的工作模式*/
    ioctl(v4l2_fd, VIDIOC_G_FMT, &fmt);
    printf("width:%d, height:%d \n", fmt.fmt.pix.width, fmt.fmt.pix.height);
    return 1;
}
  1. 申请帧缓冲、内存映射
/*申请帧缓冲、内存映射*/
static int v4l2_init_buffer(void)
{
    struct v4l2_requestbuffers reqbuf;
    struct v4l2_buffer buf;

    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf.count = 4;  //帧缓冲的数量
    reqbuf.memory =  V4L2_MEMORY_MMAP;
    /*申请帧缓冲*/
    if(ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0){
        printf("error: v4l2_init_buffer\r\n");
        return 0;
    }

    buf.index = 0;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    /*内存映射*/
    for(buf.index = 0;buf.index < 4;buf.index++)
    {
        ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf);
        frm_base[buf.index] = mmap(NULL, buf.length, \
                                PROT_READ | PROT_WRITE, MAP_SHARED, \
                                v4l2_fd, buf.m.offset);
        if (MAP_FAILED == frm_base[buf.index]) {
            perror("mmap error");
            return -1;
        }
        printf("查询内存成功  buf[%d]==%d长度\r\n",buf.index,buf.length);
        if(ioctl(v4l2_fd,VIDIOC_QBUF,&buf) < 0){//加入缓冲队列
            printf("error: VIDIOC_QBUF\r\n");
            return 0;
        }
    }
    return 1;
}
  1. 打开摄像头
static int v4l2_stream_on(void)
{
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    /* 打开摄像头、摄像头开始采集数据 */
    if(ioctl(v4l2_fd,  VIDIOC_STREAMON, &type) < 0){
        printf("error: v4l2_stream_on\r\n");
        return 0;
    }
    printf("Camera_open : success\r\n");
    return 1;
}
  1. 读取数据
static void v4l2_read_data(void)
{
    struct v4l2_buffer buf;

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 1;

    while(1)
    {
		for(buf.index = 1; buf.index < 4; buf.index++)
		{
		    if(ioctl(v4l2_fd, VIDIOC_DQBUF, &buf)!=0)//出队
		    {
		        printf("提取数据失败\r\n");
		        break;
		    }
            Send_Video_Data(connfd,frm_base[buf.index],buf.length);

		    if(ioctl(v4l2_fd, VIDIOC_QBUF, &buf)!=0)//入队
		    {
		        printf("放回队列失败\r\n");
		        exit(0);
		    }
		    usleep(33000);
		}
    }
}

服务端整体代码

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>     
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>

#define SERVER_PORT 55555

static int sockfd, connfd;
static int v4l2_fd = -1;               //摄像头设备文件描述符
static unsigned char *frm_base[4] = {NULL};             //帧缓冲起始地址

/* 初始化摄像头 */
static int v4l2_dev_init(char *path)
{
    v4l2_fd = open(path, O_RDWR);
    if(v4l2_fd < 0) {
        perror("open_video error");
        exit(1);
    }
    return 1;
}
/* 枚举出摄像头所支持的所有视频像素格式\采集分辨率\帧率 */
static void v4l2_print_formats(void)
{
    struct v4l2_fmtdesc fmtdesc;
    struct v4l2_frmsizeenum frmsize;
    struct v4l2_frmivalenum frmival;

    fmtdesc.index = 0;
    fmtdesc.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频采集
    /*查看支持的像素格式*/
    while(ioctl(v4l2_fd, VIDIOC_ENUM_FMT, &fmtdesc)==0)
    {
        printf("fmt: \" %s \"  <0x%d>\n", fmtdesc.description, fmtdesc.pixelformat);
        fmtdesc.index++;

        frmsize.index = 0;
        frmsize.type =  V4L2_BUF_TYPE_VIDEO_CAPTURE;
        frmsize.pixel_format = fmtdesc.pixelformat;
        /*查看支持的分辨率*/
        while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &frmsize) == 0)
        {
            printf("frm_size<%d*%d>   ", frmsize.discrete.width, frmsize.discrete.height);
            frmsize.index++;

            frmival.index = 0;
            frmival.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
            frmival.pixel_format = fmtdesc.pixelformat;
            frmival.width = frmsize.discrete.width;
            frmival.height = frmsize.discrete.height;
            /*查看支持的帧率*/
            while(ioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &frmival) == 0)
            {
                printf("<%dfps>\n", (frmival.discrete.denominator / frmival.discrete.numerator));
                frmival.index++;
            }
        }
        printf("\r\n");
    }
}
/* 设置格式 */
static int v4l2_set_format(unsigned int format, int width, int height)
{
    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 = format;//设置视频输出格式
    if(ioctl(v4l2_fd, VIDIOC_S_FMT, &fmt) < 0){
        printf("Error: v4l2_set_format\r\n");
        return 0;
    }
    /*查询当前摄像头的工作模式*/
    ioctl(v4l2_fd, VIDIOC_G_FMT, &fmt);
    printf("width:%d, height:%d \n", fmt.fmt.pix.width, fmt.fmt.pix.height);
    return 1;
}
/*申请帧缓冲、内存映射*/
static int v4l2_init_buffer(void)
{
    struct v4l2_requestbuffers reqbuf;
    struct v4l2_buffer buf;

    reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    reqbuf.count = 4;  //帧缓冲的数量
    reqbuf.memory =  V4L2_MEMORY_MMAP;
    /*申请帧缓冲*/
    if(ioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0){
        printf("error: v4l2_init_buffer\r\n");
        return 0;
    }

    buf.index = 0;
    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    /*内存映射*/
    for(buf.index = 0;buf.index < 4;buf.index++)
    {
        ioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf);
        frm_base[buf.index] = mmap(NULL, buf.length, \
                                PROT_READ | PROT_WRITE, MAP_SHARED, \
                                v4l2_fd, buf.m.offset);
        if (MAP_FAILED == frm_base[buf.index]) {
            perror("mmap error");
            return -1;
        }
        printf("查询内存成功  buf[%d]==%d长度\r\n",buf.index,buf.length);
        if(ioctl(v4l2_fd,VIDIOC_QBUF,&buf) < 0){//加入缓冲队列
            printf("error: VIDIOC_QBUF\r\n");
            return 0;
        }
    }
    return 1;
}

static int v4l2_stream_on(void)
{
    enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    /* 打开摄像头、摄像头开始采集数据 */
    if(ioctl(v4l2_fd,  VIDIOC_STREAMON, &type) < 0){
        printf("error: v4l2_stream_on\r\n");
        return 0;
    }
    printf("Camera_open : success\r\n");
    return 1;
}

void Send_Video_Data(int fd,uint8_t * data,int data_len)
{
    int tmp = 0;
    int current = 0;
    if(fd > 0)
    {
        while(1)
        {
            tmp = write(fd,data,data_len);
            if(tmp < 0){
                perror("write buf");
                close("fd");
                exit(1);
            }
            current = data_len - tmp;//还有多少字节没有写入
            data+=tmp;//指针位移
            data_len = current;//写入剩下的字节
            if(data_len == 0)
            {
                break;
            }
        } 
    }  
}

unsigned char rgbdatabuf[640*480*4]={0};
static void v4l2_read_data(void)
{
    struct v4l2_buffer buf;

    buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    buf.memory = V4L2_MEMORY_MMAP;
    buf.index = 1;

    while(1)
    {
		for(buf.index = 1; buf.index < 4; buf.index++)
		{
		    if(ioctl(v4l2_fd, VIDIOC_DQBUF, &buf)!=0)//出队
		    {
		        printf("提取数据失败\r\n");
		        break;
		    }
            Send_Video_Data(connfd,frm_base[buf.index],buf.length);

		    if(ioctl(v4l2_fd, VIDIOC_QBUF, &buf)!=0)//入队
		    {
		        printf("放回队列失败\r\n");
		        exit(0);
		    }
		    usleep(33000);
		}
    }
}

void tcp_server(void)
{
    struct sockaddr_in server_addr = {0};
    struct sockaddr_in client_addr = {0};
    char ip_str[20] = {'\0'};//客户端IP
    int addrlen = sizeof(struct sockaddr_in);//结构体 struct sockaddr_in 所占字节
    int ret;

    /* 打开套接字,得到套接字描述符 */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (0 > sockfd) {
        perror("socket error");
        exit(1);
    }
    /*配置监听描述符地址复用属性*/ 
    int opt = 1;//opt 只有(关闭(0)/打开(1))
    ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
    if(ret < 0) {
        perror("setsockopt error");
        exit(1);
    }
    /* 将套接字与指定端口号进行绑定 */
    server_addr.sin_family = AF_INET;//协议族为IPV4
    server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//绑定IP
    server_addr.sin_port = htons(SERVER_PORT);//绑定端口
    ret = bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (0 > ret) {
        perror("bind error");
        close(sockfd);
        exit(1);
    }
    /* 使服务器进入监听状态 */
    ret = listen(sockfd, 50);
    if (0 > ret) {
        perror("listen error");
        close(sockfd);
        exit(1);
    }
    /* 阻塞等待客户端连接 */
    connfd = accept(sockfd, (struct sockaddr *)&client_addr, &addrlen);
    if (0 > connfd) {
        printf("\n有客户端连接失败\n");
        exit(1);
    }
    printf("有客户端接入...\n");
    //将二进制 Ipv4 地址转换成 点分十进制
    inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip_str, sizeof(ip_str));
    printf("客户端主机的 IP 地址: %s\n", ip_str);
    printf("客户端进程的端口号: %d\n", client_addr.sin_port);
}

int main(int argc, char *argv[])
{
    v4l2_dev_init(argv[1]);
    v4l2_print_formats();
    v4l2_set_format(V4L2_PIX_FMT_YUYV, 640, 480);
    v4l2_init_buffer();
    v4l2_stream_on();
    tcp_server();

    v4l2_read_data();
}

客户端

初始化 LCD

/* 初始化 LCD */
static int fb_dev_init(void)
{
    struct fb_var_screeninfo fb_var = {0};
    struct fb_fix_screeninfo fb_fix = {0};
    unsigned long screen_size;
    /* 打开framebuffer设备 */
    fb_fd = open(FB_DEV, O_RDWR);
    if (0 > fb_fd) {
        perror("open_fb error");
        return -1;
    }
    /* 获取framebuffer设备信息 */
    ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var);
    ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix);

    screen_size = fb_fix.line_length * fb_var.yres;
    width = fb_var.xres_virtual;
    height = fb_var.yres_virtual;
    printf("%d*%d\n", width, height);
    /* 内存映射 */
    screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap error");
        close(fb_fd);
        return -1;
    }
    /* LCD背景刷白 */
    memset(screen_base, 0xFF, screen_size);
    return 0;
}

显示图片

void show_pic(unsigned char * pic_data, int w, int h)
{
    int i,j;
    unsigned int * p = screen_base;//LCD起始地址
    unsigned int tmpdata;

    for(i=0;i<h;i++)//对某一行
    {
        for(j=0;j<w;j++)//一行中的一个像素点
        {
            //三个十六进制表示一个像素点
			//j*3表示当前行的第j+1个十六进制的数据
			//i*w*3表示第i+1行
            tmpdata = (pic_data[j*3+i*w*3]<<16 | pic_data[j*3+i*w*3+1]<<8 | pic_data[(j*3)+(i*w*3)+2]<<0);
            * (p+j) = tmpdata;
        }
        p+=width;
    }
}

YUYV422 转RGB 数据

//YUYV422 转RGB 数据
void yuyv_to_rgb(unsigned char *yuyvdata, unsigned char *rgbdata, int w, int h)
{
    //码流Y0 U0 Y1 V1 Y2 U2 Y3 V3 --》YUYV像素[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]--》RGB像素
    int r1, g1, b1; 
    int r2, g2, b2;
    int i =0 ;
    for(i=0; i<w*h/2; i++)
    {
        char data[4];
        memcpy(data, yuyvdata+i*4, 4);
        unsigned char Y0=data[0];
        unsigned char U0=data[1];
        unsigned char Y1=data[2];
                unsigned char V1=data[3]; 
        //Y0U0Y1V1  -->[Y0 U0 V1] [Y1 U0 V1]
        r1 = Y0+1.4075*(V1-128); if(r1>255)r1=255; if(r1<0)r1=0;
        g1 =Y0- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g1>255)g1=255; if(g1<0)g1=0;
        b1 = Y0 + 1.779 * (U0-128);  if(b1>255)b1=255; if(b1<0)b1=0;
            
        r2 = Y1+1.4075*(V1-128);if(r2>255)r2=255; if(r2<0)r2=0;
        g2 = Y1- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g2>255)g2=255; if(g2<0)g2=0;
        b2 = Y1 + 1.779 * (U0-128);  if(b2>255)b2=255; if(b2<0)b2=0;
                
        rgbdata[i*6+0]=r1;
        rgbdata[i*6+1]=g1;
        rgbdata[i*6+2]=b1;
        rgbdata[i*6+3]=r2;
        rgbdata[i*6+4]=g2;
        rgbdata[i*6+5]=b2;
    }
}

彩色图像水平镜像

/**
*  @desc       彩色图像水平镜像
*  @param pImg 图像缓存,3个像素一个字节,RGB888格式
*  @param w    图像宽度
*  @param h    图像高度 
**/
void rotateColorImgMirrorH(unsigned char *pImg,unsigned int w,unsigned int h)
{
	unsigned char tmp;
	unsigned int i=0,j=0,m=0;	
	unsigned char *t = NULL,*tt = NULL;	
	unsigned int w3 = w*3;	
	tt = pImg;
	for(i=0;i<h;i++)
	{
		t = tt + ((w-1)*3);
		for(j=0;j<(w>>1);j++)
		{
			for(m=0;m<3;m++)
			{
				tmp = *tt;
				*tt = *t;
				*t = tmp;
				tt++;
				t++;
			}
			t -= 6;
		}
 		tt += ((w>>1)*3);
	}			
}

客户端整体程序

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>     
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/videodev2.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/fb.h>

#define SERVER_PORT 55555
#define FB_DEV "/dev/fb0"

int sockfd;
static int width;                       //LCD宽度
static int height;                      //LCD高度
static int fb_fd = -1;                  //LCD设备文件描述符
static int v4l2_fd = -1;               //摄像头设备文件描述符
static unsigned int *screen_base = NULL;//LCD显存基地址
static unsigned char *frm_base[4] = {NULL};             //帧缓冲起始地址
unsigned char rgbdatabuf[640*480*4]={0};
char yuyvbuf[614400]={0};

/* 初始化 LCD */
static int fb_dev_init(void)
{
    struct fb_var_screeninfo fb_var = {0};
    struct fb_fix_screeninfo fb_fix = {0};
    unsigned long screen_size;
    /* 打开framebuffer设备 */
    fb_fd = open(FB_DEV, O_RDWR);
    if (0 > fb_fd) {
        perror("open_fb error");
        return -1;
    }
    /* 获取framebuffer设备信息 */
    ioctl(fb_fd, FBIOGET_VSCREENINFO, &fb_var);
    ioctl(fb_fd, FBIOGET_FSCREENINFO, &fb_fix);

    screen_size = fb_fix.line_length * fb_var.yres;
    width = fb_var.xres_virtual;
    height = fb_var.yres_virtual;
    printf("%d*%d\n", width, height);
    /* 内存映射 */
    screen_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    if (MAP_FAILED == (void *)screen_base) {
        perror("mmap error");
        close(fb_fd);
        return -1;
    }
    /* LCD背景刷白 */
    memset(screen_base, 0xFF, screen_size);
    return 0;
}
//YUYV422 转RGB 数据
void yuyv_to_rgb(unsigned char *yuyvdata, unsigned char *rgbdata, int w, int h)
{
    //码流Y0 U0 Y1 V1 Y2 U2 Y3 V3 --》YUYV像素[Y0 U0 V1] [Y1 U0 V1] [Y2 U2 V3] [Y3 U2 V3]--》RGB像素
    int r1, g1, b1; 
    int r2, g2, b2;
    int i =0 ;
    for(i=0; i<w*h/2; i++)
    {
        char data[4];
        memcpy(data, yuyvdata+i*4, 4);
        unsigned char Y0=data[0];
        unsigned char U0=data[1];
        unsigned char Y1=data[2];
                unsigned char V1=data[3]; 
        //Y0U0Y1V1  -->[Y0 U0 V1] [Y1 U0 V1]
        r1 = Y0+1.4075*(V1-128); if(r1>255)r1=255; if(r1<0)r1=0;
        g1 =Y0- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g1>255)g1=255; if(g1<0)g1=0;
        b1 = Y0 + 1.779 * (U0-128);  if(b1>255)b1=255; if(b1<0)b1=0;
            
        r2 = Y1+1.4075*(V1-128);if(r2>255)r2=255; if(r2<0)r2=0;
        g2 = Y1- 0.3455 * (U0-128) - 0.7169*(V1-128); if(g2>255)g2=255; if(g2<0)g2=0;
        b2 = Y1 + 1.779 * (U0-128);  if(b2>255)b2=255; if(b2<0)b2=0;
                
        rgbdata[i*6+0]=r1;
        rgbdata[i*6+1]=g1;
        rgbdata[i*6+2]=b1;
        rgbdata[i*6+3]=r2;
        rgbdata[i*6+4]=g2;
        rgbdata[i*6+5]=b2;
    }
}
/**
*  @desc       彩色图像水平镜像
*  @param pImg 图像缓存,3个像素一个字节,RGB888格式
*  @param w    图像宽度
*  @param h    图像高度 
**/
void rotateColorImgMirrorH(unsigned char *pImg,unsigned int w,unsigned int h)
{
	unsigned char tmp;
	unsigned int i=0,j=0,m=0;	
	unsigned char *t = NULL,*tt = NULL;	
	unsigned int w3 = w*3;	
	tt = pImg;
	for(i=0;i<h;i++)
	{
		t = tt + ((w-1)*3);
		for(j=0;j<(w>>1);j++)
		{
			for(m=0;m<3;m++)
			{
				tmp = *tt;
				*tt = *t;
				*t = tmp;
				tt++;
				t++;
			}
			t -= 6;
		}
 		tt += ((w>>1)*3);
	}			
}
void show_pic(unsigned char * pic_data, int w, int h)
{
    int i,j;
    unsigned int * p = screen_base;//LCD起始地址
    unsigned int tmpdata;

    for(i=0;i<h;i++)//对某一行
    {
        for(j=0;j<w;j++)//一行中的一个像素点
        {
            //三个十六进制表示一个像素点
			//j*3表示当前行的第j+1个十六进制的数据
			//i*w*3表示第i+1行
            tmpdata = (pic_data[j*3+i*w*3]<<16 | pic_data[j*3+i*w*3+1]<<8 | pic_data[(j*3)+(i*w*3)+2]<<0);
            * (p+j) = tmpdata;
        }
        p+=width;
    }
}
void Recv_Video_Data(int fd,uint8_t * data,int data_len)
{
    int tmp = 0;
    int current = 0;
    if(fd > 0)
    {
        while(1)
        {
            tmp = read(fd,data,data_len);
            if(tmp < 0){
                perror("read buf");
                close("fd");
                exit(1);
            }
            current = data_len - tmp;
            data+=tmp;
            data_len = current;
            if(data_len == 0)
            {   
                break;
            }
        }
    }  
}
void tcp_client(char * SERVER_IP)
{
    struct sockaddr_in server_addr = {0};
    int ret;

    /* 打开套接字,得到套接字描述符 */
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (0 > sockfd) {
        perror("socket error");
        exit(EXIT_FAILURE);
    }
    /* 调用 connect 连接远端服务器 */
    server_addr.sin_family = AF_INET;//IPV4
    server_addr.sin_port = htons(SERVER_PORT); //端口号
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    // inet_pton(AF_INET, SERVER_IP, &server_addr.sin_addr);//IP 地址
    
    /* 请求与服务器建立连接 */
    ret = connect(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (0 > ret) {
        perror("connect error");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
    printf("服务器连接成功...\n\n");

    /* 向服务器发送数据 */
    while(1) 
    {
        Recv_Video_Data(sockfd,yuyvbuf,sizeof(yuyvbuf));
        yuyv_to_rgb(yuyvbuf, rgbdatabuf ,640, 480);
        rotateColorImgMirrorH(rgbdatabuf,640,480);
        show_pic(rgbdatabuf,640,480);
        usleep(66000);
    }
    close(sockfd);
    exit(EXIT_SUCCESS);
}

int main(int argc, char **argv)
{
    fb_dev_init();
    tcp_client("192.168.88.88");
}
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值