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 **/
mm_jpeg_mpo_write_long_little_endian(uint8_t * buff_addr,uint32_t buff_offset,uint32_t buffer_size,int value,uint8_t * overflow)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 **/
mm_jpeg_mpo_write_long(uint8_t * buff_addr,uint32_t buff_offset,uint32_t buffer_size,int value,uint8_t * overflow)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 **/
mm_jpeg_mpo_get_app_marker(uint8_t * buffer_addr,int buffer_size,int app_marker)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 **/
mm_jpeg_mpo_get_mp_header(uint8_t * app2_start_offset)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 **/
mm_jpeg_mpo_update_header(mm_jpeg_mpo_info_t * mpo_info)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 **/
mm_jpeg_mpo_compose(mm_jpeg_mpo_info_t * mpo_info)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