This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TDA4VH-Q1: Can I display 4 RGB images using multi-display or mosaic?

Part Number: TDA4VH-Q1

Hi experts,

I'm trying to display 4 RGB images using multi-display or mosaic.

The data flow is image->cv::mat->vx_image_RGB->display.

However, for multi-display, there are only 2 display to use (TIVX_TARGET_DISPLAY1 & TIVX_TARGET_DISPLAY2).

I try to use M2M display, but there is not much example code that I can refer to.

For mosaic, I can't display RGB images either.

Is there a way to display 4 RGB images succesfully?

I will show my code (.cpp) here.

mosaic:

#include <iostream>
#include <stdexcept>

//OpenVX includes
#include <VX/vx.h>

extern "C" 
{
#include <utils/app_init/include/app_init.h>
#include <utils/grpx/include/app_grpx.h>
#include "display_common.h"
#include "app_img_mosaic_module.h"
#include <TI/video_io_display.h>
#include <TI/video_io_display_m2m.h>
#include <TI/hwa_kernels.h>
#include <TI/video_io_kernels.h>
#include <TI/tivx.h>
#include <TI/tivx_task.h>
}
#include "test_vximage_mosaic.h"

//OpenCV includes
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"

#define CAPTURE_BUFFER_Q_DEPTH  (4)
#define APP_BUFFER_Q_DEPTH      (4)
#define APP_PIPELINE_DEPTH      (7)

#define INPUT_DISPLAY_WIDTH   1920
#define INPUT_DISPLAY_HEIGHT  720

#define INPUT_DISPLAY_WIDTH_DISPLAY   1920
#define INPUT_DISPLAY_HEIGHT_DISPLAY  720

vx_status app_init_display1(vx_context context, DisplayObj *displayObj, char *objName);
void app_deinit_display1(DisplayObj *displayObj);
void app_delete_display1(DisplayObj *displayObj);
vx_status app_create_graph_display1(vx_graph graph, DisplayObj *displayObj, vx_image disp_image);

vx_status app_run_graph(AppObj *obj);
void app_draw_graphics(Draw2D_Handle *handle, Draw2D_BufInfo *draw2dBufInfo, uint32_t update_type);
static vx_status app_create_graph(AppObj *obj);
inline vx_image vxCvMatToVxImage(const vx_context context, const cv::Mat &cv_image);

static void set_img_mosaic_params(ImgMosaicObj *imgMosaicObj)
{
    
    imgMosaicObj->out_width   = INPUT_DISPLAY_WIDTH;
    imgMosaicObj->out_height   = INPUT_DISPLAY_HEIGHT;
    imgMosaicObj->num_inputs   = 4;
    tivxImgMosaicParamsSetDefaults(&imgMosaicObj->params);

    imgMosaicObj->params.windows[0].startX  = 0;
    imgMosaicObj->params.windows[0].startY  = 0;
    imgMosaicObj->params.windows[0].width   = INPUT_DISPLAY_WIDTH/2;
    imgMosaicObj->params.windows[0].height  = INPUT_DISPLAY_HEIGHT/2;
    imgMosaicObj->params.windows[0].input_select   = 0;
    imgMosaicObj->params.windows[0].channel_select = 0;

    imgMosaicObj->params.windows[1].startX  = 1920-INPUT_DISPLAY_WIDTH/2;
    imgMosaicObj->params.windows[1].startY  = 0;
    imgMosaicObj->params.windows[1].width   = INPUT_DISPLAY_WIDTH/2;
    imgMosaicObj->params.windows[1].height  = INPUT_DISPLAY_HEIGHT/2;
    imgMosaicObj->params.windows[1].input_select   = 1;
    imgMosaicObj->params.windows[1].channel_select = 0;

    imgMosaicObj->params.windows[2].startX  = 0;
    imgMosaicObj->params.windows[2].startY  = INPUT_DISPLAY_HEIGHT/2;
    imgMosaicObj->params.windows[2].width   = INPUT_DISPLAY_WIDTH/2;
    imgMosaicObj->params.windows[2].height  = INPUT_DISPLAY_HEIGHT/2;
    imgMosaicObj->params.windows[2].input_select   = 2;
    imgMosaicObj->params.windows[2].channel_select = 0;

    imgMosaicObj->params.windows[3].startX  = 1920-INPUT_DISPLAY_WIDTH/2;
    imgMosaicObj->params.windows[3].startY  = INPUT_DISPLAY_HEIGHT/2;
    imgMosaicObj->params.windows[3].width   = INPUT_DISPLAY_WIDTH/2;
    imgMosaicObj->params.windows[3].height  = INPUT_DISPLAY_HEIGHT/2;
    imgMosaicObj->params.windows[3].input_select   = 3;
    imgMosaicObj->params.windows[3].channel_select = 0; 

    imgMosaicObj->params.num_windows  = 4;
    // imgMosaicObj->params.clear_count  = 1;
}

