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