Camera3: Handle different aspect ratios for thumbnail and main image

If thumbnail and main image aspect ratios are different, crop
the crop the thumbnail before downscale to prevent distortion/streching.
Also ensure thumbnail FOV is not outside the main image FOV in case
main image is cropped.

Bug: 14322819
Change-Id: I9b56fb8e94f92018aa7e8d8c2e50a7f855a4a426
diff --git a/camera/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h b/camera/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
index 629049d..55ac502 100644
--- a/camera/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
+++ b/camera/QCamera2/stack/mm-jpeg-interface/inc/mm_jpeg.h
@@ -43,6 +43,7 @@
 #define MM_JPEG_CIRQ_SIZE 30
 #define MM_JPEG_MAX_SESSION 10
 #define MAX_EXIF_TABLE_ENTRIES 50
+#define ASPECT_TOLERANCE 0.001
 
 typedef struct {
   struct cam_list list;
diff --git a/camera/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c b/camera/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
index bb72cfa..5b82bdb 100644
--- a/camera/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
+++ b/camera/QCamera2/stack/mm-jpeg-interface/src/mm_jpeg.c
@@ -35,6 +35,7 @@
 #include <sys/prctl.h>
 #include <fcntl.h>
 #include <poll.h>
+#include <math.h>
 
 #include "mm_jpeg_dbg.h"
 #include "mm_jpeg_interface.h"
@@ -105,6 +106,23 @@
 #define GET_SESSION_IDX(x) (((x) >> 8) & 0xff)
 #define GET_JOB_IDX(x) (((x) >> 16) & 0xff)
 
+/** GCD:
+ *  @x: input number
+ *  @y: input number
+ *  @gcd: gcd of x and y
+ *
+ *  Find the GCD of 2 numbers
+ **/
+#define GCD( x, y, gcd) ({ \
+  int tmp; \
+  while (*y != 0) { \
+    tmp = *x % *y; \
+    *x = *y; \
+    *y = tmp; \
+  } \
+  *gcd = *x; \
+})
+
 OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent,
     OMX_PTR pAppData,
     OMX_BUFFERHEADERTYPE* pBuffer);
@@ -778,6 +796,50 @@
   return ret;
 }
 
+/** mm_jpeg_get_thumbnail_crop
+ *
+ *  Arguments:
+ *    @p_thumb_dim: thumbnail dimension
+ *    @p_main_dim: main image dimension
+ *    @crop_width : flag indicating if width needs to be cropped
+ *
+ *  Return:
+ *       OMX error values
+ *
+ *  Description:
+ *    If the main image and thumbnail ascpect ratios are differnt,
+ *    re-calculate the thumbnail crop info to prevent distortion
+ *
+ */
+OMX_ERRORTYPE mm_jpeg_get_thumbnail_crop(mm_jpeg_dim_t *p_thumb_dim,
+  mm_jpeg_dim_t *p_main_dim, uint8_t crop_width) {
+  OMX_ERRORTYPE ret = OMX_ErrorNone;
+  int divisor;
+  int cropped_width = 0, cropped_height = 0;
+
+  if(crop_width) {
+   //Keep height constant
+   cropped_height = p_thumb_dim->src_dim.height;
+   cropped_width =  floor((cropped_height * p_thumb_dim->dst_dim.width) /
+      p_thumb_dim->dst_dim.height);
+  } else {
+    //Keep width constant
+    cropped_width =  p_thumb_dim->src_dim.width;
+    cropped_height = floor((cropped_width * p_thumb_dim->dst_dim.height) /
+      p_thumb_dim->dst_dim.width);
+  }
+  p_thumb_dim->crop.left = floor(p_thumb_dim->src_dim.width - cropped_width)/2;
+  p_thumb_dim->crop.top = floor(p_thumb_dim->src_dim.height - cropped_height)/2;
+  p_thumb_dim->crop.width = cropped_width;
+  p_thumb_dim->crop.height = cropped_height;
+
+  CDBG_HIGH("%s %d New thumbnail crop: left %d, top %d, crop width %d, crop height %d",
+    __func__, __LINE__, p_thumb_dim->crop.left, p_thumb_dim->crop.top,
+    p_thumb_dim->crop.width, p_thumb_dim->crop.height);
+
+  return ret;
+}
+
 /** mm_jpeg_omx_config_thumbnail:
  *
  *  Arguments:
@@ -853,10 +915,6 @@
   thumbnail_info.scaling_enabled = 1;
   thumbnail_info.input_width = p_thumb_dim->src_dim.width;
   thumbnail_info.input_height = p_thumb_dim->src_dim.height;
-  thumbnail_info.crop_info.nWidth = p_thumb_dim->crop.width;
-  thumbnail_info.crop_info.nHeight = p_thumb_dim->crop.height;
-  thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left;
-  thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top;
   thumbnail_info.quality = p_params->thumb_quality;
 
   if ((p_main_dim->src_dim.width < p_thumb_dim->src_dim.width) ||
@@ -878,6 +936,48 @@
     }
   }
 
+  //If the main image and thumbnail aspect ratio are different, reset the
+  // thumbnail crop info to avoid distortion
+  double main_aspect_ratio = (double)p_main_dim->dst_dim.width /
+    (double)p_main_dim->dst_dim.height;
+  double thumb_aspect_ratio = (double)p_thumb_dim->dst_dim.width /
+    (double)p_thumb_dim->dst_dim.height;
+  if ((thumb_aspect_ratio - main_aspect_ratio) > ASPECT_TOLERANCE) {
+    mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 0);
+  } else if((main_aspect_ratio - thumb_aspect_ratio) > ASPECT_TOLERANCE){
+    mm_jpeg_get_thumbnail_crop(p_thumb_dim, p_main_dim, 1);
+  }
+
+
+  //Fill thumbnail crop info
+  thumbnail_info.crop_info.nWidth = p_thumb_dim->crop.width;
+  thumbnail_info.crop_info.nHeight = p_thumb_dim->crop.height;
+  thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left;
+  thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top;
+
+  //If main image cropping/scaling is enabled, thumb FOV should be within
+  //main image FOV
+  if ((p_main_dim->crop.width != p_main_dim->src_dim.width) ||
+    (p_main_dim->crop.height != p_main_dim->src_dim.height)) {
+     if ((p_thumb_dim->crop.left < p_main_dim->crop.left) ||
+       ((p_thumb_dim->crop.left + p_thumb_dim->crop.width) >
+       (p_main_dim->crop.left + p_main_dim->crop.width)) ||
+       (p_thumb_dim->crop.top < p_main_dim->crop.top) ||
+       ((p_thumb_dim->crop.top + p_thumb_dim->crop.height) >
+       (p_main_dim->crop.top + p_main_dim->crop.height))) {
+       //Reset the FOV for the thumbnail
+        CDBG_HIGH("%s:%d] Resetting the thumbnail FOV wrt main image",
+          __func__, __LINE__);
+       thumbnail_info.crop_info.nLeft = p_main_dim->crop.left;
+       thumbnail_info.crop_info.nTop = p_main_dim->crop.height;
+       if ((p_thumb_dim->crop.width > p_main_dim->crop.width) ||
+         (p_thumb_dim->crop.height > p_main_dim->crop.height)) {
+         thumbnail_info.crop_info.nWidth = p_main_dim->crop.width;
+         thumbnail_info.crop_info.nHeight = p_main_dim->crop.height;
+       }
+    }
+  }
+
   if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width)
     || (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) {
     CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d",