void app_draw_graphics(Draw2D_Handle *handle, Draw2D_BufInfo *draw2dBufInfo, uint32_t update_type)
{
  AppObj *obj = &gAppObj;

  appGrpxDrawDefault(handle, draw2dBufInfo, update_type);

  if(update_type == 0)
  {
    Draw2D_FontPrm sHeading;
    Draw2D_FontPrm sAlgo1;
    Draw2D_FontPrm sAlgo2;
    Draw2D_FontPrm sAlgo3;
    Draw2D_FontPrm sAlgo4;
    Draw2D_FontPrm sAlgo5;
    Draw2D_FontPrm sAlgo6;

    Draw2D_BmpPrm bmp;

    sHeading.fontIdx = 5;
    Draw2D_drawString(handle, 620, 40, "Image Display Test", &sHeading);

    // sAlgo1.fontIdx = 1;
    // Draw2D_drawString(handle, INPUT_DISPLAY_WIDTH/2 - 120 , (DISPLAY_HEIGHT + INPUT_DISPLAY_HEIGHT)/2 - 75, "Display 1", &sAlgo1);
    // sAlgo1.fontIdx = 1;
    // Draw2D_drawString(handle, DISPLAY_WIDTH - (INPUT_DISPLAY_WIDTH2/2 + 120) , (DISPLAY_HEIGHT + INPUT_DISPLAY_HEIGHT2)/2 - 75, "Display 2", &sAlgo1);
  }

  return;
}


static vx_status app_init(AppObj *obj)
{
    vx_status status = VX_SUCCESS;
    app_grpx_init_prms_t grpx_prms;

    if (status == VX_SUCCESS)
    {
        /* Create OpenVx Context */
        obj->context = vxCreateContext();
        status = vxGetStatus((vx_reference)obj->context);
        APP_PRINTF("Creating context done!\n");
    }

    if (status == VX_SUCCESS)
    {
        tivxHwaLoadKernels(obj->context);
        tivxVideoIOLoadKernels(obj->context);
        APP_PRINTF("Kernel loading done!\n");
    }

    /* Initialize modules */

    if (status == VX_SUCCESS)
    {
        status = app_init_img_mosaic(obj->context, &obj->imgMosaicObj, "img_mosaic_obj", APP_BUFFER_Q_DEPTH);
        APP_PRINTF("Img Mosaic init done!\n");
    }

    if (status == VX_SUCCESS)
    {
        status = app_init_display1(obj->context, &obj->displayObj, "display_obj");
        APP_PRINTF("Display init done!\n");
    }

    appGrpxInitParamsInit(&grpx_prms, obj->context);
    grpx_prms.draw_callback = app_draw_graphics;
    appGrpxInit(&grpx_prms);

    return status;
}

static vx_status app_create_graph(AppObj *obj)
{
    vx_status status = VX_SUCCESS;
    vx_graph_parameter_queue_params_t graph_parameters_queue_params_list[2] = {0};
    vx_int32 graph_parameter_index;

    obj->graph = vxCreateGraph(obj->context);
    status = vxGetStatus((vx_reference)obj->graph);
    if (status == VX_SUCCESS)
    {
        status = vxSetReferenceName((vx_reference)obj->graph, "app_multi_cam_graph");
        APP_PRINTF("Graph create done!\n");
    }


    vx_int32 idx = 0;
    vx_object_array mosaic_in_arr1;
    vx_object_array mosaic_in_arr2;
    vx_object_array mosaic_in_arr3;
    vx_object_array mosaic_in_arr4;
    mosaic_in_arr1 = vxCreateObjectArray(obj->context, (vx_reference)obj->display_image1, 1);
    mosaic_in_arr2 = vxCreateObjectArray(obj->context, (vx_reference)obj->display_image2, 1);
    mosaic_in_arr3 = vxCreateObjectArray(obj->context, (vx_reference)obj->display_image1, 1);
    mosaic_in_arr4 = vxCreateObjectArray(obj->context, (vx_reference)obj->display_image2, 1);

    obj->imgMosaicObj.input_arr[0] = mosaic_in_arr1;
    obj->imgMosaicObj.input_arr[1] = mosaic_in_arr2;
    obj->imgMosaicObj.input_arr[2] = mosaic_in_arr3;
    obj->imgMosaicObj.input_arr[3] = mosaic_in_arr4;
    obj->imgMosaicObj.num_inputs = 4;
    
    vx_image display_in_image;

    status = app_create_graph_img_mosaic(obj->graph, &obj->imgMosaicObj, NULL);
    APP_PRINTF("Img Mosaic graph done!\n");
    display_in_image = obj->imgMosaicObj.output_image[0];


    if(status == VX_SUCCESS)
    {
        status = app_create_graph_display1(obj->graph, &obj->displayObj, display_in_image);
        APP_PRINTF("Display graph done!\n");
    }
    if(status == VX_SUCCESS)
    {
        status = vxVerifyGraph(obj->graph);
    }
    return status;
}


