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.

TDA4VM: mosaic module cause image blurring

Part Number: TDA4VM

Hi TIers,

      Recently, we use mosaic module to mosaic multiple images which are from 10 cameras, when we unplug some of the cameras, the rest of the images will blur, as shown bellow:

Connect 10 cameras at the same time, none of them are unplugged:

Connect 8 cameras at the same time, and 2 cameras are unplugged:

here is mosaic init:

app_init_img_mosaic(obj->context, &obj->mosaicObj, "img_mosaic_obj", 1);
vx_image input_img = vxCreateImage(obj->context, 960, 540, VX_DF_IMAGE_NV12);
obj->mosaicObj.input_arr[0] = vxCreateObjectArray(obj->context, (vx_reference)input_img, 3);
vxReleaseImage(&input_img);

and here is mosaic task:

#include <utils/perf_stats/include/app_perf_stats.h>
#include <utils/console_io/include/app_get.h>
#include <utils/grpx/include/app_grpx.h>
#include <VX/vx_khr_pipelining.h>

#include "app_common.h"
#include "app_socket_module.h"
#include "app_decode_module.h"
#include "app_img_mosaic_module.h"

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

typedef struct {

    SocketObj       socketObj_ar0233_b;
    SocketObj       socketObj_ar0147;
    
    SocketObj       socketObj_ar0143;
    SocketObj       socketObj_ar0233_a;
    
    DecodeObj       decodeObj_ar0233_b;
    DecodeObj       decodeObj_ar0147;

    ImgMosaicObj    mosaicObj;

    tivx_event      event_ar0233_b;
    tivx_event      event_ar0147;

    // vx_graph        graph_decode_ar0233_b;
    // vx_graph        graph_decode_ar0147;

    vx_char output_file_path[APP_MAX_FILE_PATH];

    /* OpenVX references */
    vx_context context;
    // vx_graph   graph;

    vx_int32 en_out_img_write;
    vx_int32 en_out_bitstream_write;
    vx_int32 test_mode;

    vx_uint32 is_interactive;

    vx_uint32 num_frames_to_run;

    vx_uint32 num_frames_to_write;
    vx_uint32 num_frames_to_skip;

    // tivx_task task;
    // vx_uint32 stop_task;
    // vx_uint32 stop_task_done;

    app_perf_point_t total_perf;
    app_perf_point_t fileio_perf;
    app_perf_point_t draw_perf;

    int32_t enable_ldc;
    int32_t enable_viss;
    int32_t enable_aewb;
    int32_t enable_mosaic;
    int32_t enable_encode;
    int32_t enable_display;

    int32_t enable_socket;

    int32_t pipeline;

    int32_t enqueueCnt;
    int32_t dequeueCnt;

    int32_t write_file;

    tivx_task   fpsFifo_task;

    int fpsFifo_fd;
    char fpsFifo_buf[1024];
    vx_uint32 stop_task_fpsFifo;
    vx_uint32 stop_task_done_fpsFifo;
    App_FifoFps fpsFifoMsg;

    pthread_mutex_t decode_0147_mutex;    // canrx数据互斥锁
    pthread_mutex_t socket_0233a_mutex;    // canrx数据互斥锁
    pthread_mutex_t socket_0143_mutex;    // canrx数据互斥锁

    pthread_mutex_t image_recv_mutex;

    tivx_event      event_print_fps;
} AppObj;


static vx_status app_init(AppObj *obj);
static vx_status app_run_graph_interactive(AppObj *obj);
static vx_status app_create_graph(AppObj *obj);
static void app_default_param_set(AppObj *obj);
static void app_pipeline_params_defaults(AppObj *obj);
static void app_parse_cmd_line_args(AppObj *obj, vx_int32 argc, vx_char *argv[]);
static void app_delete_graph(AppObj *obj);
static void app_run_task_delete(AppObj *obj);
static void app_deinit(AppObj *obj);

AppObj gAppObj;


vx_int32 app_yh_socket_recv_main(vx_int32 argc, vx_char* argv[])
{
    vx_status status = VX_SUCCESS;

    AppObj *obj = &gAppObj;

    /*Optional parameter setting*/
    app_default_param_set(obj);

    /*Config parameter reading*/
    app_parse_cmd_line_args(obj, argc, argv);

    // /*Update of parameters are config file read*/
    // app_update_param_set(obj);

    if (status == VX_SUCCESS)
    {
        status = app_init(obj);
    }
    if(status == VX_SUCCESS)
    {
        APP_PRINTF("App Init Done! \n");

        status = app_create_graph(obj);

        if(status == VX_SUCCESS)
        {
            APP_PRINTF("App Create Graph Done! \n");

            // status = app_verify_graph(obj);

            if(status == VX_SUCCESS)
            {
                APP_PRINTF("App Verify Graph Done! \n");

                if (status == VX_SUCCESS)
                {
                    APP_PRINTF("App Send Error Frame Done! \n");
                    // if(obj->is_interactive)
                    // {
                        status = app_run_graph_interactive(obj);
                    // }
                    // else
                    // {
                    //     // status = app_run_graph(obj);
                    // }
                }
            }
        }

        APP_PRINTF("App Run Graph Done! \n");
    }

    app_delete_graph(obj);

    APP_PRINTF("App Delete Graph Done! \n");

    app_deinit(obj);

    APP_PRINTF("App De-init Done! \n");

    return status;
}

static void app_pipeline_params_defaults(AppObj *obj)
{
    obj->pipeline       = -APP_BUFFER_Q_DEPTH + 1;
    obj->enqueueCnt     = 0;
    obj->dequeueCnt     = 0;
}

static void app_default_param_set(AppObj *obj)
{
    app_pipeline_params_defaults(obj);

    obj->is_interactive = 1;
    obj->test_mode = 0;
    obj->write_file = 0;
}

static void app_parse_cfg_file(AppObj *obj, vx_char *cfg_file_name)
{
    FILE *fp = fopen(cfg_file_name, "r");
    vx_char line_str[1024];
    vx_char *token;

    if(fp==NULL)
    {
        printf("# ERROR: Unable to open config file [%s]\n", cfg_file_name);
        exit(0);
    }

    while(fgets(line_str, sizeof(line_str), fp)!=NULL)
    {
        vx_char s[]=" \t";

        if (strchr(line_str, '#'))
        {
            continue;
        }

        /* get the first token */
        token = strtok(line_str, s);
        if(token != NULL)
        {
            if(strcmp(token, "is_interactive")==0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token)-1]=0;
                    obj->is_interactive = atoi(token);
                    if(obj->is_interactive > 1)
                    {
                        obj->is_interactive = 1;
                    }
                }
            }
            else
            if(strcmp(token, "enable_socket")==0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    obj->enable_socket = atoi(token);
                    if(obj->enable_socket > 1)
                        obj->enable_socket = 1;
                }
            }
            else
            if (strcmp(token, "udp_port_ar0233") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    obj->socketObj_ar0233_b.port = atoi(token);

                }
            }
            else
            if (strcmp(token, "udp_port_ar0147") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    obj->socketObj_ar0147.port = atoi(token);

                }
            }
            else
            if (strcmp(token, "udp_ip") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    strcpy(obj->socketObj_ar0147.udp_ip, token);
                    strcpy(obj->socketObj_ar0233_b.udp_ip, token);
                    printf("udp_ip is %s! \n", obj->socketObj_ar0233_b.udp_ip);
                }
            }
            else
            if (strcmp(token, "inWidth_ar0233") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    obj->decodeObj_ar0233_b.inWidth = atoi(token);

                }
            }
            else
            if (strcmp(token, "inWidth_ar0147") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    obj->decodeObj_ar0147.inWidth = atoi(token);

                }
            }
            else
            if (strcmp(token, "inHeight_ar0233") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    obj->decodeObj_ar0233_b.inHeight = atoi(token);

                }
            }
            else
            if (strcmp(token, "inHeight_ar0147") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    obj->decodeObj_ar0147.inHeight = atoi(token);

                }
            }
            else
            if (strcmp(token, "path_name_ar0233") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    strcpy(obj->socketObj_ar0233_a.path_name, token);
                    printf("udp_ip is %s! \n", obj->socketObj_ar0233_a.path_name);
                }
            }
            else
            if (strcmp(token, "path_name_ar0143") == 0)
            {
                token = strtok(NULL, s);
                if(token != NULL)
                {
                    token[strlen(token) - 1] = 0;
                    strcpy(obj->socketObj_ar0143.path_name, token);
                    printf("udp_ip is %s! \n", obj->socketObj_ar0143.path_name);
                }
            }

        }
    }

    fclose(fp);

}

static void app_show_usage(vx_int32 argc, vx_char* argv[])
{
    printf("\n");
    printf(" app_yh_socket_recv Demo - (c) Yihang 2020\n");
    printf(" ========================================================\n");
    printf("\n");
    printf(" Usage,\n");
    printf("  %s --cfg <config file>\n", argv[0]);
    printf("\n");
}

static void app_parse_cmd_line_args(AppObj *obj, vx_int32 argc, vx_char *argv[])
{
    vx_int32 i;
    // vx_bool set_test_mode = vx_false_e;


    if(argc==1)
    {
        app_show_usage(argc, argv);
        exit(0);
    }

    for(i=0; i<argc; i++)
    {
        if(strcmp(argv[i], "--cfg")==0)
        {
            i++;
            if(i>=argc)
            {
                app_show_usage(argc, argv);
            }
            app_parse_cfg_file(obj, argv[i]);
        }
        else
        if(strcmp(argv[i], "--help")==0)
        {
            app_show_usage(argc, argv);
            exit(0);
        }
    }
    return;
}

static vx_int32 calc_grid_size(vx_uint32 ch)
{
    if(0==ch)
    {
        return -1;
    }
    else if(1==ch)
    {
        return 1;
    }
    else if(4>=ch)
    {
        return 2;
    }
    else if(9>=ch)
    {
        return 3;
    }
    else if(16>=ch)
    {
        return 4;
    }else
    {
        return -1;
    }
}


static void set_img_mosaic_params(ImgMosaicObj *imgMosaicObj, vx_uint32 in_width, vx_uint32 in_height, vx_int32 numCh)
{
    vx_int32 idx, ch;
    vx_int32 grid_size = calc_grid_size(numCh);

    imgMosaicObj->out_width    = DISPLAY_WIDTH;
    imgMosaicObj->out_height   = DISPLAY_HEIGHT;
    imgMosaicObj->num_inputs   = 1;

    idx = 0;

    tivxImgMosaicParamsSetDefaults(&imgMosaicObj->params);

    for(ch = 0; ch < numCh; ch++)
    {
        vx_int32 winX = ch%grid_size;
        vx_int32 winY = ch/grid_size;

        imgMosaicObj->params.windows[idx].startX  = (winX * (in_width/grid_size));
        imgMosaicObj->params.windows[idx].startY  = (winY * (in_height/grid_size));
        imgMosaicObj->params.windows[idx].width   = in_width/grid_size;
        imgMosaicObj->params.windows[idx].height  = in_height/grid_size;
        imgMosaicObj->params.windows[idx].input_select   = 0;
        imgMosaicObj->params.windows[idx].channel_select = ch;
        idx++;
    }

    imgMosaicObj->params.num_windows  = idx;

    /* Number of time to clear the output buffer before it gets reused */
    imgMosaicObj->params.clear_count  = APP_BUFFER_Q_DEPTH;
    imgMosaicObj->params.enable_overlay = 0;
}

