Adding Error Check for Output Buffer Size

The output buffer size given by the application, needs to be checked
in every process call. This is required in the case of resolution
change.

Bug: 70399408
Test: manual
Change-Id: Id0d615e44d30f61702b3839be7b679d7d77a2411
(cherry picked from commit 7c88212153fbff998b337e899b496e2e382af54c)
diff --git a/decoder/impeg2d_api_main.c b/decoder/impeg2d_api_main.c
index 0a59310..847c4f7 100644
--- a/decoder/impeg2d_api_main.c
+++ b/decoder/impeg2d_api_main.c
@@ -125,6 +125,7 @@
 
 void impeg2d_init_arch(void *pv_codec);
 void impeg2d_init_function_ptr(void *pv_codec);
+UWORD32 impeg2d_get_outbuf_size(WORD32 pic_wd,UWORD32 pic_ht, WORD32 u1_chroma_format,UWORD32 *p_buf_size);
 
 /*****************************************************************************/
 /*                                                                           */
@@ -211,6 +212,8 @@
     dec_state_t *ps_dec_state;
     dec_state_multi_core_t *ps_dec_state_multi_core;
     UWORD32 u4_num_disp_bufs;
+    UWORD32 u4_disp_buf_size[3];
+    UWORD32 num_bufs;
 
 
     dec_disp_ip = (ivd_set_display_frame_ip_t  *)pv_api_ip;
@@ -224,12 +227,41 @@
     ps_dec_state_multi_core = (dec_state_multi_core_t *) (ps_dechdl->pv_codec_handle);
     ps_dec_state = ps_dec_state_multi_core->ps_dec_state[0];
 
+    num_bufs = dec_disp_ip->s_disp_buffer[0].u4_num_bufs;
+
     if(ps_dec_state->u4_share_disp_buf)
     {
         pic_buf_t *ps_pic_buf;
         ps_pic_buf = (pic_buf_t *)ps_dec_state->pv_pic_buf_base;
+
+        /* Get the sizes of the first buffer structure. Compare this with the
+         * rest to make sure all the buffers are of the same size.
+         */
+        u4_disp_buf_size[0] =
+            dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[0];
+        u4_disp_buf_size[1] =
+            dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[1];
+        u4_disp_buf_size[2] =
+            dec_disp_ip->s_disp_buffer[0].u4_min_out_buf_size[2];
         for(i = 0; i < u4_num_disp_bufs; i++)
         {
+            /* Verify all buffer structures have the same sized buffers as the
+             * first buffer structure*/
+            if ((dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[0]
+                 != u4_disp_buf_size[0])
+                 || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[1]
+                     != u4_disp_buf_size[1])
+                 || (dec_disp_ip->s_disp_buffer[i].u4_min_out_buf_size[2]
+                     != u4_disp_buf_size[2]))
+            {
+              return IV_FAIL;
+            }
+            /* Verify all buffer structures have the same number of
+             * buffers (e.g. y, u, v) */
+            if (dec_disp_ip->s_disp_buffer[i].u4_num_bufs != num_bufs)
+            {
+                return IV_FAIL;
+            }
 
             ps_pic_buf->pu1_y = dec_disp_ip->s_disp_buffer[i].pu1_bufs[0];
             if(IV_YUV_420P == ps_dec_state->i4_chromaFormat)
@@ -764,35 +796,6 @@
     ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_in_bufs = 1;
     ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs = 1;
 
-    if(ps_dec_state->i4_chromaFormat == IV_YUV_420P)
-    {
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
-                        MIN_OUT_BUFS_420;
-    }
-    else if((ps_dec_state->i4_chromaFormat == IV_YUV_420SP_UV)
-                    || (ps_dec_state->i4_chromaFormat == IV_YUV_420SP_VU))
-    {
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
-                        MIN_OUT_BUFS_420SP;
-    }
-    else if(ps_dec_state->i4_chromaFormat == IV_YUV_422ILE)
-    {
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
-                        MIN_OUT_BUFS_422ILE;
-    }
-    else if(ps_dec_state->i4_chromaFormat == IV_RGB_565)
-    {
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
-                        MIN_OUT_BUFS_RGB565;
-    }
-    else
-    {
-        //Invalid chroma format; Error code may be updated, verify in testing if needed
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code =
-                        IVD_INIT_DEC_COL_FMT_NOT_SUPPORTED;
-        return IV_FAIL;
-    }
-
     for(u4_i = 0; u4_i < IVD_VIDDEC_MAX_IO_BUFFERS; u4_i++)
     {
         ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_in_buf_size[u4_i] =
@@ -827,31 +830,19 @@
     u4_stride = ALIGN16(u4_stride);
     u4_height = ALIGN32(ps_dec_state->u2_frame_height) + 9;
 
-    if(ps_dec_state->i4_chromaFormat == IV_YUV_420P)
+    ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs =
+                    impeg2d_get_outbuf_size(
+                                    u4_stride,
+                                    u4_height,
+                                    ps_dec_state->i4_chromaFormat,
+                                    &ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0]);
+
+    if (0 == ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_num_out_bufs)
     {
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0] =
-                        (u4_stride * u4_height);
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[1] =
-                        (u4_stride * u4_height) >> 2;
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[2] =
-                        (u4_stride * u4_height) >> 2;
-    }
-    else if((ps_dec_state->i4_chromaFormat == IV_YUV_420SP_UV)
-                    || (ps_dec_state->i4_chromaFormat == IV_YUV_420SP_VU))
-    {
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0] =
-                        (u4_stride * u4_height);
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[1] =
-                        (u4_stride * u4_height) >> 1;
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[2] = 0;
-    }
-    else if(ps_dec_state->i4_chromaFormat == IV_YUV_422ILE)
-    {
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[0] =
-                        (u4_stride * u4_height) * 2;
-        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[1] =
-                        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_min_out_buf_size[2] =
-                                        0;
+        //Invalid chroma format; Error code may be updated, verify in testing if needed
+        ps_ctl_bufinfo_op->s_ivd_ctl_getbufinfo_op_t.u4_error_code =
+                        IVD_INIT_DEC_COL_FMT_NOT_SUPPORTED;
+        return IV_FAIL;
     }
 
     /* Adding initialization for 2 uninitialized values */