vx_status app_run_graph(AppObj *obj)
{
    uint32_t curFileNum;
    int32_t outputFileNum;
    uint32_t iterations = 1;
    vx_status status = VX_SUCCESS;

    uint32_t num_buf;
    num_buf = MAX_NUM_BUF;

    int32_t pipeline = -num_buf;
    int32_t enqueueCnt = 0;

    vx_int32 img_array_idx = -1;

    vx_uint32 test_counter = 0;
    if(status == VX_SUCCESS)
    {
        if(status == VX_SUCCESS)
        {
            for(int i = 0; i < 200; i++)
            {
                status = vxProcessGraph(obj->graph);
                std::cout << "Processed iterations: " << i << std::endl;
            }
        }
    }

    printf(" Ran %d times successfully!\n", 100);
    return status;
}

vx_status app_init_display1(vx_context context, DisplayObj *displayObj, char *objName)
{
  vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (1 == displayObj->display_option))
    {
        memset(&displayObj->display_params1, 0, sizeof(tivx_display_params_t));
        displayObj->display_config1 = vxCreateUserDataObject(context, "tivx_display_params_t",
             sizeof(tivx_display_params_t), NULL);
        APP_ASSERT_VALID_REF(displayObj->display_config1);

        vxSetReferenceName((vx_reference)displayObj->display_config1, "InputDisplayConfiguration");

        displayObj->display_params1.opMode=TIVX_KERNEL_DISPLAY_ZERO_BUFFER_COPY_MODE;
        displayObj->display_params1.pipeId = 0;
        displayObj->display_params1.outWidth = INPUT_DISPLAY_WIDTH_DISPLAY;
        displayObj->display_params1.outHeight = INPUT_DISPLAY_HEIGHT_DISPLAY;
        displayObj->display_params1.posX = 0;
        displayObj->display_params1.posY = 0;

        status = vxCopyUserDataObject(displayObj->display_config1, 0, sizeof(tivx_display_params_t), &displayObj->display_params1, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
        APP_ASSERT(status==VX_SUCCESS);
    }
  return status;
}


void app_deinit_display1(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (displayObj->display_option == 1))
    {
        vxReleaseUserDataObject(&displayObj->display_config1);
    }
}

void app_delete_display1(DisplayObj *displayObj)
{

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (displayObj->display_option == 1))
    {
        vxReleaseNode(&displayObj->node1);
    }

}

vx_status app_create_graph_display1(vx_graph graph, DisplayObj *displayObj, vx_image disp_image)
{
    vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (displayObj->display_option == 1))
    {
        displayObj->node1 = tivxDisplayNode(
            graph,
            displayObj->display_config1,
            disp_image);
        status = vxGetStatus((vx_reference)displayObj->node1);
        if (VX_SUCCESS != status)
        {
            printf("# ERROR: Display is not enabled on this platform, please disable it in config \n");
        }
        APP_ASSERT(VX_SUCCESS == status);
        status = vxSetNodeTarget(displayObj->node1, VX_TARGET_STRING, TIVX_TARGET_DISPLAY1);
        APP_ASSERT(status==VX_SUCCESS);
        vxSetReferenceName((vx_reference)displayObj->node1, "Output Display");
    }

    return status;
}

