rcar-du 通过DRM/KMS实现DU显示测试demo

app .c文件

/*
本ソースの使用方法

	(1)	下記コマンドでビルド実行
		make

	(2)	下記コマンドでaltボード実機用rootfsにコピー
		sudo cp camera_test /tftpboot/work_hieng/rootfs/home/root/

	(3) altボード実機上linuxコンソールにて、下記コマンドを実施して、テストプログラム実行
		cd /home/root/
		./camera_test

*/

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

// スレッド関連インクルード
#include <pthread.h>

// VINアクセス用インクルード
#include <linux/videodev2.h>

// DUアクセス用インクルード
#include <xf86drm.h>
#include <xf86drmMode.h>
#include <drm_fourcc.h>
#include <libkms.h>

// テストプログラム用ヘッダ
#include "camera_test.h"

#ifndef TRUE            // TRUE が定義されていなかったら
#define TRUE 1
#endif

#ifndef FALSE           // FALSE が定義されていなかったら
#define FALSE 0
#endif


// 各種グローバル変数宣言

// VIN0のデバイスノード名
const char cVinDevName[] = "/dev/video0";
// DUのアクセス用構造体
static struct device	stDuDev;
// VIN0のファイルディスクリプタ
static int				iVin0DevFd = 0;
// スレッド実行フラグ
static int				iThreadExecFlg = FALSE;

// 画像サイズ関連グローバル変数
static uint32_t guiWidth     = WIDTH_MAX;								// 画像データ幅(デフォルト1280)
static uint32_t guiHeight    = HEIGHT_MAX;								// 画像データ高(デフォルト720)
static uint32_t guiDuPosLeft = DU_OUTPUT_POSITION_LEFT(WIDTH_MAX);		// 画像データ出力位置(左)
static uint32_t guiDuPosTop  = DU_OUTPUT_POSITION_TOP(HEIGHT_MAX);		// 画像データ出力位置(上)

static	unsigned char	*gpcMap[VIN0_BUFFER_NUM];
static int				giLength[VIN0_BUFFER_NUM];
struct v4l2_buffer		gstVin0Buf;		// VIN0のバッファ構造体;

unsigned int			handles[4], pitches[4], offsets[4] = {0};
void					*virtual=NULL;
void					*virtual2=NULL;
int						v_flg=0;
struct kms_bo			*bo;
struct kms_bo			*bo2;


#define MALLOC_REQ_SIZE		(WIDTH_MAX*HEIGHT_MAX*4)


// 関数プロトタイプ宣言

static void
set_pixel(unsigned char *mem, unsigned int width,
		  unsigned int height, unsigned int stride ,unsigned int count,unsigned char *pcMap);

static void
set_pixel2(unsigned char *mem, unsigned int width,
		  unsigned int height, unsigned int stride ,unsigned int count);

static struct kms_bo *
allocate_buffer(struct kms_driver *kms, unsigned int width, unsigned int height,
		unsigned int *stride);

struct kms_bo *
create_test_buffer(struct kms_driver *kms, unsigned int format,
		   unsigned int width, unsigned int height,
		   unsigned int handles[4], unsigned int pitches[4],
		   unsigned int offsets[4],
		   unsigned int count,unsigned char *pcMap);

int put_image(struct device *dev);
int outputDuFromFrame(struct device *dev,unsigned char *pcMap);

int fInitVin0(int *piVin0DevFd);
int fInitDu(struct device *pstDuDev);
int fInitDuInLoop(struct device *pstDuDev);
void *fMainLoop(void* pParam);


// 関数実体宣言

static void set_color_space(unsigned char *pcMap,unsigned char r,unsigned char g,unsigned char b)
{
	unsigned int x;
	unsigned int y;
	//unsigned int n=0;
	unsigned int m=0;

	for (y = 0; y < HEIGHT_MAX; ++y){
		for (x = 0; x < WIDTH_MAX; ++x){
			((unsigned char *)pcMap)[m+0]= b;   /*Blueのデータ */
			((unsigned char *)pcMap)[m+1]= g;   /*Greenのデータ*/
			((unsigned char *)pcMap)[m+2]= r;   /*Redのデータ  */
			((unsigned char *)pcMap)[m+3] = 0xFF;         /*alpha値      */

			m=m+4;
//			n=n+4;
		}
	}
}
static void
set_pixel(unsigned char *mem, unsigned int width,
		  unsigned int height, unsigned int stride ,unsigned int count,unsigned char *pcMap)
{
	unsigned int x;
	unsigned int y;
//	unsigned int n=0;
	unsigned int m=0;

	memcpy(mem,pcMap,height * width * 4);
	#if 0
	for (y = 0; y < height; ++y){
		for (x = 0; x < width; ++x){
//			((unsigned char *)mem)[m+0]=pcMap[n  ];   /*Blueのデータ */
//			((unsigned char *)mem)[m+1]=pcMap[n+1];   /*Greenのデータ*/
//			((unsigned char *)mem)[m+2]=pcMap[n+2];   /*Redのデータ  */
			((unsigned char *)mem)[m+3]=0xFF;         /*alpha値      */

			m=m+4;
//			n=n+4;
		}
	}
	#endif
//	return;
}

