1. 程式人生 > >zigbee無線感測網實訓---實現LCD開發板連線攝像頭實時顯示(The Fifth day)

zigbee無線感測網實訓---實現LCD開發板連線攝像頭實時顯示(The Fifth day)

攝像頭:
        常見的攝像頭:針孔攝像頭(有線和無線)、紅外攝像頭(有線),usb攝像頭;
        攝像頭採集影象的格式:yuyv 、jpeg(v4l2)

api_v4l2.h

/*************************************************
 File name : api_v4l2.h
 Create date : 2014-07-01 19:42
 Modified date : 2014-07-01 19:42
 Author : heqingde
 Email : [email protected]
 
 ***********************************************/
#ifndef API_V4L2_H_
#define API_V4L2_H_

#define VIDEO_WIDTH  640
#define VIDEO_HEIGHT 480
#define MAX_CAM_RES 32 //camres res
#define BUFFER_COUNT 4 //buffer zone
#define FPS 30
#define MAX_CAM_RES 32
//#define CAMERA_DEVICE "/dev/video1"

#define exit_error(s)\
	do{\
		printf("%s is error\n",s);\
		return (-1);\
		}while(0)


/*********************************
*  NAME:VideoBuffer  struct
*  Function: Describe buffer V4L2 driver assigns and maps
*  Member:  start: point of buffer
*  length: total length of buffer
**********************************/
typedef struct Video_Buffer
{
	void *start;
    	int length;
}VideoBuffer;
/*******************************
*  name :fream_buffer
*  Function: save fream
*  member: buf :point of buf
*  length:total length op buf
********************************/
typedef struct Frame_Buffer
{
	char buf[1843200];
	int length;
	
}FrameBuffer;
/************************************
*name:CamRes
*Function:Camera format
*Member: width : format width
*height: format height 
*/
typedef struct CamRes 
{
	int width;
	int height;
}CamRes;
/*************************************
*name:CamResList struct
*Function:CamRes  format list
*Member:  cam_res :struct CamRes
*res_num:Camera format number		
*/
typedef struct CamResList
{
	struct CamRes *cam_res;
	int res_num;
}CamResList;


/*************************************
*Name:open_device Function
*Function:open the device
*/
void linux_v4l2_open_device();

/*************************************
*name:device_init
*Function:Initial Camera v4l2 
*/
int linux_v4l2_device_init(const char *dev);

/*************************************
*name: init_mmap
*Function: mmap 
*/
int linux_v4l2_init_mmap();

/************************************
*name:start_capturing
*Function: starting Capture Options 
*/
int linux_v4l2_start_capturing();

/************************************
*name:stop_capturing
*Function: stop Capture Options
*/
int linux_v4l2_stop_capturing();

/************************************
*name :device_uinit
*Function:uinit device
*/
int linux_v4l2_device_uinit();
/************************************
*name :linux_v4l2_get_fream
*Function:save device_stream data;
*/
int linux_v4l2_get_fream(FrameBuffer *freambuf);
#endif /*API_V4L2_H*/

camera.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <pthread.h>

#include "lcdjpg.h"
#include "api_v4l2.h" //包含攝像頭的標頭檔案

int lcd_draw_jpg(unsigned int x,unsigned int y,const char *pjpg_path,char *pjpg_buf,unsigned int jpg_buf_size,unsigned int jpg_half);

int iPhonex;
struct sockaddr_in phoneaddr;
//執行緒的功能函式,接收來自手機app傳送的控制命令
void *myrecvmsg(void *arg)
{
	char buf[200];
	int addrsize=sizeof(phoneaddr);
	while(1)
	{
		bzero(buf,200);//清零
		//聊天,收發資料,接收手機發送過來的控制命令
		recvfrom(iPhonex,buf,200,0,(struct sockaddr *)&phoneaddr,&addrsize);
		printf("phone send msg is:%s ip:%s  port:%hu\n",buf,inet_ntoa(phoneaddr.sin_addr),ntohs(phoneaddr.sin_port));
		
	}
}


int main(void)
{
	//買手機--->建立套接字
	iPhonex = socket( AF_INET, SOCK_DGRAM,0);
	
	
	// 定義一個ipv4地址結構體變數
	struct sockaddr_in bindaddr;
	bindaddr.sin_family = AF_INET; 
	bindaddr.sin_addr.s_addr = inet_addr("192.168.1.123");//繫結開發板無線網絡卡的ip
	bindaddr.sin_port = htons(2234); //繫結埠號
	
	//買卡--->繫結自己的ip
	int ret = bind(iPhonex, (struct sockaddr *)&bindaddr, sizeof(bindaddr));
	if(ret == -1)
	{
		printf("繫結失敗!\n");
		exit(0);
	}
	//開啟攝像頭
	linux_v4l2_device_init("/dev/video7");
	//啟動攝像捕捉
	linux_v4l2_start_capturing();
	//開始捕捉
	
	//建立執行緒,專門接受手機端傳送過來的資訊
	pthread_t p_id;
	pthread_create( &p_id, NULL, myrecvmsg, NULL);
	
	FrameBuffer mybuf;
	while(1)
	{	
		linux_v4l2_get_fream(&mybuf);
		
		//開發板顯示攝像頭拍攝的畫面
		lcd_draw_jpg(0,0,NULL,mybuf.buf,mybuf.length,0);
		//將畫面傳輸給手機
		sendto(iPhonex,mybuf.buf,mybuf.length,0,(struct sockaddr *)&phoneaddr,sizeof(phoneaddr));
		printf("phone ip:%s  port:%hu\n",inet_ntoa(phoneaddr.sin_addr),ntohs(phoneaddr.sin_port));	
		//拍照....
	}
	return 0;
}