static void app_update_param_set(AppObj *obj)
{

    vx_uint16 resized_width, resized_height;
    appIssGetResizeParams(960, 540, 1920, 1080, &resized_width, &resized_height);

    set_img_mosaic_params(&obj->mosaicObj, resized_width, resized_height, 3);

}


static uint32_t timer_cnt = 0;

void app_timer_fxn(int m)
{
    AppObj *obj = &gAppObj;  

    timer_cnt++;

    obj->socketObj_ar0233_b.cnt_fps++;
    obj->socketObj_ar0147.cnt_fps++;
    obj->socketObj_ar0143.cnt_fps++;
    obj->socketObj_ar0233_a.cnt_fps++;

    if(obj->socketObj_ar0233_b.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND)
    {
        obj->socketObj_ar0233_b.fps = 0;
        obj->socketObj_ar0233_b.cam_error_flag[0] = 1;
        obj->socketObj_ar0233_b.cam_error_flag[1] = 1;
        obj->socketObj_ar0233_b.cam_error_flag[2] = 1;
        obj->socketObj_ar0233_b.cam_error_flag[3] = 1;
        obj->socketObj_ar0233_b.cnt_fps = 0;
        VX_PRINT(VX_ZONE_ERROR, "ar0233_b.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND err\r\n");
    }

    if(obj->socketObj_ar0147.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND)
    {
        obj->socketObj_ar0147.fps = 0;
        obj->socketObj_ar0147.cam_error_flag[0] = 1;
        obj->socketObj_ar0147.cam_error_flag[1] = 1;
        obj->socketObj_ar0147.cam_error_flag[2] = 1;
        obj->socketObj_ar0147.cam_error_flag[3] = 1;
        obj->socketObj_ar0147.cnt_fps = 0;
        VX_PRINT(VX_ZONE_ERROR, "ar0147.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND err\r\n");
    }

    if(obj->socketObj_ar0143.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND)
    {
        obj->socketObj_ar0143.fps = 0;
        obj->socketObj_ar0143.cnt_fps = 0;
        obj->socketObj_ar0143.cam_error_flag[0] = 1;
        obj->socketObj_ar0143.cam_error_flag[1] = 1;
        obj->socketObj_ar0143.cam_error_flag[2] = 1;
        obj->socketObj_ar0143.cam_error_flag[3] = 1;
        VX_PRINT(VX_ZONE_ERROR, "ar0143.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND err\r\n");
    }

    if(obj->socketObj_ar0233_a.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND)
    {
        obj->socketObj_ar0233_a.fps = 0;
        obj->socketObj_ar0233_a.cnt_fps = 0;
        obj->socketObj_ar0233_a.cam_error_flag[0] = 1;
        obj->socketObj_ar0233_a.cam_error_flag[1] = 1;
        obj->socketObj_ar0233_a.cam_error_flag[2] = 1;
        obj->socketObj_ar0233_a.cam_error_flag[3] = 1;
        VX_PRINT(VX_ZONE_ERROR, "ar0233_a.cnt_fps > APP_SOCKET_CMD_FPS_TIMEOUT_CNT_SENCOND err\r\n");
    }

    if(timer_cnt >= 10)
    {
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_A fps is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_A]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0143 fps is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0143]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_B fps is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_B]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0147 fps is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0147]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0147 cam 0 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][0]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0147 cam 1 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][1]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0147 cam 2 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][2]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0147 cam 3 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][3]);

        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_A cam 0 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][0]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_A cam 1 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][1]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_A cam 2 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][2]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_A cam 3 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][3]);

        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_B cam 0 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][0]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_B cam 1 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][1]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_B cam 2 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][2]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0233_B cam 3 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][3]);

        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0143 cam 0 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][0]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0143 cam 1 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][1]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0143 cam 2 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][2]);
        VX_PRINT(VX_ZONE_INFO, "APP_CAM_NAME_0143 cam 3 error status is %d\r\n", obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][3]);
        timer_cnt = 0;
    }
  

}



static vx_status app_init(AppObj *obj)
{
    vx_status 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);
        tivxImagingLoadKernels(obj->context);
        tivxFileIOLoadKernels(obj->context);
        APP_PRINTF("Kernel loading done!\n");
    }

    status = tivxEventCreate(&obj->event_ar0147);
    if(VX_SUCCESS != status)
    {
        APP_PRINTF("event_dof_graph create failed\n");
        return status;
    }

    status = tivxEventCreate(&obj->event_ar0233_b);
    if(VX_SUCCESS != status)
    {
        APP_PRINTF("event_dof_graph create failed\n");
        return status;
    }

    status = tivxEventCreate(&obj->event_print_fps);
    if(VX_SUCCESS != status)
    {
        APP_PRINTF("event_dof_graph create failed\n");
        return status;
    }
    
    obj->mosaicObj.ptr_event_print_fps = &obj->event_print_fps;

    if (pthread_mutex_init(&obj->decode_0147_mutex, NULL) != 0){

        printf("Ddecode_0147_mutex CREATE ERROR!\n");
    }

    if (pthread_mutex_init(&obj->socket_0233a_mutex, NULL) != 0){

        printf("socket_0233a_mutex CREATE ERROR!\n");
    }

    if (pthread_mutex_init(&obj->socket_0143_mutex, NULL) != 0){

        printf("socket_0143_mutex CREATE ERROR!\n");
    }

    if (pthread_mutex_init(&obj->image_recv_mutex, NULL) != 0){

        printf("socket_0143_mutex CREATE ERROR!\n");
    }

    if (pthread_mutex_init(&obj->socketObj_ar0147.socket_image_mutex, NULL) != 0){

        printf("socket_0143_mutex CREATE ERROR!\n");
    }

    // 设置定时器,用于监测状态信号丢失

    /*connect the signal to Habdler fuction*/
    signal(SIGALRM, app_timer_fxn);

    // 设置定时器周期为1s
	struct itimerval itv;
    
    //设置定时器启动时间
	itv.it_value.tv_sec = 0;    //timer start after 3 seconds later
	itv.it_value.tv_usec = 1000;
 
    // 设置定时器周期
	itv.it_interval.tv_sec = 1;
	itv.it_interval.tv_usec = 0;
 
 	setitimer(ITIMER_REAL,&itv,NULL);


    APP_PRINTF("creat obj->mosaicObj.input_arr[0]\n");
    app_update_param_set(obj);
    obj->mosaicObj.ptr_decode_0147_mutex = &obj->decode_0147_mutex;
    obj->mosaicObj.ptr_socket_0143_mutex = &obj->socket_0143_mutex;
    obj->mosaicObj.ptr_socket_0233a_mutex = &obj->socket_0233a_mutex;
    obj->mosaicObj.ptr_socket_image_mutex = &obj->socketObj_ar0147.socket_image_mutex;

    app_init_img_mosaic(obj->context, &obj->mosaicObj, "img_mosaic_obj", 1);
    vx_image input_img = vxCreateImage(obj->context, 960, 540, VX_DF_IMAGE_NV12);
    obj->mosaicObj.input_arr[0] = vxCreateObjectArray(obj->context, (vx_reference)input_img, 3);
    vxReleaseImage(&input_img);

    

    obj->socketObj_ar0233_b.ptr_event = &obj->event_ar0233_b;
    obj->socketObj_ar0233_b.appSocketType = APP_SOCKET_MODULE_TYPE_INTER_SOC_SERVER;
    obj->socketObj_ar0233_b.ptr_decodeObj = &obj->decodeObj_ar0233_b;
    status = app_init_socket(obj->context, &obj->socketObj_ar0233_b);
    if(status != 0 )
    {
        printf("app_init_socket error\r\n");
    }
    APP_PRINTF("app_init_socket 0233 init done and return %d!\n", status);

    // obj->socketObj_ar0147.ptr_socket_mutex = 
    obj->socketObj_ar0147.video_in = vx_false_e;
    obj->socketObj_ar0147.ptr_event = &obj->event_ar0147;
    obj->socketObj_ar0147.appSocketType = APP_SOCKET_MODULE_TYPE_INTER_SOC_SERVER;
    obj->socketObj_ar0147.ptr_decodeObj = &obj->decodeObj_ar0147;

    obj->socketObj_ar0147.images = (vx_image)vxGetObjectArrayItem(obj->mosaicObj.input_arr[0], 2);
    status = app_init_socket(obj->context, &obj->socketObj_ar0147);
    if(status != 0 )
    {
        printf("app_init_socket error\r\n");
    }
    APP_PRINTF("app_init_socket 0147 init done and return %d!\n", status);

    // obj->socketObj_ar0143.ptr_event = &obj->event_ar0147;
    obj->socketObj_ar0143.images = (vx_image)vxGetObjectArrayItem(obj->mosaicObj.input_arr[0], 0);
    // obj->socketObj_ar0143.images = vxCreateImage(obj->context,
    //                                               960,
    //                                               540,
    //                                               VX_DF_IMAGE_NV12);
    obj->socketObj_ar0143.ptr_socket_mutex = &obj->socket_0143_mutex;
    obj->socketObj_ar0143.ptr_image_recv_mutex = &obj->image_recv_mutex;
    obj->socketObj_ar0143.video_in = vx_false_e;
    obj->socketObj_ar0143.appSocketType = APP_SOCKET_MODULE_TYPE_INTER_APP_SERVER;
    obj->socketObj_ar0143.port = 143;
    status = app_init_socket(obj->context, &obj->socketObj_ar0143);
    if(status != 0 )
    {
        printf("app_init_socket error\r\n");
    }
    APP_PRINTF("app_init_socket 0143 init done and return %d!\n", status);

    obj->socketObj_ar0233_a.ptr_socket_mutex = &obj->socket_0233a_mutex;
    obj->socketObj_ar0233_a.ptr_image_recv_mutex = &obj->image_recv_mutex;
    obj->socketObj_ar0233_a.video_in = vx_false_e;
    obj->socketObj_ar0233_a.port = 233;
    obj->socketObj_ar0233_a.images = (vx_image)vxGetObjectArrayItem(obj->mosaicObj.input_arr[0], 1);
    // obj->socketObj_ar0233_a.images = vxCreateImage(obj->context,
    //                                               960,
    //                                               540,
    //                                               VX_DF_IMAGE_NV12);
    obj->socketObj_ar0233_a.appSocketType = APP_SOCKET_MODULE_TYPE_INTER_APP_SERVER;
    status = app_init_socket(obj->context, &obj->socketObj_ar0233_a);
    if(status != 0 )
    {
        printf("app_init_socket error\r\n");
    }
    APP_PRINTF("app_init_socket0233_a init done and return %d!\n", status);

    obj->decodeObj_ar0233_b.output_image = vxCreateImage(obj->context, 960, 540, VX_DF_IMAGE_NV12);
    obj->decodeObj_ar0233_b.ptr_event = &obj->event_ar0233_b;
    // obj->decodeObj_ar0233_b.ptr_socketObj = &obj->socketObj_ar0233_b;
    status = app_init_decode(obj->context, &obj->decodeObj_ar0233_b);
    if(status != 0 )
    {
        printf("app_init_decode error\r\n");
    }
    APP_PRINTF("app_init_decode 0233 init done and return %d!\n", status);

    obj->decodeObj_ar0147.output_image = vxCreateImage(obj->context, 960, 540, VX_DF_IMAGE_NV12);
    obj->decodeObj_ar0147.ptr_decode_mutex = &obj->decode_0147_mutex;
    // obj->decodeObj_ar0147.output_image = (vx_image)vxGetObjectArrayItem(obj->mosaicObj.input_arr[0], 2);
    obj->decodeObj_ar0147.ptr_event = &obj->event_ar0147;
    // obj->decodeObj_ar0233_b.ptr_socketObj = &obj->socketObj_ar0233_b;
    status = app_init_decode(obj->context, &obj->decodeObj_ar0147);
    if(status != 0 )
    {
        printf("app_init_decode error\r\n");
    }
    APP_PRINTF("app_init_decode 0147 init done and return %d!\n", status);


    // APP_PRINTF("Cam power on\n");
    // appSensorPowerOn();
    // APP_PRINTF("Cam power on complete\n");
    /* Initialize modules */
    // if (status == VX_SUCCESS)
    // {
    //     status = app_init_sensor(&obj->sensorObj, "sensor_obj");
    // }

    // if (status == VX_SUCCESS)
    // {
    //     APP_PRINTF("Sensor init done!\n");
    //     status = app_init_capture(obj->context, &obj->captureObj, &obj->sensorObj, "capture_obj", APP_BUFFER_Q_DEPTH);
    // }

    // if((1 == obj->enable_viss) && (status == VX_SUCCESS))
    // {
    //     status = app_init_viss(obj->context, &obj->vissObj, &obj->sensorObj, "viss_obj");
    //     APP_PRINTF("VISS init done!\n");
    // }

    // if((1 == obj->enable_aewb) && (status == VX_SUCCESS))
    // {
    //     status = app_init_aewb(obj->context, &obj->aewbObj, &obj->sensorObj, "aewb_obj");
    //     APP_PRINTF("AEWB init done!\n");
    // }
        
    // if((obj->sensorObj.enable_ldc == 1) && (status == VX_SUCCESS))
    // {
    //     status = app_init_ldc(obj->context, &obj->ldcObj, &obj->sensorObj, "ldc_obj");
    //     APP_PRINTF("LDC init done!\n");
    // }


    // if((obj->enable_mosaic == 1) && (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");
    // }
    appPerfPointSetName(&obj->total_perf , "TOTAL");
    appPerfPointSetName(&obj->fileio_perf, "FILEIO");
    return status;
}

