Home | History | Annotate | Download | only in test
      1 /* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions are
      5  * met:
      6  *     * Redistributions of source code must retain the above copyright
      7  *       notice, this list of conditions and the following disclaimer.
      8  *     * Redistributions in binary form must reproduce the above
      9  *       copyright notice, this list of conditions and the following
     10  *       disclaimer in the documentation and/or other materials provided
     11  *       with the distribution.
     12  *     * Neither the name of The Linux Foundation nor the names of its
     13  *       contributors may be used to endorse or promote products derived
     14  *       from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  *
     28  */
     29 
     30 // System dependencies
     31 #include <pthread.h>
     32 #include <stdlib.h>
     33 #define TIME_H <SYSTEM_HEADER_PREFIX/time.h>
     34 #include TIME_H
     35 
     36 // JPEG dependencies
     37 #include "mm_jpeg_interface.h"
     38 #include "mm_jpeg_ionbuf.h"
     39 
     40 // Camera dependencies
     41 #include "mm_camera_dbg.h"
     42 
     43 #define MAX_NUM_BUFS (12)
     44 #define MAX_NUM_CLIENT (8)
     45 
     46 /** DUMP_TO_FILE:
     47  *  @filename: file name
     48  *  @p_addr: address of the buffer
     49  *  @len: buffer length
     50  *
     51  *  dump the image to the file
     52  **/
     53 #define DUMP_TO_FILE(filename, p_addr, len) ({ \
     54   FILE *fp = fopen(filename, "w+"); \
     55   if (fp) { \
     56     fwrite(p_addr, 1, len, fp); \
     57     fclose(fp); \
     58   } else { \
     59     LOGE("cannot dump image"); \
     60   } \
     61 })
     62 
     63 static uint32_t g_count = 1U, g_i;
     64 
     65 typedef struct {
     66   mm_jpeg_color_format fmt;
     67   cam_rational_type_t mult;
     68   const char *str;
     69 } mm_jpeg_intf_test_colfmt_t;
     70 
     71 typedef struct {
     72   char *filename;
     73   int width;
     74   int height;
     75   char *out_filename;
     76   uint32_t burst_mode;
     77   uint32_t min_out_bufs;
     78   mm_jpeg_intf_test_colfmt_t col_fmt;
     79   uint32_t encode_thumbnail;
     80   int tmb_width;
     81   int tmb_height;
     82   int main_quality;
     83   int thumb_quality;
     84   char *qtable_luma_file;
     85   char *qtable_chroma_file;
     86   int client_cnt;
     87 } jpeg_test_input_t;
     88 
     89 /* Static constants */
     90 /*  default Luma Qtable */
     91 uint8_t DEFAULT_QTABLE_0[QUANT_SIZE] = {
     92   16, 11, 10, 16, 24, 40, 51, 61,
     93   12, 12, 14, 19, 26, 58, 60, 55,
     94   14, 13, 16, 24, 40, 57, 69, 56,
     95   14, 17, 22, 29, 51, 87, 80, 62,
     96   18, 22, 37, 56, 68, 109, 103, 77,
     97   24, 35, 55, 64, 81, 104, 113, 92,
     98   49, 64, 78, 87, 103, 121, 120, 101,
     99   72, 92, 95, 98, 112, 100, 103, 99
    100 };
    101 
    102 /*  default Chroma Qtable */
    103 uint8_t DEFAULT_QTABLE_1[QUANT_SIZE] = {
    104   17, 18, 24, 47, 99, 99, 99, 99,
    105   18, 21, 26, 66, 99, 99, 99, 99,
    106   24, 26, 56, 99, 99, 99, 99, 99,
    107   47, 66, 99, 99, 99, 99, 99, 99,
    108   99, 99, 99, 99, 99, 99, 99, 99,
    109   99, 99, 99, 99, 99, 99, 99, 99,
    110   99, 99, 99, 99, 99, 99, 99, 99,
    111   99, 99, 99, 99, 99, 99, 99, 99
    112 };
    113 
    114 typedef struct {
    115   char *filename[MAX_NUM_BUFS];
    116   int width;
    117   int height;
    118   char *out_filename[MAX_NUM_BUFS];
    119   pthread_mutex_t lock;
    120   pthread_cond_t cond;
    121   pthread_t thread_id;
    122   buffer_t input[MAX_NUM_BUFS];
    123   buffer_t output[MAX_NUM_BUFS];
    124   int use_ion;
    125   uint32_t handle;
    126   mm_jpeg_ops_t ops;
    127   uint32_t job_id[MAX_NUM_BUFS];
    128   mm_jpeg_encode_params_t params;
    129   mm_jpeg_job_t job;
    130   uint32_t session_id;
    131   uint32_t num_bufs;
    132   uint32_t min_out_bufs;
    133   size_t buf_filled_len[MAX_NUM_BUFS];
    134   mm_dimension pic_size;
    135   int ret;
    136   int clinet_id;
    137 } mm_jpeg_intf_test_t;
    138 
    139 
    140 
    141 static const mm_jpeg_intf_test_colfmt_t color_formats[] =
    142 {
    143   { MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2, {3, 2}, "YCRCBLP_H2V2" },
    144   { MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2, {3, 2}, "YCBCRLP_H2V2" },
    145   { MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1, {2, 1}, "YCRCBLP_H2V1" },
    146   { MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1, {2, 1}, "YCBCRLP_H2V1" },
    147   { MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2, {2, 1}, "YCRCBLP_H1V2" },
    148   { MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2, {2, 1}, "YCBCRLP_H1V2" },
    149   { MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1, {3, 1}, "YCRCBLP_H1V1" },
    150   { MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1, {3, 1}, "YCBCRLP_H1V1" }
    151 };
    152 
    153 static jpeg_test_input_t jpeg_input[] = {
    154   { QCAMERA_DUMP_FRM_LOCATION"test_1.yuv", 4000, 3008, QCAMERA_DUMP_FRM_LOCATION"test_1.jpg", 0, 0,
    155     { MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2, {3, 2}, "YCRCBLP_H2V2" },
    156       0, 320, 240, 80, 80, NULL, NULL, 1}
    157 };
    158 
    159 static void mm_jpeg_encode_callback(jpeg_job_status_t status,
    160   uint32_t client_hdl,
    161   uint32_t jobId,
    162   mm_jpeg_output_t *p_output,
    163   void *userData)
    164 {
    165   mm_jpeg_intf_test_t *p_obj = (mm_jpeg_intf_test_t *)userData;
    166 
    167   pthread_mutex_lock(&p_obj->lock);
    168 
    169   if (status == JPEG_JOB_STATUS_ERROR) {
    170     LOGE("Encode error");
    171   } else {
    172     int i = 0;
    173     for (i = 0; p_obj->job_id[i] && (jobId != p_obj->job_id[i]); i++)
    174       ;
    175     if (!p_obj->job_id[i]) {
    176       LOGE("Cannot find job ID!!!");
    177       goto error;
    178     }
    179     LOGE("Encode success addr %p len %zu idx %d",
    180        p_output->buf_vaddr, p_output->buf_filled_len, i);
    181 
    182     p_obj->buf_filled_len[i] = p_output->buf_filled_len;
    183     if (p_obj->min_out_bufs) {
    184       LOGE("Saving file%s addr %p len %zu",
    185            p_obj->out_filename[i],
    186           p_output->buf_vaddr, p_output->buf_filled_len);
    187       DUMP_TO_FILE(p_obj->out_filename[i], p_output->buf_vaddr,
    188         p_output->buf_filled_len);
    189     }
    190   }
    191   g_i++;
    192 
    193 error:
    194 
    195   if (g_i >= g_count) {
    196     LOGE("Signal the thread");
    197     pthread_cond_signal(&p_obj->cond);
    198   }
    199   pthread_mutex_unlock(&p_obj->lock);
    200 }
    201 
    202 int mm_jpeg_test_alloc(buffer_t *p_buffer, int use_pmem)
    203 {
    204   int ret = 0;
    205   /*Allocate buffers*/
    206   if (use_pmem) {
    207     p_buffer->addr = (uint8_t *)buffer_allocate(p_buffer, 0);
    208     if (NULL == p_buffer->addr) {
    209       LOGE("Error");
    210       return -1;
    211     }
    212   } else {
    213     /* Allocate heap memory */
    214     p_buffer->addr = (uint8_t *)malloc(p_buffer->size);
    215     if (NULL == p_buffer->addr) {
    216       LOGE("Error");
    217       return -1;
    218     }
    219   }
    220   return ret;
    221 }
    222 
    223 void mm_jpeg_test_free(buffer_t *p_buffer)
    224 {
    225   if (p_buffer->addr == NULL)
    226     return;
    227 
    228   if (p_buffer->p_pmem_fd >= 0)
    229     buffer_deallocate(p_buffer);
    230   else
    231     free(p_buffer->addr);
    232 
    233   memset(p_buffer, 0x0, sizeof(buffer_t));
    234 }
    235 
    236 int mm_jpeg_test_read(mm_jpeg_intf_test_t *p_obj, uint32_t idx)
    237 {
    238   FILE *fp = NULL;
    239   size_t file_size = 0;
    240   fp = fopen(p_obj->filename[idx], "rb");
    241   if (!fp) {
    242     LOGE("error");
    243     return -1;
    244   }
    245   fseek(fp, 0, SEEK_END);
    246   file_size = (size_t)ftell(fp);
    247   fseek(fp, 0, SEEK_SET);
    248   LOGE("input file size is %zu buf_size %zu",
    249      file_size, p_obj->input[idx].size);
    250 
    251   if (p_obj->input[idx].size > file_size) {
    252     LOGE("error");
    253     fclose(fp);
    254     return -1;
    255   }
    256   fread(p_obj->input[idx].addr, 1, p_obj->input[idx].size, fp);
    257   fclose(fp);
    258   return 0;
    259 }
    260 
    261 /** mm_jpeg_test_read_qtable:
    262  *
    263  *  Arguments:
    264  *    @filename: Qtable filename
    265  *    @chroma_flag: Flag indicating chroma qtable
    266  *
    267  *  Return:
    268  *    0 success, failure otherwise
    269  *
    270  *  Description:
    271  *    Reads qtable from file and sets it in appropriate qtable
    272  *    based on flag.
    273  **/
    274 int mm_jpeg_test_read_qtable(const char *filename, bool chroma_flag)
    275 {
    276   FILE *fp = NULL;
    277   int i;
    278 
    279   if (filename == NULL)
    280     return 0;
    281 
    282   fp = fopen(filename, "r");
    283   if (!fp) {
    284     LOGE("error cannot open file");
    285     return -1;
    286   }
    287 
    288   if (chroma_flag) {
    289     for (i = 0; i < QUANT_SIZE; i++)
    290       fscanf(fp, "%hhu,", &DEFAULT_QTABLE_1[i]);
    291   } else {
    292     for (i = 0; i < QUANT_SIZE; i++)
    293       fscanf(fp, "%hhu,", &DEFAULT_QTABLE_0[i]);
    294   }
    295 
    296   fclose(fp);
    297   return 0;
    298 }
    299 
    300 static int encode_init(jpeg_test_input_t *p_input, mm_jpeg_intf_test_t *p_obj,
    301   int client_id)
    302 {
    303   int rc = -1;
    304   size_t size = (size_t)(p_input->width * p_input->height);
    305   mm_jpeg_encode_params_t *p_params = &p_obj->params;
    306   mm_jpeg_encode_job_t *p_job_params = &p_obj->job.encode_job;
    307   uint32_t i = 0;
    308   uint32_t burst_mode = p_input->burst_mode;
    309   jpeg_test_input_t *p_in = p_input;
    310 
    311   do {
    312     p_obj->filename[i] = p_in->filename;
    313     p_obj->width = p_input->width;
    314     p_obj->height = p_input->height;
    315     p_obj->out_filename[i] = p_in->out_filename;
    316     p_obj->use_ion = 1;
    317     p_obj->min_out_bufs = p_input->min_out_bufs;
    318 
    319     /* allocate buffers */
    320     p_obj->input[i].size = size * (size_t)p_input->col_fmt.mult.numerator /
    321         (size_t)p_input->col_fmt.mult.denominator;
    322     rc = mm_jpeg_test_alloc(&p_obj->input[i], p_obj->use_ion);
    323     if (rc) {
    324       LOGE("Error");
    325       return -1;
    326     }
    327 
    328 
    329     rc = mm_jpeg_test_read(p_obj, i);
    330     if (rc) {
    331       LOGE("Error, unable to read input image");
    332       return -1;
    333     }
    334 
    335     mm_jpeg_test_read_qtable(p_input->qtable_luma_file, false);
    336     if (rc) {
    337       LOGE("Error, unable to read luma qtable");
    338       return -1;
    339     }
    340 
    341     mm_jpeg_test_read_qtable(p_input->qtable_chroma_file, true);
    342     if (rc) {
    343       LOGE("Error, unable to read chrome qtable");
    344       return -1;
    345     }
    346 
    347     /* src buffer config*/
    348     p_params->src_main_buf[i].buf_size = p_obj->input[i].size;
    349     p_params->src_main_buf[i].buf_vaddr = p_obj->input[i].addr;
    350     p_params->src_main_buf[i].fd = p_obj->input[i].p_pmem_fd;
    351     p_params->src_main_buf[i].index = i;
    352     p_params->src_main_buf[i].format = MM_JPEG_FMT_YUV;
    353     p_params->src_main_buf[i].offset.mp[0].len = (uint32_t)size;
    354     p_params->src_main_buf[i].offset.mp[0].stride = p_input->width;
    355     p_params->src_main_buf[i].offset.mp[0].scanline = p_input->height;
    356     p_params->src_main_buf[i].offset.mp[1].len = (uint32_t)(size >> 1);
    357 
    358     /* src buffer config*/
    359     p_params->src_thumb_buf[i].buf_size = p_obj->input[i].size;
    360     p_params->src_thumb_buf[i].buf_vaddr = p_obj->input[i].addr;
    361     p_params->src_thumb_buf[i].fd = p_obj->input[i].p_pmem_fd;
    362     p_params->src_thumb_buf[i].index = i;
    363     p_params->src_thumb_buf[i].format = MM_JPEG_FMT_YUV;
    364     p_params->src_thumb_buf[i].offset.mp[0].len = (uint32_t)size;
    365     p_params->src_thumb_buf[i].offset.mp[0].stride = p_input->width;
    366     p_params->src_thumb_buf[i].offset.mp[0].scanline = p_input->height;
    367     p_params->src_thumb_buf[i].offset.mp[1].len = (uint32_t)(size >> 1);
    368 
    369 
    370     i++;
    371   } while((++p_in)->filename);
    372 
    373   p_obj->num_bufs = i;
    374 
    375   pthread_mutex_init(&p_obj->lock, NULL);
    376   pthread_cond_init(&p_obj->cond, NULL);
    377 
    378 
    379   /* set encode parameters */
    380   p_params->jpeg_cb = mm_jpeg_encode_callback;
    381   p_params->userdata = p_obj;
    382   p_params->color_format = p_input->col_fmt.fmt;
    383   p_params->thumb_color_format = p_input->col_fmt.fmt;
    384 
    385   if (p_obj->min_out_bufs) {
    386     p_params->num_dst_bufs = 2;
    387   } else {
    388     p_params->num_dst_bufs = p_obj->num_bufs;
    389   }
    390 
    391   for (i = 0; i < (uint32_t)p_params->num_dst_bufs; i++) {
    392     p_obj->output[i].size = size * 3/2;
    393 
    394 #ifdef MM_JPEG_USE_PIPELINE
    395     rc = mm_jpeg_test_alloc(&p_obj->output[i], 1);
    396 #else
    397     rc = mm_jpeg_test_alloc(&p_obj->output[i], 0);
    398 #endif
    399 
    400     if (rc) {
    401       LOGE("Error");
    402       return -1;
    403     }
    404     /* dest buffer config */
    405     p_params->dest_buf[i].buf_size = p_obj->output[i].size;
    406     p_params->dest_buf[i].buf_vaddr = p_obj->output[i].addr;
    407     p_params->dest_buf[i].fd = p_obj->output[i].p_pmem_fd;
    408     p_params->dest_buf[i].index = i;
    409   }
    410 
    411 
    412   p_params->num_src_bufs = p_obj->num_bufs;
    413   p_params->num_tmb_bufs = 0;
    414   g_count = p_params->num_src_bufs;
    415 
    416   p_params->encode_thumbnail = p_input->encode_thumbnail;
    417   if (p_params->encode_thumbnail) {
    418       p_params->num_tmb_bufs = p_obj->num_bufs;
    419   }
    420   p_params->quality = (uint32_t)p_input->main_quality;
    421   p_params->thumb_quality = (uint32_t)p_input->thumb_quality;
    422 
    423   p_job_params->dst_index = 0;
    424   p_job_params->src_index = 0;
    425   p_job_params->rotation = 0;
    426 
    427   /* main dimension */
    428   p_job_params->main_dim.src_dim.width = p_obj->width;
    429   p_job_params->main_dim.src_dim.height = p_obj->height;
    430   p_job_params->main_dim.dst_dim.width = p_obj->width;
    431   p_job_params->main_dim.dst_dim.height = p_obj->height;
    432   p_job_params->main_dim.crop.top = 0;
    433   p_job_params->main_dim.crop.left = 0;
    434   p_job_params->main_dim.crop.width = p_obj->width;
    435   p_job_params->main_dim.crop.height = p_obj->height;
    436 
    437   p_params->main_dim  = p_job_params->main_dim;
    438 
    439   /* thumb dimension */
    440   p_job_params->thumb_dim.src_dim.width = p_obj->width;
    441   p_job_params->thumb_dim.src_dim.height = p_obj->height;
    442   p_job_params->thumb_dim.dst_dim.width = p_input->tmb_width;
    443   p_job_params->thumb_dim.dst_dim.height = p_input->tmb_height;
    444   p_job_params->thumb_dim.crop.top = 0;
    445   p_job_params->thumb_dim.crop.left = 0;
    446   p_job_params->thumb_dim.crop.width = 0;
    447   p_job_params->thumb_dim.crop.height = 0;
    448 
    449   p_params->thumb_dim  = p_job_params->thumb_dim;
    450 
    451   p_job_params->exif_info.numOfEntries = 0;
    452   p_params->burst_mode = burst_mode;
    453 
    454   /* Qtable */
    455   p_job_params->qtable[0].eQuantizationTable =
    456     OMX_IMAGE_QuantizationTableLuma;
    457   p_job_params->qtable[1].eQuantizationTable =
    458     OMX_IMAGE_QuantizationTableChroma;
    459   p_job_params->qtable_set[0] = 1;
    460   p_job_params->qtable_set[1] = 1;
    461 
    462   for (i = 0; i < QUANT_SIZE; i++) {
    463     p_job_params->qtable[0].nQuantizationMatrix[i] = DEFAULT_QTABLE_0[i];
    464     p_job_params->qtable[1].nQuantizationMatrix[i] = DEFAULT_QTABLE_1[i];
    465   }
    466 
    467   p_obj->pic_size.w = (uint32_t)p_input->width;
    468   p_obj->pic_size.h = (uint32_t)p_input->height;
    469 
    470   p_obj->clinet_id = client_id;
    471 
    472   return 0;
    473 }
    474 
    475 static void *encode_test(void *data)
    476 {
    477   int rc = 0;
    478   mm_jpeg_intf_test_t *jpeg_obj = (mm_jpeg_intf_test_t *)data;
    479   char file_name[64];
    480 
    481   uint32_t i = 0;
    482   jpeg_obj->handle = jpeg_open(&jpeg_obj->ops, NULL, jpeg_obj->pic_size, NULL);
    483   if (jpeg_obj->handle == 0) {
    484     LOGE("Error");
    485     jpeg_obj->ret = -1;
    486     goto end;
    487   }
    488 
    489   rc = jpeg_obj->ops.create_session(jpeg_obj->handle, &jpeg_obj->params,
    490     &jpeg_obj->job.encode_job.session_id);
    491   if (jpeg_obj->job.encode_job.session_id == 0) {
    492     LOGE("Error");
    493     jpeg_obj->ret = -1;
    494     goto end;
    495   }
    496 
    497   for (i = 0; i < jpeg_obj->num_bufs; i++) {
    498     jpeg_obj->job.job_type = JPEG_JOB_TYPE_ENCODE;
    499     jpeg_obj->job.encode_job.src_index = (int32_t) i;
    500     jpeg_obj->job.encode_job.dst_index = (int32_t) i;
    501     jpeg_obj->job.encode_job.thumb_index = (uint32_t) i;
    502 
    503     if (jpeg_obj->params.burst_mode && jpeg_obj->min_out_bufs) {
    504       jpeg_obj->job.encode_job.dst_index = -1;
    505     }
    506 
    507     rc = jpeg_obj->ops.start_job(&jpeg_obj->job, &jpeg_obj->job_id[i]);
    508     if (rc) {
    509       LOGE("Error");
    510       jpeg_obj->ret = rc;
    511       goto end;
    512     }
    513   }
    514   jpeg_obj->job_id[i] = 0;
    515 
    516   /*
    517   usleep(5);
    518   jpeg_obj->ops.abort_job(jpeg_obj->job_id[0]);
    519   */
    520   pthread_mutex_lock(&jpeg_obj->lock);
    521   pthread_cond_wait(&jpeg_obj->cond, &jpeg_obj->lock);
    522   pthread_mutex_unlock(&jpeg_obj->lock);
    523 
    524   jpeg_obj->ops.destroy_session(jpeg_obj->job.encode_job.session_id);
    525   jpeg_obj->ops.close(jpeg_obj->handle);
    526 
    527 end:
    528   for (i = 0; i < jpeg_obj->num_bufs; i++) {
    529     if (!jpeg_obj->min_out_bufs) {
    530       // Save output files
    531       LOGE("Saving file%s addr %p len %zu",
    532           jpeg_obj->out_filename[i],
    533           jpeg_obj->output[i].addr, jpeg_obj->buf_filled_len[i]);
    534 
    535       snprintf(file_name, sizeof(file_name), "%s_%d.jpg",
    536         jpeg_obj->out_filename[i], jpeg_obj->clinet_id);
    537       fprintf(stderr, "Output file for client %d = %s\n",
    538         jpeg_obj->clinet_id, file_name);
    539 
    540       DUMP_TO_FILE(file_name, jpeg_obj->output[i].addr,
    541         jpeg_obj->buf_filled_len[i]);
    542     }
    543     mm_jpeg_test_free(&jpeg_obj->input[i]);
    544     mm_jpeg_test_free(&jpeg_obj->output[i]);
    545   }
    546   return NULL;
    547 }
    548 
    549 #define MAX_FILE_CNT (20)
    550 static int mm_jpeg_test_get_input(int argc, char *argv[],
    551     jpeg_test_input_t *p_test)
    552 {
    553   int c;
    554   size_t in_file_cnt = 0, out_file_cnt = 0, i;
    555   int idx = 0;
    556   jpeg_test_input_t *p_test_base = p_test;
    557 
    558   char *in_files[MAX_FILE_CNT];
    559   char *out_files[MAX_FILE_CNT];
    560 
    561   while ((c = getopt(argc, argv, "-I:O:W:H:F:BTx:y:Q:J:K:C:q:")) != -1) {
    562     switch (c) {
    563     case 'B':
    564       fprintf(stderr, "%-25s\n", "Using burst mode");
    565       p_test->burst_mode = 1;
    566       break;
    567     case 'I':
    568       for (idx = optind - 1; idx < argc; idx++) {
    569         if (argv[idx][0] == '-') {
    570           break;
    571         }
    572         in_files[in_file_cnt++] = argv[idx];
    573       }
    574       optind = idx -1;
    575 
    576       break;
    577     case 'O':
    578       for (idx = optind - 1; idx < argc; idx++) {
    579         if (argv[idx][0] == '-') {
    580           break;
    581         }
    582         out_files[out_file_cnt++] = argv[idx];
    583       }
    584       optind = idx -1;
    585 
    586       break;
    587     case 'W':
    588       p_test->width = atoi(optarg);
    589       fprintf(stderr, "%-25s%d\n", "Width: ", p_test->width);
    590       break;
    591     case 'H':
    592       p_test->height = atoi(optarg);
    593       fprintf(stderr, "%-25s%d\n", "Height: ", p_test->height);
    594       break;
    595     case 'F':
    596       p_test->col_fmt = color_formats[atoi(optarg)];
    597       fprintf(stderr, "%-25s%s\n", "Format: ", p_test->col_fmt.str);
    598       break;
    599     case 'M':
    600       p_test->min_out_bufs = 1;
    601       fprintf(stderr, "%-25s\n", "Using minimum number of output buffers");
    602       break;
    603     case 'T':
    604       p_test->encode_thumbnail = 1;
    605       fprintf(stderr, "%-25s\n", "Encode thumbnail");
    606       break;
    607     case 'x':
    608       p_test->tmb_width = atoi(optarg);
    609       fprintf(stderr, "%-25s%d\n", "Tmb Width: ", p_test->tmb_width);
    610       break;
    611     case 'y':
    612       p_test->tmb_height = atoi(optarg);
    613       fprintf(stderr, "%-25s%d\n", "Tmb Height: ", p_test->tmb_height);
    614       break;
    615     case 'Q':
    616       p_test->main_quality = atoi(optarg);
    617       fprintf(stderr, "%-25s%d\n", "Main quality: ", p_test->main_quality);
    618       break;
    619     case 'q':
    620       p_test->thumb_quality = atoi(optarg);
    621       fprintf(stderr, "%-25s%d\n", "Thumb quality: ", p_test->thumb_quality);
    622       break;
    623     case 'J':
    624       p_test->qtable_luma_file = optarg;
    625       fprintf(stderr, "%-25s%s\n", "Qtable luma path",
    626         p_test->qtable_luma_file);
    627       break;
    628     case 'K':
    629       p_test->qtable_chroma_file = optarg;
    630       fprintf(stderr, "%-25s%s\n", "Qtable chroma path",
    631         p_test->qtable_chroma_file);
    632       break;
    633     case 'C':
    634       p_test->client_cnt = atoi(optarg);
    635       fprintf(stderr, "%-25s%d\n", "Number of clients ",
    636         p_test->client_cnt);
    637     default:;
    638     }
    639   }
    640   fprintf(stderr, "Infiles: %zu Outfiles: %zu\n", in_file_cnt, out_file_cnt);
    641 
    642   if (p_test->client_cnt > MAX_NUM_CLIENT) {
    643     fprintf(stderr, "Clients requested exceeds max limit %d\n",
    644       MAX_NUM_CLIENT);
    645     return 1;
    646   }
    647   if (in_file_cnt > out_file_cnt) {
    648     fprintf(stderr, "%-25s\n", "Insufficient number of output files!");
    649     return 1;
    650   }
    651 
    652   // Discard the extra out files
    653   out_file_cnt = in_file_cnt;
    654 
    655   p_test = realloc(p_test, (in_file_cnt + 1) * sizeof(*p_test));
    656   if (!p_test) {
    657     LOGE("Error");
    658     return 1;
    659   }
    660   memset(p_test+1, 0, (in_file_cnt) * sizeof(*p_test));
    661 
    662   for (i = 0; i < in_file_cnt; i++, p_test++) {
    663     memcpy(p_test, p_test_base, sizeof(*p_test));
    664     p_test->filename = in_files[i];
    665     p_test->out_filename = out_files[i];
    666     fprintf(stderr, "Inf: %s Outf: %s\n", in_files[i], out_files[i]);
    667   }
    668 
    669   return 0;
    670 }
    671 
    672 static void mm_jpeg_test_print_usage()
    673 {
    674   fprintf(stderr, "Usage: program_name [options]\n");
    675   fprintf(stderr, "Mandatory options:\n");
    676   fprintf(stderr, "  -I FILE1 [FILE2] [FILEN]\tList of input files\n");
    677   fprintf(stderr, "  -O FILE1 [FILE2] [FILEN]\tList of output files\n");
    678   fprintf(stderr, "  -W WIDTH\t\tOutput image width\n");
    679   fprintf(stderr, "  -H HEIGHT\t\tOutput image height\n");
    680   fprintf(stderr, "  -F \t\tColor format: \n");
    681   fprintf(stderr, "\t\t\t\t%s (0), %s (1), %s (2) %s (3)\n"
    682       "\t\t\t\t%s (4), %s (5), %s (6) %s (7)\n ",
    683       color_formats[0].str, color_formats[1].str,
    684       color_formats[2].str, color_formats[3].str,
    685       color_formats[4].str, color_formats[5].str,
    686       color_formats[6].str, color_formats[7].str);
    687   fprintf(stderr, "Optional:\n");
    688   fprintf(stderr, "  -T \t\Encode thumbnail\n");
    689   fprintf(stderr, "  -x TMB_WIDTH\t\tThumbnail width\n");
    690   fprintf(stderr, "  -y TMB_HEIGHT\t\tThumbnail height\n");
    691   fprintf(stderr, "  -Q MAIN_QUALITY\t\tMain image quality\n");
    692   fprintf(stderr, "  -q TMB_QUALITY\t\tThumbnail image quality\n");
    693   fprintf(stderr, "  -B \t\tBurst mode. Utilize both encoder engines on"
    694           "supported targets\n");
    695   fprintf(stderr, "  -M \t\tUse minimum number of output buffers \n");
    696   fprintf(stderr, "  -J \t\tLuma QTable filename. Comma separated 8x8"
    697     " matrix\n");
    698   fprintf(stderr, "  -K \t\tChroma QTable filename. Comma separated"
    699     " 8x8 matrix\n");
    700   fprintf(stderr, "  -C \t\tNumber of clients to run in parllel\n");
    701   fprintf(stderr, "\n");
    702 }
    703 
    704 /** main:
    705  *
    706  *  Arguments:
    707  *    @argc
    708  *    @argv
    709  *
    710  *  Return:
    711  *       0 or -ve values
    712  *
    713  *  Description:
    714  *       main function
    715  *
    716  **/
    717 int main(int argc, char* argv[])
    718 {
    719   jpeg_test_input_t *p_test_input;
    720   mm_jpeg_intf_test_t client[MAX_NUM_CLIENT];
    721   int ret = 0;
    722   int i = 0;
    723   int thread_cnt = 0;
    724 
    725   if (argc > 1) {
    726     p_test_input = calloc(2, sizeof(*p_test_input));
    727     if (!p_test_input) {
    728       LOGE("Error");
    729       goto exit;
    730     }
    731     memcpy(p_test_input, &jpeg_input[0], sizeof(*p_test_input));
    732     ret = mm_jpeg_test_get_input(argc, argv, p_test_input);
    733     if (ret) {
    734       LOGE("Error");
    735       goto exit;
    736     }
    737   } else {
    738     mm_jpeg_test_print_usage();
    739     return 1;
    740   }
    741 
    742   for (i = 0; i < p_test_input->client_cnt; i++) {
    743     memset(&client[i], 0x0, sizeof(mm_jpeg_intf_test_t));
    744     ret = encode_init(p_test_input, &client[i], i);
    745     if (ret) {
    746       LOGE("Error");
    747       return -1;
    748     }
    749 
    750     ret = pthread_create(&client[i].thread_id, NULL, encode_test,
    751       &client[i]);
    752     if (ret != 0) {
    753        fprintf(stderr, "Error in thread creation\n");
    754        break;
    755     }
    756   }
    757 
    758   thread_cnt = i;
    759   for (i = 0; i < thread_cnt; i++) {
    760     pthread_join(client[i].thread_id, NULL);
    761   }
    762 
    763 exit:
    764   for (i = 0; i < thread_cnt; i++) {
    765     if (!client[i].ret) {
    766       fprintf(stderr, "%-25s %d %s\n", "Client", i, "Success!");
    767     } else {
    768       fprintf(stderr, "%-25s %d %s\n", "Client", i, "Fail!");
    769     }
    770   }
    771 
    772   if (argc > 1) {
    773     if (p_test_input) {
    774       free(p_test_input);
    775       p_test_input = NULL;
    776     }
    777   }
    778 
    779   return ret;
    780 }
    781 
    782 
    783