inline vx_image vxCvMatToVxImage(const vx_context context, const cv::Mat &cv_image)
{
    vx_df_image vx_image_type;
    switch (cv_image.type())
    {
    case CV_8UC1:
        vx_image_type = VX_DF_IMAGE_U8;
        break;
    case CV_8UC3:
        vx_image_type = VX_DF_IMAGE_RGB;
        break;
    default:
        return NULL;
    }

    int width = cv_image.cols;
    int height = cv_image.rows;


    vx_image image = vxCreateImage(context, width, height, vx_image_type);

    vx_rectangle_t patch;
    patch.start_x = 0;
    patch.start_y = 0;
    patch.end_x = width;
    patch.end_y = height;

    vx_map_id map_id;
    vx_imagepatch_addressing_t addr;
    unsigned char *ptr;
    vx_status status = vxMapImagePatch(image, &patch, 0, &map_id, &addr, (void **)&ptr, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X);
    if (status != VX_SUCCESS)
    {
        return NULL;
    }

    if (addr.stride_x != 1 && addr.stride_x != 3)
    {
        return NULL;
    }

    for (int y = 0; y < height; y++)
    {
        unsigned char *ptr_y = ptr + y * addr.stride_y;
        memcpy(ptr_y, cv_image.ptr(y), addr.stride_y);
    }

    status = vxUnmapImagePatch(image, map_id);
    if (status != VX_SUCCESS)
    {
        return NULL;
    }

    return image;
}


int main()
{
    // read image from file 
    std::string imgPath1 = "test.jpg";
    cv::Mat cvimage1 = cv::imread(imgPath1);
    cv::cvtColor(cvimage1, cvimage1, cv::COLOR_BGR2RGB);
    // resize image
    cv::resize(cvimage1, cvimage1, cv::Size(1920/6, 1080/6));
    if (cvimage1.empty()) {
        throw std::runtime_error("Failed to read image from file1");
    }

    // read image from file 
    std::string imgPath2 = "test2.jpg";
    cv::Mat cvimage2 = cv::imread(imgPath2);
    cv::cvtColor(cvimage2, cvimage2, cv::COLOR_BGR2RGB);
    // resize image
    cv::resize(cvimage2, cvimage2, cv::Size(1920/6, 1080/6));
    if (cvimage2.empty()) {
        throw std::runtime_error("Failed to read image from file2");
    }

    appInit();
    AppObj *obj = &gAppObj;
    vx_status status = VX_SUCCESS;
    obj->displayObj.display_option = 1;
    set_img_mosaic_params(&obj->imgMosaicObj);
    status = app_init(obj);

    vx_image image1 = vxCvMatToVxImage(obj->context, cvimage1);
    vx_image image2 = vxCvMatToVxImage(obj->context, cvimage2);
    obj->display_image1 = image1;
    obj->display_image2 = image2;
    status = app_create_graph(obj);
    status = app_run_graph(obj);
    vxReleaseImage(&obj->display_image1);    
    vxReleaseImage(&obj->display_image2);   

    app_delete_display1(&obj->displayObj);
    app_delete_img_mosaic(&obj->imgMosaicObj);
    vxReleaseGraph(&obj->graph);
    app_deinit_display1(&obj->displayObj);
    app_deinit_img_mosaic(&obj->imgMosaicObj, 4);
    if (1 == obj->displayObj.display_option)
    {
        appGrpxDeInit();
    }
    tivxVideoIOUnLoadKernels(obj->context);
    tivxHwaUnLoadKernels(obj->context);
    vxReleaseContext(&obj->context);

}

m2m display:

#include <iostream>
#include <stdexcept>

//OpenVX includes
#include <VX/vx.h>

extern "C" 
{
#include <utils/app_init/include/app_init.h>
#include <utils/grpx/include/app_grpx.h>
#include "display_common.h"
#include <TI/video_io_display.h>
#include <TI/video_io_display_m2m.h>
#include <TI/hwa_kernels.h>
#include <TI/video_io_kernels.h>
#include <TI/tivx.h>
#include <TI/tivx_task.h>
}
#include "test_vximage.h"

//OpenCV includes
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"



vx_status app_init_display1(vx_context context, DisplayObj *displayObj, char *objName);
vx_status app_init_display2(vx_context context, DisplayObj *displayObj, char *objName);
vx_status app_init_display3(vx_context context, DisplayObj *displayObj, char *objName);
vx_status app_init_display4(vx_context context, DisplayObj *displayObj, char *objName);

void app_deinit_display1(DisplayObj *displayObj);
void app_deinit_display2(DisplayObj *displayObj);
void app_deinit_display3(DisplayObj *displayObj);
void app_deinit_display4(DisplayObj *displayObj);

void app_delete_display1(DisplayObj *displayObj);
void app_delete_display2(DisplayObj *displayObj);
void app_delete_display3(DisplayObj *displayObj);
void app_delete_display4(DisplayObj *displayObj);

vx_status app_create_graph_display1(vx_graph graph, DisplayObj *displayObj, vx_image disp_image);
vx_status app_create_graph_display2(vx_graph graph, DisplayObj *displayObj, vx_image disp_image);
vx_status app_create_graph_display3(vx_graph graph, DisplayObj *displayObj, vx_image disp_image);
vx_status app_create_graph_display4(vx_graph graph, DisplayObj *displayObj, vx_image disp_image);