static char menu[] = {
    "\n"
    "\n ========================="
    "\n Demo : Camera Demo"
    "\n ========================="
    "\n"
    "\n s: Save CSIx, VISS and LDC outputs"
    "\n"
    "\n p: Print performance statistics"
    "\n"
    "\n x: Exit"
    "\n"
    "\n Enter Choice: "
};

static vx_status app_fifo_send(AppObj *obj)
{
    vx_status vxStatus = VX_SUCCESS;
    uint8_t *buf;

    while(1)
    {
        obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_A] = obj->socketObj_ar0233_a.fps;
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][0] = obj->socketObj_ar0233_a.cam_error_flag[0];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][1] = obj->socketObj_ar0233_a.cam_error_flag[1];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][2] = obj->socketObj_ar0233_a.cam_error_flag[2];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_A][3] = obj->socketObj_ar0233_a.cam_error_flag[3];
        obj->fpsFifoMsg.fps[APP_CAM_NAME_0143] = obj->socketObj_ar0143.fps;
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][0] = obj->socketObj_ar0143.cam_error_flag[0];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][1] = obj->socketObj_ar0143.cam_error_flag[1];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][2] = obj->socketObj_ar0143.cam_error_flag[2];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0143][3] = obj->socketObj_ar0143.cam_error_flag[3];
        obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_B] = obj->socketObj_ar0233_b.fps;
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][0] = obj->socketObj_ar0233_b.cam_error_flag[0];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][1] = obj->socketObj_ar0233_b.cam_error_flag[1];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][2] = obj->socketObj_ar0233_b.cam_error_flag[2];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0233_B][3] = obj->socketObj_ar0233_b.cam_error_flag[3];
        obj->fpsFifoMsg.fps[APP_CAM_NAME_0147] = obj->socketObj_ar0147.fps;
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][0] = obj->socketObj_ar0147.cam_error_flag[0];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][1] = obj->socketObj_ar0147.cam_error_flag[1];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][2] = obj->socketObj_ar0147.cam_error_flag[2];
        obj->fpsFifoMsg.cam_error_flag[APP_CAM_NAME_0147][3] = obj->socketObj_ar0147.cam_error_flag[3];
        if(obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_A] < 25 || obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_A] > 35)
        {
            VX_PRINT(VX_ZONE_INFO, "CAM_NAME_0233_A fps out of range and value is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_A]);
        }

        if(obj->fpsFifoMsg.fps[APP_CAM_NAME_0143] < 20 || obj->fpsFifoMsg.fps[APP_CAM_NAME_0143] > 30)
        {
            VX_PRINT(VX_ZONE_INFO, "CAM_NAME_0143 fps out of range and value is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0143]);
        }

        if(obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_B] < 25 || obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_B] > 35)
        {
            VX_PRINT(VX_ZONE_INFO, "CAM_NAME_0233_B fps out of range and value is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0233_B]);
        }

        if(obj->fpsFifoMsg.fps[APP_CAM_NAME_0147] < 15 || obj->fpsFifoMsg.fps[APP_CAM_NAME_0147] > 30)
        {
            VX_PRINT(VX_ZONE_INFO, "CAM_NAME_0147 fps out of range and value is %f\r\n", obj->fpsFifoMsg.fps[APP_CAM_NAME_0147]);
        }

        buf = &obj->fpsFifoMsg;
        if(write(obj->fpsFifo_fd, buf, sizeof(App_FifoFps)) < 0)  // 写入到FIFO中
        {
            perror("Write FIFO Failed");
        }


        // if(obj->decodeObj_ar0147.video_in
        // && obj->socketObj_ar0143.video_in
        // && obj->socketObj_ar0233_a.video_in)
        // {
        //     obj->mosaicObj.video_in = vx_true_e;
        // }

        tivxTaskWaitMsecs(APP_SOCKET_CMD_FPS_INTER_IN_SENCOND * 1000);
    }

    return vxStatus;
    
}


void app_fps_fifo_task(void *app_var)
{
    AppObj *obj = (AppObj *)app_var;
    vx_status status = VX_SUCCESS;

    printf("I am app_fps_fifo_task process.\n"); // 说明进程ID
    

    // if(mkfifo(APP_FPS_FIFO_NAME, 0666) < 0 && errno!=EEXIST) // 创建FIFO管道
    //      perror("Create FIFO Failed");

    if((obj->fpsFifo_fd = open(APP_FPS_FIFO_NAME, O_WRONLY)) < 0) // 以写打开一个FIFO 
    {
        perror("Open FIFO Failed");
    }


    while((!obj->stop_task_fpsFifo) && (status == VX_SUCCESS))
    {

        status = app_fifo_send(obj);
    }
    close(obj->fpsFifo_fd);
    obj->stop_task_done_fpsFifo = 1;
}


static int32_t app_run_task_create(AppObj *obj)
{
    tivx_task_create_params_t params;
    vx_status status;

    tivxTaskSetDefaultCreateParams(&params);
    params.task_main = app_socket_recv_task;
    params.app_var = &obj->socketObj_ar0233_b;

    obj->socketObj_ar0233_b.stop_task_done = 0;
    obj->socketObj_ar0233_b.stop_task = 0;

    status = tivxTaskCreate(&obj->socketObj_ar0233_b.task, &params);

    tivxTaskSetDefaultCreateParams(&params);
    params.task_main = app_socket_recv_task;
    params.app_var = &obj->socketObj_ar0147;

    obj->socketObj_ar0147.stop_task_done = 0;
    obj->socketObj_ar0147.stop_task = 0;

    status = tivxTaskCreate(&obj->socketObj_ar0147.task, &params);

    tivxTaskSetDefaultCreateParams(&params);
    params.task_main = app_socket_recv_task;
    params.app_var = &obj->socketObj_ar0143;

    obj->socketObj_ar0143.stop_task_done = 0;
    obj->socketObj_ar0143.stop_task = 0;

    status = tivxTaskCreate(&obj->socketObj_ar0143.task, &params);

    tivxTaskSetDefaultCreateParams(&params);
    params.task_main = app_socket_recv_task;
    params.app_var = &obj->socketObj_ar0233_a;

    obj->socketObj_ar0233_a.stop_task_done = 0;
    obj->socketObj_ar0233_a.stop_task = 0;

    status = tivxTaskCreate(&obj->socketObj_ar0233_a.task, &params);

    // tivxTaskSetDefaultCreateParams(&params);
    // params.task_main = app_decode_task;
    // params.app_var = &obj->decodeObj_ar0233_b;
    // // params.priority = TIVX_TASK_PRI_LOWEST - 3;

    // obj->decodeObj_ar0233_b.stop_task_done = 0;
    // obj->decodeObj_ar0233_b.stop_task = 0;

    // status = tivxTaskCreate(&obj->decodeObj_ar0233_b.task, &params);

    // tivxTaskSetDefaultCreateParams(&params);
    // params.task_main = app_decode_task;
    // params.app_var = &obj->decodeObj_ar0147;
    // // params.priority = TIVX_TASK_PRI_LOWEST - 3;

    // obj->decodeObj_ar0147.stop_task_done = 0;
    // obj->decodeObj_ar0147.stop_task = 0;

    // status = tivxTaskCreate(&obj->decodeObj_ar0147.task, &params);
    #if 1
    tivxTaskSetDefaultCreateParams(&params);
    params.task_main = app_fps_fifo_task;
    params.app_var = obj;
    params.priority = TIVX_TASK_PRI_LOWEST;

    obj->stop_task_done_fpsFifo = 0;
    obj->stop_task_fpsFifo = 0;

    status = tivxTaskCreate(&obj->fpsFifo_task, &params);
    #endif

    tivxTaskSetDefaultCreateParams(&params);
    params.task_main = app_mosaic_run_task;
    params.app_var = &obj->mosaicObj;
    params.priority = TIVX_TASK_PRI_LOWEST;

    obj->mosaicObj.stop_task = 0;
    obj->mosaicObj.stop_task_done = 0;

    status = tivxTaskCreate(&obj->mosaicObj.task, &params);

    return status;
}