@@ -1514,6 +1505,100 @@
 
 }
 
+UWORD32 impeg2d_get_outbuf_size(WORD32 pic_wd,UWORD32 pic_ht, WORD32 u1_chroma_format,UWORD32 *p_buf_size)
+{
+    UWORD32 u4_min_num_out_bufs = 0;
+    if(u1_chroma_format == IV_YUV_420P)
+        u4_min_num_out_bufs = MIN_OUT_BUFS_420;
+    else if(u1_chroma_format == IV_YUV_422ILE)
+        u4_min_num_out_bufs = MIN_OUT_BUFS_422ILE;
+    else if(u1_chroma_format == IV_RGB_565)
+        u4_min_num_out_bufs = MIN_OUT_BUFS_RGB565;
+    else if((u1_chroma_format == IV_YUV_420SP_UV)
+                    || (u1_chroma_format == IV_YUV_420SP_VU))
+        u4_min_num_out_bufs = MIN_OUT_BUFS_420SP;
+
+    if(u1_chroma_format == IV_YUV_420P)
+    {
+        p_buf_size[0] = (pic_wd * pic_ht);
+        p_buf_size[1] = (pic_wd * pic_ht)
+                        >> 2;
+        p_buf_size[2] = (pic_wd * pic_ht)
+                        >> 2;
+    }
+    else if(u1_chroma_format == IV_YUV_422ILE)
+    {
+        p_buf_size[0] = (pic_wd * pic_ht)
+                        * 2;
+        p_buf_size[1] =
+                        p_buf_size[2] = 0;
+    }
+    else if(u1_chroma_format == IV_RGB_565)
+    {
+        p_buf_size[0] = (pic_wd * pic_ht)
+                        * 2;
+        p_buf_size[1] =
+                        p_buf_size[2] = 0;
+    }
+    else if((u1_chroma_format == IV_YUV_420SP_UV)
+                    || (u1_chroma_format == IV_YUV_420SP_VU))
+    {
+        p_buf_size[0] = (pic_wd * pic_ht);
+        p_buf_size[1] = (pic_wd * pic_ht)
+                        >> 1;
+        p_buf_size[2] = 0;
+    }
+
+    return u4_min_num_out_bufs;
+}
+
+WORD32 check_app_out_buf_size(dec_state_t *ps_dec)
+{
+    UWORD32 au4_min_out_buf_size[IVD_VIDDEC_MAX_IO_BUFFERS];
+    UWORD32 u4_min_num_out_bufs, i;
+    UWORD32 pic_wd, pic_ht;
+
+    pic_wd = ps_dec->u2_horizontal_size;
+    pic_ht = ps_dec->u2_vertical_size;
+
+    if(ps_dec->u4_frm_buf_stride > pic_wd)
+        pic_wd = ps_dec->u4_frm_buf_stride;
+
+    u4_min_num_out_bufs = impeg2d_get_outbuf_size(pic_wd, pic_ht, ps_dec->i4_chromaFormat, &au4_min_out_buf_size[0]);
+
+    if (0 == ps_dec->u4_share_disp_buf)
+    {
+        if(ps_dec->ps_out_buf->u4_num_bufs < u4_min_num_out_bufs)
+        {
+            return IV_FAIL;
+        }
+
+        for (i = 0 ; i < u4_min_num_out_bufs; i++)
+        {
+            if(ps_dec->ps_out_buf->u4_min_out_buf_size[i] < au4_min_out_buf_size[i])
+                return (IV_FAIL);
+        }
+    }
+    else
+    {
+        if(ps_dec->as_disp_buffers[0].u4_num_bufs < u4_min_num_out_bufs)
+            return IV_FAIL;
+
+        for (i = 0 ; i < u4_min_num_out_bufs; i++)
+        {
+            /* We need to check only with the disp_buffer[0], because we have
+            * already ensured that all the buffers are of the same size in
+            * impeg2d_api_set_display_frame.
+            */
+            if(ps_dec->as_disp_buffers[0].u4_min_out_buf_size[i] <
+                   au4_min_out_buf_size[i])
+                return (IV_FAIL);
+        }
+    }
+
+    return(IV_SUCCESS);
+}
+
 
 
 /*****************************************************************************/