common.c

/****************************************************************************************
 *Éè    ¼Æ:ÎÂ×Óì÷
 *ÈÕ    ÆÚ:2015-5-29
 *˵	Ã÷:³£Óú¯Êý
****************************************************************************************/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <sys/stat.h>

/****************************************************
 *º¯ÊýÃû³Æ:file_size_get
 *ÊäÈë²ÎÊý:pfile_path	-Îļþ·¾¶
 *·µ »Ø Öµ:-1		-ʧ°Ü
		   ÆäËûÖµ	-Îļþ´óС
 *˵	Ã÷:»ñÈ¡Îļþ´óС
 ****************************************************/
unsigned long file_size_get(const char *pfile_path)
{
	unsigned long filesize = -1;	
	struct stat statbuff;
	
	if(stat(pfile_path, &statbuff) < 0)
	{
		return filesize;
	}
	else
	{
		filesize = statbuff.st_size;
	}
	
	return filesize;
}

unsigned char bcc_check(unsigned char *buf, int n)
{
    int i;
    unsigned char bcc=0;
	
    for(i = 0; i < n; i++)
    {
        bcc ^= *(buf+i);
    }
	
    return (~bcc);
}

lcdjpg.c

#include <stdio.h>   	
#include <fcntl.h>		 	 
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <stdlib.h>

#include "lcdjpg.h"

#if EN_LCD_SHOW_JPG
#include "jpeglib.h"
#endif

//#include "api_v4l2.h"
unsigned long file_size_get(const char *pfile_path);
static char g_color_buf[FB_SIZE]={0};

static int  g_fb_fd;
static int *g_pfb_memory;

/* video_chat.c »­Öл­ÏÔʾµÄ×ø±ê */
volatile int g_jpg_in_jpg_x;
volatile int g_jpg_in_jpg_y;

//LCD»­µã
void lcd_draw_point(unsigned int x,unsigned int y, unsigned int color)
{
	*(g_pfb_memory+y*800+x)=color;
}

