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