@@ -1797,7 +1882,6 @@
         }
     }
 
-
     ps_dec_state = ps_dec_state_multi_core->ps_dec_state[0];
 
     if((ps_dec_state->i4_chromaFormat  == IV_YUV_422ILE)
@@ -3379,6 +3463,13 @@
             {
                 ps_dec_state->u1_flushcnt    = 0;
 
+                ps_dec_state->ps_out_buf = &ps_dec_ip->s_ivd_video_decode_ip_t.s_out_buffer;
+                if (IV_SUCCESS != check_app_out_buf_size(ps_dec_state))
+                {
+                    ps_dec_op->s_ivd_video_decode_op_t.u4_error_code = IVD_DISP_FRM_ZERO_OP_BUF_SIZE;
+                    return IV_FAIL;
+                }
+
                 /*************************************************************************/
                 /*                              Frame Decode                             */
                 /*************************************************************************/
diff --git a/decoder/impeg2d_structs.h b/decoder/impeg2d_structs.h
index 46538bf..bdda8b8 100644
--- a/decoder/impeg2d_structs.h
+++ b/decoder/impeg2d_structs.h
@@ -363,6 +363,8 @@
     /* Number of bytes in the input bitstream */
     UWORD32         u4_num_inp_bytes;
 
+    ivd_out_bufdesc_t *ps_out_buf;
+
     /* Bytes consumed */
     WORD32          i4_bytes_consumed;
 
diff --git a/test/decoder/main.c b/test/decoder/main.c
index 7a6db46..6229f50 100644
--- a/test/decoder/main.c
+++ b/test/decoder/main.c
@@ -2246,6 +2246,7 @@
                             u4_ip_buf_len);
                     codec_exit(ac_error_str);
                 }
+
                 s_app_ctx.num_disp_buf = s_ctl_op.u4_num_disp_bufs;
                 /* Allocate output buffer only if display buffers are not shared */
                 /* Or if shared and output is 420P */
@@ -3012,6 +3013,12 @@
 
                     break;
                 }
+                else if (IVD_DISP_FRM_ZERO_OP_BUF_SIZE ==
+                                (IMPEG2D_ERROR_CODES_T)s_video_decode_op.u4_error_code)
+                {
+                    printf("Output buffer is not large enough!\n");
+                    break;
+                }
             }
 
             if((1 == s_app_ctx.display) &&