#if EN_LCD_SHOW_JPG
int lcd_draw_jpg(unsigned int x,unsigned int y,const char *pjpg_path,char *pjpg_buf,unsigned int jpg_buf_size,unsigned int jpg_half)  
{
	//³õʼ»¯LCD
	g_fb_fd = open("/dev/fb0", O_RDWR);
	
	if(g_fb_fd<0)
	{
			printf("open lcd error\n");
			return -1;
	}

	g_pfb_memory  = (int *)mmap(	NULL, 					//Ó³ÉäÇøµÄ¿ªÊ¼µØÖ·£¬ÉèÖÃΪNULLʱ±íʾÓÉϵͳ¾ö¶¨Ó³ÉäÇøµÄÆðʼµØÖ·
									FB_SIZE, 									//Ó³ÉäÇøµÄ³¤¶È
									PROT_READ|PROT_WRITE, 		//ÄÚÈÝ¿ÉÒÔ±»¶ÁÈ¡ºÍдÈë
									MAP_SHARED,							//¹²ÏíÄÚ´æ
									g_fb_fd, 									//ÓÐЧµÄÎļþÃèÊö´Ê
									0												//±»Ó³Éä¶ÔÏóÄÚÈݵÄÆðµã
								);
	
	/*¶¨Òå½âÂë¶ÔÏ󣬴íÎó´¦Àí¶ÔÏó*/
	struct 	jpeg_decompress_struct 	cinfo;
	struct 	jpeg_error_mgr 			jerr;	
	
	char 	*pcolor_buf = g_color_buf;
	char 	*pjpg;
	
	unsigned int 	i=0;
	unsigned int	color =0;
	unsigned int	count =0;
	
	unsigned int 	x_s = x;
	unsigned int 	x_e ;	
	unsigned int 	y_e ;
	
			 int	jpg_fd;
	unsigned int 	jpg_size;
	
	unsigned int 	jpg_width;
	unsigned int 	jpg_height;
	

	if(pjpg_path!=NULL)
	{
		/* ÉêÇëjpg×ÊÔ´£¬È¨Ï޿ɶÁ¿Éд */	
		jpg_fd=open(pjpg_path,O_RDWR);
		
		if(jpg_fd == -1)
		{
		   printf("open %s error\n",pjpg_path);
		   
		   return -1;	
		}	
		
		/* »ñÈ¡jpgÎļþµÄ´óС */
		jpg_size=file_size_get(pjpg_path);	

		/* ΪjpgÎļþÉêÇëÄÚ´æ¿Õ¼ä */	
		pjpg = malloc(jpg_size);

		/* ¶ÁÈ¡jpgÎļþËùÓÐÄÚÈݵ½ÄÚ´æ */		
		read(jpg_fd,pjpg,jpg_size);
	}
	else
	{
		jpg_size = jpg_buf_size;
		
		pjpg = pjpg_buf;
	}

	/*×¢²á³ö´í´¦Àí*/
	cinfo.err = jpeg_std_error(&jerr);
	
	/*´´½¨½âÂë*/
	jpeg_create_decompress(&cinfo);

	/*Ö±½Ó½âÂëÄÚ´æÊý¾Ý*/		
	jpeg_mem_src(&cinfo,pjpg,jpg_size);
	
	/*¶ÁÎļþÍ·*/
	jpeg_read_header(&cinfo, TRUE);

	/*¿ªÊ¼½âÂë*/
	jpeg_start_decompress(&cinfo);	
	
	
	if(jpg_half)
	{
		x_e	= x_s+(cinfo.output_width/2);
		y_e	= y  +(cinfo.output_height/2);		
		
		/*¶Á½âÂëÊý¾Ý*/
		while(cinfo.output_scanline < cinfo.output_height)
		{		
			pcolor_buf = g_color_buf;
			
			/* ¶ÁÈ¡jpgÒ»ÐеÄrgbÖµ */
			jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);			
			
			/* ÔÙ¶ÁÈ¡jpgÒ»ÐеÄrgbÖµ */
			jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);

			for(i=0; i<(cinfo.output_width/2); i++)
			{
				/* »ñÈ¡rgbÖµ */
				color = 		*(pcolor_buf+2);
				color = color | *(pcolor_buf+1)<<8;
				color = color | *(pcolor_buf)<<16;
				
				/* ÏÔʾÏñËصã */
				lcd_draw_point(x,y,color);
				
				pcolor_buf +=6;
				
				x++;
			}
			
			/* »»ÐÐ */
			y++;					
			
			x = x_s;	
		}
	}
	else
	{
		x_e	= x_s+cinfo.output_width;
		y_e	= y  +cinfo.output_height;	

		/*¶Á½âÂëÊý¾Ý*/
		while(cinfo.output_scanline < cinfo.output_height )
		{		
			pcolor_buf = g_color_buf;
			
			/* ¶ÁÈ¡jpgÒ»ÐеÄrgbÖµ */
			jpeg_read_scanlines(&cinfo,(JSAMPARRAY)&pcolor_buf,1);
			
			for(i=0; i<cinfo.output_width; i++)
			{
				/* »ñÈ¡rgbÖµ */
				color = 		*(pcolor_buf+2);
				color = color | *(pcolor_buf+1)<<8;
				color = color | *(pcolor_buf)<<16;
				
				/* ÏÔʾÏñËصã */
				lcd_draw_point(x,y,color);
				
				pcolor_buf +=3;
				
				x++;
			}
			
			/* »»ÐÐ */
			y++;			
			
			x = x_s;
			
		}		
	}
	
	/*½âÂëÍê³É*/
	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);

	if(pjpg_path!=NULL)
	{
		/* ¹Ø±ÕjpgÎļþ */
		close(jpg_fd);	
		
		/* ÊÍ·ÅjpgÎļþÄÚ´æ¿Õ¼ä */
		free(pjpg);		
	}
	//LCD¹Ø±Õ
	/* È¡ÏûÄÚ´æÓ³Éä */
	munmap(g_pfb_memory, FB_SIZE);
	
	/* ¹Ø±ÕLCDÉ豸 */
	close(g_fb_fd);
	return 0;
}
#endif

lcdjpg.h

#ifndef __LCD_H__
#define __LCD_H__

#define LCD_WIDTH  			800
#define LCD_HEIGHT 			480
#define FB_SIZE				(LCD_WIDTH * LCD_HEIGHT * 4)


#define EN_LCD_SHOW_JPG		1

/* video_chat.c 畫中畫顯示的座標 */
extern volatile int g_jpg_in_jpg_x;
extern volatile int g_jpg_in_jpg_y;


#endif

編譯:

虛擬機器:

arm-none-linux-gnueabi-gcc *.c -o main -I/home/gec/jpeg/include -L./ -lapi_v4l2_arm -lpthread -L/home/gec/jpeg/lib -ljpeg

    //*號表示萬用字元
    //-I --> 指明標頭檔案的路徑
    //-L --> 指明庫檔案的路徑
    //-l --> 指定要連線的庫名(去掉字首lib 去掉字尾.** 剩下的就是庫的名字)

LCD開發板:

$:tftp -g 192.168.1.147 -r main
$:chmod 777 main 
$:./main

結果: