概述
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: %sn",
strerror(-ret));
return NULL;
}
ret = kms_bo_get_prop(bo, KMS_PITCH, stride);
if (ret) {
fprintf(stderr, "failed to retreive buffer stride: %sn",
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: %sn",
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: %sn",
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: %sn",
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 %un",
// 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: %sn", strerror(errno));
return -1;
}
else{
// printf("success. drmModeAddFB2n");
}
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: %sn",
strerror(errno));
return -1;
}
else{
// printf("success. drmModeSetPlanen");
}
}
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:%dn",plane_id);
// fprintf(stderr, "testing %dx%d overlay plane %un",
// 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: %sn", strerror(errno));
return -1;
}
else{
// printf("success. drmModeAddFB2n");
}
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: %sn",
strerror(errno));
return -1;
}
else{
// printf("success. drmModeSetPlanen");
}
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 errorn");
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 = %dn",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 = %sn",stVin0Query.driver);
printf("card = %sn",stVin0Query.card);
printf("bus_info = %sn",stVin0Query.bus_info);
printf("version = 0x%08Xn",stVin0Query.version);
printf("capabilities = 0x%08Xn",stVin0Query.capabilities);
printf("device_caps = 0x%08Xn",stVin0Query.device_caps);
// デバイスがキャプチャ能力を備えているかチェック
if (!(stVin0Query.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {
fprintf (stderr, "VIN0 is NOT video capture devicen");
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 errorn");
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: %sn",
strerror(-ret));
return -1;
}else{
printf("success. kms_createn");
}
return 0;
}
// DU初期化(ループ内用)
// 引数:
// pstDuDev : DUのアクセス用構造体へのポインタ
// 戻り値: 0=正常終了 -1=異常終了
int fInitDuInLoop(struct device *pstDuDev)
{
int ret;
if(pstDuDev == NULL)
{
// 引数異常
fprintf(stderr, "fInitDu arg errorn");
return -1;
}
ret = kms_create(pstDuDev->fd, &pstDuDev->kms);
if (ret) {
fprintf(stderr, "failed to create kms driver: %sn",
strerror(-ret));
return -1;
}else{
// printf("success. kms_createn");
}
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 stopn");
//(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] namen",argv[0]);
fprintf(stderr, "argument error (%s)n",argv[0]);
exit(EXIT_FAILURE);
}
}
printf("guiWidth = %dn",guiWidth);
printf("guiHeight = %dn",guiHeight);
printf("guiDuPosLeft = %dn",guiDuPosLeft);
printf("guiDuPosTop = %dn",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)
最后
以上就是甜甜外套为你收集整理的rcar-du 通过DRM/KMS实现DU显示测试demo的全部内容,希望文章能够帮你解决rcar-du 通过DRM/KMS实现DU显示测试demo所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复