vx_status app_run_graph(AppObj *obj);
void app_draw_graphics(Draw2D_Handle *handle, Draw2D_BufInfo *draw2dBufInfo, uint32_t update_type);
vx_status app_create_graph(AppObj *obj);
inline vx_image vxCvMatToVxImage(const vx_context context, const cv::Mat &cv_image);


void app_draw_graphics(Draw2D_Handle *handle, Draw2D_BufInfo *draw2dBufInfo, uint32_t update_type)
{
  AppObj *obj = &gAppObj;

  appGrpxDrawDefault(handle, draw2dBufInfo, update_type);

  if(update_type == 0)
  {
    Draw2D_FontPrm sHeading;
    Draw2D_FontPrm sAlgo1;
    Draw2D_FontPrm sAlgo2;
    Draw2D_FontPrm sAlgo3;
    Draw2D_FontPrm sAlgo4;
    Draw2D_FontPrm sAlgo5;
    Draw2D_FontPrm sAlgo6;

    Draw2D_BmpPrm bmp;

    sHeading.fontIdx = 5;
    Draw2D_drawString(handle, 620, 40, "Image Display Test", &sHeading);

    // sAlgo1.fontIdx = 1;
    // Draw2D_drawString(handle, INPUT_DISPLAY_WIDTH/2 - 120 , (DISPLAY_HEIGHT + INPUT_DISPLAY_HEIGHT)/2 - 75, "Display 1", &sAlgo1);
    // sAlgo1.fontIdx = 1;
    // Draw2D_drawString(handle, DISPLAY_WIDTH - (INPUT_DISPLAY_WIDTH2/2 + 120) , (DISPLAY_HEIGHT + INPUT_DISPLAY_HEIGHT2)/2 - 75, "Display 2", &sAlgo1);
  }

  return;
}


vx_status app_init(AppObj *obj)
{
    app_grpx_init_prms_t grpx_prms;
    vx_status status = VX_SUCCESS;

    obj->context = vxCreateContext();
    if(status == VX_SUCCESS)
    {
        status = vxGetStatus((vx_reference) obj->context);
    }

    tivxHwaLoadKernels(obj->context);
    tivxVideoIOLoadKernels(obj->context);

    /* Initialize modules */
    if(status == VX_SUCCESS)
    {
        status = app_init_display1( obj->context, &obj->displayObj , "display1Obj");
    }
    if(status == VX_SUCCESS)
    {
        status = app_init_display2( obj->context, &obj->displayObj , "display2Obj");
    }
    if(status == VX_SUCCESS)
    {
        status = app_init_display3( obj->context, &obj->displayObj , "display3Obj");
    }
    if(status == VX_SUCCESS)
    {
        status = app_init_display4( obj->context, &obj->displayObj , "display4Obj");
    }
    if (1 == obj->displayObj.display_option)
    {
        appGrpxInitParamsInit(&grpx_prms, obj->context);
        grpx_prms.draw_callback = app_draw_graphics;
        appGrpxInit(&grpx_prms);
    }
    return status;
}

vx_status app_create_graph(AppObj *obj)
{
    vx_status status = VX_SUCCESS;

    obj->graph = vxCreateGraph(obj->context);

    status = vxGetStatus((vx_reference) obj->graph);

    if (status == VX_SUCCESS)
    {
        status = app_create_graph_display1(obj->graph, &obj->displayObj, obj->display_image1);
    }
    if(status == VX_SUCCESS)
    {
        status = app_create_graph_display2(obj->graph, &obj->displayObj, obj->display_image2);
    }
    if (status == VX_SUCCESS)
    {
        status = app_create_graph_display3(obj->graph, &obj->displayObj, obj->display_image1);
    }
    if(status == VX_SUCCESS)
    {
        status = app_create_graph_display4(obj->graph, &obj->displayObj, obj->display_image2);
    }
    if(status == VX_SUCCESS)
    {
        status = vxVerifyGraph(obj->graph);
    }

    return status;
}

vx_status app_run_graph(AppObj *obj)
{
    uint32_t curFileNum;
    int32_t outputFileNum;
    uint32_t iterations = 1;
    vx_status status = VX_SUCCESS;

    uint32_t num_buf;
    num_buf = MAX_NUM_BUF;

    int32_t pipeline = -num_buf;
    int32_t enqueueCnt = 0;

    vx_int32 img_array_idx = -1;

    vx_uint32 test_counter = 0;
    if(status == VX_SUCCESS)
    {
        if(status == VX_SUCCESS)
        {
            for(int i = 0; i < 200; i++)
            {
                status = vxProcessGraph(obj->graph);
                std::cout << "Processed iterations: " << i << std::endl;
            }
        }
    }

    printf(" Ran %d times successfully!\n", 100);
    return status;
}