static vx_status app_run_graph_interactive(AppObj *obj)
{
    vx_status status;
    uint32_t done = 0;

    char ch;
    FILE *fp;
    app_perf_point_t *perf_arr[1];

    status = app_run_task_create(obj);
    if(status == VX_FAILURE)
    {
        printf("app_tidl: ERROR: Unable to create task\n");
    }
    else
    {
        appPerfStatsResetAll();
        while(1)
        {
            tivxEventWait(obj->event_print_fps, TIVX_EVENT_TIMEOUT_WAIT_FOREVER);
            appPerfStatsPrintAll();
            status = tivx_utils_graph_perf_print(obj->decodeObj_ar0233_b.graph);
            appPerfPointPrint(&obj->decodeObj_ar0233_b.total_perf);
            // appPerfPointPrint(&obj->total_perf);
            printf("\n");
            appPerfPointPrintFPS(&obj->decodeObj_ar0233_b.total_perf);
            appPerfPointReset(&obj->decodeObj_ar0233_b.total_perf);
            printf("\n");

            appPerfStatsPrintAll();
            status = tivx_utils_graph_perf_print(obj->decodeObj_ar0147.graph);
            appPerfPointPrint(&obj->decodeObj_ar0147.total_perf);
            printf("\n");
            appPerfPointPrintFPS(&obj->decodeObj_ar0147.total_perf);
            appPerfPointReset(&obj->decodeObj_ar0147.total_perf);
            printf("\n");

            appPerfStatsPrintAll();
            status = tivx_utils_graph_perf_print(obj->mosaicObj.graph);
            appPerfPointPrint(&obj->mosaicObj.total_perf);
            printf("\n");
            appPerfPointPrintFPS(&obj->mosaicObj.total_perf);
            appPerfPointReset(&obj->mosaicObj.total_perf);
            printf("\n");


            // tivxTaskWaitMsecs(100000);
        }
        while(!done)
        {
            printf(menu);
            ch = getchar();
            printf("\n");

            switch(ch)
            {
                case 'p':
                    appPerfStatsPrintAll();
                    status = tivx_utils_graph_perf_print(obj->decodeObj_ar0233_b.graph);
                    appPerfPointPrint(&obj->decodeObj_ar0233_b.total_perf);
                    // appPerfPointPrint(&obj->total_perf);
                    printf("\n");
                    appPerfPointPrintFPS(&obj->decodeObj_ar0233_b.total_perf);
                    appPerfPointReset(&obj->decodeObj_ar0233_b.total_perf);
                    printf("\n");

                    appPerfStatsPrintAll();
                    status = tivx_utils_graph_perf_print(obj->decodeObj_ar0147.graph);
                    appPerfPointPrint(&obj->decodeObj_ar0147.total_perf);
                    printf("\n");
                    appPerfPointPrintFPS(&obj->decodeObj_ar0147.total_perf);
                    appPerfPointReset(&obj->decodeObj_ar0147.total_perf);
                    printf("\n");

                    appPerfStatsPrintAll();
                    status = tivx_utils_graph_perf_print(obj->mosaicObj.graph);
                    appPerfPointPrint(&obj->mosaicObj.total_perf);
                    printf("\n");
                    appPerfPointPrintFPS(&obj->mosaicObj.total_perf);
                    appPerfPointReset(&obj->mosaicObj.total_perf);
                    printf("\n");

                    break;
                case 'e':
                    perf_arr[0] = &obj->total_perf;
                    fp = appPerfStatsExportOpenFile(".", "basic_demos_app_multi_cam");
                    if (NULL != fp)
                    {
                        appPerfStatsExportAll(fp, perf_arr, 1);
                        if (status == VX_SUCCESS)
                        {
                            status = tivx_utils_graph_perf_export(fp, obj->decodeObj_ar0233_b.graph);
                        }
                        appPerfStatsExportCloseFile(fp);
                        appPerfStatsResetAll();
                    }
                    else
                    {
                        printf("fp is null\n");
                    }
                    break;
                case 's':
                    obj->write_file = 1;
                    break;
                case 'x':
                    obj->socketObj_ar0233_b.stop_task = 1;
                    obj->socketObj_ar0147.stop_task = 1;
                    done = 1;
                    break;
            }
        }
        app_run_task_delete(obj);
    }
    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];
    // vx_int32 graph_parameter_index;

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

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

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

    if(status == VX_SUCCESS)
    {
        status = app_create_graph_decode(obj->decodeObj_ar0233_b.graph, &obj->decodeObj_ar0233_b);
        APP_PRINTF("Decode ar0233 graph done!\n");
    }

    if(status == VX_SUCCESS)
    {
        status = app_create_graph_decode(obj->decodeObj_ar0147.graph, &obj->decodeObj_ar0147);
        APP_PRINTF("Decode ar0233 graph done!\n");
    }

    if(status == VX_SUCCESS)
    {
        obj->mosaicObj.num_inputs = 1;
        status = app_create_graph_img_mosaic(obj->mosaicObj.graph, &obj->mosaicObj);
        APP_PRINTF("mosaic graph done!\n");
    }

    // if(status == VX_SUCCESS)
    // {
    //     status = app_create_graph_decode(obj->decodeObj_ar0147.graph, &obj->decodeObj_ar0147);
    //     APP_PRINTF("Decode ar0233 graph done!\n");
    // }

    // if(status == VX_SUCCESS)
    // {
    //     graph_parameter_index = 0;
    //     add_graph_parameter_by_node_index(obj->graph, obj->captureObj.node, 1);
    //     obj->captureObj.graph_parameter_index = graph_parameter_index;
    //     graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index;
    //     graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = APP_BUFFER_Q_DEPTH;
    //     graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference*)&obj->captureObj.raw_image_arr[0];
    //     graph_parameter_index++;

    //     if((obj->en_out_img_write == 1) || (obj->test_mode == 1))
    //     {
    //         add_graph_parameter_by_node_index(obj->graph, obj->imgMosaicObj.node, 1);
    //         obj->imgMosaicObj.graph_parameter_index = graph_parameter_index;
    //         graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index;
    //         graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = APP_BUFFER_Q_DEPTH;
    //         graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference*)&obj->imgMosaicObj.output_image[0];
    //         graph_parameter_index++;
    //     }

    //     if((obj->en_out_bitstream_write == 1) && (obj->enable_encode == 1))
    //     {
    //         add_graph_parameter_by_node_index(obj->graph, obj->encodeObj.node, 2);
    //         obj->encodeObj.graph_parameter_index = graph_parameter_index;
    //         graph_parameters_queue_params_list[graph_parameter_index].graph_parameter_index = graph_parameter_index;
    //         graph_parameters_queue_params_list[graph_parameter_index].refs_list_size = APP_BUFFER_Q_DEPTH;
    //         graph_parameters_queue_params_list[graph_parameter_index].refs_list = (vx_reference*)&obj->encodeObj.bitstream_obj[0];
    //         graph_parameter_index++;
    //     }

    //     status = vxSetGraphScheduleConfig(obj->graph,
    //             VX_GRAPH_SCHEDULE_MODE_QUEUE_AUTO,
    //             graph_parameter_index,
    //             graph_parameters_queue_params_list);

    //     if (status == VX_SUCCESS)
    //     {
    //         status = tivxSetGraphPipelineDepth(obj->graph, APP_PIPELINE_DEPTH);
    //     }
    //     if((obj->enable_viss == 1) && (status == VX_SUCCESS))
    //     {
    //         status = tivxSetNodeParameterNumBufByIndex(obj->vissObj.node, 6, APP_BUFFER_Q_DEPTH);
    //         if (status == VX_SUCCESS)
    //         {
    //             status = tivxSetNodeParameterNumBufByIndex(obj->vissObj.node, 9, APP_BUFFER_Q_DEPTH);
    //         }
    //         if (status == VX_SUCCESS)
    //         {
    //             status = tivxSetNodeParameterNumBufByIndex(obj->aewbObj.node, 4, APP_BUFFER_Q_DEPTH);
    //         }
    //     }
    //     if((obj->sensorObj.enable_ldc == 1) && (status == VX_SUCCESS))
    //     {
    //         status = tivxSetNodeParameterNumBufByIndex(obj->ldcObj.node, 7, APP_BUFFER_Q_DEPTH);
    //     }
    //     if((obj->enable_mosaic == 1) && (status == VX_SUCCESS))
    //     {
    //         status = tivxSetNodeParameterNumBufByIndex(obj->imgMosaicObj.node, 1, APP_BUFFER_Q_DEPTH);
    //         APP_PRINTF("Pipeline params setup done!\n");
    //     }

    //     if((obj->enable_encode == 1) && (status == VX_SUCCESS))
    //     {
    //         status = tivxSetNodeParameterNumBufByIndex(obj->encodeObj.node, 2, APP_BUFFER_Q_DEPTH);
    //         APP_PRINTF("Pipeline params setup done!\n");
    //     }
    // }

    return status;
}

static void app_delete_graph(AppObj *obj)
{
    app_delete_socket(&obj->socketObj_ar0233_b);
    APP_PRINTF("app_delete_socket delete done!\n");

    app_delete_decode(&obj->decodeObj_ar0233_b);
    APP_PRINTF("app_delete_decode delete done!\n");

    app_delete_socket(&obj->socketObj_ar0147);
    APP_PRINTF("app_delete_socket delete done!\n");

    app_delete_decode(&obj->decodeObj_ar0147);
    APP_PRINTF("app_delete_decode delete done!\n");
}

static void app_deinit(AppObj *obj)
{
    app_deinit_socket(&obj->socketObj_ar0233_b);
    APP_PRINTF("Sensor deinit done!\n");

    app_deinit_decode(&obj->decodeObj_ar0233_b);
    APP_PRINTF("Capture deinit done!\n");

    app_deinit_socket(&obj->socketObj_ar0147);
    APP_PRINTF("Sensor deinit done!\n");

    app_deinit_decode(&obj->decodeObj_ar0147);
    APP_PRINTF("Capture deinit done!\n");


    tivxHwaUnLoadKernels(obj->context);
    tivxImagingUnLoadKernels(obj->context);
    tivxFileIOUnLoadKernels(obj->context);
    APP_PRINTF("Kernels unload done!\n");

    vxReleaseContext(&obj->context);
    APP_PRINTF("Release context done!\n");
}

static void app_run_task_delete(AppObj *obj)
{
    while(obj->socketObj_ar0233_b.stop_task_done==0)
    {
        tivxTaskWaitMsecs(100);
    }

    tivxTaskDelete(&obj->socketObj_ar0233_b.task);

    while(obj->socketObj_ar0147.stop_task_done==0)
    {
        tivxTaskWaitMsecs(100);
    }

    tivxTaskDelete(&obj->decodeObj_ar0233_b.task);

    while(obj->decodeObj_ar0233_b.stop_task_done==0)
    {
        tivxTaskWaitMsecs(100);
    }

    tivxTaskDelete(&obj->decodeObj_ar0233_b.task);

    while(obj->decodeObj_ar0147.stop_task_done==0)
    {
        tivxTaskWaitMsecs(100);
    }

    tivxTaskDelete(&obj->decodeObj_ar0147.task);

}

and here is mosaic target file vx_img_mosaic_msc_target.c:

/*
*
* Copyright (c) 2019 Texas Instruments Incorporated
*
* All rights reserved not granted herein.
*
* Limited License.
*
* Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive
* license under copyrights and patents it now or hereafter owns or controls to make,
* have made, use, import, offer to sell and sell ("Utilize") this software subject to the
* terms herein.  With respect to the foregoing patent license, such license is granted
* solely to the extent that any such patent is necessary to Utilize the software alone.
* The patent license shall not apply to any combinations which include this software,
* other than combinations with devices manufactured by or for TI ("TI Devices").
* No hardware patent is licensed hereunder.
*
* Redistributions must preserve existing copyright notices and reproduce this license
* (including the above copyright notice and the disclaimer and (if applicable) source
* code license limitations below) in the documentation and/or other materials provided
* with the distribution
*
* Redistribution and use in binary form, without modification, are permitted provided
* that the following conditions are met:
*
* *       No reverse engineering, decompilation, or disassembly of this software is
* permitted with respect to any software provided in binary form.
*
* *       any redistribution and use are licensed by TI for use only with TI Devices.
*
* *       Nothing shall obligate TI to provide you with source code for the software
* licensed and provided to you in object code.
*
* If software source code is provided to you, modification and redistribution of the
* source code are permitted provided that the following conditions are met:
*
* *       any redistribution and use of the source code, including any resulting derivative
* works, are licensed by TI for use only with TI Devices.
*
* *       any redistribution and use of any object code compiled from the source code
* and any resulting derivative works, are licensed by TI for use only with TI Devices.
*
* Neither the name of Texas Instruments Incorporated nor the names of its suppliers
*
* may be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* DISCLAIMER.
*
* THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/

#include <TI/tivx.h>
#include <TI/j7.h>
#include <TI/tivx_event.h>
#include <TI/tivx_img_proc.h>
#include <TI/tivx_target_kernel.h>

#include <tivx_kernels_target_utils.h>
#include <tivx_img_mosaic_host.h>
#include <ti/drv/vhwa/include/vhwa_m2mMsc.h>
#include <utils/mem/include/app_mem.h>

#include <utils/perf_stats/include/app_perf_stats.h>

/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

#define TIVX_IMAGE_MOSAIC_MAX_PLANES    (2u) /* one plane for Y, one plane for C */

#define TIVX_IMAGE_MOSAIC_MSC_MAX_INST  (2u)

/* ========================================================================== */
/*                         Structure Declarations                             */
/* ========================================================================== */

/* Mosaic MSC internal object */
typedef struct
{
    Vhwa_M2mMscCreatePrms   createArgs;
    Vhwa_M2mMscParams       msc_prms;
    Fvid2_Handle            handle;
    tivx_event              wait_for_compl;

    Fvid2_FrameList         inFrmList;
    Fvid2_FrameList         outFrmList;
    Fvid2_Frame             inFrm;
    Fvid2_Frame             outFrm;
    Fvid2_CbParams          cbPrms;

    uint32_t                msc_drv_inst_id;

    uint64_t                time;

    uint32_t                scIdx;
} tivxImgMosaicMscInstObj;

typedef struct
{
    tivxImgMosaicMscInstObj inst_obj[TIVX_IMAGE_MOSAIC_MSC_MAX_INST];

    Msc_Coeff               coeffCfg;

    tivxImgMosaicWindow    *tmp_win[TIVX_IMAGE_MOSAIC_MSC_MAX_INST];
    uint32_t                tmp_in_ch[TIVX_IMAGE_MOSAIC_MSC_MAX_INST];
    uint32_t                tmp_ch_sel[TIVX_IMAGE_MOSAIC_MSC_MAX_INST];

    tivx_obj_desc_object_array_t *in_arr_desc[TIVX_IMAGE_MOSAIC_MSC_MAX_INST];
    tivx_obj_desc_image_t        *in_img_desc[TIVX_IMAGE_MOSAIC_MSC_MAX_INST][TIVX_OBJECT_ARRAY_MAX_ITEMS];

    app_perf_hwa_id_t       app_hwa_inst_id[TIVX_IMAGE_MOSAIC_MSC_MAX_INST];
  
    vx_uint32               max_msc_instances;
    vx_uint32               msc_instance;

} tivxImgMosaicMscObj;


/* ========================================================================== */
/*                          Function Declarations                             */
/* ========================================================================== */

/* Interface API Functions */
static vx_status VX_CALLBACK tivxKernelImgMosaicMscCreate(
    tivx_target_kernel_instance kernel,
    tivx_obj_desc_t *obj_desc[],
    vx_uint16 num_params,
    void *priv_arg);
static vx_status VX_CALLBACK tivxKernelImgMosaicMscDelete(
    tivx_target_kernel_instance kernel,
    tivx_obj_desc_t *obj_desc[],
    vx_uint16 num_params,
    void *priv_arg);
static vx_status VX_CALLBACK tivxKernelImgMosaicMscProcess(
    tivx_target_kernel_instance kernel,
    tivx_obj_desc_t *obj_desc[],
    vx_uint16 num_params,
    void *priv_arg);

/* Local Functions */
static vx_status tivxKernelImgMosaicMscDrvCreate(
    tivxImgMosaicMscInstObj *inst_obj, uint32_t inst_id);
static vx_status tivxKernelImgMosaicMscDrvDelete(
    tivxImgMosaicMscInstObj *inst_obj);
static void tivxKernelImgMosaicMscDrvSetScCfg(
    Msc_ScConfig *sc_cfg,
    const tivx_obj_desc_image_t *in_img_desc,
    const tivxImgMosaicWindow *window);
static int32_t tivxKernelImgMosaicMscDrvCompCb(
    Fvid2_Handle handle,
    void *appData);
static vx_status tivxKernelImgMosaicMscSetCoeffsCmd(tivxImgMosaicMscObj *msc_obj);
static void scale_set_coeff(
    tivx_vpac_msc_coefficients_t *coeff,
    uint32_t interpolation);

static vx_status tivxKernelImgMosaicMscDrvPrepare(
    tivxImgMosaicMscInstObj *inst_obj,
    const tivx_obj_desc_image_t *in_img_desc,
    const tivxImgMosaicWindow *window,
    const tivx_obj_desc_image_t* out_img_desc);
static vx_status tivxKernelImgMosaicMscDrvSubmit(tivxImgMosaicMscInstObj *inst_obj);
static void tivxKernelImgMosaicMscDrvWait(tivxImgMosaicMscInstObj *inst_obj);
static vx_status tivxKernelImgMosaicMscDrvGetReq(tivxImgMosaicMscInstObj *inst_obj);


/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

static tivx_target_kernel vx_imgMosaicMsc1_kernel = NULL;
static tivx_target_kernel vx_imgMosaicMsc2_kernel = NULL;

/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

void tivxAddTargetKernelImgMosaicMsc(void)
{
    char target_name[TIVX_TARGET_MAX_NAME];

    /* Both scalars are used, but the target used it always MSC0 */
    strncpy(target_name, TIVX_TARGET_VPAC_MSC1, TIVX_TARGET_MAX_NAME);
    vx_imgMosaicMsc1_kernel = tivxAddTargetKernelByName(
                                 TIVX_KERNEL_IMG_MOSAIC_NAME,
                                 target_name,
                                 tivxKernelImgMosaicMscProcess,
                                 tivxKernelImgMosaicMscCreate,
                                 tivxKernelImgMosaicMscDelete,
                                 NULL,
                                 NULL);
    if(NULL == vx_imgMosaicMsc1_kernel)
    {
        VX_PRINT(VX_ZONE_ERROR, "Failed to Add Img Mosaic MSC TargetKernel\n");
    }

    strncpy(target_name, TIVX_TARGET_VPAC_MSC2, TIVX_TARGET_MAX_NAME);
    vx_imgMosaicMsc2_kernel = tivxAddTargetKernelByName(
                                 TIVX_KERNEL_IMG_MOSAIC_NAME,
                                 target_name,
                                 tivxKernelImgMosaicMscProcess,
                                 tivxKernelImgMosaicMscCreate,
                                 tivxKernelImgMosaicMscDelete,
                                 NULL,
                                 NULL);
    if(NULL == vx_imgMosaicMsc2_kernel)
    {
        VX_PRINT(VX_ZONE_ERROR, "Failed to Add Img Mosaic MSC TargetKernel\n");
    }
}

void tivxRemoveTargetKernelImgMosaicMsc(void)
{
    vx_status status;

    status = tivxRemoveTargetKernel(vx_imgMosaicMsc1_kernel);
    if(status == VX_SUCCESS)
    {
        vx_imgMosaicMsc1_kernel = NULL;
    }
    else
    {
        VX_PRINT(VX_ZONE_ERROR, "Failed to Remove Img Mosaic MSC TargetKernel\n");
    }
    status = tivxRemoveTargetKernel(vx_imgMosaicMsc2_kernel);
    if(status == VX_SUCCESS)
    {
        vx_imgMosaicMsc2_kernel = NULL;
    }
    else
    {
        VX_PRINT(VX_ZONE_ERROR, "Failed to Remove Img Mosaic MSC TargetKernel\n");
    }
}

/* ========================================================================== */
/*                              OPENVX Callbacks                              */
/* ========================================================================== */

