Added Support for Scaling and Stitching master
authorKrunal Bhargav <a0227568@ti.com>
Fri, 16 Nov 2018 16:53:57 +0000 (10:53 -0600)
committerKrunal Bhargav <a0227568@ti.com>
Fri, 16 Nov 2018 21:50:40 +0000 (15:50 -0600)
New feature added to demonstrate GC320's ability to scale images and stitch
images together.

Signed-off-by: Krunal Bhargav <a0227568@ti.com>
disp_obj.cpp
gc320.cpp
gc320.h
main.cpp
video_graphics_test.cpp

index 7bbc3dcbfcb9c4299381c2e7344aafe845df9d81..79b5a676aba5706328e6d58d9fdfa6007abea680 100755 (executable)
@@ -137,7 +137,7 @@ int DispObj::set_properties(uint32_t src_w, uint32_t src_h,
     strcpy(propname[9], "FB_ID");
     propval[9] = fb_id;            //frame buffer id
     strcpy(propname[10], "global_alpha");
-    propval[10] = 150;             //Alpha value for blending
+    propval[10] = 200;             //Alpha value for blending
 
     /* Set the plane properties once. After that only set those properties that changes each time a frame is 
     displayed - like fb_id. */
index fee3c54e9429ce61fc49fca62ebf133cf7e61206..0d095206ee8f508355f80a0de1a3ebc8a03c6a74 100755 (executable)
--- a/gc320.cpp
+++ b/gc320.cpp
 * as they cost some performance overhead if configured per frame. Since the
 * buffer parameters aren't changing in this application run time, we can save the overhead 
 */
-Gc320Obj::Gc320Obj(uint32_t num_src_surf, uint32_t num_dst_surf, BufObj *src_bo, BufObj *dst_bo){
+Gc320Obj::Gc320Obj(uint32_t num_src, uint32_t num_src_surf, uint32_t num_dst_surf, BufObj **src_bo, BufObj *dst_bo){
     m_dst_width   = dst_bo->m_width;
     m_dst_height  = dst_bo->m_height;
     m_dst_stride  = dst_bo->m_stride; 
-    m_dst_format  = gcvSURF_UYVY; 
-
-    m_src_width  = src_bo->m_width;
-    m_src_height = src_bo->m_height;
-    m_src_stride = src_bo->m_stride;
+    m_dst_format  = gcvSURF_UYVY;
+    m_num_dst_ctx = num_dst_surf; 
+
+    m_num_src     = num_src;
+    m_num_src_ctx = num_src_surf;
+    m_src_surf_ctxt = (surf_context **) malloc(m_num_src * sizeof(*m_src_surf_ctxt));
+    m_src_width     = (uint32_t *) malloc(m_num_src * sizeof(uint32_t));
+    m_src_height    = (uint32_t *) malloc(m_num_src * sizeof(uint32_t));
+    m_src_stride    = (uint32_t *) malloc(m_num_src * sizeof(uint32_t));
     m_src_format = gcvSURF_UYVY;
 
-    m_src_surf_ctxt = (surf_context *) malloc(num_src_surf * sizeof(surf_context));
-    m_dst_surf_ctxt = (surf_context *) malloc(num_src_surf * sizeof(surf_context));
+    for (uint32_t i = 0; i < m_num_src; i++){
+           m_src_width[i]  = src_bo[i]->m_width;
+           m_src_height[i] = src_bo[i]->m_height;
+           m_src_stride[i] = src_bo[i]->m_stride;
+           m_src_surf_ctxt[i] = (surf_context *) malloc(m_num_src_ctx * sizeof(surf_context));
+    }
+    m_dst_surf_ctxt = (surf_context *) malloc(m_num_dst_ctx * sizeof(surf_context));
 
     init_gc320();
 
-    configure_surface(m_src_surf_ctxt, num_src_surf, src_bo, m_src_format);
-    configure_surface(m_dst_surf_ctxt, num_dst_surf, dst_bo, m_dst_format);
+    for (uint32_t i = 0; i < m_num_src; i++){
+           configure_surface(m_src_surf_ctxt[i], m_num_src_ctx, src_bo[i], m_src_format);
+    }
+    configure_surface(m_dst_surf_ctxt, m_num_dst_ctx, dst_bo, m_dst_format);
+
+
 }
 
 
@@ -70,49 +83,55 @@ Gc320Obj::Gc320Obj(uint32_t num_src_surf, uint32_t num_dst_surf, BufObj *src_bo,
 * free all resources
 */
 Gc320Obj::~Gc320Obj(){
-    if (m_hal != gcvNULL){
-        gcoHAL_Commit(m_hal, true);
-    }
-
-    for(uint32_t i = 0; i < m_num_dst_ctx; i++){
-        if (m_dst_surf_ctxt[i].surf != gcvNULL){
-            gceHARDWARE_TYPE type;
-
-            gcoHAL_GetHardwareType(gcvNULL, &type);
-
-            gcmVERIFY_OK(gcoSURF_Unlock(m_dst_surf_ctxt[i].surf, gcvNULL));
-            gcmVERIFY_OK(gcoSURF_Destroy(m_dst_surf_ctxt[i].surf));
-            gcmVERIFY_OK(gcoHAL_Commit(gcvNULL, true));
-
-            gcoHAL_SetHardwareType(gcvNULL, type);
-        }
-    }
-
-    for(uint32_t i = 0; i < m_num_src_ctx; i++){
-        if (m_src_surf_ctxt[i].surf != gcvNULL){
-            gceHARDWARE_TYPE type;
+       if (m_hal != gcvNULL){
+               gcoHAL_Commit(m_hal, true);
+       }
+
+       for(uint32_t i = 0; i < m_num_dst_ctx; i++){
+               if (m_dst_surf_ctxt[i].surf != gcvNULL){
+                       gceHARDWARE_TYPE type;
+                       gcoHAL_GetHardwareType(gcvNULL, &type);
+                       gcmVERIFY_OK(gcoSURF_Unlock(m_dst_surf_ctxt[i].surf, gcvNULL));
+                       gcmVERIFY_OK(gcoSURF_Destroy(m_dst_surf_ctxt[i].surf));
+                       gcmVERIFY_OK(gcoHAL_Commit(gcvNULL, true));
+                       gcoHAL_SetHardwareType(gcvNULL, type);
+               }
+       }
+
+       for(uint32_t i = 0; i < m_num_src; i++){
+               for(uint32_t j = 0; j < m_num_src_ctx; j++){
+                       if (m_src_surf_ctxt[i][j].surf != gcvNULL){
+                               gceHARDWARE_TYPE type;
+                               gcoHAL_GetHardwareType(gcvNULL, &type);
+                               gcmVERIFY_OK(gcoSURF_Unlock(m_src_surf_ctxt[i][j].surf, gcvNULL));
+                               gcmVERIFY_OK(gcoSURF_Destroy(m_src_surf_ctxt[i][j].surf));
+                               gcmVERIFY_OK(gcoHAL_Commit(gcvNULL, true));
+                               gcoHAL_SetHardwareType(gcvNULL, type);
+                       }
+               }
+       }
 
-            gcoHAL_GetHardwareType(gcvNULL, &type);
+       for (uint32_t i = 0; i < m_num_src; i++){
+               free(m_src_surf_ctxt[i]);
+       }
 
-            gcmVERIFY_OK(gcoSURF_Unlock(m_src_surf_ctxt[i].surf, gcvNULL));
-            gcmVERIFY_OK(gcoSURF_Destroy(m_src_surf_ctxt[i].surf));
-            gcmVERIFY_OK(gcoHAL_Commit(gcvNULL, true));
+       free(m_src_surf_ctxt);
+       free(m_src_width);
+       free(m_src_height);
+       free(m_src_stride);
 
-            gcoHAL_SetHardwareType(gcvNULL, type);
-        }
-    }
+       free(m_dst_surf_ctxt);
 
-    if (m_hal != gcvNULL){
-        gcoHAL_Commit(m_hal, true);
-        gcoHAL_Destroy(m_hal);
-    }
+       if (m_hal != gcvNULL){
+               gcoHAL_Commit(m_hal, true);
+               gcoHAL_Destroy(m_hal);
+       }
 
-    if (m_os != gcvNULL){
-        gcoOS_Destroy(m_os);
-    }
+       if (m_os != gcvNULL){
+               gcoOS_Destroy(m_os);
+       }
 }
 
-
 int Gc320Obj::chip_check(){
     gceSTATUS status;
     uint32_t i;
@@ -334,10 +353,11 @@ bool Gc320Obj::rotation_90deg(uint32_t src_surf_indx, uint32_t dst_surf_indx){
 
     // render to dest surface
     // blit with 90 rotation
+    // only have one surface and one destination 
     src_rect.left   = 0;
     src_rect.top    = 0;
-    src_rect.right  = m_src_width;
-    src_rect.bottom = m_src_height;
+    src_rect.right  = m_src_width[0];
+    src_rect.bottom = m_src_height[0];
 
     // set the clipping according to the rotation
     clip_rect.left       = 0;
@@ -349,14 +369,14 @@ bool Gc320Obj::rotation_90deg(uint32_t src_surf_indx, uint32_t dst_surf_indx){
 
        //Since the buffer is getting rotated 90 degree, make sure the destination buffer width is larger than source buffer height */
     dst_rect.left   = 0;
-    dst_rect.top    = (m_dst_width - m_src_height);
-    dst_rect.right  = dst_rect.left + m_src_width;
-    dst_rect.bottom = dst_rect.top + m_src_height;
+    dst_rect.top    = (m_dst_width - m_src_height[0]);
+    dst_rect.right  = dst_rect.left + m_src_width[0];
+    dst_rect.bottom = dst_rect.top + m_src_height[0];
 
     gcmONERROR(gco2D_SetGenericSource(m_engine2d,
-        m_src_surf_ctxt[src_surf_indx].phys_address, 1, &m_src_stride, 1,
+        m_src_surf_ctxt[0][src_surf_indx].phys_address, 1, &m_src_stride[0], 1,
         gcvLINEAR, m_src_format, gcvSURF_0_DEGREE,
-        m_src_width, m_src_height));
+        m_src_width[0], m_src_height[0]));
 
     gcmONERROR(gco2D_SetSource(m_engine2d, &src_rect));
 
@@ -380,4 +400,99 @@ bool Gc320Obj::rotation_90deg(uint32_t src_surf_indx, uint32_t dst_surf_indx){
 OnError:
     ERROR("Failed: %s\n", gcoOS_DebugStatus2Name(status));
        return false;
+}
+    /** For the following example, we are going to take two identical source images
+    * (640x480), scale the images down (320x480), and stitch them together on one destination image (640x480).
+    *
+    * (0,0)****************************************
+    * *[Source Image -1]       *[Source Image -2]     *
+    * *                        *                      *
+    * *[Rotated 0 degrees]     * [Rotated 90 degrees] *
+    * *                        *                      *
+    * *[320x480]               * [320x480]            *
+    * *                                *                      *
+    * *****************************************(640x480)
+    */
+bool Gc320Obj::composition(uint32_t src_surf_indx, uint32_t dst_surf_indx){
+
+    // src_rect tells GC320 which area to capture from the source image
+    // dst_rect tells GC320 where to display the captured source image
+    gcsRECT src_rect, dst_rect;
+    gceSTATUS status = gcvSTATUS_OK;
+
+    for(int i = 0; i < 2; i++){
+        gcmONERROR(gco2D_SetCurrentSourceIndex(m_engine2d, i));
+
+       gcmONERROR(gco2D_SetGenericSource(m_engine2d,
+           m_src_surf_ctxt[i][src_surf_indx].phys_address, 1,
+           &m_src_stride[i], 1, gcvLINEAR, m_src_format, gcvSURF_0_DEGREE,
+           m_src_width[i], m_src_height[i]));
+
+       switch (i % 2) {
+           case 0:
+               src_rect.left   = 0;
+               src_rect.top    = 0;
+               src_rect.right  = m_src_width[i];
+               src_rect.bottom = m_src_height[i];
+
+               dst_rect.left   = 0;
+               dst_rect.top    = 0;
+               dst_rect.right  = ((m_dst_width)/2);
+               dst_rect.bottom = m_dst_height;
+               break;
+
+            case 1:
+               src_rect.left   = 0;
+               src_rect.top    = 0;
+               src_rect.right  = m_src_height[i]; // remember we are going to rotate the image by 90 degrees
+               src_rect.bottom = m_src_width[i]; // so our width and height flip
+
+               dst_rect.left   = ((m_dst_width)/2);
+               dst_rect.top    = 0;
+               dst_rect.right  = m_dst_width;
+               dst_rect.bottom = m_dst_height;
+               break;
+
+        }
+
+       gcmONERROR(gco2D_SetSource(m_engine2d, &src_rect));
+
+       gcmONERROR(gco2D_SetGenericTarget(m_engine2d, &m_dst_surf_ctxt[dst_surf_indx].phys_address[0],
+           1, &m_dst_stride, 1, gcvLINEAR,
+           m_dst_format, gcvSURF_0_DEGREE,
+           m_dst_width,m_dst_height));
+
+       gcmONERROR(gco2D_SetClipping(m_engine2d, &dst_rect));
+
+       if (i==1){    // Second image is going to be rotated by 90 degrees
+           gcmONERROR(gco2D_FilterBlitEx2(m_engine2d,
+               m_src_surf_ctxt[i][src_surf_indx].phys_address, 1,
+               &m_src_stride[i], 1,
+               gcvLINEAR, m_src_format, gcvSURF_90_DEGREE, // to disbale the rotation change the parameter to gcvSURF_0_DEGREE
+               m_src_width[i],  m_src_height[i], &src_rect,
+               &m_dst_surf_ctxt[dst_surf_indx].phys_address[0], 1, &m_dst_stride, 1,
+               gcvLINEAR, m_dst_format, gcvSURF_0_DEGREE,
+               m_dst_width, m_dst_height, &dst_rect, gcvNULL));
+       }
+
+       else{
+           gcmONERROR(gco2D_FilterBlitEx2(m_engine2d,
+               m_src_surf_ctxt[i][src_surf_indx].phys_address, 1,
+               &m_src_stride[i], 1,
+               gcvLINEAR, m_src_format, gcvSURF_0_DEGREE,
+               m_src_width[i],  m_src_height[i], &src_rect,
+               &m_dst_surf_ctxt[dst_surf_indx].phys_address[0], 1, &m_dst_stride, 1,
+               gcvLINEAR, m_dst_format, gcvSURF_0_DEGREE,
+               m_dst_width, m_dst_height, &dst_rect, gcvNULL));
+       }
+
+
+    }
+    gcmONERROR(gco2D_Flush(m_engine2d));
+    gcmONERROR(gcoHAL_Commit(m_hal, true));
+
+    return true;
+OnError:
+    ERROR("Failed: %s\n", gcoOS_DebugStatus2Name(status));
+    return false;
 }
diff --git a/gc320.h b/gc320.h
index 399d9cb554f1bb28533c12bcc03a42018f2da6c4..8d98235a47f5938eacd28a4eeba97c1e37369d3f 100755 (executable)
--- a/gc320.h
+++ b/gc320.h
@@ -54,7 +54,7 @@ class Gc320Obj
 public:
 
     /// Constructor
-    Gc320Obj(uint32_t num_src_surf, uint32_t num_dst_surf, BufObj *src_bo, BufObj *dst_bo);
+    Gc320Obj(uint32_t num_src, uint32_t num_src_surf, uint32_t num_dst_surf, BufObj **src_bo, BufObj *dst_bo);
     ~Gc320Obj();
 
     /**
@@ -75,6 +75,18 @@ public:
     */
     bool rotation_90deg(uint32_t a, uint32_t b);
 
+    /**
+    * gc320 composition()
+    * Purpose: Program GC320 to stitch two images together
+    * One image will be rotated 90 degrees and the second image will be rotated 0 degrees
+    *
+    * @param index to source surface
+    * @param index to desitination surface
+    *
+    * @return bool true/success or false/failure
+    */
+    bool composition(uint32_t src_surf_indx, uint32_t dst_surf_indx);
+
 
 private:
 
@@ -101,7 +113,7 @@ private:
     gcoHAL          m_hal;
     gco2D           m_engine2d;
 
-    /* Dest surface. */
+    /* Dest surface. (1 Dest. Surface) */
     gceSURF_FORMAT m_dst_format;
     uint32_t      m_dst_width;
     uint32_t      m_dst_height;
@@ -109,13 +121,14 @@ private:
     surf_context  *m_dst_surf_ctxt;
     uint32_t       m_num_dst_ctx;
 
-    /* Source surface. */
+    /* Source surface. (1 or more Source Surface) */
     gceSURF_FORMAT m_src_format;
-    uint32_t      m_src_width;
-    uint32_t      m_src_height;
-    uint32_t      m_src_stride;
-    surf_context  *m_src_surf_ctxt;
+    uint32_t      *m_src_width;
+    uint32_t      *m_src_height;
+    uint32_t      *m_src_stride;
+    surf_context  **m_src_surf_ctxt;
     uint32_t       m_num_src_ctx;
+    uint32_t      m_num_src; // Defines number of source surface
 };
 
 #endif // GC320_H
index c7194dacca383eef2d836d6b0cfebd854d12851f..37e349e4b5bce38e6f3119b7d596e6d4bf28d409 100644 (file)
--- a/main.cpp
+++ b/main.cpp
@@ -51,7 +51,7 @@ DSS IP like scaling, alpha blending and overlaying. Along with DSS advance capab
 QPA for hardware accelerated rendering of the graphcis content on SGX, this application also 
 demonstrates video rotation feature using GC320 IP, video capture using VIP interface and 
 displaying these content on two screens. The data flow is as follows
-             ---->GC320 rotate 90 degree --> QT QPA (draws the graphics content from qml file, scale, alpha blend and overlay (on DSS) the video with SGX output)
+             ---->GC320 stitch/rotate 90 degree --> QT QPA (draws the graphics content from qml file, scale, alpha blend and overlay (on DSS) the video with SGX output)
                        |
 VIP Capture -
             |
index 248a7d55a4aac7d4fd8fa4fd4084f74f678d5a45..7b3a849a0a2b4e118944fe47daad5e54f02bca79 100755 (executable)
     ((uint32_t)(uint8_t)(d) << 24 ))
 #define FOURCC_STR(str)    FOURCC(str[0], str[1], str[2], str[3])
 
-#define DISP_QUEUE_DEPTH 4
+#define DISP_QUEUE_DEPTH 2
 #define NUM_CAP_BUFS      (DISP_QUEUE_DEPTH+3)
 #define NUM_GC320_BUFS    (DISP_QUEUE_DEPTH+1)
 #define CAP_W 640
 #define CAP_H 480
+#define NUM_SRC 2  // Defines how many input sources the user wants to use
 #define DEQUEUE_WAIT_TIME 100 //worst case wait for 30 ms before flagging error
 
 uint32_t gc320_buf_idx[NUM_GC320_BUFS];
@@ -73,8 +74,11 @@ void run_video_graphics_test(BufObj *bo_cap, BufObj *bo_gc320, V4l2Obj *cap,
         //Get the capture video
         int cap_buf_index = cap->dequeue_buf();
 
-        //Call GC320 for 90 degree rotation on captured video
-        gc320_proc->rotation_90deg(cap_buf_index, gc320_buf_idx);
+       //Call rotation_90deg for just rotating the image (By default not called)
+        //Call GC320 for stitching two captured video together
+        if(gc320_proc->composition(cap_buf_index, gc320_buf_idx) == false){
+               ERROR("error running gc320 example\n");
+       }
 
         //Queue the GC320 processed video to scale, overlay and alpha blend with graphics and display on DISPLAY1
         //There can be multiple (on AM57x, upto 3 planes) video planes that can be submitted to same display
@@ -139,11 +143,16 @@ void VideoGraphicsThread::run(){
 
     uint32_t cap_w = CAP_W;
     uint32_t cap_h = CAP_H;
+    uint32_t num_src = NUM_SRC;// Set the number of source to 1 if running the rotation_90deg test (Default=2 sources) 
 
-    /* Since in this example GC320 is rotating the capture video input to 90 degree,
-          make sure the GC320 output buffer width is larger than capture buffer height */
-       uint32_t gc320_out_w = (cap_w > cap_h) ? cap_w : cap_h; // 
-    uint32_t gc320_out_h = gc320_out_w;
+    // Going to create the GC320 output buffer 
+    // Swap the width and height if running the rotation_90deg test (Not required for the composition test)
+    uint32_t gc320_out_w = cap_w;
+    uint32_t gc320_out_h = cap_h;
+
+    // Set Display width/height
+    uint32_t screen_w = cap_w;
+    uint32_t screen_h = cap_h;
 
     bool dual_display = (g_qt_app->screens().count() > 1) ? true : false;
 
@@ -162,15 +171,22 @@ void VideoGraphicsThread::run(){
     }
 
     /*Create buffer objects for GC320 output
-       * Vivante needs address to be 0x80 bytes aligned
-       * Vivante HAL needs 16 pixel alignment in width and 4 pixel alignment in
-    * height.
-    */
+     * Vivante needs address to be 0x80 bytes aligned
+     * Vivante HAL needs 16 pixel alignment in width and 4 pixel alignment in
+     * height.
+     */
     BufObj bo_gc320_out(gc320_out_w, gc320_out_h, 2, FOURCC_STR("YUYV"), 0x80, NUM_GC320_BUFS);
 
     //Create GC320 object
     //Initialize GC320 core, and it's input and output surfaces
-    Gc320Obj gc320_proc(NUM_CAP_BUFS, NUM_GC320_BUFS, &bo_cap, &bo_gc320_out);
+    //
+    //Note for the second input I am passing the same buffer oject as the first input
+    BufObj *gc320_in[num_src];
+    for (uint32_t i = 0; i < num_src; i++){
+           gc320_in[i] = &bo_cap;// this can take buffer objects from different sources
+    }
+
+    Gc320Obj gc320_proc(num_src, NUM_CAP_BUFS, NUM_GC320_BUFS, gc320_in, &bo_gc320_out);
 
     //Create QT QPA object to get handles of various APIs from QT QPA to configure DSS hardware planes for video scaling and overlays
     QpaCtlObj qpa_ctl(g_qt_app);
@@ -195,11 +211,12 @@ void VideoGraphicsThread::run(){
 
        uint32_t offset = 0;
     for (uint32_t i = 0; i < NUM_GC320_BUFS; i++) {
-               /* Export the video overlay buffers to DISPLAY1
-               GC320 processed (90 degree rotated) video will be displayed on DISPLAY1
-               Since the video is 90 degree rotated to original content, buffer width and height are swapped
-               */
-        disp1.export_buf2_qpa(cap_h, cap_w, FOURCC_STR("YUYV"), &bo_gc320_out.m_stride, &offset,  bo_gc320_out.m_fd[i], 
+       /* Export the video overlay buffers to DISPLAY1
+       GC320 processed (90 degree rotated) video will be displayed on DISPLAY1
+       Since the video is 90 degree rotated to original content, buffer width and height are swapped
+       NO swapping required for the composition test
+       */
+        disp1.export_buf2_qpa(screen_w, screen_h, FOURCC_STR("YUYV"), &bo_gc320_out.m_stride, &offset,  bo_gc320_out.m_fd[i], 
             &bo_gc320_out.m_fb_id[i]);
     }
 
@@ -210,17 +227,18 @@ void VideoGraphicsThread::run(){
         //Export the video overlay buffers to DISPLAY2
         //Camera captured buffers will be displayed on DISPLAY2
         if(dual_display)
-            disp2.export_buf2_qpa(cap_w, cap_h, FOURCC_STR("YUYV"), &bo_cap.m_stride, &offset,  bo_cap.m_fd[i], 
+            disp2.export_buf2_qpa(screen_w, screen_h, FOURCC_STR("YUYV"), &bo_cap.m_stride, &offset,  bo_cap.m_fd[i], 
             &bo_cap.m_fb_id[i]);
     }
 
     //Set the DSS hardware video plane properties for Display1
     //Since we are rotating the capture buffer by 90 degree and displaying it, the width and height are swapped
-    disp1.set_properties(cap_h, cap_w, bo_gc320_out.m_fb_id[0], 0);
+    //NO swapping required for the composition test
+    disp1.set_properties(screen_w, screen_h, bo_gc320_out.m_fb_id[0], 0);
 
     //Set the DSS hardware video plane properties for Display2
     if(dual_display)
-        disp2.set_properties(cap_w, cap_h, bo_cap.m_fb_id[0], 0);
+        disp2.set_properties(screen_w, screen_h, bo_cap.m_fb_id[0], 0);
 
     //Start camera streaming
     if (vip_cap.stream_on() < 0) exit(-1);