vx_status app_init_display1(vx_context context, DisplayObj *displayObj, char *objName)
{
  vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (1 == displayObj->display_option))
    {
        memset(&displayObj->display_params1, 0, sizeof(tivx_display_params_t));
        displayObj->display_config1 = vxCreateUserDataObject(context, "tivx_display_params_t",
             sizeof(tivx_display_params_t), NULL);
        APP_ASSERT_VALID_REF(displayObj->display_config1);

        vxSetReferenceName((vx_reference)displayObj->display_config1, "InputDisplayConfiguration");

        displayObj->display_params1.opMode=TIVX_KERNEL_DISPLAY_ZERO_BUFFER_COPY_MODE;
        displayObj->display_params1.pipeId = 1;
        displayObj->display_params1.outWidth = INPUT_DISPLAY_WIDTH;
        displayObj->display_params1.outHeight = INPUT_DISPLAY_HEIGHT;
        displayObj->display_params1.posX = 0;
        displayObj->display_params1.posY = 0;

        status = vxCopyUserDataObject(displayObj->display_config1, 0, sizeof(tivx_display_params_t), &displayObj->display_params1, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
        APP_ASSERT(status==VX_SUCCESS);
    }
  return status;
}

vx_status app_init_display2(vx_context context, DisplayObj *displayObj, char *objName)
{
  vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY2) && (1 == displayObj->display_option))
    {
        memset(&displayObj->display_params2, 0, sizeof(tivx_display_params_t));
        displayObj->display_config2 = vxCreateUserDataObject(context, "tivx_display_params_t",
             sizeof(tivx_display_params_t), NULL);
        APP_ASSERT_VALID_REF(displayObj->display_config2);

        vxSetReferenceName((vx_reference)displayObj->display_config2, "OutputDisplayConfiguration");

        displayObj->display_params2.opMode=TIVX_KERNEL_DISPLAY_ZERO_BUFFER_COPY_MODE;
        displayObj->display_params2.pipeId = 0;
        displayObj->display_params2.outWidth = INPUT_DISPLAY_WIDTH;
        displayObj->display_params2.outHeight = INPUT_DISPLAY_HEIGHT;
        displayObj->display_params2.posX = (DISPLAY_WIDTH-INPUT_DISPLAY_WIDTH);
        displayObj->display_params2.posY = 0;

        status = vxCopyUserDataObject(displayObj->display_config2, 0, sizeof(tivx_display_params_t), &displayObj->display_params2, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
        APP_ASSERT(status==VX_SUCCESS);
    }

  return status;
}

vx_status app_init_display3(vx_context context, DisplayObj *displayObj, char *objName)
{
  vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M1) && (1 == displayObj->display_option))
    {
        memset(&displayObj->display_params3, 0, sizeof(tivx_display_m2m_params_t));
        // new
        tivx_display_m2m_params_init(&displayObj->display_params3);
        displayObj->display_config3 = vxCreateUserDataObject(context,
                                        "tivx_display_m2m_params_t",
                                        sizeof(tivx_display_m2m_params_t),
                                        &displayObj->display_params3),

        vxSetReferenceName((vx_reference)displayObj->display_config3, "OutputDisplayConfiguration");
        displayObj->display_params3.instId = 0U;
        /* Only one pipeline is supported */
        displayObj->display_params3.numPipe    = 1U;
        displayObj->display_params3.pipeId[0U] = 3U;
        displayObj->display_params3.overlayId  = 3U;
         
        // status = vxCopyUserDataObject(displayObj->display_config3, 0, sizeof(tivx_display_m2m_params_t), &displayObj->display_params3, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
        APP_ASSERT(status==VX_SUCCESS);
    }

  return status;
}