static vx_status VX_CALLBACK tivxKernelImgMosaicMscCreate(
    tivx_target_kernel_instance kernel,
    tivx_obj_desc_t *obj_desc[],
    vx_uint16 num_params,
    void *priv_arg)
{
    vx_status                         status = VX_SUCCESS;
    uint32_t                          i;
    tivx_obj_desc_user_data_object_t *config_desc;
    void                             *config_target_ptr;
    tivx_obj_desc_image_t            *out_img_desc;
    tivx_obj_desc_object_array_t     *input_image_arr_desc;
    tivx_obj_desc_image_t            *in_img_desc[TIVX_OBJECT_ARRAY_MAX_ITEMS];
    tivxImgMosaicParams              *params;
    vx_int32                          win;
    vx_int32                          num_inputs;
    tivxImgMosaicMscObj              *msc_obj = NULL;

    for(i = 0U; i < num_params; i++)
    {
        if(NULL == obj_desc[i])
        {
            status = VX_FAILURE;
            break;
        }
    }

    if(VX_SUCCESS == status)
    {
        /* Alloc mosaic object */
        msc_obj = tivxMemAlloc(sizeof(tivxImgMosaicMscObj), TIVX_MEM_EXTERNAL);
        if(NULL == msc_obj)
        {
            status = VX_ERROR_NO_MEMORY;
        }
        else
        {
            tivxSetTargetKernelInstanceContext(kernel, msc_obj,  sizeof(tivxImgMosaicMscObj));
        }
    }

    if(VX_SUCCESS == status)
    {
        /* 0 - config, 1 - output image, 2 onwards is array of inputs */
        num_inputs = num_params - 2U;

        config_desc = (tivx_obj_desc_user_data_object_t *)
            obj_desc[TIVX_IMG_MOSAIC_HOST_CONFIG_IDX];
        config_target_ptr = tivxMemShared2TargetPtr(&config_desc->mem_ptr);
        tivxMemBufferMap(
            config_target_ptr,
            config_desc->mem_size,
            VX_MEMORY_TYPE_HOST,VX_READ_ONLY);
        params = (tivxImgMosaicParams *) config_target_ptr;
        if(params->num_windows > TIVX_IMG_MOSAIC_MAX_WINDOWS)
        {
            VX_PRINT(VX_ZONE_ERROR,
                "Num windows %d greater than supported max %d\n",
                params->num_windows, TIVX_IMG_MOSAIC_MAX_WINDOWS);
            status = VX_FAILURE;
        }

        out_img_desc = (tivx_obj_desc_image_t *)
            obj_desc[TIVX_IMG_MOSAIC_HOST_OUTPUT_IMAGE_IDX];
        if(VX_SUCCESS == status)
        {
            for(win = 0U; win < params->num_windows; win++)
            {
                tivxImgMosaicWindow *window =
                    (tivxImgMosaicWindow *) &params->windows[win];
                vx_int32 in = window->input_select;
                vx_int32 ch = window->channel_select;

                if(in > num_inputs)
                {
                    VX_PRINT(VX_ZONE_ERROR,
                        "Input ID %d greater than num_inputs %d\n",
                        in, num_inputs);
                    status = VX_FAILURE;
                    break;
                }

                input_image_arr_desc = (tivx_obj_desc_object_array_t *)
                    obj_desc[TIVX_IMG_MOSAIC_INPUT_START_IDX + in];
                tivxGetObjDescList(
                    input_image_arr_desc->obj_desc_id,
                    (tivx_obj_desc_t **) &in_img_desc[0U],
                    input_image_arr_desc->num_items);

                if(ch > input_image_arr_desc->num_items)
                {
                    VX_PRINT(VX_ZONE_ERROR,
                        "Channel ID %d greater than num_items %d\n",
                        ch, input_image_arr_desc->num_items);
                    status = VX_FAILURE;
                    break;
                }

                if(((window->startX + window->width) > out_img_desc->width) ||
                   ((window->startY + window->height) > out_img_desc->height))
                {
                    VX_PRINT(VX_ZONE_ERROR,
                        "Window %d, does not fit within output image!\n", win);
                    status = VX_FAILURE;
                }
            }
        }
        
        VX_PRINT(VX_ZONE_INFO, "num_msc_instance = %d \n", params->num_msc_instances);
        VX_PRINT(VX_ZONE_INFO, "msc_instance = %d \n", params->msc_instance);
        
        if (params->num_msc_instances < TIVX_IMAGE_MOSAIC_MSC_MAX_INST)
        {
            msc_obj->max_msc_instances = params->num_msc_instances;
        }
        else
        {
            msc_obj->max_msc_instances = TIVX_IMAGE_MOSAIC_MSC_MAX_INST;
        }

        if (params->msc_instance > TIVX_IMAGE_MOSAIC_MSC_MAX_INST)
        {
            msc_obj->msc_instance = 0;
        }
        else
        {
            msc_obj->msc_instance = params->msc_instance;
        }

        tivxMemBufferUnmap(
            config_target_ptr,
            config_desc->mem_size,
            VX_MEMORY_TYPE_HOST, VX_READ_ONLY);
    }

    if(VX_SUCCESS == status)
    {
        if (msc_obj->max_msc_instances == 2)
        {
            msc_obj->app_hwa_inst_id[0] = APP_PERF_HWA_MSC0;
            msc_obj->app_hwa_inst_id[1] = APP_PERF_HWA_MSC1;
        }
        else if(msc_obj->max_msc_instances == 1)
        {
            if(msc_obj->msc_instance == 0)
            {
                msc_obj->app_hwa_inst_id[0] = APP_PERF_HWA_MSC0;
            }
            else if (msc_obj->msc_instance == 1)
            {
                msc_obj->app_hwa_inst_id[0] = APP_PERF_HWA_MSC1;
            }
        }

        for (i = 0u; i < msc_obj->max_msc_instances; i ++)
        {
            if (0u == i)
            {
                msc_obj->inst_obj[i].scIdx = i;
            }
            else
            {
                msc_obj->inst_obj[i].scIdx = MSC_MAX_OUTPUT - 1U - i;
            }

            /* MSC driver create */
            status = tivxKernelImgMosaicMscDrvCreate(&msc_obj->inst_obj[i], i);
        }
    }

    if(VX_SUCCESS == status)
    {
        status = tivxKernelImgMosaicMscSetCoeffsCmd(msc_obj);
    }

    /* Free the allocated memory incase of error */
    if(VX_SUCCESS != status)
    {
        if(msc_obj != NULL)
        {
            for (i = 0u; i < msc_obj->max_msc_instances; i ++)
            {
                /* MSC driver create */
                status = tivxKernelImgMosaicMscDrvDelete(
                    &msc_obj->inst_obj[i]);
            }

            tivxMemFree(msc_obj, sizeof(tivxImgMosaicMscObj), TIVX_MEM_EXTERNAL);
        }
    }

    return (status);
}

static vx_status VX_CALLBACK tivxKernelImgMosaicMscDelete(
    tivx_target_kernel_instance kernel,
    tivx_obj_desc_t *obj_desc[],
    vx_uint16 num_params,
    void *priv_arg)
{
    vx_status            status = VX_SUCCESS;
    tivxImgMosaicMscObj *msc_obj = NULL;
    uint32_t             i;
    vx_uint32            size;

    for(i = 0U; i < num_params; i++)
    {
        if(NULL == obj_desc[i])
        {
            status = VX_FAILURE;
            break;
        }
    }

    status = tivxGetTargetKernelInstanceContext(kernel, (void **)&msc_obj, &size);
    if ((VX_SUCCESS != status) || (NULL == msc_obj) ||  (sizeof(tivxImgMosaicMscObj) != size))
    {
        status = VX_FAILURE;
    }
    else
    {
        for (i = 0u; i < msc_obj->max_msc_instances; i ++)
        {
            status = tivxKernelImgMosaicMscDrvDelete(
                &msc_obj->inst_obj[i]);
        }

        tivxMemFree(msc_obj, sizeof(tivxImgMosaicMscObj), TIVX_MEM_EXTERNAL);
    }

    return (status);
}

static vx_status VX_CALLBACK tivxKernelImgMosaicMscProcess(
    tivx_target_kernel_instance kernel,
    tivx_obj_desc_t *obj_desc[],
    vx_uint16 num_params,
    void *priv_arg)
{
    vx_status                         status = VX_SUCCESS;
    tivx_obj_desc_user_data_object_t *config_desc;
    void                             *config_target_ptr;
    tivx_obj_desc_image_t            *out_img_desc;
    tivx_obj_desc_image_t            *in_img_desc;
    void                             *output_image_target_ptr[2U];
    vx_int32                          win, in, ch, msc_cnt;
    vx_int32                          num_inputs;
    tivxImgMosaicParams              *params;
    tivxImgMosaicMscObj              *msc_obj = NULL;
    vx_uint32                         size, num_inst;
    uint32_t                         do_process[TIVX_IMAGE_MOSAIC_MSC_MAX_INST];
    vx_enum                          io_mem_type;

    status = tivxGetTargetKernelInstanceContext(kernel, (void **)&msc_obj, &size);
    if((VX_SUCCESS != status) || (NULL == msc_obj) ||  (sizeof(tivxImgMosaicMscObj) != size))
    {
        status = VX_FAILURE;
    }

    if(VX_SUCCESS == status)
    {
        /* Map config data - index 0 */
        config_desc = (tivx_obj_desc_user_data_object_t *)
            obj_desc[TIVX_IMG_MOSAIC_HOST_CONFIG_IDX];
        config_target_ptr = tivxMemShared2TargetPtr(&config_desc->mem_ptr);
        tivxMemBufferMap(
            config_target_ptr,
            config_desc->mem_size,
            VX_MEMORY_TYPE_HOST,VX_READ_ONLY);
        params = (tivxImgMosaicParams *) config_target_ptr;

        if((params->enable_overlay==1) && (params->clear_count > 0U))
        {
            io_mem_type = VX_MEMORY_TYPE_HOST;
        }
        else
        {
            io_mem_type = TIVX_MEMORY_TYPE_DMA;
        }

        /* Map output image - index 1 */
        out_img_desc = (tivx_obj_desc_image_t *)
            obj_desc[TIVX_IMG_MOSAIC_HOST_OUTPUT_IMAGE_IDX];
        output_image_target_ptr[0U] = tivxMemShared2TargetPtr(&out_img_desc->mem_ptr[0U]);
        tivxMemBufferMap(
            output_image_target_ptr[0U],
            out_img_desc->mem_size[0U],
            io_mem_type,VX_WRITE_ONLY);
        if(out_img_desc->mem_ptr[1U].shared_ptr != NULL)
        {
            output_image_target_ptr[1U] = tivxMemShared2TargetPtr(&out_img_desc->mem_ptr[1U]);
            tivxMemBufferMap(
                output_image_target_ptr[1U],
                out_img_desc->mem_size[1U],
                io_mem_type,VX_WRITE_ONLY);
        }

        /* Memset output buffers for initial count */
        if(params->clear_count > 0U)
        {
              memset(output_image_target_ptr[0U], 0U, out_img_desc->mem_size[0U]);

              if(output_image_target_ptr[1U] != NULL)
              {
                  memset(output_image_target_ptr[1U], 0x80U, out_img_desc->mem_size[1U]);
              }

              if(params->enable_overlay==1)
              {
                void vx_img_mosaic_draw_overlay_avp2(void *addr[], uint32_t pitch[], uint32_t width, uint32_t height);
                void *addr[2];
                uint32_t pitch[2];
                uint32_t width, height;

                addr[0] = output_image_target_ptr[0];
                addr[1] = output_image_target_ptr[1];
                width   = out_img_desc->width;
                height  = out_img_desc->height;
                pitch[0]= out_img_desc->imagepatch_addr[0].stride_y;
                pitch[1]= out_img_desc->imagepatch_addr[1].stride_y;

                vx_img_mosaic_draw_overlay_avp2(addr, pitch, width, height);
              }

              appMemCacheWb(output_image_target_ptr[0U], out_img_desc->mem_size[0U]);
              if(output_image_target_ptr[1U] != NULL)
              {
                  appMemCacheWb(output_image_target_ptr[1U], out_img_desc->mem_size[1U]);
              }
              params->clear_count--;
        }

        /* 0 - config, 1 - output image, 2 onwards is array of inputs */
        num_inputs = num_params - 2U;

        /* Perform scale operation for each of the output mosaic window */
        for(win = 0U; win < params->num_windows; win += msc_obj->max_msc_instances)
        {
            if ((params->num_windows - win) < msc_obj->max_msc_instances)
            {
                num_inst = params->num_windows - win;
            }
            else
            {
                num_inst = msc_obj->max_msc_instances;
            }

            for (msc_cnt = 0u; (msc_cnt < num_inst) &&
                    (VX_SUCCESS == status); msc_cnt ++)
            {
                msc_obj->tmp_win[msc_cnt] =
                    (tivxImgMosaicWindow *) &params->windows[win + msc_cnt];
                in = msc_obj->tmp_win[msc_cnt]->input_select;
                ch = msc_obj->tmp_win[msc_cnt]->channel_select;

                if (in < num_inputs)
                {
                    msc_obj->in_arr_desc[msc_cnt] = (tivx_obj_desc_object_array_t *)
                        obj_desc[TIVX_IMG_MOSAIC_INPUT_START_IDX + in];

                    tivxGetObjDescList(
                        msc_obj->in_arr_desc[msc_cnt]->obj_desc_id,
                        (tivx_obj_desc_t **) &msc_obj->in_img_desc[msc_cnt][0U],
                        msc_obj->in_arr_desc[msc_cnt]->num_items);

                    status = tivxKernelImgMosaicMscDrvPrepare(
                        &msc_obj->inst_obj[msc_cnt],
                        msc_obj->in_img_desc[msc_cnt][ch],
                        msc_obj->tmp_win[msc_cnt], out_img_desc);

                    if (VX_SUCCESS != status)
                    {
                        break;
                    }

                    msc_obj->tmp_in_ch[msc_cnt] = in;
                    msc_obj->tmp_ch_sel[msc_cnt] = ch;
                    do_process[msc_cnt] = 1;
                }
                else
                {
                    do_process[msc_cnt] = 0;
                }
            }
            for (msc_cnt = 0u; (msc_cnt < num_inst) &&
                    (VX_SUCCESS == status); msc_cnt ++)
            {
                if (do_process[msc_cnt])
                {
                    msc_obj->inst_obj[msc_cnt].time =
                        tivxPlatformGetTimeInUsecs();
                }
            }

            for (msc_cnt = 0u; (msc_cnt < num_inst) &&
                    (VX_SUCCESS == status); msc_cnt ++)
            {
                if (do_process[msc_cnt])
                {
                    status = tivxKernelImgMosaicMscDrvSubmit(
                        &msc_obj->inst_obj[msc_cnt]);
                }
            }

            for (msc_cnt = 0u; (msc_cnt < num_inst) &&
                    (VX_SUCCESS == status); msc_cnt ++)
            {
                if (do_process[msc_cnt])
                {
                    tivxKernelImgMosaicMscDrvWait(
                        &msc_obj->inst_obj[msc_cnt]);
                }
            }

            for (msc_cnt = 0u; (msc_cnt < num_inst) &&
                    (VX_SUCCESS == status); msc_cnt ++)
            {
                if (do_process[msc_cnt])
                {
                    status = tivxKernelImgMosaicMscDrvGetReq(
                        &msc_obj->inst_obj[msc_cnt]);
                }
            }

            for (msc_cnt = 0u; (msc_cnt < num_inst) &&
                    (VX_SUCCESS == status); msc_cnt ++)
            {
                if (do_process[msc_cnt])
                {
                    msc_obj->inst_obj[msc_cnt].time =
                        tivxPlatformGetTimeInUsecs() - msc_obj->inst_obj[msc_cnt].time;

                    ch = msc_obj->tmp_win[msc_cnt]->channel_select;

                    in_img_desc = msc_obj->in_img_desc[msc_cnt][ch];
                    size = (in_img_desc->imagepatch_addr[0].dim_x *
                        in_img_desc->imagepatch_addr[0].dim_y) +
                        (in_img_desc->imagepatch_addr[1].dim_x *
                        in_img_desc->imagepatch_addr[1].dim_y);
                    
                    appPerfStatsHwaUpdateLoad(msc_obj->app_hwa_inst_id[msc_cnt],
                        msc_obj->inst_obj[msc_cnt].time, size/* pixels processed */);
                }
            }

            if (VX_SUCCESS != status)
            {
                break;
            }
        }

        /* unmap config and output image buffer */
        tivxMemBufferUnmap(
            config_target_ptr,
            config_desc->mem_size,
            VX_MEMORY_TYPE_HOST, VX_READ_ONLY);
        tivxMemBufferUnmap(
            output_image_target_ptr[0U],
            out_img_desc->mem_size[0U],
            io_mem_type, VX_WRITE_ONLY);
        if(out_img_desc->mem_ptr[1U].shared_ptr != NULL)
        {
            tivxMemBufferUnmap(
                output_image_target_ptr[1U],
                out_img_desc->mem_size[1U],
                io_mem_type, VX_READ_ONLY);
        }
    }

    return (status);
}

