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: M2M display example?

Part Number: TDA4VH-Q1

Hi experts,

I'm trying to use multi-display to display several images.

There are only 2 default display (TIVX_TARGET_DISPLAY1 and TIVX_TARGET_DISPLAY2).

Now I want to add (TIVX_TARGET_DISPLAY_M2M1, TIVX_TARGET_DISPLAY_M2M2, TIVX_TARGET_DISPLAY_M2M3), but don't know how to use them.

Are there any example code that I can refer to?

Thanks

  • You can create separate display node, add target as TIVX_TARGET_DISPLAY1 and TIVX_TARGET_DISPLA2 and start using it. You can refer to below FAQ, which uses similar approach.

    https://e2e.ti.com/support/processors-group/processors/f/processors-forum/1107628/faq-processor-sdk-j721e-how-to-enable-multiple-displays-by-sending-bigger-size-frames-from-dss

    Regards,

    Brijesh

  • Hi,

    Thanks for providing this example.

    How do you verify graph here?

    I tried to use 2 displayObj for TIVX_TARGET_DISPLAY1, but stuck at vxVerifyGraph.

  • No, you should use difference target for each display node and also different display pipeid.. using same pipeld or target id is incorrect for the display node. 

    Regards,

    Brijesh

  • Hi,

    Does this mean I can only display two images?

    I want to display total 5 images here.

  • Hi,

    What do you mean displaying 5 images? I didn't get it, can you please elaborate? 

    Regards,

    Brijesh

  • For each iteration in vxProcessGraph, I want to show a total of 5 images in the display at the same time, like this image:

  • In this case, you can use mosaic node to create this layout from 5 images. This is possible using mosaic node, there is no need to use multiple display nodes in this case. 

    Regards,

    Brijesh

  • Hi,

    For the rightmost image, is it able to set it in mosaic node too? Is there example code for mosaic node usage

  • Yes, if you set the position and size correctly, it can generate this output image from the input object array.

    Regards,

    Brijesh

  • Ok, got it. By the way, do you have some straightforward example for mosaicnode usage

    Like which you provided for displaynode last time.

    /*
    *
    * Copyright (c) 2017 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 <stdio.h>
    #include <VX/vx.h>
    #include <TI/tivx.h>
    #include <vx_internal.h>
    #include <TI/video_io_kernels.h>
    #include <TI/video_io_display.h>
    #include <utils/app_init/include/app_init.h>
    
    
    static vx_status readYUVInput(char* file_name, vx_image in_img)
    {
        vx_status status;
    
        FILE * fp = fopen(file_name,"rb");
        vx_int32 j;
    
        if(fp == NULL)
        {
            printf("Unable to open file %s \n", file_name);
            return (VX_FAILURE);
        }
    
        vx_rectangle_t rect;
        vx_imagepatch_addressing_t image_addr;
        vx_map_id map_id;
        void * data_ptr;
        vx_uint32  img_width;
        vx_uint32  img_height;
        vx_uint32  num_bytes = 0;
    
        vxQueryImage(in_img, VX_IMAGE_WIDTH, &img_width, sizeof(vx_uint32));
        vxQueryImage(in_img, VX_IMAGE_HEIGHT, &img_height, sizeof(vx_uint32));
    
        printf("%d x %d \n", img_width, img_height);
    
        rect.start_x = 0;
        rect.start_y = 0;
        rect.end_x = img_width;
        rect.end_y = img_height;
        status = vxMapImagePatch(in_img,
                                &rect,
                                0,
                                &map_id,
                                &image_addr,
                                &data_ptr,
                                VX_WRITE_ONLY,
                                VX_MEMORY_TYPE_HOST,
                                VX_NOGAP_X);
    
        /* Copy Luma */
        for (j = 0; j < img_height; j++)
        {
            num_bytes += fread(data_ptr, 1, img_width, fp);
            data_ptr += image_addr.stride_y;
        }
        printf("data_ptr = 0x%p\n", data_ptr);
    
        if(num_bytes != (img_width*img_height))
        {
            printf("Luma bytes read = %d, expected = %d\n", num_bytes, img_width*img_height);
        }
        else
        {
            printf("Luma bytes success read = %d, expected = %d\n", num_bytes, img_width*img_height);
        }
    
        vxUnmapImagePatch(in_img, map_id);
    
        rect.start_x = 0;
        rect.start_y = 0;
        rect.end_x = img_width;
        rect.end_y = img_height / 2;
        status = vxMapImagePatch(in_img,
                                &rect,
                                1,
                                &map_id,
                                &image_addr,
                                &data_ptr,
                                VX_WRITE_ONLY,
                                VX_MEMORY_TYPE_HOST,
                                VX_NOGAP_X);
    
        /* Copy CbCr */
        num_bytes = 0;
        for (j = 0; j < img_height/2; j++)
        {
            num_bytes += fread(data_ptr, 1, img_width, fp);
            data_ptr += image_addr.stride_y;
        }
        printf("U data_ptr = 0x%p\n", data_ptr);
    
        if(num_bytes != (img_width*img_height/2))
        {
            printf("CbCr bytes read = %d, expected = %d\n", num_bytes, img_width*img_height/2);
        }
        else
        {
            printf("CbCr bytes success read = %d, expected = %d\n", num_bytes, img_width*img_height/2);
        }
    
        vxUnmapImagePatch(in_img, map_id);
    
        fclose(fp);
    
        return(status);
    }
    
    static vx_status writeYUVInput(char* file_name, vx_image out_img)
    {
        vx_status status;
    
        FILE * fp = fopen(file_name,"wb");
        vx_int32 j;
    
        if(fp == NULL)
        {
            printf("Unable to open file %s \n", file_name);
            return (VX_FAILURE);
        }
    
        vx_rectangle_t rect;
        vx_imagepatch_addressing_t image_addr;
        vx_map_id map_id;
        void * data_ptr;
        vx_uint32  img_width;
        vx_uint32  img_height;
        vx_uint32  num_bytes = 0;
    
        vxQueryImage(out_img, VX_IMAGE_WIDTH, &img_width, sizeof(vx_uint32));
        vxQueryImage(out_img, VX_IMAGE_HEIGHT, &img_height, sizeof(vx_uint32));
    
        rect.start_x = 0;
        rect.start_y = 0;
        rect.end_x = img_width;
        rect.end_y = img_height;
        status = vxMapImagePatch(out_img,
                                &rect,
                                0,
                                &map_id,
                                &image_addr,
                                &data_ptr,
                                VX_READ_ONLY,
                                VX_MEMORY_TYPE_HOST,
                                VX_NOGAP_X);
    
        /* Copy Luma */
        for (j = 0; j < img_height; j++)
        {
            num_bytes += fwrite(data_ptr, 1, img_width, fp);
            data_ptr += image_addr.stride_y;
        }
        printf("O data_ptr = 0x%p\n", data_ptr);
    
        if(num_bytes != (img_width*img_height))
            printf("Luma bytes written = %d, expected = %d\n", num_bytes, img_width*img_height);
    
        vxUnmapImagePatch(out_img, map_id);
    
        rect.start_x = 0;
        rect.start_y = 0;
        rect.end_x = img_width;
        rect.end_y = img_height / 2;
        status = vxMapImagePatch(out_img,
                                &rect,
                                1,
                                &map_id,
                                &image_addr,
                                &data_ptr,
                                VX_READ_ONLY,
                                VX_MEMORY_TYPE_HOST,
                                VX_NOGAP_X);
    
        /* Copy CbCr */
        num_bytes = 0;
        for (j = 0; j < img_height/2; j++)
        {
            num_bytes += fwrite(data_ptr, 1, img_width, fp);
            data_ptr += image_addr.stride_y;
        }
        printf("OU data_ptr = 0x%p\n", data_ptr);
    
        if(num_bytes != (img_width*img_height/2))
            printf("CbCr bytes written = %d, expected = %d\n", num_bytes, img_width*img_height/2);
    
        vxUnmapImagePatch(out_img, map_id);
    
        fclose(fp);
    
        return(status);
    }
    
    /**
     * \brief Tutorial Entry Point
     */
    int main()
    {
        int status = 0;
        tivx_display_params_t display_params;
        vx_user_data_object display_param_obj;
        vx_node displayNode;
        vx_image display_image;
        int i = 0;
        vx_imagepatch_addressing_t  input_image_addr, display_image_addr;
        tivx_obj_desc_image_t *input_obj_desc = NULL;
        tivx_obj_desc_image_t *output_obj_desc = NULL;
    
        status = appInit();
    
        if(status == VX_SUCCESS)
        {
    
            vx_context context = vxCreateContext();
    
            tivxVideoIOLoadKernels(context);
    
            vx_graph graph = vxCreateGraph(context);
    
            memset(&display_params, 0, sizeof(tivx_display_params_t));
            display_params.opMode = TIVX_KERNEL_DISPLAY_ZERO_BUFFER_COPY_MODE;
            display_params.pipeId = 2;
            display_params.outHeight = OUTPUT_TEX_HEIGHT;
            display_params.outWidth = OUTPUT_TEX_WIDTH;
            display_params.posX = 0;
            display_params.posY = 0;
    
            display_image = vxCreateImage(context, OUTPUT_TEX_WIDTH, OUTPUT_TEX_HEIGHT, VX_DF_IMAGE_NV12);
    
            // Display Initialization    
    
            display_param_obj = vxCreateUserDataObject(context, "tivx_display_params_t", sizeof(tivx_display_params_t), &display_params);
            displayNode = tivxDisplayNode(graph, display_param_obj, display_image);
    
            if(status == VX_SUCCESS)
            {
                status = vxSetNodeTarget(displayNode, VX_TARGET_STRING, TIVX_TARGET_DISPLAY1);
                printf("Display Set Target done\n");
            }
    
            if(status == VX_SUCCESS)
            {
                status = vxVerifyGraph(graph);
                printf("Verify Graph\n");
            }
    
            status = readYUVInput(IN_FILE_NAME, display_image);
            printf("Input file filled\n");
    
            if(status == VX_SUCCESS)
            {
                status = writeYUVInput(OUT_FILE_NAME, display_image);
                printf("Output file to test if the image read correctly before sending to display\n");
            }
            if(status == VX_SUCCESS)
            {
                if(status == VX_SUCCESS)
                {
                    for(i = 0; i < LOOPCOUNT; i++)
                    {
                        status = vxProcessGraph(graph);
                    }
                }
            }
    
    
            if(status == VX_SUCCESS)
            {
                status = vxReleaseUserDataObject(&display_param_obj);
    
                status |= vxReleaseImage(&display_image);
    
                status |= vxReleaseNode(&displayNode);
    
                status |= vxReleaseGraph(&graph);
    
                tivxVideoIOUnLoadKernels(context);
        
                status |= vxReleaseContext(&context);
                printf("Release Graph and context\n");
            }
        }
        else
        {
            printf("app init fail \n");
        }
    
        return 0;
    }
    

  • Hi,

    I think you can refer to multiple camera example. It uses mosaic node to create 2x2 or 3x3 mosaic output. You can update it based on your requirement. 

    Regards,

    Brijesh