vx_status app_init_display4(vx_context context, DisplayObj *displayObj, char *objName)
{
  vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M1) && (1 == displayObj->display_option))
    {
        memset(&displayObj->display_params4, 0, sizeof(tivx_display_m2m_params_t));
        // new
        tivx_display_m2m_params_init(&displayObj->display_params4);
        displayObj->display_config4 = vxCreateUserDataObject(context,
                                        "tivx_display_m2m_params_t",
                                        sizeof(tivx_display_m2m_params_t),
                                        &displayObj->display_params4),

        vxSetReferenceName((vx_reference)displayObj->display_config4, "OutputDisplayConfiguration");
        displayObj->display_params4.instId = 0U;
        /* Only one pipeline is supported */
        displayObj->display_params4.numPipe    = 1U;
        displayObj->display_params4.pipeId[0U] = 3U;
        displayObj->display_params4.overlayId  = 3U;
         
        // status = vxCopyUserDataObject(displayObj->display_config4, 0, sizeof(tivx_display_m2m_params_t), &displayObj->display_params4, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
        APP_ASSERT(status==VX_SUCCESS);
    }

  return status;
}



void app_deinit_display1(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (displayObj->display_option == 1))
    {
        vxReleaseUserDataObject(&displayObj->display_config1);
    }
}

void app_deinit_display2(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY2) && (displayObj->display_option == 1))
    {
        vxReleaseUserDataObject(&displayObj->display_config2);
    }

}

void app_deinit_display3(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M2) && (displayObj->display_option == 1))
    {
        vxReleaseUserDataObject(&displayObj->display_config3);
    }


}

void app_deinit_display4(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M1) && (displayObj->display_option == 1))
    {
        vxReleaseUserDataObject(&displayObj->display_config4);
    }

}

void app_delete_display1(DisplayObj *displayObj)
{

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (displayObj->display_option == 1))
    {
        vxReleaseNode(&displayObj->node1);
    }

}
void app_delete_display2(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY2) && (displayObj->display_option == 1))
    {
        vxReleaseNode(&displayObj->node2);
    }
}

void app_delete_display3(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M1) && (displayObj->display_option == 1))
    {
        vxReleaseNode(&displayObj->node3);
    }
}

void app_delete_display4(DisplayObj *displayObj)
{
    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M2) && (displayObj->display_option == 1))
    {
        vxReleaseNode(&displayObj->node4);
    }
}

vx_status app_create_graph_display1(vx_graph graph, DisplayObj *displayObj, vx_image disp_image)
{
    vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY1) && (displayObj->display_option == 1))
    {
        displayObj->node1 = tivxDisplayNode(
            graph,
            displayObj->display_config1,
            disp_image);
        status = vxGetStatus((vx_reference)displayObj->node1);
        if (VX_SUCCESS != status)
        {
            printf("# ERROR: Display is not enabled on this platform, please disable it in config \n");
        }
        APP_ASSERT(VX_SUCCESS == status);
        status = vxSetNodeTarget(displayObj->node1, VX_TARGET_STRING, TIVX_TARGET_DISPLAY1);
        APP_ASSERT(status==VX_SUCCESS);
        vxSetReferenceName((vx_reference)displayObj->node1, "Output Display");
    }

    return status;
}

vx_status app_create_graph_display2(vx_graph graph, DisplayObj *displayObj, vx_image disp_image)
{
    vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY2) && (displayObj->display_option == 1))
    {
      displayObj->node2  = tivxDisplayNode(
            graph,
            displayObj->display_config2,
            disp_image);
        status = vxGetStatus((vx_reference)displayObj->node2);
        if (VX_SUCCESS != status)
        {
            printf("# ERROR: Display is not enabled on this platform, please disable it in config \n");
        }
        APP_ASSERT(VX_SUCCESS == status);
        status = vxSetNodeTarget(displayObj->node2, VX_TARGET_STRING, TIVX_TARGET_DISPLAY2);
        APP_ASSERT(status==VX_SUCCESS);
        vxSetReferenceName((vx_reference)displayObj->node2, "Input Display");
    }
    return status;
}

vx_status app_create_graph_display3(vx_graph graph, DisplayObj *displayObj, vx_image disp_image)
{
    vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY_M2M1) && (displayObj->display_option == 1))
    {
      displayObj->node3  = tivxDisplayM2MNode(
            graph,
            displayObj->display_config3,
            disp_image,
            disp_image);
        status = vxGetStatus((vx_reference)displayObj->node3);
        if (VX_SUCCESS != status)
        {
            printf("# ERROR: Display is not enabled on this platform, please disable it in config \n");
        }
        APP_ASSERT(VX_SUCCESS == status);
        status = vxSetNodeTarget(displayObj->node3, VX_TARGET_STRING, TIVX_TARGET_DISPLAY_M2M1);
        APP_ASSERT(status==VX_SUCCESS);
        vxSetReferenceName((vx_reference)displayObj->node3, "Input Display");
    }
    return status;
}