/* ========================================================================== */
/*                              Local Functions                               */
/* ========================================================================== */

static vx_status tivxKernelImgMosaicMscDrvCreate(tivxImgMosaicMscInstObj *inst_obj, uint32_t inst_id)
{
    vx_status   status = VX_SUCCESS;

    /* Hard code to first instance */
    inst_obj->msc_drv_inst_id = inst_id;

    Vhwa_M2mMscCreatePrmsInit(&inst_obj->createArgs);
    status = tivxEventCreate(&inst_obj->wait_for_compl);
    if(VX_SUCCESS == status)
    {
        inst_obj->cbPrms.cbFxn   = tivxKernelImgMosaicMscDrvCompCb;
        inst_obj->cbPrms.appData = inst_obj;

        inst_obj->handle = Fvid2_create(
            FVID2_VHWA_M2M_MSC_DRV_ID,
            inst_obj->msc_drv_inst_id,
            &inst_obj->createArgs,
            NULL,
            &inst_obj->cbPrms);
        if(NULL == inst_obj->handle)
        {
            VX_PRINT(VX_ZONE_ERROR, "Fvid2_create failed\n");
            status = VX_ERROR_NO_RESOURCES;
        }
        else
        {
            Fvid2Frame_init(&inst_obj->inFrm);
            Fvid2Frame_init(&inst_obj->outFrm);
        }
    }
    else
    {
        VX_PRINT(VX_ZONE_ERROR, "Failed to allocate Event\n");
    }

    return (status);
}

static vx_status tivxKernelImgMosaicMscDrvDelete(tivxImgMosaicMscInstObj *inst_obj)
{
    vx_status   status = VX_SUCCESS;

    if(NULL != inst_obj->handle)
    {
        Fvid2_delete(inst_obj->handle, NULL);
        inst_obj->handle = NULL;
    }
    if(NULL != inst_obj->wait_for_compl)
    {
        tivxEventDelete(&inst_obj->wait_for_compl);
        inst_obj->wait_for_compl = NULL;
    }

    return (status);
}

/* ========================================================================== */
/*                    Control Command Implementation                          */
/* ========================================================================== */

static vx_status tivxKernelImgMosaicMscSetCoeffsCmd(tivxImgMosaicMscObj *msc_obj)
{
    vx_status                         status = VX_SUCCESS;
    int32_t                           fvid2_status = FVID2_SOK;
    uint32_t                          cnt;
    tivx_vpac_msc_coefficients_t      coeffs;
    Msc_Coeff                        *coeffCfg;

    scale_set_coeff(&coeffs, VX_INTERPOLATION_BILINEAR);

    coeffCfg = &msc_obj->coeffCfg;

    Msc_coeffInit(coeffCfg);

    for (cnt = 0u; cnt < MSC_MAX_SP_COEFF_SET; cnt ++)
    {
        coeffCfg->spCoeffSet[cnt] = &coeffs.single_phase[cnt][0u];
    }

    for (cnt = 0u; cnt < MSC_MAX_MP_COEFF_SET; cnt ++)
    {
        coeffCfg->mpCoeffSet[cnt] = &coeffs.multi_phase[cnt][0u];
    }

    if (VX_SUCCESS == status)
    {
        fvid2_status = Fvid2_control(msc_obj->inst_obj[0u].handle, VHWA_M2M_IOCTL_MSC_SET_COEFF,
            coeffCfg, NULL);
        if (FVID2_SOK != fvid2_status)
        {
            VX_PRINT(VX_ZONE_ERROR,
                "tivxKernelImgMosaicMscSetCoeffsCmd: Failed to create coefficients\n");
            status = VX_FAILURE;
        }
    }

    return (status);
}


static vx_status tivxKernelImgMosaicMscDrvPrepare(
    tivxImgMosaicMscInstObj *inst_obj,
    const tivx_obj_desc_image_t *in_img_desc,
    const tivxImgMosaicWindow *window,
    const tivx_obj_desc_image_t* out_img_desc)
{
    vx_status           status = VX_SUCCESS;
    Vhwa_M2mMscParams  *msc_prms;
    Fvid2_Format       *fmt;
    Msc_ScConfig       *sc_cfg;
    Fvid2_Frame        *frm;
    uint32_t            plane_cnt;
    vx_uint32           startX, startY;
    uint32_t            scIdx;

    msc_prms = &inst_obj->msc_prms;
    Vhwa_m2mMscParamsInit(msc_prms);

    /* Set input format */
    fmt = &msc_prms->inFmt;
    scIdx = inst_obj->scIdx;

    if(in_img_desc->format == VX_DF_IMAGE_U8 ||in_img_desc->format == VX_DF_IMAGE_U16)
    {
        fmt->dataFormat = FVID2_DF_LUMA_ONLY;
    }
    else
    {
        fmt->dataFormat = FVID2_DF_YUV420SP_UV;
    }

    if(in_img_desc->format == VX_DF_IMAGE_U16)
    {
        fmt->ccsFormat  = FVID2_CCSF_BITS12_UNPACKED16;
    }
    else
    {
        fmt->ccsFormat  = FVID2_CCSF_BITS8_PACKED;
    }

    fmt->width      = in_img_desc->imagepatch_addr[0U].dim_x;
    fmt->height     = in_img_desc->imagepatch_addr[0U].dim_y;
    fmt->pitch[0U]  = in_img_desc->imagepatch_addr[0U].stride_y;
    fmt->pitch[1U]  = in_img_desc->imagepatch_addr[1U].stride_y;

    /* Set output format */
    sc_cfg = &msc_prms->mscCfg.scCfg[scIdx];       /* Only one output used */
    tivxKernelImgMosaicMscDrvSetScCfg(sc_cfg, in_img_desc, window);
    fmt = &msc_prms->outFmt[scIdx];                /* Only one output used */

    if(out_img_desc->format == VX_DF_IMAGE_U8 ||in_img_desc->format == VX_DF_IMAGE_U16)
    {
        fmt->dataFormat = FVID2_DF_LUMA_ONLY;
    }
    else
    {
        fmt->dataFormat = FVID2_DF_YUV420SP_UV;
    }

    if(out_img_desc->format == VX_DF_IMAGE_U16)
    {
        fmt->ccsFormat  = FVID2_CCSF_BITS12_UNPACKED16;
    }
    else
    {
        fmt->ccsFormat  = FVID2_CCSF_BITS8_PACKED;
    }

    fmt->width      = sc_cfg->outWidth;
    fmt->height     = sc_cfg->outHeight;
    /* Use the output overlay pitch */
    fmt->pitch[0U]  = out_img_desc->imagepatch_addr[0U].stride_y;
    fmt->pitch[1U]  = out_img_desc->imagepatch_addr[1U].stride_y;

    status = Fvid2_control(
        inst_obj->handle, VHWA_M2M_IOCTL_MSC_SET_PARAMS, msc_prms, NULL);
    if(FVID2_SOK != status)
    {
        VX_PRINT(VX_ZONE_ERROR, "Fvid2_control Failed: Set Params\n");
        status = VX_FAILURE;
    }
    else
    {
        status = VX_SUCCESS;
    }

    if(VX_SUCCESS == status)
    {
        frm = &inst_obj->inFrm;
        for(plane_cnt = 0U; plane_cnt < TIVX_IMAGE_MOSAIC_MAX_PLANES; plane_cnt++)
        {
            frm->addr[plane_cnt] = tivxMemShared2PhysPtr(
                in_img_desc->mem_ptr[plane_cnt].shared_ptr,
                in_img_desc->mem_ptr[plane_cnt].mem_heap_region);
        }

        /* Adjust start X/Y so that we center the input when input size is less
         * than the window size */
        startX = window->startX + ((window->width  - sc_cfg->outWidth)  >> 1U);
        startY = window->startY + ((window->height - sc_cfg->outHeight) >> 1U);
        startX = ((startX >> 1U) << 1U);    /* Make it even for YUV420SP */
        startY = ((startY >> 1U) << 1U);    /* Make it even for YUV420SP */
        frm = &inst_obj->outFrm;
        for(plane_cnt = 0U; plane_cnt < TIVX_IMAGE_MOSAIC_MAX_PLANES; plane_cnt++)
        {
            uint64_t    temp;
            temp = tivxMemShared2PhysPtr(
                       out_img_desc->mem_ptr[plane_cnt].shared_ptr,
                       out_img_desc->mem_ptr[plane_cnt].mem_heap_region);
            /* Manipulate output overlay pointer to point to right offset
             * to do scaling */
            if(0U == plane_cnt)
            {
                frm->addr[plane_cnt] = temp +
                    (startY * out_img_desc->imagepatch_addr[0U].stride_y) +
                    startX;
            }
            else
            {
                frm->addr[plane_cnt] = temp +
                    ((startY >> 1U) * out_img_desc->imagepatch_addr[0U].stride_y) +
                    startX;
            }
        }
    }

    return (status);
}

