本文介绍了基于TDA4VM EVM在屏幕上显示图形文件的实现步骤
1. 按照TI官方要求创建在Linux操作系统下的开发环境。目标可以在Vision_apps使用make生成目标文件。本文的环境是基于SDK8.0.5,Ubuntu 20.04 LTS + Docker
2. 在vision_apps/apps创建文件夹custom_usecase; 在custom_usecase下创建my_disp_img文件夹
3. 在my_disp_img文件夹下创建以下文件
a. concerto.mak
ifeq ($(TARGET_CPU),$(filter $(TARGET_CPU), x86_64 A72))
include $(PRELUDE)
TARGET := my_disp_img
CSOURCES := main.c
ifeq ($(TARGET_CPU),A72)
ifeq ($(TARGET_OS),$(filter $(TARGET_OS), LINUX QNX))
TARGETTYPE := exe
CSOURCES += main_linux_arm.c
include $(VISION_APPS_PATH)/apps/concerto_a72_inc.mak
endif
endif
ifeq ($(TARGET_OS),SYSBIOS)
ifeq ($(TARGET_CPU),$(filter $(TARGET_CPU), A72))
TARGETTYPE := library
endif
endif
include $(FINALE)
endif
b. app_common.h
#ifndef _APP_COMMON
#define _APP_COMMON
#include <TI/tivx.h>
#include <TI/tivx_task.h>
#include <tivx_utils_file_rd_wr.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
#include <float.h>
#include <math.h>
//#define APP_DEBUG
#define APP_MAX_FILE_PATH (256u)
#define APP_ASSERT(x) assert((x))
#define APP_ASSERT_VALID_REF(ref) (APP_ASSERT(vxGetStatus((vx_reference)(ref))==VX_SUCCESS));
#define MAX_IMG_WIDTH (2048)
#define MAX_IMG_HEIGHT (1024)
#define DISPLAY_WIDTH (1280)
#define DISPLAY_HEIGHT (720)
#ifdef APP_DEBUG
#define APP_PRINTF(f_, ...) printf((f_), ##__VA_ARGS__)
#else
#define APP_PRINTF(f_, ...)
#endif
#endif
c. main.c
#include "app_common.h"
typedef struct {
/* config options */
char input_file_path[APP_MAX_FILE_PATH];
char input_file_list[APP_MAX_FILE_PATH];
/* Input image params */
tivx_utils_bmp_image_params_t imgParams;
vx_uint32 img_width;
vx_uint32 img_height;
vx_uint32 img_stride;
/* OpenVX references */
vx_context context;
vx_graph disp_graph;
vx_node disp_node;
vx_image disp_image;
vx_user_data_object disp_params_obj;
tivx_display_params_t disp_params;
vx_uint32 display_option;
vx_uint32 delay_in_msecs;
tivx_task task;
uint32_t stop_task;
uint32_t stop_task_done;
} AppObj;
AppObj gAppObj;
static vx_status app_init(AppObj *obj);
static void app_deinit(AppObj *obj);
static vx_status app_create_graph(AppObj *obj);
static vx_status app_verify_graph(AppObj *obj);
static vx_status app_run_graph(AppObj *obj);
static vx_status app_run_graph_interactive(AppObj *obj);
static void app_delete_graph(AppObj *obj);
int app_disp_img_main()
{
int status = 0;
AppObj *obj = &gAppObj;
status = app_init(obj);
if(status == VX_SUCCESS)
{
status = app_create_graph(obj);
}
if(status == VX_SUCCESS)
{
status = app_verify_graph(obj);
}
if(status == VX_SUCCESS)
{
status = app_run_graph_interactive(obj);
}
app_delete_graph(obj);
app_deinit(obj);
return status;
}
static int app_init(AppObj *obj)
{
APP_PRINTF("disp_img: Init ... \n");
obj->context = vxCreateContext();
APP_ASSERT_VALID_REF(obj->context);
obj->disp_image = vxCreateImage(obj->context, DISPLAY_WIDTH, DISPLAY_HEIGHT, VX_DF_IMAGE_RGB);
APP_ASSERT_VALID_REF(obj->disp_image)
memset(&obj->disp_params, 0, sizeof(tivx_display_params_t));
obj->disp_params.opMode = TIVX_KERNEL_DISPLAY_BUFFER_COPY_MODE;
obj->disp_params.pipeId = 0;
obj->disp_params.outWidth = DISPLAY_WIDTH;
obj->disp_params.outHeight = DISPLAY_HEIGHT;
obj->disp_params.posX = (1920-DISPLAY_WIDTH)/2;
obj->disp_params.posY = (1080-DISPLAY_HEIGHT)/2;
obj->disp_params_obj = vxCreateUserDataObject(obj->context, "tivx_display_params_t", sizeof(tivx_display_params_t), &obj->disp_params);
APP_ASSERT_VALID_REF(obj->disp_params_obj)
obj->delay_in_msecs = 1000;
tivxHwaLoadKernels(obj->context);
snprintf(obj->input_file_path, APP_MAX_FILE_PATH-1, "%s",
"/opt/vision_apps/test_data/psdkra/app_tidl");
snprintf(obj->input_file_list, APP_MAX_FILE_PATH-1, "%s",
"/opt/vision_apps/test_data/psdkra/app_tidl/names.txt");
APP_PRINTF("disp_img: Init ... Done.\n");
return 0;
}
static void app_deinit(AppObj *obj)
{
tivxHwaUnLoadKernels(obj->context);
vxReleaseContext(&obj->context);
APP_PRINTF("disp_img: De-init ... Done.\n");
}
static void app_delete_graph(AppObj *obj)
{
APP_PRINTF("disp_img: Delete ... \n");
vxReleaseNode(&obj->disp_node);
vxReleaseGraph(&obj->disp_graph);
APP_PRINTF("disp_img: Delete ... Done.\n");
}
static vx_status app_create_graph(AppObj *obj)
{
vx_status status = VX_SUCCESS;
APP_PRINTF("disp_img: Creating graph ... \n");
/* Create OpenVx Graph */
obj->disp_graph = vxCreateGraph(obj->context);
APP_ASSERT_VALID_REF(obj->disp_graph)
vxSetReferenceName((vx_reference)obj->disp_graph, "Display");
obj->disp_node = tivxDisplayNode(obj->disp_graph, obj->disp_params_obj, obj->disp_image);
APP_ASSERT_VALID_REF(obj->disp_node)
vxSetNodeTarget(obj->disp_node, VX_TARGET_STRING, TIVX_TARGET_DISPLAY1);
/* Set names for diferent OpenVX objects */
vxSetReferenceName((vx_reference)obj->disp_params_obj, "DisplayParams");
vxSetReferenceName((vx_reference)obj->disp_node, "DisplayNode");
APP_PRINTF("disp_img: Creating graph ... Done.\n");
return status;
}
static void app_run_task(void *app_var)
{
AppObj *obj = (AppObj *)app_var;
vx_status status = VX_SUCCESS;
while(!obj->stop_task)
{
status = app_run_graph(obj);
if(status == VX_FAILURE)
{
printf("Error processing graph!\n");
obj->stop_task = 1;
}
}
obj->stop_task_done = 1;
}
static int32_t app_run_task_create(AppObj *obj)
{
tivx_task_create_params_t params;
int32_t status;
tivxTaskSetDefaultCreateParams(¶ms);
params.task_main = app_run_task;
params.app_var = obj;
obj->stop_task_done = 0;
obj->stop_task = 0;
status = tivxTaskCreate(&obj->task, ¶ms);
return status;
}
static void app_run_task_delete(AppObj *obj)
{
while(obj->stop_task_done==0)
{
tivxTaskWaitMsecs(100);
}
tivxTaskDelete(&obj->task);
}
static char menu[] = {
"\n"
"\n ================================="
"\n Display the images from file"
"\n ================================="
"\n"
"\n x: Exit"
"\n"
"\n Enter Choice: "
};
static vx_status app_run_graph_interactive(AppObj *obj)
{
vx_status status = VX_SUCCESS;
uint32_t done = 0;
char ch;
status = app_run_task_create(obj);
if(status != VX_SUCCESS)
{
printf("disp_img: ERROR: Unable to create task\n");
}
else
{
while((!done) && (status == VX_SUCCESS))
{
printf(menu);
ch = getchar();
printf("\n");
if(ch == 'x')
{
obj->stop_task = 1;
done = 1;
break;
}
}
app_run_task_delete(obj);
}
return status;
}
static vx_status app_verify_graph(AppObj *obj)
{
vx_status status = VX_SUCCESS;
APP_PRINTF("disp_img: Verifying graph ... \n");
/* Verify the TIDL Graph */
status = vxVerifyGraph(obj->disp_graph);
if(status != VX_SUCCESS)
{
printf("disp_img: ERROR: Verifying display graph ... Failed !!!\n");
return status;
}
APP_PRINTF("disp_img: Verifying display graph ... Done.\n");
/* wait a while for prints to flush */
tivxTaskWaitMsecs(100);
return status;
}
static vx_status app_run_graph_for_one_frame(AppObj *obj, char *curFileName, vx_uint32 counter)
{
vx_status status = VX_SUCCESS;
vx_char input_file_name[APP_MAX_FILE_PATH];
//Clear the full image to black
void *base_ptr = NULL;
vx_uint32 plane = 0;
vx_rectangle_t rect;
vx_imagepatch_addressing_t addr;
vx_map_id map_id;
rect.start_x = rect.start_y = 0;
rect.end_x = DISPLAY_WIDTH;
rect.end_y = DISPLAY_HEIGHT;
status = vxMapImagePatch(obj->disp_image, &rect, plane, &map_id,
&addr, &base_ptr,
VX_READ_AND_WRITE, VX_MEMORY_TYPE_HOST, 0);
if (status == VX_SUCCESS)
{
APP_PRINTF("Mapping successful!\n");
vx_uint32 x,y;
vx_uint8 pixel = 0;
/* 2d addressing access */
for (y = 0; y < addr.dim_y; y+=addr.step_y)
{
for (x = 0; x < addr.dim_x; x+=addr.step_x)
{
vx_uint8 *ptr2 = vxFormatImagePatchAddress2d(base_ptr,
x, y, &addr);
*ptr2 = pixel;
*(ptr2+1) = pixel;
*(ptr2+2) = pixel;
}
}
status = vxUnmapImagePatch(obj->disp_image, map_id);
}
else
{
APP_PRINTF("Mapping failed!\n");
}
snprintf(input_file_name, APP_MAX_FILE_PATH-1, "%s/%s",
obj->input_file_path,
curFileName
);
APP_PRINTF("disp_img: Reading input file %s ... \n", curFileName);
/* Read input from file */
status = tivx_utils_load_vximage_from_bmpfile ( obj->disp_image, input_file_name, (vx_bool)vx_false_e);
APP_PRINTF("disp_image: Reading input file Done!\n");
/* Execute the display graph */
if(status == VX_SUCCESS)
{
status = vxProcessGraph(obj->disp_graph);
}
APP_PRINTF("disp_img: Running display graph ... Done.\n");
return status;
}
static vx_status app_run_graph(AppObj *obj)
{
vx_status status = VX_SUCCESS;
vx_char curFileName[APP_MAX_FILE_PATH];
uint64_t cur_time;
uint64_t max_frames = INT64_MAX;
vx_uint32 counter = 0;
FILE* test_case_file;
test_case_file = fopen(obj->input_file_list,"r");
if(test_case_file==NULL)
{
printf("Open file Error");
status = VX_FAILURE;
}
if(status == VX_SUCCESS)
{
while (fgets(curFileName, sizeof(curFileName), test_case_file) && (counter < max_frames))
{
curFileName[strlen(curFileName) - 1] = 0;
cur_time = tivxPlatformGetTimeInUsecs();
APP_PRINTF("Input file: %s ...\n", curFileName);
if(status == VX_SUCCESS)
{
status = app_run_graph_for_one_frame(obj, curFileName, counter++);
}
APP_PRINTF("Display input file %s ...Done!\n", curFileName);
cur_time = tivxPlatformGetTimeInUsecs() - cur_time;
/* convert to msecs */
cur_time = cur_time/1000;
if(cur_time < obj->delay_in_msecs)
{
tivxTaskWaitMsecs(obj->delay_in_msecs - cur_time);
}
/* user asked to stop processing */
if(obj->stop_task || (status != VX_SUCCESS))
{
break;
}
}
fclose(test_case_file);
}
return status;
}
备注:记得将图像文件的路径和文件列表替换为自己。本文中使用的test_data集中的文件。
d. main_linux_arm.c
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <stdint.h>
#include <TI/tivx.h>
#include <utils/app_init/include/app_init.h>
int main()
{
int status = 0;
status = appInit();
if(status==0)
{
int app_disp_img_main();
status = app_disp_img_main();
appDeInit();
}
return status;
}
4. 在vision_apps下使用make生成可执行文件my_disp_img.out
5. 将文件my_disp_img.out拷贝至开发板/opt/vision_apps下
6. 运行my_disp_img.out将可以看到存储在EVM上的文件可以依次显示在屏幕上,时间间隔为1秒。
【函数说明】
1. tivx_utils_load_vximage_from_bmpfile()
函数定义:
vx_status tivx_utils_load_vximage_from_bmpfile | ( | vx_image | image, |
char * | filename, | ||
vx_bool | convert_to_gray_scale | ||
) |
函数功能:
将BMP文件的图像加载到已经创建的vx_image对象中。
参数
image | [in] 已经创建的图像对象 |
filename | [in] 扩展名为bmp的图像文件的文件名 |
convert_to_gray_scale | [in] vx_true_e: 将图像文件中RGB转化为8b灰度值 vx_false_e: 保留原始RGB值 备注:目前不能转化 |
返回值:
VX_SUCCESS:如果BMP文件可以成功加载到image的对象中
【参考信息】