vx_status app_create_graph_display4(vx_graph graph, DisplayObj *displayObj, vx_image disp_image)
{
    vx_status status = VX_SUCCESS;

    if (vx_true_e == tivxIsTargetEnabled(TIVX_TARGET_DISPLAY2) && (displayObj->display_option == 1))
    {
      displayObj->node4  = tivxDisplayM2MNode(
            graph,
            displayObj->display_config2,
            disp_image,
            disp_image);
        status = vxGetStatus((vx_reference)displayObj->node4);
        if (VX_SUCCESS != status)
        {
            printf("# ERROR: Display is not enabled on this platform, please disable it in config \n");
        }
        APP_ASSERT(VX_SUCCESS == status);
        status = vxSetNodeTarget(displayObj->node4, VX_TARGET_STRING, TIVX_TARGET_DISPLAY_M2M2);
        APP_ASSERT(status==VX_SUCCESS);
        vxSetReferenceName((vx_reference)displayObj->node4, "Input Display");
    }
    return status;
}

inline vx_image vxCvMatToVxImage(const vx_context context, const cv::Mat &cv_image)
{
    vx_df_image vx_image_type;
    switch (cv_image.type())
    {
    case CV_8UC1:
        vx_image_type = VX_DF_IMAGE_U8;
        break;
    case CV_8UC3:
        vx_image_type = VX_DF_IMAGE_RGB;
        break;
    default:
        return NULL;
    }

    int width = cv_image.cols;
    int height = cv_image.rows;


    vx_image image = vxCreateImage(context, width, height, vx_image_type);

    vx_rectangle_t patch;
    patch.start_x = 0;
    patch.start_y = 0;
    patch.end_x = width;
    patch.end_y = height;

    vx_map_id map_id;
    vx_imagepatch_addressing_t addr;
    unsigned char *ptr;
    vx_status status = vxMapImagePatch(image, &patch, 0, &map_id, &addr, (void **)&ptr, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X);
    if (status != VX_SUCCESS)
    {
        return NULL;
    }

    if (addr.stride_x != 1 && addr.stride_x != 3)
    {
        return NULL;
    }

    for (int y = 0; y < height; y++)
    {
        unsigned char *ptr_y = ptr + y * addr.stride_y;
        memcpy(ptr_y, cv_image.ptr(y), addr.stride_y);
    }

    status = vxUnmapImagePatch(image, map_id);
    if (status != VX_SUCCESS)
    {
        return NULL;
    }

    return image;
}


int main()
{
    // read image from file 
    std::string imgPath1 = "test.jpg";
    cv::Mat cvimage1 = cv::imread(imgPath1);
    cv::cvtColor(cvimage1, cvimage1, cv::COLOR_BGR2RGB);
    // resize image
    cv::resize(cvimage1, cvimage1, cv::Size(1920, 1080));
    if (cvimage1.empty()) {
        throw std::runtime_error("Failed to read image from file1");
    }

    // read image from file 
    std::string imgPath2 = "test2.jpg";
    cv::Mat cvimage2 = cv::imread(imgPath2);
    cv::cvtColor(cvimage2, cvimage2, cv::COLOR_BGR2RGB);
    // resize image
    cv::resize(cvimage2, cvimage2, cv::Size(1920, 1080));
    if (cvimage2.empty()) {
        throw std::runtime_error("Failed to read image from file2");
    }

    appInit();
    AppObj *obj = &gAppObj;
    vx_status status = VX_SUCCESS;
    obj->displayObj.display_option = 1;
    status = app_init(obj);

    vx_image image1 = vxCvMatToVxImage(obj->context, cvimage1);
    vx_image image2 = vxCvMatToVxImage(obj->context, cvimage2);
    obj->display_image1 = image1;
    obj->display_image2 = image2;
    status = app_create_graph(obj);
    status = app_run_graph(obj);
    vxReleaseImage(&obj->display_image1);    
    vxReleaseImage(&obj->display_image2);   

    app_delete_display1(&obj->displayObj);
    app_delete_display2(&obj->displayObj);
    app_delete_display3(&obj->displayObj);
    app_delete_display4(&obj->displayObj);
    vxReleaseGraph(&obj->graph);
    app_deinit_display1(&obj->displayObj);
    app_deinit_display2(&obj->displayObj);
    app_deinit_display3(&obj->displayObj);
    app_deinit_display4(&obj->displayObj);
    if (1 == obj->displayObj.display_option)
    {
        appGrpxDeInit();
    }
    tivxVideoIOUnLoadKernels(obj->context);
    tivxHwaUnLoadKernels(obj->context);
    vxReleaseContext(&obj->context);

}