static void
set_pixel2(unsigned char *mem, unsigned int width,
		  unsigned int height, unsigned int stride ,unsigned int count)
{
	unsigned int x;
	unsigned int y;
	unsigned int a=0;
	unsigned int p=0;

	/* 1枚目のレイヤは赤のグラデーション*/
	/* 2枚目のレイヤは青のグラデーション*/
	switch(count){
	case 0:	//1sheet of Layer
		for (y = 0; y < height; ++y) {
			for (x = 0; x < width; ++x){
				((uint32_t *)mem)[x] = 0x00FF0000 +(a << 24 );	//red
				a= (a + 1) % 256;								//alpha=0-255
			}
			mem += stride;
		}
		break;
	case 1:	//2sheet of Layer
	default:
		for (y = 0; y < height; ++y) {
				a= (a + 1) % 256;								//alpha=0-255
			for (x = 0; x < width; ++x){
				((uint32_t *)mem)[x] = 0x000000C0 +(a << 24 );  //blue
			}
			mem += stride;
		}
		break;
	}
	return;
}

static struct kms_bo *
allocate_buffer(struct kms_driver *kms, unsigned int width, unsigned int height,
		unsigned int *stride)
{
	struct kms_bo *bo;
	unsigned bo_attribs[] = {
		KMS_WIDTH,   0,
		KMS_HEIGHT,  0,
		KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8,
		KMS_TERMINATE_PROP_LIST
	};
	int ret;

	bo_attribs[1] = width;
	bo_attribs[3] = height;

	ret = kms_bo_create(kms, bo_attribs, &bo);
	if (ret) {
		fprintf(stderr, "failed to alloc buffer: %s\n",
			strerror(-ret));
		return NULL;
	}

	ret = kms_bo_get_prop(bo, KMS_PITCH, stride);
	if (ret) {
		fprintf(stderr, "failed to retreive buffer stride: %s\n",
			strerror(-ret));
		kms_bo_destroy(&bo);
		return NULL;
	}

	return bo;
}





struct kms_bo *
create_test_buffer(struct kms_driver *kms, unsigned int format,
		   unsigned int width, unsigned int height,
		   unsigned int handles[4], unsigned int pitches[4],
		   unsigned int offsets[4],
		   unsigned int count,unsigned char *pcMap)
{
	unsigned int virtual_height;
	void *planes[3] = { 0, };
	int ret;

	if( virtual == NULL ){
		virtual_height = height;

		bo = allocate_buffer(kms, width, virtual_height, &pitches[0]);
		if (!bo)
			return NULL;


		ret = kms_bo_map(bo, &virtual);
		if (ret) {
			fprintf(stderr, "failed to map buffer: %s\n",
				strerror(-ret));
			kms_bo_destroy(&bo);
			return NULL;
		}

		kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
		kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);

		bo2 = allocate_buffer(kms, width, virtual_height, &pitches[0]);
		if (!bo2)
			return NULL;


		ret = kms_bo_map(bo2, &virtual2);
		if (ret) {
			fprintf(stderr, "failed to map buffer: %s\n",
				strerror(-ret));
			kms_bo_destroy(&bo2);
			return NULL;
		}

		kms_bo_get_prop(bo2, KMS_PITCH, &pitches[0]);
		kms_bo_get_prop(bo2, KMS_HANDLE, &handles[0]);

	}



	if(v_flg==0){
		planes[0] = virtual;
		v_flg=1;
		kms_bo_get_prop(bo , KMS_HANDLE, &handles[0]);
	}
	else{
		planes[0] = virtual2;
		v_flg=0;
		kms_bo_get_prop(bo2, KMS_HANDLE, &handles[0]);
	}

	set_pixel(planes[0], width, height, pitches[0] , count , pcMap);

//	kms_bo_unmap(bo);

	return bo;

}

struct kms_bo *
create_test_buffer2(struct kms_driver *kms, unsigned int format,
		   unsigned int width, unsigned int height,
		   unsigned int handles[4], unsigned int pitches[4],
		   unsigned int offsets[4],
		   unsigned int count,unsigned char *pcMap)
{
	unsigned int virtual_height;
	void *planes[3] = { 0, };
	int ret;
	void *virtual_l=NULL;
	struct kms_bo *bo_l;

	virtual_height = height;

	bo_l = allocate_buffer(kms, width, virtual_height, &pitches[0]);
	if (!bo_l)
		return NULL;


	ret = kms_bo_map(bo_l, &virtual_l);
	if (ret) {
		fprintf(stderr, "failed to map buffer: %s\n",
			strerror(-ret));
		kms_bo_destroy(&bo_l);
		return NULL;
	}

	kms_bo_get_prop(bo_l, KMS_PITCH, &pitches[0]);
	kms_bo_get_prop(bo_l, KMS_HANDLE, &handles[0]);

	planes[0] = virtual_l;

	set_pixel2(planes[0], width, height, pitches[0],count);

	return bo_l;

}

int put_image(struct device *dev)
{
	struct kms_bo *plane_bo;
	uint32_t plane_id = 0;
	uint32_t plane_flags = 0;
	uint32_t width, height;
	unsigned int i;
	unsigned int fb_id;
	int	crtc_id;
	int ret;
	int	count;
	void *planes[3] = { 0, };

	width=1280;		//解像度指定
	height=720;
	plane_id=16;	//1枚目はPLANE番号15を使用
//	crtc_id=8;		//CRTC=8に出力
	crtc_id=7;		//CRTC=8に出力

	//2レイヤ分ループ
	for (count = 0; count < 2; count++){

		//レイヤ毎にPLANE番号を変える */
		plane_id+=count;

//		fprintf(stderr, "testing %dx%d overlay plane %u\n",
//			width, height, plane_id);

		/* バッファ作成 */
		plane_bo = create_test_buffer2(dev->kms, 
								 DRM_FORMAT_ARGB8888,
								 width,
								 height,
								 handles,
								 pitches,
								 offsets,
								 count,
								 NULL);

		if (plane_bo == NULL){
			printf("failed. create buffer...\n");
			return -1;
		}
		else{
//			printf("success. create buffer...\n");
		}

		//Overlay display via DRM
		if (drmModeAddFB2(dev->fd,
						  width,
						  height,
						  DRM_FORMAT_ARGB8888,
						  handles,
						  pitches,
						  offsets,
						  &fb_id,
						  plane_flags)
	 					  ){

			  fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
			  return -1;

		}
		else{
//			printf("success. drmModeAddFB2\n");
		}

		if (drmModeSetPlane(dev->fd,
							plane_id,
							crtc_id,
							fb_id,
							plane_flags,
							0,
							0,
							width,
							height,
							0,
							0,
							width  << 16,
							height << 16)){

				fprintf(stderr, "failed to enable plane: %s\n",
					strerror(errno));
				return -1;
		}
		else{
//			printf("success. drmModeSetPlane\n");
		}
	}

	getchar();

	return;

}


// VU出力処理(VINからのフレーム用)
// 引数:
//		pstDuDev : DUのアクセス用構造体へのポインタ
//		pcMap    : mmapによって得られたフレームの先頭ポインタ
// 戻り値: 0=正常終了 -1=異常終了

int outputDuFromFrame(struct device *dev,unsigned char *pcMap)
{

	struct kms_bo *plane_bo;
	uint32_t plane_id = 0;
	uint32_t plane_flags = 0;
	unsigned int i;
	unsigned int fb_id;
	unsigned int crtc_id;
	int	count;

	drmModePlaneResPtr planes;
	
	planes = drmModeGetPlaneResources(dev->fd);

//	crtc_id=8;		//CRTC=8に出力
	crtc_id=7;		//CRTC=8に出力
//	plane_id=15;
	plane_id = planes->planes[0];

//	printf("current plane_id:%d\n",plane_id);


//	fprintf(stderr, "testing %dx%d overlay plane %u\n",
//			width, height, plane_id);

	/* バッファ作成 */
	plane_bo = create_test_buffer(dev->kms, 
							 DRM_FORMAT_ARGB8888,
							 guiWidth,
							 guiHeight,
							 handles,
							 pitches,
							 offsets,
							 count,
							 pcMap);

	if (plane_bo == NULL){
		printf("failed. create buffer...\n");
		return -1;
	}
	else{
//		printf("success. create buffer...\n");
	}

	//Overlay display via DRM
	if (drmModeAddFB2(dev->fd,
					  guiWidth,
					  guiHeight,
					  DRM_FORMAT_ARGB8888,
					  handles,
					  pitches,
					  offsets,
					  &fb_id,
					  plane_flags)
 					  ){

		  fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
		  return -1;

	}
	else{
//		printf("success. drmModeAddFB2\n");
	}

	if (drmModeSetPlane(dev->fd,
						plane_id,
						crtc_id,
						fb_id,
						plane_flags,
						guiDuPosLeft,
						guiDuPosTop,
						guiWidth,
						guiHeight,
						0,
						0,
						guiWidth  << 16,
						guiHeight << 16)){

			fprintf(stderr, "failed to enable plane: %s\n",
				strerror(errno));
			return -1;
	}
	else{
//		printf("success. drmModeSetPlane\n");
	}

	return 0;
}

// VIN0初期化
// 引数:
//		piVin0DevFd : VIN0のファイルディスクリプタへのポインタ
// 戻り値: 0=正常終了 -1=異常終了
int fInitVin0(int *piVin0DevFd)
{
	int						iResult = 0;	// 実行結果
	int						i;
	int						iType   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	// 以下、v4l2_で始まる構造体の詳細は、下記ヘッダファイルを参照のこと。
	// /opt/poky/1.6.1/sysroots/cortexa7hf-vfp-neon-poky-linux-gnueabi/usr/include/linux/videodev2.h
	struct v4l2_capability		stVin0Query;	// VIN0のデバイス能力
	struct v4l2_crop			stVin0Crop;		// VIN0のクロッピング領域設定構造体
	struct v4l2_requestbuffers	stVin0Req;		// VIN0のバッファ要求構造体
	struct v4l2_format			stVin0Fmt;		// VIN0のフォーマットに関する情報を格納する構造体
//	struct v4l2_buffer			stVin0Buf;		// VIN0のバッファ構造体;

	if(piVin0DevFd == NULL)
	{
		// 引数異常
		fprintf(stderr, "fInitVin0 arg error\n");
		return -1;
	}

	memset(&stVin0Query,0,sizeof(stVin0Query));
	memset(&stVin0Crop,0,sizeof(stVin0Crop));
	memset(&stVin0Fmt,0,sizeof(stVin0Fmt));
	memset(&stVin0Req,0,sizeof(stVin0Req));

	// VIN0のオープン
	*piVin0DevFd = open(cVinDevName, O_RDWR);
	if (*piVin0DevFd < 0) {
		// VIN0のオーブンNG
		fprintf(stderr, "VIN0 open error : errno = %d\n",errno);
		return -1;
	}
	// VIN0のオーブンOK
	printf("VIN0 open OK!\n");

	// デバイス能力の取得
	iResult = ioctl(*piVin0DevFd,VIDIOC_QUERYCAP,(void *)&stVin0Query);
	if (iResult != 0){
		// デバイス能力の取得NG
		fprintf(stderr, "ioctl(VIDIOC_QUERYCAP) error.\n");
		return -1;
	}
	// デバイス能力の取得OK
	printf("ioctl(VIDIOC_QUERYCAP) OK.\n");
	printf("driver       = %s\n",stVin0Query.driver);
	printf("card         = %s\n",stVin0Query.card);
	printf("bus_info     = %s\n",stVin0Query.bus_info);
	printf("version      = 0x%08X\n",stVin0Query.version);
	printf("capabilities = 0x%08X\n",stVin0Query.capabilities);
	printf("device_caps  = 0x%08X\n",stVin0Query.device_caps);

	// デバイスがキャプチャ能力を備えているかチェック
	if (!(stVin0Query.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
		fprintf (stderr, "VIN0 is NOT video capture device\n");
		return -1;
	}
	printf("VIN0 is video capture device.\n");

	// VIN0の入力画像中のクロッピング領域指定
	// 参考url : http://techmemo.g.hatena.ne.jp/emergent/20080413/1208064373
	stVin0Crop.type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	stVin0Crop.c.left   = 0;						// ix VIN入力画像から切出す領域の左端座標
	stVin0Crop.c.top    = 0;						// iy VIN入力画像から切出す領域の上端座標
	stVin0Crop.c.width  = guiWidth ;				// iw VIN入力画像から切出す領域の幅
	stVin0Crop.c.height = guiHeight;				// ih VIN入力画像から切出す領域の高さ	
	iResult = ioctl(*piVin0DevFd,VIDIOC_S_CROP,(void *)&stVin0Crop);
	if (iResult != 0){
		// クロッピング領域指定NG
		fprintf(stderr, "ioctl(VIDIOC_S_CROP) error.\n");
		return -1;
	}
	// クロッピング領域指定OK
	printf("ioctl(VIDIOC_S_CROP) OK.\n");

	// VIN0のキャプチャバッファのフォーマット及びサイズを指定
	// 参考url : http://techmemo.g.hatena.ne.jp/emergent/20080413/1208064373
	// VIN0_CAPTURE_WIDTHおよびVIN0_CAPTURE_HEIGHTの定義値は本ソース冒頭参照のこと。
	stVin0Fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	stVin0Fmt.fmt.pix.width       = guiWidth; 
	stVin0Fmt.fmt.pix.height      = guiHeight;
//	stVin0Fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
	stVin0Fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB32;
	/* 受信する映像のフィールド */
//	stVin0Fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;	// インターレース
	stVin0Fmt.fmt.pix.field       = V4L2_FIELD_NONE;		// プログレッシブ
	iResult = ioctl(*piVin0DevFd,VIDIOC_S_FMT,(void *)&stVin0Fmt);
	if (iResult != 0){
		// フォーマット及びサイズを指定NG
		fprintf(stderr, "ioctl(VIDIOC_S_FMT) error.\n");
		return -1;
	}
	// フォーマット及びサイズを指定OK
	printf("ioctl(VIDIOC_S_FMT) OK.\n");

	// VIN0の入力画像中のクロッピング領域再指定
	stVin0Crop.type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	stVin0Crop.c.left   = 0;						// ix VIN入力画像から切出す領域の左端座標
	stVin0Crop.c.top    = 0;						// iy VIN入力画像から切出す領域の上端座標
	stVin0Crop.c.width  = guiWidth ;				// iw VIN入力画像から切出す領域の幅
	stVin0Crop.c.height = guiHeight;				// ih VIN入力画像から切出す領域の高さ	
	iResult = ioctl(*piVin0DevFd,VIDIOC_S_CROP,(void *)&stVin0Crop);
	if (iResult != 0){
		// クロッピング領域再指定NG
		fprintf(stderr, "ioctl(VIDIOC_S_CROP(2)) error.\n");
		return -1;
	}
	// クロッピング領域再指定OK
	printf("ioctl(VIDIOC_S_CROP(2)) OK.\n");

	// VIN0のバッファ確保要求
	// 参考url : http://techmemo.g.hatena.ne.jp/emergent/20080413/1208077336
    // MMAPでメモリをセットする場合は、バッファの数を入れる
	// Linux Interface Specification Device Driver Video Capture ユーザーズマニュアル ソフトウェア編の
	// 項「4.2 ioctl(VIDIOC_REQBUFS)」にて、下記の記述あり。
	//		v4l2_requestbuffers 構造体のcount により
	//			count 値3 以下:シングルフレームキャプチャモード
	//			count 値4 以上:連続フレームキャプチャモード
	//		が選択される
	// VIN0_BUFFER_NUMの定義値は本ソース冒頭参照のこと。
	stVin0Req.count               = VIN0_BUFFER_NUM;
    // バッファのタイプ:キャプチャ用
    stVin0Req.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    // mmapを使う
    stVin0Req.memory              = V4L2_MEMORY_MMAP;
	iResult = ioctl(*piVin0DevFd,VIDIOC_REQBUFS,(void *)&stVin0Req);
	if (iResult != 0){
		// バッファ確保要求NG
		fprintf(stderr, "ioctl(VIDIOC_REQBUFS) error.\n");
		return -1;
	}
	// バッファ確保要求OK
	printf("ioctl(VIDIOC_REQBUFS) OK.\n");

	// VIN0のバッファ状態の取得とマッピング処理
	// VIN0_BUFFER_NUMの定義値は本ソース冒頭参照のこと。
	for (i = 0; i < VIN0_BUFFER_NUM; ++i) {
		memset(&gstVin0Buf,0,sizeof(gstVin0Buf));

		gstVin0Buf.type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
		gstVin0Buf.memory	= V4L2_MEMORY_MMAP;
		gstVin0Buf.index		= i;

		iResult = ioctl(*piVin0DevFd,VIDIOC_QUERYBUF,(void *)&gstVin0Buf);
		if (iResult != 0){
			// VIN0のバッファ状態の取得とマッピング処理NG
			fprintf(stderr, "ioctl(VIDIOC_QUERYBUF(%d)) error.\n",i);
			return -1;
		}
		// VIN0のバッファ状態の取得とマッピング処理OK
		printf("ioctl(VIDIOC_QUERYBUF(%d)) OK.\n",i);

		gpcMap[i] = mmap(0, gstVin0Buf.length, PROT_READ|PROT_WRITE, MAP_SHARED,
	             *piVin0DevFd, gstVin0Buf.m.offset);
		if ((int)gpcMap == -1) {
			giLength[i] = 0;
			// VIN0のバッファ状態の取得とマッピング処理NG
			fprintf(stderr, "mmap error.\n");
			return -1;
		}
		// VIN0のバッファ状態の取得とマッピング処理OK
		printf("mmap OK.\n");
		giLength[i] = gstVin0Buf.length;
	}

	return 0;
}

// DU初期化
// 引数:
//		pstDuDev : DUのアクセス用構造体へのポインタ
// 戻り値: 0=正常終了 -1=異常終了
int fInitDu(struct device *pstDuDev)
{
	int ret;

	if(pstDuDev == NULL)
	{
		// 引数異常
		fprintf(stderr, "fInitDu arg error\n");
		return -1;
	}

	// DUのオープン
	pstDuDev->fd = drmOpen("rcar-du", NULL);
	if (pstDuDev->fd < 0) {
		fprintf(stderr, "failed to open DU.\n");
		return -1;
	}
	printf("open DU OK!\n");

	//KMS作成
	ret = kms_create(pstDuDev->fd, &pstDuDev->kms);
	if (ret) {
		fprintf(stderr, "failed to create kms driver: %s\n",
			strerror(-ret));
		return -1;
	}else{
		printf("success. kms_create\n");
	}

	return 0;
}

// DU初期化(ループ内用)
// 引数:
//		pstDuDev : DUのアクセス用構造体へのポインタ
// 戻り値: 0=正常終了 -1=異常終了
int fInitDuInLoop(struct device *pstDuDev)
{
	int ret;

	if(pstDuDev == NULL)
	{
		// 引数異常
		fprintf(stderr, "fInitDu arg error\n");
		return -1;
	}

	ret = kms_create(pstDuDev->fd, &pstDuDev->kms);
	if (ret) {
		fprintf(stderr, "failed to create kms driver: %s\n",
			strerror(-ret));
		return -1;
	}else{
//		printf("success. kms_create\n");
	}
	return 0;
}

// メインループ
// 引数:
//		pParam : スレッドパラメータへのポインタ
//		pstDuDev : DUのアクセス用構造体へのポインタ(未使用)
// 戻り値: スレッド戻り値ポインタ
void *fMainLoop(void* pParam)
{
	int					iResult = 0;	// 実行結果
	int					iRtn    = 0;	// 戻り値
	int					iType   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	int					iCount  = 1000;	// キャプチャ回数

//	struct v4l2_buffer	stVin0Buf;		// VIN0のバッファ構造体;

	int size,n,m,i;
	unsigned char *buffer;			/*入力画像用メモリのポインタ*/
	unsigned char *out_buffer;		/*出力画像用メモリのポインタ*/

	(void)pParam;

	while(iThreadExecFlg){
		// VIN0のストリーム入力開始
		iResult = ioctl(iVin0DevFd,VIDIOC_STREAMON,(void *)&iType);
		if (iResult != 0){
			// ストリーム入力開始NG
			fprintf(stderr, "ioctl(VIDIOC_STREAMON) error.\n");
			return NULL;
		}
		// ストリーム入力開始OK
//		printf("ioctl(VIDIOC_STREAMON) OK.\n");

		// キャプチャキューへの登録/開放(フレーム単位バッファ)
		for (i = 0; i < VIN0_BUFFER_NUM; ++i) {
			memset(&gstVin0Buf,0,sizeof(gstVin0Buf));

			gstVin0Buf.type		= V4L2_BUF_TYPE_VIDEO_CAPTURE;
			gstVin0Buf.memory	= V4L2_MEMORY_MMAP;
			gstVin0Buf.index		= i;

			iResult = ioctl(iVin0DevFd,VIDIOC_QBUF,(void *)&gstVin0Buf);
			if (iResult != 0){
				// VIN0のバッファ状態の取得とマッピング処理NG
				fprintf(stderr, "ioctl(VIDIOC_QBUF(%d)) error.\n",i);
				return NULL;
			}
			// VIN0のバッファ状態の取得とマッピング処理OK
//			printf("ioctl(VIDIOC_QBUF(%d)) OK.\n",i);
		}

		for (i = 0; i < VIN0_BUFFER_NUM; ++i) {
//			int ok = 0;
			fd_set sFds;
			struct timeval stTv;
			int r;

			FD_ZERO (&sFds);
			FD_SET (iVin0DevFd, &sFds);

			for(;;) {
				/* Timeout. */
				stTv.tv_sec = 2;
				stTv.tv_usec = 0;

				// ディスクリプタが読み込みOKになるまで待つ
				iResult = select ((iVin0DevFd) + 1, &sFds, NULL, NULL, &stTv);
				if (iResult == -1){
					if (errno == EINTR) {
					  continue;
					}
					// ストリーム入力開始NG
					fprintf(stderr, "select error.\n");
					iRtn = -1;
					break;
				}else if (iResult == 0){
					// ストリーム入力開始NG
					fprintf(stderr, "select timeout.\n");
					iRtn = -1;
					break;
				}else{
//					printf("select OK.\n");
					break;
				}
			}
			if (iRtn != 0)
			{
				break;
			}

			// DUの初期化実行
			iResult = fInitDuInLoop(&stDuDev);
			if (iResult != 0){
				// DUの初期化NG
				fprintf(stderr, "fInitDuInLoop error.\n");
				iRtn = -1;
				break;
			}
//			printf("fInitDuInLoop  OK!\n");

			// VINからキャプチャしたデータをDUに出力する
			iResult = outputDuFromFrame(&stDuDev,gpcMap[i]);
			if (iResult != 0){
				// NG
				fprintf(stderr, "outputDuFromFrame error.\n");
				iRtn = -1;
				break;
			}
//			printf("outputDuFromFrame OK.\n");

			memset(&gstVin0Buf,0,sizeof(gstVin0Buf));

			gstVin0Buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			gstVin0Buf.memory = V4L2_MEMORY_MMAP;
			gstVin0Buf.index		= i;
			iResult = ioctl(iVin0DevFd,VIDIOC_DQBUF,(void *)&gstVin0Buf);
			if (iResult != 0){
				// VIN0のバッファ状態の取得とマッピング処理NG
				fprintf(stderr, "ioctl(VIDIOC_DQBUF(%d)) error.\n",iCount);
				iRtn = -1;
				break;
			}
//			printf("ioctl(VIDIOC_DQBUF(%d)) OK..\n",iCount);

			// 使い終わったバッファをまたエンキューする 
			iResult = ioctl(iVin0DevFd,VIDIOC_QBUF,(void *)&gstVin0Buf);
			if (iResult != 0){
				// VIN0のバッファ状態の取得とマッピング処理NG
				fprintf(stderr, "ioctl(VIDIOC_QBUF(%d)) error.\n",iCount);
				iRtn = -1;
				break;
			}

		}
		if (iRtn != 0)
		{
			break;
		}
		iResult = ioctl(iVin0DevFd,VIDIOC_STREAMOFF,(void *)&iType);
		if (iResult != 0){
			// VIN0のバッファ状態の取得とマッピング処理NG
			fprintf(stderr, "ioctl(VIDIOC_STREAMOFF(%d)) error.\n",iCount);
			iRtn = -1;
			break;
		}
//		printf("ioctl(VIDIOC_STREAMOFF(%d)) OK..\n",iCount);

	}

	return NULL;
}

// スレッド生成
// 引数:なし
// 戻り値:なし
int fCreateThread(void)
{
	int				iResult = 0;	// 実行結果
	pthread_attr_t	stAttr;			// スレッド属性
	pthread_t		stThreadID;		// スレッドのID

	// スレッド属性初期化
	memset(&stAttr, 0, sizeof stAttr);
    iResult = pthread_attr_init(&stAttr);
	if (iResult != 0){
		fprintf(stderr, "pthread_attr_init error.\n");
		return -1;
	}

	// スレッド実行フラグTRUE設定
	iThreadExecFlg = TRUE;

	// スレッド生成
	iResult = pthread_create(&stThreadID,&stAttr,fMainLoop,NULL);
	if (iResult != 0){
		fprintf(stderr, "pthread_create error.\n");
		return -1;
	}

	// 停止指示待ち
	//printf("Press Return key to stop\n");
	//(void)getchar();
	while(1);

	// スレッド実行フラグFALSE設定
	iThreadExecFlg = FALSE;

	// スレッド終了待ち
	pthread_join(stThreadID,NULL);


	// スレッド属性の破棄
	iResult = pthread_attr_destroy(&stAttr);
	if (iResult != 0){
		fprintf(stderr, "pthread_attr_destroy error.\n");
		return -1;
	}


	return 0;
}

// メイン関数
int main(int argc,char **argv)
{
	int	iResult = 0;		// 実行結果
	int	i;					// 
    int	iOpt;				// 
	int	iGradFlg = FALSE;	// 
	int	iMode = 0;
	int	color_switch_count= 0;

	memset(&stDuDev, 0, sizeof stDuDev);

	while ((iOpt = getopt(argc, argv, "gv:")) != -1) {
		switch (iOpt) {
			case 'g':
			iGradFlg = TRUE;
			break;
	
			case 'v':
			iMode = atoi(optarg);
			switch (iMode)
			{
				case VIDEO_MODE_1280x720:
				guiWidth     = WIDTH_MODE0;
				guiHeight    = HEIGHT_MODE0;
				guiDuPosLeft = DU_OUTPUT_POSITION_LEFT(WIDTH_MODE0);
				guiDuPosTop  = DU_OUTPUT_POSITION_TOP(HEIGHT_MODE0);
				break;

				case VIDEO_MODE_720x480:
				guiWidth     = WIDTH_MODE1;
				guiHeight    = HEIGHT_MODE1;
				guiDuPosLeft = DU_OUTPUT_POSITION_LEFT(WIDTH_MODE1);
				guiDuPosTop  = DU_OUTPUT_POSITION_TOP(HEIGHT_MODE1);
				break;

				case VIDEO_MODE_640x480:
				guiWidth     = WIDTH_MODE2;
				guiHeight    = HEIGHT_MODE2;
				guiDuPosLeft = DU_OUTPUT_POSITION_LEFT(WIDTH_MODE2);
				guiDuPosTop  = DU_OUTPUT_POSITION_TOP(HEIGHT_MODE2);
				break;

				default:
				fprintf(stderr, "mode error (%d)\n",iMode);
				exit(EXIT_FAILURE);
			}
			break;
			default: /* '?' */
//			fprintf(stderr, "Usage: %s [-v nsecs] [-n] name\n",argv[0]);
			fprintf(stderr, "argument error (%s)\n",argv[0]);
			exit(EXIT_FAILURE);
		}
	}
	printf("guiWidth       = %d\n",guiWidth);
	printf("guiHeight      = %d\n",guiHeight);
	printf("guiDuPosLeft   = %d\n",guiDuPosLeft);
	printf("guiDuPosTop    = %d\n",guiDuPosTop);
#if 0
	// VIN0の初期化実行
	iResult = fInitVin0(&iVin0DevFd);
	if (iResult != 0){
		// VIN0の初期化NG
		fprintf(stderr, "VIN0 initialize error.\n");
		return -1;

	}
	printf("VIN0 Initializd  OK!\n");
#endif
	// DUの初期化実行
	iResult = fInitDu(&stDuDev);
	if (iResult != 0){
		// DUの初期化NG
		fprintf(stderr, "DU initialize error.\n");
		return -1;
	}
	printf("DU Initializd  OK!\n");

	/* カメラ画像にグラデーション画像を重ねる*/
	if (iGradFlg){
		iResult = put_image(&stDuDev);
		if (iResult != 0){
			(stderr, "put_image error.\n");
			return -1;
		}
		printf("DU Initializd  OK!\n");
	}
#if 0	
	// スレッド生成
	iResult = fCreateThread();
	if (iResult != 0){
		// メインループNG
		fprintf(stderr, "fCreateThread error.\n");
		return -1;

	}
#endif
	gpcMap[0] = malloc((size_t)MALLOC_REQ_SIZE);
	memset( gpcMap[0], 0x00, MALLOC_REQ_SIZE );

	while(1){	
		switch( color_switch_count ){
			case 0:
				set_color_space( gpcMap[0], 0,255,0 );
				break;
			case 1:
				set_color_space( gpcMap[0], 255,0,0 );
				break;
			case 2:
				set_color_space( gpcMap[0], 0,0,255 );
				color_switch_count = 0;
				break;
			default:
				break;
		}
		color_switch_count++;
		
		// DUの初期化実行
		iResult = fInitDuInLoop(&stDuDev);
		if (iResult != 0){
			// DUの初期化NG
			fprintf(stderr, "fInitDuInLoop error.\n");
//			iRtn = -1;
			break;
		}
//			printf("fInitDuInLoop  OK!\n");

		// VINからキャプチャしたデータをDUに出力する
		iResult = outputDuFromFrame(&stDuDev,gpcMap[0]);
		if (iResult != 0){
			// NG
			fprintf(stderr, "outputDuFromFrame error.\n");
//			iRtn = -1;
			break;
		}
//			printf("outputDuFromFrame OK.\n");
		sleep(3);
	}

	// DUのクローズ
	drmClose(stDuDev.fd);


	// VIN0のクローズ
	for (i = 0; i < VIN0_BUFFER_NUM; ++i) {
		if(giLength[i] != 0){
			munmap(gpcMap[i], giLength[0]);
		}
	}
//	(void)close(iVin0DevFd);

	return 0;
}

app  .h文件

// カメラテスト用ヘッダファイル
#ifndef _CAMERA_TEST_H_		// 二重インクルード防止
#define _CAMERA_TEST_H_		// 二重インクルード防止


// 各種定数定義

// VIN0のバッファ数
// 項「4.2 ioctl(VIDIOC_REQBUFS)」にて、下記の記述あり。
//		v4l2_requestbuffers 構造体のcount により
//			count 値3 以下:シングルフレームキャプチャモード
//			count 値4 以上:連続フレームキャプチャモード
//		が選択される
#define VIN0_BUFFER_NUM 1
//#define VIN0_BUFFER_NUM 4
//#define VIN0_BUFFER_NUM 24

// 画面幅と高さ最大値
#define WIDTH_MAX			1280
#define HEIGHT_MAX			720

#define WIDTH_MODE0			WIDTH_MAX
#define HEIGHT_MODE0		HEIGHT_MAX
#define WIDTH_MODE1			720
#define HEIGHT_MODE1		480
#define WIDTH_MODE2			640
#define HEIGHT_MODE2		480

// ビデオモード定義
#define VIDEO_MODE_1280x720	0
#define VIDEO_MODE_720x480	1
#define VIDEO_MODE_640x480	2

// DU出力サイズ定義
#define DU_OUTPUT_WIDTH	VIN0_CAPTURE_WIDTH
#define DU_OUTPUT_HEIGHT	VIN0_CAPTURE_HEIGHT
//#define DU_OUTPUT_WIDTH		720
//#define DU_OUTPUT_HEIGHT	480

// DU出力位置定義
#define DU_OUTPUT_POSITION_LEFT(x)	((WIDTH_MAX - x ) / 2)
#define DU_OUTPUT_POSITION_TOP(y)	((HEIGHT_MAX  - y)  / 2)


// 各種構造体定義

// DUのアクセス用構造体宣言
struct device {
	int fd;
	struct kms_driver *kms;
	struct kms_bo *bo;
};


#endif						// 二重インクルード防止

Makefile文件

TARGET=camera_test
CC = /opt/poky/1.6.1/sysroots/i686-pokysdk-linux/usr/bin/arm-poky-linux-gnueabi/arm-poky-linux-gnueabi-gcc -march=armv7-a -mthumb-interwork -mfloat-abi=hard -mfpu=neon -mtune=cortex-a15 --sysroot=/opt/poky/1.6.1/sysroots/cortexa15hf-vfp-neon-poky-linux-gnueabi
CFLAGS = -I/opt/poky/1.6.1/sysroots/cortexa15hf-vfp-neon-poky-linux-gnueabi/usr/include/ -I/opt/poky/1.6.1/sysroots/cortexa15hf-vfp-neon-poky-linux-gnueabi/usr/include/libkms -I/opt/poky/1.6.1/sysroots/cortexa15hf-vfp-neon-poky-linux-gnueabi/usr/include/libdrm
LDFLAGS = -L/opt/poky/1.6.1/sysroots/cortexa15hf-vfp-neon-poky-linux-gnueabi/usr/lib
LIBS = -ldrm -lkms
SRC=$(TARGET).c

# 僗儗僢僪梡僼儔僌捛壛
CFLAGS  += -pthread
LDFLAGS += -pthread

$(TARGET): $(SRC)
	$(CC) -o $(TARGET) $(SRC) $(CFLAGS) $(LDFLAGS) $(LIBS)

.PHONY: clean
clean:
	rm -rf $(TARGET)

 

 

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值