Home | History | Annotate | Download | only in src
      1 /* Copyright (c) 2015-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 #define ATRACE_TAG ATRACE_TAG_CAMERA
     31 
     32 // System dependencies
     33 #include <pthread.h>
     34 
     35 // JPEG dependencies
     36 #include "mm_jpeg_dbg.h"
     37 #include "mm_jpeg_mpo.h"
     38 
     39 #define M_APP0    0xe0
     40 #define M_APP1    0xe1
     41 #define M_APP2    0xe2
     42 #define M_EOI     0xd9
     43 #define M_SOI     0xd8
     44 
     45 /** READ_LONG:
     46  *  @b: Buffer start addr
     47  *  @o: Buffer offset to start reading
     48  *
     49  *  Read long value from the specified buff addr at given offset
     50  **/
     51 #define READ_LONG(b, o)  \
     52   (uint32_t)(((uint32_t)b[o] << 24) + \
     53   ((uint32_t)b[o+1] << 16) + \
     54   ((uint32_t)b[o+2] << 8) + \
     55   ((uint32_t)b[o+3]))
     56 
     57 /** READ_LONG_LITTLE:
     58  *  @b: Buffer start addr
     59  *  @o: Buffer offset to start reading
     60  *
     61  *  Read long value from the specified buff addr at given offset
     62  *  in Little Endian
     63  **/
     64 #define READ_LONG_LITTLE(b, o)  \
     65   (uint32_t)(((uint32_t)b[o + 3] << 24) + \
     66   ((uint32_t) b[o + 2] << 16) + \
     67   ((uint32_t) b[o + 1] << 8) + \
     68   (uint32_t) b[o]);
     69 
     70 /** READ_LONG:
     71  *  @b: Buffer start addr
     72  *  @o: Buffer offset to start reading
     73  *
     74  *  Read short value from the specified buff addr at given
     75  *  offset
     76  **/
     77 #define READ_SHORT(b, o)  \
     78   (uint16_t) (((uint16_t)b[o] << 8) + \
     79   (uint16_t) b[o + 1]);
     80 
     81 /*Mutex to serializa MPO composition*/
     82 static pthread_mutex_t g_mpo_lock = PTHREAD_MUTEX_INITIALIZER;
     83 
     84 /** mm_jpeg_mpo_write_long_little_endian
     85  *
     86  *  Arguments:
     87  *    @buffer_addr: image start addr
     88  *    @buff_offset: offset in the buffer
     89  *    @buffer_size: Size of the buffer
     90  *    @value: Value to write
     91  *    @overflow : Overflow flag
     92  *
     93  *  Return:
     94  *       None
     95  *
     96  *  Description:
     97  *       Write value at the given offset
     98  *
     99  **/
    100 void mm_jpeg_mpo_write_long_little_endian(uint8_t *buff_addr, uint32_t buff_offset,
    101   uint32_t buffer_size, int value, uint8_t *overflow)
    102 {
    103   if (buff_offset + 3 >= buffer_size) {
    104     *overflow = TRUE;
    105   }
    106 
    107   if (!(*overflow)) {
    108     buff_addr[buff_offset + 3] = (uint8_t)((value >> 24) & 0xFF);
    109     buff_addr[buff_offset + 2] = (uint8_t)((value >> 16) & 0xFF);
    110     buff_addr[buff_offset + 1] = (uint8_t)((value >> 8) & 0xFF);
    111     buff_addr[buff_offset] = (uint8_t)(value & 0xFF);
    112   }
    113 }
    114 
    115 /** mm_jpeg_mpo_write_long
    116  *
    117  *  Arguments:
    118  *    @buffer_addr: image start addr
    119  *    @buff_offset: offset in the buffer
    120  *    @buffer_size: Size of the buffer
    121  *    @value: Value to write
    122  *    @overflow : Overflow flag
    123  *
    124  *  Return:
    125  *       None
    126  *
    127  *  Description:
    128  *       Write value at the given offset
    129  *
    130  **/
    131 void mm_jpeg_mpo_write_long(uint8_t *buff_addr, uint32_t buff_offset,
    132   uint32_t buffer_size, int value, uint8_t *overflow)
    133 {
    134   if ((buff_offset + 3) >= buffer_size) {
    135     *overflow = TRUE;
    136   }
    137 
    138   if (!(*overflow)) {
    139     buff_addr[buff_offset] = (uint8_t)((value >> 24) & 0xFF);
    140     buff_addr[buff_offset+1] = (uint8_t)((value >> 16) & 0xFF);
    141     buff_addr[buff_offset+2] = (uint8_t)((value >> 8) & 0xFF);
    142     buff_addr[buff_offset+3] = (uint8_t)(value & 0xFF);
    143   }
    144 }
    145 
    146 /** mm_jpeg_mpo_get_app_marker
    147  *
    148  *  Arguments:
    149  *    @buffer_addr: Jpeg image start addr
    150  *    @buffer_size: Size of the Buffer
    151  *    @app_marker: app_marker to find
    152  *
    153  *  Return:
    154  *       Start offset of the specified app marker
    155  *
    156  *  Description:
    157  *       Gets the start offset of the given app marker
    158  *
    159  **/
    160 uint8_t *mm_jpeg_mpo_get_app_marker(uint8_t *buffer_addr, int buffer_size,
    161   int app_marker)
    162 {
    163   int32_t byte;
    164   uint8_t *p_current_addr = NULL, *p_start_offset = NULL;
    165   uint16_t app_marker_size = 0;
    166 
    167   p_current_addr = buffer_addr;
    168   do {
    169     do {
    170       byte = *(p_current_addr);
    171       p_current_addr++;
    172     }
    173     while ((byte != 0xFF) &&
    174       (p_current_addr < (buffer_addr + (buffer_size - 1))));
    175 
    176     //If 0xFF is not found at all, break
    177     if (byte != 0xFF) {
    178       LOGD("0xFF not found");
    179       break;
    180     }
    181 
    182     //Read the next byte after 0xFF
    183     byte = *(p_current_addr);
    184     LOGD("Byte %x", byte);
    185     if (byte == app_marker) {
    186       LOGD("Byte %x", byte);
    187       p_start_offset = ++p_current_addr;
    188       break;
    189     } else if (byte != M_SOI) {
    190       app_marker_size = READ_SHORT(p_current_addr, 1);
    191       LOGD("size %d", app_marker_size);
    192       p_current_addr += app_marker_size;
    193     }
    194   }
    195   while ((byte != M_EOI) &&
    196     (p_current_addr < (buffer_addr + (buffer_size - 1))));
    197 
    198   return p_start_offset;
    199 }
    200 
    201 /** mm_jpeg_mpo_get_mp_header
    202  *
    203  *  Arguments:
    204  *    @app2_marker: app2_marker start offset
    205  *
    206  *  Return:
    207  *       Start offset of the MP header
    208  *
    209  *  Description:
    210  *       Get the start offset of the MP header (before the MP
    211  *       Endian field). All offsets in the MP header need to be
    212  *       specified wrt this start offset.
    213  *
    214  **/
    215 uint8_t *mm_jpeg_mpo_get_mp_header(uint8_t *app2_start_offset)
    216 {
    217   uint8_t *mp_headr_start_offset = NULL;
    218 
    219   if (app2_start_offset != NULL) {
    220     mp_headr_start_offset = app2_start_offset + MP_APP2_FIELD_LENGTH_BYTES +
    221       MP_FORMAT_IDENTIFIER_BYTES;
    222   }
    223 
    224   return mp_headr_start_offset;
    225 }
    226 
    227 /** mm_jpeg_mpo_update_header
    228  *
    229  *  Arguments:
    230  *    @mpo_info: MPO Info
    231  *
    232  *  Return:
    233  *       0 - Success
    234  *       -1 - otherwise
    235  *
    236  *  Description:
    237  *      Update the MP Index IFD of the first image with info
    238  *      about about all other images.
    239  *
    240  **/
    241 int mm_jpeg_mpo_update_header(mm_jpeg_mpo_info_t *mpo_info)
    242 {
    243   uint8_t *app2_start_off_addr = NULL, *mp_headr_start_off_addr = NULL;
    244   uint32_t mp_index_ifd_offset = 0, current_offset = 0, mp_entry_val_offset = 0;
    245   uint8_t *aux_start_addr = NULL;
    246   uint8_t overflow_flag = 0;
    247   int i = 0, rc = -1;
    248   uint32_t endianess = MPO_LITTLE_ENDIAN, offset_to_nxt_ifd = 8;
    249   uint16_t ifd_tag_count = 0;
    250 
    251   //Get the addr of the App Marker
    252   app2_start_off_addr = mm_jpeg_mpo_get_app_marker(
    253     mpo_info->output_buff.buf_vaddr, mpo_info->primary_image.buf_filled_len, M_APP2);
    254   if (!app2_start_off_addr) {
    255     LOGE("Cannot find App2 marker. MPO composition failed" );
    256     return rc;
    257   }
    258   LOGD("app2_start_off_addr %p = %x",
    259     app2_start_off_addr, *app2_start_off_addr);
    260 
    261   //Get the addr of the MP Headr start offset.
    262   //All offsets in the MP header are wrt to this addr
    263   mp_headr_start_off_addr = mm_jpeg_mpo_get_mp_header(app2_start_off_addr);
    264   if (!mp_headr_start_off_addr) {
    265     LOGE("mp headr start offset is NULL. MPO composition failed" );
    266     return rc;
    267   }
    268   LOGD("mp_headr_start_off_addr %x",
    269     *mp_headr_start_off_addr);
    270 
    271   current_offset = mp_headr_start_off_addr - mpo_info->output_buff.buf_vaddr;
    272 
    273   endianess = READ_LONG(mpo_info->output_buff.buf_vaddr, current_offset);
    274   LOGD("Endianess %d", endianess);
    275 
    276   //Add offset to first ifd
    277   current_offset += MP_ENDIAN_BYTES;
    278 
    279   //Read the value to get MP Index IFD.
    280   if (endianess == MPO_LITTLE_ENDIAN) {
    281     offset_to_nxt_ifd = READ_LONG_LITTLE(mpo_info->output_buff.buf_vaddr,
    282       current_offset);
    283   } else {
    284     offset_to_nxt_ifd = READ_LONG(mpo_info->output_buff.buf_vaddr,
    285       current_offset);
    286   }
    287   LOGD("offset_to_nxt_ifd %d", offset_to_nxt_ifd);
    288 
    289   current_offset = ((mp_headr_start_off_addr + offset_to_nxt_ifd) -
    290     mpo_info->output_buff.buf_vaddr);
    291   mp_index_ifd_offset = current_offset;
    292   LOGD("mp_index_ifd_offset %d",
    293     mp_index_ifd_offset);
    294 
    295   //Traverse to MP Entry value
    296   ifd_tag_count = READ_SHORT(mpo_info->output_buff.buf_vaddr, current_offset);
    297   LOGD("Tag count in MP entry %d", ifd_tag_count);
    298   current_offset += MP_INDEX_COUNT_BYTES;
    299 
    300   /* Get MP Entry Value offset - Count * 12 (Each tag is 12 bytes)*/
    301   current_offset += (ifd_tag_count * 12);
    302   /*Add Offset to next IFD*/
    303   current_offset += MP_INDEX_OFFSET_OF_NEXT_IFD_BYTES;
    304 
    305   mp_entry_val_offset = current_offset;
    306   LOGD("MP Entry value offset %d",
    307     mp_entry_val_offset);
    308 
    309   //Update image size for primary image
    310   current_offset += MP_INDEX_ENTRY_INDIVIDUAL_IMAGE_ATTRIBUTE_BYTES;
    311   if (endianess == MPO_LITTLE_ENDIAN) {
    312     mm_jpeg_mpo_write_long_little_endian(mpo_info->output_buff.buf_vaddr,
    313       current_offset, mpo_info->output_buff_size,
    314       mpo_info->primary_image.buf_filled_len, &overflow_flag);
    315   } else {
    316     mm_jpeg_mpo_write_long(mpo_info->output_buff.buf_vaddr,
    317       current_offset, mpo_info->output_buff_size,
    318       mpo_info->primary_image.buf_filled_len, &overflow_flag);
    319   }
    320 
    321   aux_start_addr = mpo_info->output_buff.buf_vaddr +
    322     mpo_info->primary_image.buf_filled_len;
    323 
    324   for (i = 0; i < mpo_info->num_of_images - 1; i++) {
    325     //Go to MP Entry val for each image
    326     mp_entry_val_offset += MP_INDEX_ENTRY_VALUE_BYTES;
    327     current_offset = mp_entry_val_offset;
    328 
    329     //Update image size
    330     current_offset += MP_INDEX_ENTRY_INDIVIDUAL_IMAGE_ATTRIBUTE_BYTES;
    331     if (endianess == MPO_LITTLE_ENDIAN) {
    332       mm_jpeg_mpo_write_long_little_endian(mpo_info->output_buff.buf_vaddr,
    333         current_offset, mpo_info->output_buff_size,
    334         mpo_info->aux_images[i].buf_filled_len, &overflow_flag);
    335     } else {
    336       mm_jpeg_mpo_write_long(mpo_info->output_buff.buf_vaddr,
    337         current_offset, mpo_info->output_buff_size,
    338         mpo_info->aux_images[i].buf_filled_len, &overflow_flag);
    339     }
    340     LOGD("aux[start_addr %x", *aux_start_addr);
    341     //Update the offset
    342     current_offset += MP_INDEX_ENTRY_INDIVIDUAL_IMAGE_SIZE_BYTES;
    343     if (endianess == MPO_LITTLE_ENDIAN) {
    344       mm_jpeg_mpo_write_long_little_endian(mpo_info->output_buff.buf_vaddr,
    345         current_offset, mpo_info->output_buff_size,
    346         aux_start_addr - mp_headr_start_off_addr, &overflow_flag);
    347     } else {
    348       mm_jpeg_mpo_write_long(mpo_info->output_buff.buf_vaddr,
    349         current_offset, mpo_info->output_buff_size,
    350         aux_start_addr - mp_headr_start_off_addr, &overflow_flag);
    351     }
    352     aux_start_addr += mpo_info->aux_images[i].buf_filled_len;
    353   }
    354   if (!overflow_flag) {
    355     rc = 0;
    356   }
    357   return rc;
    358 }
    359 
    360 /** mm_jpeg_mpo_compose
    361  *
    362  *  Arguments:
    363  *    @mpo_info: MPO Info
    364  *
    365  *  Return:
    366  *       0 - Success
    367  *      -1 - otherwise
    368  *
    369  *  Description:
    370  *      Compose MPO image from multiple JPEG images
    371  *
    372  **/
    373 int mm_jpeg_mpo_compose(mm_jpeg_mpo_info_t *mpo_info)
    374 {
    375   uint8_t *aux_write_offset = NULL;
    376   int i = 0, rc = -1;
    377 
    378   pthread_mutex_lock(&g_mpo_lock);
    379 
    380   //Primary image needs to be copied to the o/p buffer if its not already
    381   if (mpo_info->output_buff.buf_filled_len == 0) {
    382     if (mpo_info->primary_image.buf_filled_len < mpo_info->output_buff_size) {
    383       memcpy(mpo_info->output_buff.buf_vaddr, mpo_info->primary_image.buf_vaddr,
    384         mpo_info->primary_image.buf_filled_len);
    385       mpo_info->output_buff.buf_filled_len +=
    386         mpo_info->primary_image.buf_filled_len;
    387     } else {
    388       LOGE("O/P buffer not large enough. MPO composition failed");
    389       pthread_mutex_unlock(&g_mpo_lock);
    390       return rc;
    391     }
    392   }
    393   //Append each Aux image to the buffer
    394   for (i = 0; i < mpo_info->num_of_images - 1; i++) {
    395     if ((mpo_info->output_buff.buf_filled_len +
    396       mpo_info->aux_images[i].buf_filled_len) <= mpo_info->output_buff_size) {
    397       aux_write_offset = mpo_info->output_buff.buf_vaddr +
    398         mpo_info->output_buff.buf_filled_len;
    399       memcpy(aux_write_offset, mpo_info->aux_images[i].buf_vaddr,
    400         mpo_info->aux_images[i].buf_filled_len);
    401       mpo_info->output_buff.buf_filled_len +=
    402         mpo_info->aux_images[i].buf_filled_len;
    403     } else {
    404       LOGE("O/P buffer not large enough. MPO composition failed");
    405       pthread_mutex_unlock(&g_mpo_lock);
    406       return rc;
    407     }
    408   }
    409 
    410   rc = mm_jpeg_mpo_update_header(mpo_info);
    411   pthread_mutex_unlock(&g_mpo_lock);
    412 
    413   return rc;
    414 }
    415