static vx_status tivxKernelImgMosaicMscDrvSubmit(tivxImgMosaicMscInstObj *inst_obj)
{
    vx_status           status = VX_SUCCESS;

    Fvid2FrameList_init(&inst_obj->inFrmList);
    Fvid2FrameList_init(&inst_obj->outFrmList);

    /* Set up Framelist */
    inst_obj->inFrmList.numFrames = 1U;
    inst_obj->inFrmList.frames[0U] = &inst_obj->inFrm;
    inst_obj->outFrmList.numFrames = MSC_MAX_OUTPUT;
    inst_obj->outFrmList.frames[inst_obj->scIdx] = &inst_obj->outFrm;

    /* Submit MSC Request*/
    status = Fvid2_processRequest(
                 inst_obj->handle,
                 &inst_obj->inFrmList,
                 &inst_obj->outFrmList,
                 FVID2_TIMEOUT_FOREVER);
    if(FVID2_SOK != status)
    {
        VX_PRINT(VX_ZONE_ERROR, "Failed to Submit Request\n");
        status = VX_FAILURE;
    }

    return (status);
}

static void tivxKernelImgMosaicMscDrvWait(tivxImgMosaicMscInstObj *inst_obj)
{
    /* Wait for Frame Completion */
    tivxEventWait(inst_obj->wait_for_compl, TIVX_EVENT_TIMEOUT_WAIT_FOREVER);
}

static vx_status tivxKernelImgMosaicMscDrvGetReq(tivxImgMosaicMscInstObj *inst_obj)
{
    vx_status           status = VX_SUCCESS;

    status = Fvid2_getProcessedRequest(
                 inst_obj->handle,
                 &inst_obj->inFrmList,
                 &inst_obj->outFrmList,
                 0U);
    if(FVID2_SOK != status)
    {
        VX_PRINT(VX_ZONE_ERROR, "Failed to Get Processed Request\n");
        /* status = VX_FAILURE; */
    }

    return (status);
}

static void tivxKernelImgMosaicMscDrvSetScCfg(
    Msc_ScConfig *sc_cfg,
    const tivx_obj_desc_image_t *in_img_desc,
    const tivxImgMosaicWindow *window)
{
    sc_cfg->enable = TRUE;
    if(window->width > in_img_desc->imagepatch_addr[0U].dim_x)
    {
        /* Upscaling not supported - set MSC width same as input */
        sc_cfg->outWidth = in_img_desc->imagepatch_addr[0U].dim_x;
    }
    else
    {
        sc_cfg->outWidth = window->width;
    }
    if(window->height > in_img_desc->imagepatch_addr[0U].dim_y)
    {
        /* Upscaling not supported - set MSC height same as input */
        sc_cfg->outHeight = in_img_desc->imagepatch_addr[0U].dim_y;
    }
    else
    {
        sc_cfg->outHeight = window->height;
    }
    /* Crop setting - same as input size */
    if(window->enable_roi == 0)
    {
        sc_cfg->inRoi.cropStartX = 0U;
        sc_cfg->inRoi.cropStartY = 0U;
        sc_cfg->inRoi.cropWidth  = in_img_desc->imagepatch_addr[0U].dim_x;
        sc_cfg->inRoi.cropHeight = in_img_desc->imagepatch_addr[0U].dim_y;
    }
    else
    {
        sc_cfg->inRoi.cropStartX = window->roiStartX;
        sc_cfg->inRoi.cropStartY = window->roiStartY;
        sc_cfg->inRoi.cropWidth  = window->roiWidth;
        sc_cfg->inRoi.cropHeight = window->roiHeight;
    }

    /* For Scale, multi phase coefficients are used. */
    sc_cfg->filtMode     = MSC_FILTER_MODE_MULTI_PHASE;
    sc_cfg->phaseMode    = MSC_PHASE_MODE_64PHASE;
    sc_cfg->hsMpCoeffSel = MSC_MULTI_64PHASE_COEFF_SET_0;
    sc_cfg->vsMpCoeffSel = MSC_MULTI_64PHASE_COEFF_SET_0;
    sc_cfg->coeffShift   = MSC_COEFF_SHIFT_8;
}

static void scale_set_coeff(
    tivx_vpac_msc_coefficients_t *coeff,
    uint32_t interpolation)
{
    uint32_t i;
    uint32_t idx;
    uint32_t weight;

    idx = 0;
    coeff->single_phase[0][idx++] = 0;
    coeff->single_phase[0][idx++] = 0;
    coeff->single_phase[0][idx++] = 256;
    coeff->single_phase[0][idx++] = 0;
    coeff->single_phase[0][idx++] = 0;
    idx = 0;
    coeff->single_phase[1][idx++] = 0;
    coeff->single_phase[1][idx++] = 0;
    coeff->single_phase[1][idx++] = 256;
    coeff->single_phase[1][idx++] = 0;
    coeff->single_phase[1][idx++] = 0;

    if(VX_INTERPOLATION_BILINEAR == interpolation)
    {
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            weight = i<<2;
            coeff->multi_phase[0][idx++] = 0;
            coeff->multi_phase[0][idx++] = 0;
            coeff->multi_phase[0][idx++] = 256-weight;
            coeff->multi_phase[0][idx++] = weight;
            coeff->multi_phase[0][idx++] = 0;
        }
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            weight = (i+32)<<2;
            coeff->multi_phase[1][idx++] = 0;
            coeff->multi_phase[1][idx++] = 0;
            coeff->multi_phase[1][idx++] = 256-weight;
            coeff->multi_phase[1][idx++] = weight;
            coeff->multi_phase[1][idx++] = 0;
        }
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            weight = i<<2;
            coeff->multi_phase[2][idx++] = 0;
            coeff->multi_phase[2][idx++] = 0;
            coeff->multi_phase[2][idx++] = 256-weight;
            coeff->multi_phase[2][idx++] = weight;
            coeff->multi_phase[2][idx++] = 0;
        }
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            weight = (i+32)<<2;
            coeff->multi_phase[3][idx++] = 0;
            coeff->multi_phase[3][idx++] = 0;
            coeff->multi_phase[3][idx++] = 256-weight;
            coeff->multi_phase[3][idx++] = weight;
            coeff->multi_phase[3][idx++] = 0;
        }
    }
    else /* STR_VX_INTERPOLATION_NEAREST_NEIGHBOR */
    {
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            coeff->multi_phase[0][idx++] = 0;
            coeff->multi_phase[0][idx++] = 0;
            coeff->multi_phase[0][idx++] = 256;
            coeff->multi_phase[0][idx++] = 0;
            coeff->multi_phase[0][idx++] = 0;
        }
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            coeff->multi_phase[1][idx++] = 0;
            coeff->multi_phase[1][idx++] = 0;
            coeff->multi_phase[1][idx++] = 0;
            coeff->multi_phase[1][idx++] = 256;
            coeff->multi_phase[1][idx++] = 0;
        }
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            coeff->multi_phase[2][idx++] = 0;
            coeff->multi_phase[2][idx++] = 0;
            coeff->multi_phase[2][idx++] = 256;
            coeff->multi_phase[2][idx++] = 0;
            coeff->multi_phase[2][idx++] = 0;
        }
        idx = 0;
        for(i = 0; i < 32; i++)
        {
            coeff->multi_phase[3][idx++] = 0;
            coeff->multi_phase[3][idx++] = 0;
            coeff->multi_phase[3][idx++] = 0;
            coeff->multi_phase[3][idx++] = 256;
            coeff->multi_phase[3][idx++] = 0;
        }
    }
}

/* ========================================================================== */
/*                              Driver Callbacks                              */
/* ========================================================================== */

static int32_t tivxKernelImgMosaicMscDrvCompCb(Fvid2_Handle handle, void *appData)
{
    tivxImgMosaicMscInstObj *inst_obj = (tivxImgMosaicMscInstObj *) appData;

    if(NULL != inst_obj)
    {
        tivxEventPost(inst_obj->wait_for_compl);
    }

    return FVID2_SOK;
}

what's the matter with it?

Regards,

Jason

 

  • Hello Jason,

    A few questions for you below:

    1. Which SDK version are you using?

    2. If you run this application with the mosaic node on the C66x DSP using vxSetNodeTarget(<mosaic_node>, VX_TARGET_STRING, TIVX_TARGET_DSP1), do you still see this issue?

    3. When you have cameras disconnected, what are you passing to the mosaic node in place of those two camera images?

    Regards,

    Lucas

  • Hi Lucas,

          1.We use SDK7.1

          2.I will try it, and feedback to you

          3. An NV12 image, you know we initiate mosaic module like this:

              

              

     Regards,

    Jason

      

  • Hello Jason,

    For #3, what I am wondering about is how you are populating the image data buffers themselves.  Could you provide a diagram of the graph that you are using for this application?  It looks like the capture and VISS node creation is commented out, so is this only a single mosaic node graph or are there other connections? 

    And in the case of 8 cameras connected, are you initializing the buffers with data or are you just passing the image directly to the mosaic node?  If you do not initialize the data within the OpenVX image data buffers, they will just have junk data which you appear to be seeing.

    Regards,

    Lucas

  • Hi Lucas,

          Could you provide a diagram of the graph that you are using for this application?------Some urgent matters need to be dealt with first, I will give you feedback later.

          It looks like the capture and VISS node creation is commented out, so is this only a single mosaic node graph or are there other connections? -----Correct.

         And in the case of 8 cameras connected, are you initializing the buffers with data or are you just passing the image directly to the mosaic node? ------I will check it soon give you feedback later.

    Regards,

    Jason