1 /*
2 Copyright (c) 2012, The Linux Foundation. All rights reserved.
3 
4 Redistribution and use in source and binary forms, with or without
5 modification, are permitted provided that the following conditions are
6 met:
7     * Redistributions of source code must retain the above copyright
8       notice, this list of conditions and the following disclaimer.
9     * Redistributions in binary form must reproduce the above
10       copyright notice, this list of conditions and the following
11       disclaimer in the documentation and/or other materials provided
12       with the distribution.
13     * Neither the name of The Linux Foundation nor the names of its
14       contributors may be used to endorse or promote products derived
15       from this software without specific prior written permission.
16 
17 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 
30 #include <pthread.h>
31 #include <errno.h>
32 #include <sys/ioctl.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <fcntl.h>
36 #include <poll.h>
37 #include <semaphore.h>
38 
39 #include "mm_jpeg_dbg.h"
40 #include "mm_jpeg_interface.h"
41 #include "mm_jpeg.h"
42 
43 /* define max num of supported concurrent jpeg jobs by OMX engine.
44  * Current, only one per time */
45 #define NUM_MAX_JPEG_CNCURRENT_JOBS 1
46 
47 #define INPUT_PORT_MAIN         0
48 #define INPUT_PORT_THUMBNAIL    2
49 #define OUTPUT_PORT             1
50 
51 void mm_jpeg_job_wait_for_event(mm_jpeg_obj *my_obj, uint32_t evt_mask);
52 void mm_jpeg_job_wait_for_cmd_complete(mm_jpeg_obj *my_obj,
53                                        int cmd,
54                                        int status);
55 OMX_ERRORTYPE mm_jpeg_etbdone(OMX_HANDLETYPE hComponent,
56                               OMX_PTR pAppData,
57                               OMX_BUFFERHEADERTYPE* pBuffer);
58 OMX_ERRORTYPE mm_jpeg_ftbdone(OMX_HANDLETYPE hComponent,
59                               OMX_PTR pAppData,
60                               OMX_BUFFERHEADERTYPE* pBuffer);
61 OMX_ERRORTYPE mm_jpeg_handle_omx_event(OMX_HANDLETYPE hComponent,
62                                        OMX_PTR pAppData,
63                                        OMX_EVENTTYPE eEvent,
64                                        OMX_U32 nData1,
65                                        OMX_U32 nData2,
66                                        OMX_PTR pEventData);
67 /* special queue functions for job queue */
68 int32_t mm_jpeg_queue_update_flag(mm_jpeg_queue_t* queue, uint32_t job_id, uint8_t flag);
69 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(mm_jpeg_queue_t* queue, uint32_t client_hdl);
70 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(mm_jpeg_queue_t* queue, uint32_t job_id);
71 
mm_jpeg_omx_load(mm_jpeg_obj * my_obj)72 int32_t mm_jpeg_omx_load(mm_jpeg_obj* my_obj)
73 {
74     int32_t rc = 0;
75     OMX_CALLBACKTYPE callbacks;
76 
77     callbacks.EmptyBufferDone = mm_jpeg_etbdone;
78     callbacks.FillBufferDone = mm_jpeg_ftbdone;
79     callbacks.EventHandler = mm_jpeg_handle_omx_event;
80     rc = OMX_GetHandle(&my_obj->omx_handle,
81                        "OMX.qcom.image.jpeg.encoder",
82                        (void*)my_obj,
83                        &callbacks);
84 
85     if (0 != rc) {
86         CDBG_ERROR("%s : OMX_GetHandle failed (%d)",__func__, rc);
87         return rc;
88     }
89 
90     rc = OMX_Init();
91     if (0 != rc) {
92         CDBG_ERROR("%s : OMX_Init failed (%d)",__func__, rc);
93         OMX_FreeHandle(my_obj->omx_handle);
94     }
95 
96     return rc;
97 }
98 
mm_jpeg_omx_unload(mm_jpeg_obj * my_obj)99 int32_t mm_jpeg_omx_unload(mm_jpeg_obj *my_obj)
100 {
101     int32_t rc = 0;
102     rc = OMX_Deinit();
103     OMX_FreeHandle(my_obj->omx_handle);
104 
105     return rc;
106 }
107 
mm_jpeg_omx_abort_job(mm_jpeg_obj * my_obj,mm_jpeg_job_entry * job_entry)108 int32_t mm_jpeg_omx_abort_job(mm_jpeg_obj *my_obj, mm_jpeg_job_entry* job_entry)
109 {
110     int32_t rc = 0;
111     uint8_t i, j;
112 
113     OMX_SendCommand(my_obj->omx_handle, OMX_CommandFlush, 0, NULL);
114     mm_jpeg_job_wait_for_event(my_obj,
115         MM_JPEG_EVENT_MASK_JPEG_DONE|MM_JPEG_EVENT_MASK_JPEG_ABORT|MM_JPEG_EVENT_MASK_JPEG_ERROR);
116     CDBG("%s:waitForEvent: OMX_CommandFlush: DONE", __func__);
117 
118     OMX_SendCommand(my_obj->omx_handle, OMX_CommandStateSet, OMX_StateIdle, NULL);
119     OMX_SendCommand(my_obj->omx_handle, OMX_CommandStateSet, OMX_StateLoaded, NULL);
120 
121     /* free buffers used in OMX processing */
122     for (i = 0; i < JPEG_SRC_IMAGE_TYPE_MAX; i++) {
123         for (j = 0; j < job_entry->src_bufs[i].num_bufs; j++) {
124             if (NULL != job_entry->src_bufs[i].bufs[j].buf_header) {
125                 OMX_FreeBuffer(my_obj->omx_handle,
126                                job_entry->src_bufs[i].bufs[j].portIdx,
127                                job_entry->src_bufs[i].bufs[j].buf_header);
128             }
129         }
130     }
131     OMX_FreeBuffer(my_obj->omx_handle,
132                    job_entry->sink_buf.portIdx,
133                    job_entry->sink_buf.buf_header);
134 
135     return rc;
136 }
137 
138 /* TODO: needs revisit after omx lib supports multi src buffers */
mm_jpeg_omx_config_main_buffer_offset(mm_jpeg_obj * my_obj,src_image_buffer_info * src_buf)139 int32_t mm_jpeg_omx_config_main_buffer_offset(mm_jpeg_obj* my_obj, src_image_buffer_info *src_buf)
140 {
141     int32_t rc = 0;
142     uint8_t i;
143     OMX_INDEXTYPE buf_offset_idx;
144     omx_jpeg_buffer_offset buffer_offset;
145 
146     for (i = 0; i < src_buf->num_bufs; i++) {
147         OMX_GetExtensionIndex(my_obj->omx_handle,
148                               "omx.qcom.jpeg.exttype.buffer_offset",
149                               &buf_offset_idx);
150         memset(&buffer_offset, 0, sizeof(buffer_offset));
151 
152         switch (src_buf->img_fmt) {
153         case JPEG_SRC_IMAGE_FMT_YUV:
154             if (1 == src_buf->src_image[i].offset.num_planes) {
155                 buffer_offset.yOffset =
156                     src_buf->src_image[i].offset.sp.y_offset;
157                 buffer_offset.cbcrOffset =
158                     src_buf->src_image[i].offset.sp.cbcr_offset;
159                 buffer_offset.totalSize =
160                     src_buf->src_image[i].offset.sp.len;
161             } else {
162                 buffer_offset.yOffset =
163                     src_buf->src_image[i].offset.mp[0].offset;
164                 buffer_offset.cbcrOffset =
165                     src_buf->src_image[i].offset.mp[1].offset;
166                 buffer_offset.totalSize =
167                     src_buf->src_image[i].offset.frame_len;
168             }
169             CDBG("%s: idx=%d, yOffset =%d, cbcrOffset =%d, totalSize = %d\n",
170                  __func__, i, buffer_offset.yOffset, buffer_offset.cbcrOffset, buffer_offset.totalSize);
171             OMX_SetParameter(my_obj->omx_handle, buf_offset_idx, &buffer_offset);
172             break;
173         case JPEG_SRC_IMAGE_FMT_BITSTREAM:
174             /* TODO: need visit here when bit stream is supported */
175             buffer_offset.yOffset =
176                 src_buf->bit_stream[i].data_offset;
177             buffer_offset.totalSize =
178                 src_buf->bit_stream[i].buf_size;
179             CDBG("%s: idx=%d, yOffset =%d, cbcrOffset =%d, totalSize = %d\n",
180                  __func__, i, buffer_offset.yOffset, buffer_offset.cbcrOffset, buffer_offset.totalSize);
181             OMX_SetParameter(my_obj->omx_handle, buf_offset_idx, &buffer_offset);
182             break;
183         default:
184             break;
185         }
186     }
187 
188     return rc;
189 }
190 
191 /* TODO: needs revisit after omx lib supports multi src buffers */
mm_jpeg_omx_config_port(mm_jpeg_obj * my_obj,src_image_buffer_info * src_buf,int port_idx)192 int32_t mm_jpeg_omx_config_port(mm_jpeg_obj* my_obj, src_image_buffer_info *src_buf, int port_idx)
193 {
194     int32_t rc = 0;
195     uint8_t i;
196     OMX_PARAM_PORTDEFINITIONTYPE input_port;
197 
198     for (i = 0; i < src_buf->num_bufs; i++) {
199         memset(&input_port, 0, sizeof(input_port));
200         input_port.nPortIndex = port_idx;
201         OMX_GetParameter(my_obj->omx_handle, OMX_IndexParamPortDefinition, &input_port);
202         input_port.format.image.nFrameWidth = src_buf->src_dim.width;
203         input_port.format.image.nFrameHeight =src_buf->src_dim.height;
204         input_port.format.image.nStride = src_buf->src_dim.width;
205         input_port.format.image.nSliceHeight = src_buf->src_dim.height;
206         switch (src_buf->img_fmt) {
207         case JPEG_SRC_IMAGE_FMT_YUV:
208             input_port.nBufferSize = src_buf->src_image[i].offset.frame_len;
209             break;
210         case JPEG_SRC_IMAGE_FMT_BITSTREAM:
211             input_port.nBufferSize = src_buf->bit_stream[i].buf_size;
212             break;
213         }
214 
215         OMX_SetParameter(my_obj->omx_handle, OMX_IndexParamPortDefinition, &input_port);
216     }
217 
218     return rc;
219 }
220 
map_jpeg_format(mm_jpeg_color_format color_fmt)221 omx_jpeg_color_format map_jpeg_format(mm_jpeg_color_format color_fmt)
222 {
223     switch (color_fmt) {
224     case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2:
225         return OMX_YCRCBLP_H2V2;
226     case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2:
227         return OMX_YCBCRLP_H2V2;
228     case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1:
229         return OMX_YCRCBLP_H2V1;
230     case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1:
231         return OMX_YCBCRLP_H2V1;
232     case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2:
233         return OMX_YCRCBLP_H1V2;
234     case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2:
235         return OMX_YCBCRLP_H1V2;
236     case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1:
237         return OMX_YCRCBLP_H1V1;
238     case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1:
239         return OMX_YCBCRLP_H1V1;
240     case MM_JPEG_COLOR_FORMAT_RGB565:
241         return OMX_RGB565;
242     case MM_JPEG_COLOR_FORMAT_RGB888:
243         return OMX_RGB888;
244     case MM_JPEG_COLOR_FORMAT_RGBa:
245         return OMX_RGBa;
246     case MM_JPEG_COLOR_FORMAT_BITSTREAM:
247         /* TODO: need to change to new bitstream value once omx interface changes */
248         return OMX_JPEG_BITSTREAM_H2V2;
249     default:
250         return OMX_JPEG_COLOR_FORMAT_MAX;
251     }
252 }
253 
mm_jpeg_omx_config_user_preference(mm_jpeg_obj * my_obj,mm_jpeg_encode_job * job)254 int32_t mm_jpeg_omx_config_user_preference(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job)
255 {
256     int32_t rc = 0;
257     OMX_INDEXTYPE user_pref_idx;
258     omx_jpeg_user_preferences user_preferences;
259 
260     memset(&user_preferences, 0, sizeof(user_preferences));
261     user_preferences.color_format =
262         map_jpeg_format(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_MAIN].color_format);
263     if (job->encode_parm.buf_info.src_imgs.src_img_num > 1) {
264         user_preferences.thumbnail_color_format =
265             map_jpeg_format(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_THUMB].color_format);
266     }
267     OMX_GetExtensionIndex(my_obj->omx_handle,
268                           "omx.qcom.jpeg.exttype.user_preferences",
269                           &user_pref_idx);
270     CDBG("%s:User Preferences: color_format %d, thumbnail_color_format = %d",
271          __func__, user_preferences.color_format, user_preferences.thumbnail_color_format);
272     OMX_SetParameter(my_obj->omx_handle, user_pref_idx, &user_preferences);
273     return rc;
274 }
275 
mm_jpeg_omx_config_thumbnail(mm_jpeg_obj * my_obj,mm_jpeg_encode_job * job)276 int32_t mm_jpeg_omx_config_thumbnail(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job)
277 {
278     int32_t rc = -1;
279     OMX_INDEXTYPE thumb_idx, q_idx;
280     omx_jpeg_thumbnail thumbnail;
281     omx_jpeg_thumbnail_quality quality;
282 
283     src_image_buffer_info *src_buf =
284         &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_THUMB]);
285 
286     /* config port */
287     rc = mm_jpeg_omx_config_port(my_obj, src_buf, INPUT_PORT_THUMBNAIL);
288     if (0 != rc) {
289         CDBG_ERROR("%s: config port failed", __func__);
290         return rc;
291     }
292 
293     /* check crop boundary */
294     if ((src_buf->crop.width == 0) || (src_buf->crop.height == 0) ||
295         (src_buf->crop.width + src_buf->crop.offset_x > src_buf->src_dim.width) ||
296         (src_buf->crop.height + src_buf->crop.offset_y > src_buf->src_dim.height)) {
297         CDBG_ERROR("%s: invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)",
298                    __func__,
299                    src_buf->crop.width,
300                    src_buf->crop.height,
301                    src_buf->crop.offset_x,
302                    src_buf->crop.offset_y,
303                    src_buf->src_dim.width,
304                    src_buf->src_dim.height);
305         return rc;
306     }
307 
308     memset(&thumbnail, 0, sizeof(thumbnail));
309 
310     /* thumbnail crop info */
311     thumbnail.cropWidth = CEILING2(src_buf->crop.width);
312     thumbnail.cropHeight = CEILING2(src_buf->crop.height);
313     thumbnail.left = src_buf->crop.offset_x;
314     thumbnail.top = src_buf->crop.offset_y;
315 
316     /* thumbnail output dimention */
317     thumbnail.width = src_buf->out_dim.width;
318     thumbnail.height = src_buf->out_dim.height;
319 
320     /* set scaling flag */
321     if (thumbnail.left > 0 || thumbnail.top > 0 ||
322         src_buf->crop.width != src_buf->out_dim.width ||
323         src_buf->crop.height != src_buf->out_dim.height) {
324         thumbnail.scaling = 1;
325     }
326 
327     /* set omx thumbnail info */
328     OMX_GetExtensionIndex(my_obj->omx_handle, "omx.qcom.jpeg.exttype.thumbnail", &thumb_idx);
329     OMX_SetParameter(my_obj->omx_handle, thumb_idx, &thumbnail);
330 
331     OMX_GetExtensionIndex(my_obj->omx_handle, "omx.qcom.jpeg.exttype.thumbnail_quality", &q_idx);
332     OMX_GetParameter(my_obj->omx_handle, q_idx, &quality);
333     quality.nQFactor = src_buf->quality;
334     OMX_SetParameter(my_obj->omx_handle, q_idx, &quality);
335 
336     rc = 0;
337     return rc;
338 }
339 
mm_jpeg_omx_config_main_crop(mm_jpeg_obj * my_obj,src_image_buffer_info * src_buf)340 int32_t mm_jpeg_omx_config_main_crop(mm_jpeg_obj* my_obj, src_image_buffer_info *src_buf)
341 {
342     int32_t rc = 0;
343     OMX_CONFIG_RECTTYPE rect_type;
344 
345     /* error check first */
346     if (src_buf->crop.width + src_buf->crop.offset_x > src_buf->src_dim.width ||
347         src_buf->crop.height + src_buf->crop.offset_y > src_buf->src_dim.height) {
348         CDBG_ERROR("%s: invalid crop boundary (%d, %d) out of (%d, %d)", __func__,
349                    src_buf->crop.width + src_buf->crop.offset_x,
350                    src_buf->crop.height + src_buf->crop.offset_y,
351                    src_buf->src_dim.width,
352                    src_buf->src_dim.height);
353         return -1;
354     }
355 
356     if (src_buf->crop.width && src_buf->crop.width) {
357         /* Scaler information */
358         memset(&rect_type, 0, sizeof(rect_type));
359         rect_type.nWidth = CEILING2(src_buf->crop.width);
360         rect_type.nHeight = CEILING2(src_buf->crop.width);
361         rect_type.nLeft = src_buf->crop.offset_x;
362         rect_type.nTop = src_buf->crop.offset_y;
363         rect_type.nPortIndex = OUTPUT_PORT;
364         OMX_SetConfig(my_obj->omx_handle, OMX_IndexConfigCommonInputCrop, &rect_type);
365 
366         if (src_buf->out_dim.width && src_buf->out_dim.height) {
367             memset(&rect_type, 0, sizeof(rect_type));
368             rect_type.nWidth = src_buf->out_dim.width;
369             rect_type.nHeight = src_buf->out_dim.height;
370             rect_type.nPortIndex = OUTPUT_PORT;
371             OMX_SetConfig(my_obj->omx_handle, OMX_IndexConfigCommonOutputCrop, &rect_type);
372         }
373 
374     } else {
375         CDBG_ERROR("%s: There is no main image scaling information", __func__);
376         rc = -1;
377     }
378 
379     return rc;
380 }
381 
mm_jpeg_omx_config_main(mm_jpeg_obj * my_obj,mm_jpeg_encode_job * job)382 int32_t mm_jpeg_omx_config_main(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job)
383 {
384     int32_t rc = 0;
385     src_image_buffer_info *src_buf =
386         &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_MAIN]);
387     OMX_IMAGE_PARAM_QFACTORTYPE q_factor;
388 
389     /* config port */
390     rc = mm_jpeg_omx_config_port(my_obj, src_buf, INPUT_PORT_MAIN);
391     if (0 != rc) {
392         CDBG_ERROR("%s: config port failed", __func__);
393         return rc;
394     }
395 
396     /* config buffer offset */
397     rc = mm_jpeg_omx_config_main_buffer_offset(my_obj, src_buf);
398     if (0 != rc) {
399         CDBG_ERROR("%s: config buffer offset failed", __func__);
400         return rc;
401     }
402 
403     /* config crop */
404     rc = mm_jpeg_omx_config_main_crop(my_obj, src_buf);
405     if (0 != rc) {
406         CDBG_ERROR("%s: config crop failed", __func__);
407         return rc;
408     }
409 
410     /* set quality */
411     memset(&q_factor, 0, sizeof(q_factor));
412     q_factor.nPortIndex = INPUT_PORT_MAIN;
413     OMX_GetParameter(my_obj->omx_handle, OMX_IndexParamQFactor, &q_factor);
414     q_factor.nQFactor = src_buf->quality;
415     OMX_SetParameter(my_obj->omx_handle, OMX_IndexParamQFactor, &q_factor);
416 
417     return rc;
418 }
419 
mm_jpeg_omx_config_common(mm_jpeg_obj * my_obj,mm_jpeg_encode_job * job)420 int32_t mm_jpeg_omx_config_common(mm_jpeg_obj* my_obj, mm_jpeg_encode_job* job)
421 {
422     int32_t rc;
423     int i;
424     OMX_INDEXTYPE exif_idx;
425     omx_jpeg_exif_info_tag tag;
426     OMX_CONFIG_ROTATIONTYPE rotate;
427 
428     /* config user prefernces */
429     rc = mm_jpeg_omx_config_user_preference(my_obj, job);
430     if (0 != rc) {
431         CDBG_ERROR("%s: config user preferences failed", __func__);
432         return rc;
433     }
434 
435     /* set rotation */
436     memset(&rotate, 0, sizeof(rotate));
437     rotate.nPortIndex = OUTPUT_PORT;
438     rotate.nRotation = job->encode_parm.rotation;
439     OMX_SetConfig(my_obj->omx_handle, OMX_IndexConfigCommonRotate, &rotate);
440     CDBG("%s: Set rotation to %d\n", __func__, job->encode_parm.rotation);
441 
442     /* set exif tags */
443     OMX_GetExtensionIndex(my_obj->omx_handle, "omx.qcom.jpeg.exttype.exif", &exif_idx);
444     for(i = 0; i < job->encode_parm.exif_numEntries; i++) {
445         memcpy(&tag, job->encode_parm.exif_data + i, sizeof(omx_jpeg_exif_info_tag));
446         OMX_SetParameter(my_obj->omx_handle, exif_idx, &tag);
447     }
448 
449     return rc;
450 }
451 
mm_jpeg_omx_use_buf(mm_jpeg_obj * my_obj,src_image_buffer_info * src_buf,mm_jpeg_omx_src_buf * omx_src_buf,int port_idx)452 int32_t mm_jpeg_omx_use_buf(mm_jpeg_obj* my_obj,
453                             src_image_buffer_info *src_buf,
454                             mm_jpeg_omx_src_buf* omx_src_buf,
455                             int port_idx)
456 {
457     int32_t rc = 0;
458     uint8_t i;
459     omx_jpeg_pmem_info pmem_info;
460 
461     omx_src_buf->num_bufs = src_buf->num_bufs;
462     for (i = 0; i < src_buf->num_bufs; i++) {
463         memset(&pmem_info, 0, sizeof(pmem_info));
464         switch (src_buf->img_fmt) {
465         case JPEG_SRC_IMAGE_FMT_YUV:
466             pmem_info.fd = src_buf->src_image[i].fd;
467             pmem_info.offset = 0;
468             omx_src_buf->bufs[i].portIdx = port_idx;
469             OMX_UseBuffer(my_obj->omx_handle,
470                           &omx_src_buf->bufs[i].buf_header,
471                           port_idx,
472                           &pmem_info,
473                           src_buf->src_image[i].offset.frame_len,
474                           (void *)src_buf->src_image[i].buf_vaddr);
475             break;
476         case JPEG_SRC_IMAGE_FMT_BITSTREAM:
477             pmem_info.fd = src_buf->bit_stream[i].fd;
478             pmem_info.offset = 0;
479             omx_src_buf->bufs[i].portIdx = port_idx;
480             OMX_UseBuffer(my_obj->omx_handle,
481                           &omx_src_buf->bufs[i].buf_header,
482                           port_idx,
483                           &pmem_info,
484                           src_buf->bit_stream[i].buf_size,
485                           (void *)src_buf->bit_stream[i].buf_vaddr);
486             break;
487         default:
488             rc = -1;
489             break;
490         }
491     }
492 
493     return rc;
494 }
495 
mm_jpeg_omx_encode(mm_jpeg_obj * my_obj,mm_jpeg_job_entry * job_entry)496 int32_t mm_jpeg_omx_encode(mm_jpeg_obj* my_obj, mm_jpeg_job_entry* job_entry)
497 {
498     int32_t rc = 0;
499     uint8_t i;
500     mm_jpeg_encode_job* job = &job_entry->job.encode_job;
501     uint8_t has_thumbnail = job->encode_parm.buf_info.src_imgs.src_img_num > 1? 1 : 0;
502     src_image_buffer_info *src_buf[JPEG_SRC_IMAGE_TYPE_MAX];
503     mm_jpeg_omx_src_buf *omx_src_buf[JPEG_SRC_IMAGE_TYPE_MAX];
504 
505     /* config main img */
506     rc = mm_jpeg_omx_config_main(my_obj, job);
507     if (0 != rc) {
508         CDBG_ERROR("%s: config main img failed", __func__);
509         return rc;
510     }
511 
512     /* config thumbnail */
513     rc = mm_jpeg_omx_config_thumbnail(my_obj, job);
514     if (0 != rc) {
515         CDBG_ERROR("%s: config thumbnail img failed", __func__);
516         return rc;
517     }
518 
519     /* common config */
520     rc = mm_jpeg_omx_config_common(my_obj, job);
521     if (0 != rc) {
522         CDBG_ERROR("%s: config common failed", __func__);
523         return rc;
524     }
525 
526     /* config input omx buffer for main input */
527     src_buf[JPEG_SRC_IMAGE_TYPE_MAIN] = &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_MAIN]);
528     omx_src_buf[JPEG_SRC_IMAGE_TYPE_MAIN] = &job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_MAIN];
529     rc = mm_jpeg_omx_use_buf(my_obj,
530                              src_buf[JPEG_SRC_IMAGE_TYPE_MAIN],
531                              omx_src_buf[JPEG_SRC_IMAGE_TYPE_MAIN],
532                              INPUT_PORT_MAIN);
533     if (0 != rc) {
534         CDBG_ERROR("%s: config main input omx buffer failed", __func__);
535         return rc;
536     }
537 
538     /* config input omx buffer for thumbnail input if there is thumbnail */
539     if (has_thumbnail) {
540         src_buf[JPEG_SRC_IMAGE_TYPE_THUMB] = &(job->encode_parm.buf_info.src_imgs.src_img[JPEG_SRC_IMAGE_TYPE_THUMB]);
541         omx_src_buf[JPEG_SRC_IMAGE_TYPE_THUMB] = &job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_THUMB];
542         rc = mm_jpeg_omx_use_buf(my_obj,
543                                  src_buf[JPEG_SRC_IMAGE_TYPE_THUMB],
544                                  omx_src_buf[JPEG_SRC_IMAGE_TYPE_THUMB],
545                                  INPUT_PORT_THUMBNAIL);
546         if (0 != rc) {
547             CDBG_ERROR("%s: config thumbnail input omx buffer failed", __func__);
548             return rc;
549         }
550     }
551 
552     /* config output omx buffer */
553     job_entry->sink_buf.portIdx = OUTPUT_PORT;
554     OMX_UseBuffer(my_obj->omx_handle,
555                   &job_entry->sink_buf.buf_header,
556                   job_entry->sink_buf.portIdx,
557                   NULL,
558                   job->encode_parm.buf_info.sink_img.buf_len,
559                   (void *)job->encode_parm.buf_info.sink_img.buf_vaddr);
560 
561     /* wait for OMX state ready */
562     mm_jpeg_job_wait_for_cmd_complete(my_obj, OMX_CommandStateSet, OMX_StateIdle);
563     CDBG("%s: State changed to OMX_StateIdle\n", __func__);
564 
565     /* start OMX encoding by sending executing cmd */
566     OMX_SendCommand(my_obj->omx_handle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
567     mm_jpeg_job_wait_for_cmd_complete(my_obj, OMX_CommandStateSet, OMX_StateExecuting);
568 
569     /* start input fedding and output writing */
570     for (i = 0; i < job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_MAIN].num_bufs; i++) {
571         OMX_EmptyThisBuffer(my_obj->omx_handle,
572                             job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_MAIN].bufs[i].buf_header);
573     }
574     if (has_thumbnail) {
575         for (i = 0; i < job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_THUMB].num_bufs; i++) {
576             OMX_EmptyThisBuffer(my_obj->omx_handle,
577                                 job_entry->src_bufs[JPEG_SRC_IMAGE_TYPE_THUMB].bufs[i].buf_header);
578         }
579     }
580     OMX_FillThisBuffer(my_obj->omx_handle, job_entry->sink_buf.buf_header);
581 
582     return rc;
583 }
584 
mm_jpeg_notify_thread(void * data)585 static void *mm_jpeg_notify_thread(void *data)
586 {
587     mm_jpeg_job_q_node_t* job_node = (mm_jpeg_job_q_node_t *)data;
588     mm_jpeg_job_entry * job_entry = &job_node->entry;
589     mm_jpeg_obj* my_obj = (mm_jpeg_obj *)job_entry->jpeg_obj;
590     void* node = NULL;
591     int32_t rc = 0;
592 
593     if (NULL == my_obj) {
594         CDBG_ERROR("%s: jpeg obj is NULL", __func__);
595         return NULL;
596     }
597 
598     /* Add to cb queue */
599     rc = mm_jpeg_queue_enq(&my_obj->cb_q, data);
600     if (0 != rc) {
601         CDBG_ERROR("%s: enqueue into cb_q failed", __func__);
602         return NULL;
603     }
604 
605     /* call cb */
606     if (NULL != job_entry->job.encode_job.jpeg_cb) {
607         /* has callback, send CB */
608         job_entry->job.encode_job.jpeg_cb(job_entry->job_status,
609                                           job_entry->thumbnail_dropped,
610                                           job_entry->client_hdl,
611                                           job_entry->jobId,
612                                           job_entry->job.encode_job.encode_parm.buf_info.sink_img.buf_vaddr,
613                                           job_entry->jpeg_size,
614                                           job_entry->job.encode_job.userdata);
615     } else {
616         CDBG_ERROR("%s: no cb provided, no action", __func__);
617     }
618 
619     /* Remove from cb queue */
620     node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->cb_q, job_entry->jobId);
621     if (NULL != node) {
622         free(node);
623     }
624 
625     return NULL;
626 }
627 
628 /* process encoding job */
mm_jpeg_process_encoding_job(mm_jpeg_obj * my_obj,mm_jpeg_job_q_node_t * job_node)629 int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node)
630 {
631     int32_t rc = 0;
632     mm_jpeg_job_entry* job_entry = &job_node->entry;
633 
634     /* call OMX_Encode */
635     rc = mm_jpeg_omx_encode(my_obj, job_entry);
636     if (0 == rc) {
637         /* sent encode cmd to OMX, queue job into ongoing queue */
638         rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, job_node);
639     } else {
640         /* OMX encode failed, notify error through callback */
641         job_entry->job_status = JPEG_JOB_STATUS_ERROR;
642         if (NULL != job_entry->job.encode_job.jpeg_cb) {
643             /* has callback, create a thread to send CB */
644             pthread_create(&job_entry->cb_pid,
645                            NULL,
646                            mm_jpeg_notify_thread,
647                            (void *)job_node);
648 
649         } else {
650             CDBG_ERROR("%s: no cb provided, return here", __func__);
651             free(job_node);
652         }
653     }
654 
655     return rc;
656 }
657 /* process job (encoding/decoding) */
mm_jpeg_process_job(mm_jpeg_obj * my_obj,mm_jpeg_job_q_node_t * job_node)658 int32_t mm_jpeg_process_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node)
659 {
660     int32_t rc = 0;
661 
662     switch (job_node->entry.job.job_type) {
663     case JPEG_JOB_TYPE_ENCODE:
664         rc = mm_jpeg_process_encoding_job(my_obj, job_node);
665         break;
666     default:
667         CDBG_ERROR("%s: job type not supported (%d)",
668                    __func__, job_node->entry.job.job_type);
669         rc = -1;
670         break;
671     }
672 
673     return rc;
674 }
675 
mm_jpeg_jobmgr_thread(void * data)676 static void *mm_jpeg_jobmgr_thread(void *data)
677 {
678     int rc = 0;
679     int running = 1;
680     uint32_t num_ongoing_jobs = 0;
681     mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data;
682     mm_jpeg_job_cmd_thread_t *cmd_thread =
683                 (mm_jpeg_job_cmd_thread_t *)data;
684     mm_jpeg_job_q_node_t* node = NULL;
685 
686     do {
687         do {
688             rc = sem_wait(&cmd_thread->job_sem);
689             if (rc != 0 && errno != EINVAL) {
690                 CDBG_ERROR("%s: sem_wait error (%s)",
691                            __func__, strerror(errno));
692                 return NULL;
693             }
694         } while (rc != 0);
695 
696         /* check ongoing q size */
697         num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q);
698         if (num_ongoing_jobs >= NUM_MAX_JPEG_CNCURRENT_JOBS) {
699             continue;
700         }
701 
702         pthread_mutex_lock(&my_obj->job_lock);
703         /* can go ahead with new work */
704         node = (mm_jpeg_job_q_node_t*)mm_jpeg_queue_deq(&cmd_thread->job_queue);
705         if (node != NULL) {
706             switch (node->type) {
707             case MM_JPEG_CMD_TYPE_JOB:
708                 rc = mm_jpeg_process_job(my_obj, node);
709                 if (0 != rc) {
710                     /* free node in error case */
711                     free(node);
712                 }
713                 break;
714             case MM_JPEG_CMD_TYPE_EXIT:
715             default:
716                 /* free node */
717                 free(node);
718                 /* set running flag to false */
719                 running = 0;
720                 break;
721             }
722         }
723         pthread_mutex_unlock(&my_obj->job_lock);
724 
725     } while (running);
726     return NULL;
727 }
728 
mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj * my_obj)729 int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj * my_obj)
730 {
731     int32_t rc = 0;
732     mm_jpeg_job_cmd_thread_t * job_mgr = &my_obj->job_mgr;
733 
734     sem_init(&job_mgr->job_sem, 0, 0);
735     mm_jpeg_queue_init(&job_mgr->job_queue);
736 
737     /* launch the thread */
738     pthread_create(&job_mgr->pid,
739                    NULL,
740                    mm_jpeg_jobmgr_thread,
741                    (void *)my_obj);
742     return rc;
743 }
744 
mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj)745 int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj)
746 {
747     int32_t rc = 0;
748     mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr;
749     mm_jpeg_job_q_node_t* node =
750         (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
751     if (NULL == node) {
752         CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
753         return -1;
754     }
755 
756     memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
757     node->type = MM_JPEG_CMD_TYPE_EXIT;
758 
759     mm_jpeg_queue_enq(&cmd_thread->job_queue, node);
760     sem_post(&cmd_thread->job_sem);
761 
762     /* wait until cmd thread exits */
763     if (pthread_join(cmd_thread->pid, NULL) != 0) {
764         CDBG("%s: pthread dead already\n", __func__);
765     }
766     mm_jpeg_queue_deinit(&cmd_thread->job_queue);
767 
768     sem_destroy(&cmd_thread->job_sem);
769     memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t));
770     return rc;
771 }
772 
mm_jpeg_init(mm_jpeg_obj * my_obj)773 int32_t mm_jpeg_init(mm_jpeg_obj *my_obj)
774 {
775     int32_t rc = 0;
776 
777     /* init locks */
778     pthread_mutex_init(&my_obj->job_lock, NULL);
779     pthread_mutex_init(&my_obj->omx_evt_lock, NULL);
780     pthread_cond_init(&my_obj->omx_evt_cond, NULL);
781 
782     /* init ongoing job queue */
783     rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q);
784 
785     /* init job semaphore and launch jobmgr thread */
786     CDBG("%s : Launch jobmgr thread",__func__);
787     rc = mm_jpeg_jobmgr_thread_launch(my_obj);
788 
789     /* load OMX */
790     rc = mm_jpeg_omx_load(my_obj);
791     if (0 != rc) {
792         /* roll back in error case */
793         mm_jpeg_jobmgr_thread_release(my_obj);
794         mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
795         pthread_mutex_destroy(&my_obj->job_lock);
796         pthread_mutex_destroy(&my_obj->omx_evt_lock);
797         pthread_cond_destroy(&my_obj->omx_evt_cond);
798     }
799 
800     return rc;
801 }
802 
mm_jpeg_deinit(mm_jpeg_obj * my_obj)803 int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj)
804 {
805     int32_t rc = 0;
806 
807     /* unload OMX engine */
808     rc = mm_jpeg_omx_unload(my_obj);
809 
810     /* release jobmgr thread */
811     rc = mm_jpeg_jobmgr_thread_release(my_obj);
812 
813     /* deinit ongoing job queue */
814     rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
815 
816     /* destroy locks */
817     pthread_mutex_destroy(&my_obj->job_lock);
818     pthread_mutex_destroy(&my_obj->omx_evt_lock);
819     pthread_cond_destroy(&my_obj->omx_evt_cond);
820 
821     return rc;
822 }
823 
mm_jpeg_new_client(mm_jpeg_obj * my_obj)824 uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj)
825 {
826     uint32_t client_hdl = 0;
827     uint8_t idx;
828 
829     if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) {
830         CDBG_ERROR("%s: num of clients reached limit", __func__);
831         return client_hdl;
832     }
833 
834     for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) {
835         if (0 == my_obj->clnt_mgr[idx].is_used) {
836             break;
837         }
838     }
839 
840     if (idx < MAX_JPEG_CLIENT_NUM) {
841         /* client entry avail */
842         /* generate client handler by index */
843         client_hdl = mm_jpeg_util_generate_handler(idx);
844 
845         /* update client entry */
846         my_obj->clnt_mgr[idx].is_used = 1;
847         my_obj->clnt_mgr[idx].client_handle = client_hdl;
848 
849         /* increse client count */
850         my_obj->num_clients++;
851     }
852 
853     return client_hdl;
854 }
855 
mm_jpeg_start_job(mm_jpeg_obj * my_obj,uint32_t client_hdl,mm_jpeg_job * job,uint32_t * jobId)856 int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj,
857                           uint32_t client_hdl,
858                           mm_jpeg_job* job,
859                           uint32_t* jobId)
860 {
861     int32_t rc = -1;
862     uint8_t clnt_idx = 0;
863     uint32_t job_id = 0;
864     mm_jpeg_job_q_node_t* node = NULL;
865 
866     *jobId = 0;
867 
868     /* check if valid client */
869     clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
870     if (clnt_idx >= MAX_JPEG_CLIENT_NUM ) {
871         CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
872         return rc;
873     }
874 
875     /* generate client handler by index */
876     job_id = mm_jpeg_util_generate_handler(clnt_idx);
877 
878     /* enqueue new job into todo job queue */
879     node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
880     if (NULL == node) {
881         CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
882         return -rc;
883     }
884 
885     memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
886     node->type = MM_JPEG_CMD_TYPE_JOB;
887     node->entry.client_hdl = client_hdl;
888     node->entry.jobId = job_id;
889     memcpy(&node->entry.job, job, sizeof(mm_jpeg_job));
890     node->entry.jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */
891 
892     rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, node);
893     if (0 == rc) {
894         sem_post(&my_obj->job_mgr.job_sem);
895         *jobId = job_id;
896     }
897 
898     return rc;
899 }
900 
mm_jpeg_abort_job(mm_jpeg_obj * my_obj,uint32_t client_hdl,uint32_t jobId)901 int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj,
902                           uint32_t client_hdl,
903                           uint32_t jobId)
904 {
905     int32_t rc = -1;
906     uint8_t clnt_idx = 0;
907     void * node = NULL;
908     mm_jpeg_job_entry* job_entry = NULL;
909 
910     /* check if valid client */
911     clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
912     if (clnt_idx >= MAX_JPEG_CLIENT_NUM ) {
913         CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
914         return rc;
915     }
916 
917     pthread_mutex_lock(&my_obj->job_lock);
918 
919     /* abort job if in ongoing queue */
920     node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId);
921     if (NULL != node) {
922         /* find job that is OMX ongoing, ask OMX to abort the job */
923         job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);
924         rc = mm_jpeg_omx_abort_job(my_obj, job_entry);
925         free(node);
926         goto abort_done;
927     }
928 
929     /* abort job if in todo queue */
930     node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId);
931     if (NULL != node) {
932         /* simply delete it */
933         free(node);
934         goto abort_done;
935     }
936 
937     /* abort job if in cb queue */
938     node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->cb_q, jobId);
939     if (NULL != node) {
940         /* join cb thread */
941         job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);
942         if (pthread_join(job_entry->cb_pid, NULL) != 0) {
943             CDBG("%s: pthread dead already\n", __func__);
944         }
945         free(node);
946     }
947 
948 abort_done:
949     pthread_mutex_unlock(&my_obj->job_lock);
950 
951     /* wake up jobMgr thread to work on new job if there is any */
952     sem_post(&my_obj->job_mgr.job_sem);
953 
954     return rc;
955 }
956 
mm_jpeg_close(mm_jpeg_obj * my_obj,uint32_t client_hdl)957 int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl)
958 {
959     int32_t rc = -1;
960     uint8_t clnt_idx = 0;
961     void* node = NULL;
962     mm_jpeg_job_entry* job_entry = NULL;
963 
964     /* check if valid client */
965     clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
966     if (clnt_idx >= MAX_JPEG_CLIENT_NUM ) {
967         CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
968         return rc;
969     }
970 
971     /* abort all jobs from the client */
972     pthread_mutex_lock(&my_obj->job_lock);
973 
974     /* abort job if in ongoing queue */
975     node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->ongoing_job_q, client_hdl);
976     while (NULL != node) {
977         /* find job that is OMX ongoing, ask OMX to abort the job */
978         job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);
979         rc = mm_jpeg_omx_abort_job(my_obj, job_entry);
980         free(node);
981 
982         /* find next job from ongoing queue that belongs to this client */
983         node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->ongoing_job_q, client_hdl);
984     }
985 
986     /* abort job if in todo queue */
987     node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->job_mgr.job_queue, client_hdl);
988     while (NULL != node) {
989         /* simply delete the job if in todo queue */
990         free(node);
991 
992         /* find next job from todo queue that belongs to this client */
993         node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->job_mgr.job_queue, client_hdl);
994     }
995 
996     /* abort job if in cb queue */
997     node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->cb_q, client_hdl);
998     while (NULL != node) {
999         /* join cb thread */
1000         job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);
1001         if (pthread_join(job_entry->cb_pid, NULL) != 0) {
1002             CDBG("%s: pthread dead already\n", __func__);
1003         }
1004         free(node);
1005 
1006         /* find next job from cb queue that belongs to this client */
1007         node = mm_jpeg_queue_remove_job_by_client_id(&my_obj->cb_q, client_hdl);
1008     }
1009 
1010     pthread_mutex_unlock(&my_obj->job_lock);
1011 
1012     /* invalidate client entry */
1013     memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t));
1014 
1015     return rc;
1016 }
1017 
mm_jpeg_job_wait_for_event(mm_jpeg_obj * my_obj,uint32_t evt_mask)1018 void mm_jpeg_job_wait_for_event(mm_jpeg_obj *my_obj, uint32_t evt_mask)
1019 {
1020     pthread_mutex_lock(&my_obj->omx_evt_lock);
1021     while (!(my_obj->omx_evt_rcvd.evt & evt_mask)) {
1022         pthread_cond_wait(&my_obj->omx_evt_cond, &my_obj->omx_evt_lock);
1023     }
1024     CDBG("%s:done", __func__);
1025     pthread_mutex_unlock(&my_obj->omx_evt_lock);
1026 }
1027 
mm_jpeg_job_wait_for_cmd_complete(mm_jpeg_obj * my_obj,int cmd,int status)1028 void mm_jpeg_job_wait_for_cmd_complete(mm_jpeg_obj *my_obj,
1029                                        int cmd,
1030                                        int status)
1031 {
1032     pthread_mutex_lock(&my_obj->omx_evt_lock);
1033     while (!((my_obj->omx_evt_rcvd.evt & MM_JPEG_EVENT_MASK_CMD_COMPLETE) &&
1034              (my_obj->omx_evt_rcvd.omx_value1 == cmd) &&
1035              (my_obj->omx_evt_rcvd.omx_value2 == status))) {
1036         pthread_cond_wait(&my_obj->omx_evt_cond, &my_obj->omx_evt_lock);
1037     }
1038     CDBG("%s:done", __func__);
1039     pthread_mutex_unlock(&my_obj->omx_evt_lock);
1040 }
1041 
mm_jpeg_etbdone(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_BUFFERHEADERTYPE * pBuffer)1042 OMX_ERRORTYPE mm_jpeg_etbdone(OMX_HANDLETYPE hComponent,
1043                               OMX_PTR pAppData,
1044                               OMX_BUFFERHEADERTYPE* pBuffer)
1045 {
1046     /* no process needed for etbdone, return here */
1047     return 0;
1048 }
1049 
mm_jpeg_ftbdone(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_BUFFERHEADERTYPE * pBuffer)1050 OMX_ERRORTYPE mm_jpeg_ftbdone(OMX_HANDLETYPE hComponent,
1051                               OMX_PTR pAppData,
1052                               OMX_BUFFERHEADERTYPE* pBuffer)
1053 {
1054     int rc = 0;
1055     void* node = NULL;
1056     mm_jpeg_job_entry* job_entry = NULL;
1057     mm_jpeg_obj * my_obj = (mm_jpeg_obj*)pAppData;
1058 
1059     if (NULL != my_obj) {
1060         CDBG_ERROR("%s: pAppData is NULL, return here", __func__);
1061         return rc;
1062     }
1063 
1064     /* signal JPEG_DONE event */
1065     pthread_mutex_lock(&my_obj->omx_evt_lock);
1066     my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_JPEG_DONE;
1067     pthread_cond_signal(&my_obj->omx_evt_cond);
1068     pthread_mutex_unlock(&my_obj->omx_evt_lock);
1069 
1070     /* If OMX can support multi encoding, it should provide a way to pass jobID.
1071      * then we can find job by jobID from ongoing queue.
1072      * For now, since OMX only support one job per time, we simply dequeue it. */
1073     pthread_mutex_lock(&my_obj->job_lock);
1074     node = mm_jpeg_queue_deq(&my_obj->ongoing_job_q);
1075     if (NULL != node) {
1076         job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);;
1077         /* find job that is OMX ongoing */
1078         job_entry->jpeg_size = pBuffer->nFilledLen;
1079         job_entry->job_status = JPEG_JOB_STATUS_DONE;
1080         CDBG("%s:filled len = %u, status = %d",
1081              __func__, job_entry->jpeg_size, job_entry->job_status);
1082 
1083         if (NULL != job_entry->job.encode_job.jpeg_cb) {
1084             /* has callback, create a thread to send CB */
1085             pthread_create(&job_entry->cb_pid,
1086                            NULL,
1087                            mm_jpeg_notify_thread,
1088                            node);
1089 
1090         } else {
1091             CDBG_ERROR("%s: no cb provided, return here", __func__);
1092             free(node);
1093         }
1094     }
1095     pthread_mutex_unlock(&my_obj->job_lock);
1096 
1097     /* Wake up jobMgr thread to work on next job if there is any */
1098     sem_post(&my_obj->job_mgr.job_sem);
1099 
1100     return rc;
1101 }
1102 
mm_jpeg_handle_omx_event(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_EVENTTYPE eEvent,OMX_U32 nData1,OMX_U32 nData2,OMX_PTR pEventData)1103 OMX_ERRORTYPE mm_jpeg_handle_omx_event(OMX_HANDLETYPE hComponent,
1104                                        OMX_PTR pAppData,
1105                                        OMX_EVENTTYPE eEvent,
1106                                        OMX_U32 nData1,
1107                                        OMX_U32 nData2,
1108                                        OMX_PTR pEventData)
1109 {
1110     int rc = 0;
1111     void* node = NULL;
1112     mm_jpeg_job_entry* job_entry = NULL;
1113     mm_jpeg_obj * my_obj = (mm_jpeg_obj*)pAppData;
1114     uint32_t jobId = 0;
1115 
1116     if (NULL != my_obj) {
1117         CDBG_ERROR("%s: pAppData is NULL, return here", __func__);
1118         return rc;
1119     }
1120 
1121     /* signal event */
1122     switch (eEvent) {
1123     case  OMX_EVENT_JPEG_ABORT:
1124         {
1125             /* signal error evt */
1126             pthread_mutex_lock(&my_obj->omx_evt_lock);
1127             my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_JPEG_ABORT;
1128             pthread_cond_signal(&my_obj->omx_evt_cond);
1129             pthread_mutex_unlock(&my_obj->omx_evt_lock);
1130         }
1131         break;
1132     case OMX_EventError:
1133         {
1134             switch (nData1) {
1135             case OMX_EVENT_THUMBNAIL_DROPPED:
1136                 {
1137                     uint8_t thumbnail_dropped_flag = 1;
1138                     mm_jpeg_queue_update_flag(&my_obj->ongoing_job_q,
1139                                               jobId,
1140                                               thumbnail_dropped_flag);
1141                 }
1142                 break;
1143             case OMX_EVENT_JPEG_ERROR:
1144                 {
1145                     /* signal error evt */
1146                     pthread_mutex_lock(&my_obj->omx_evt_lock);
1147                     my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_JPEG_ERROR;
1148                     pthread_cond_signal(&my_obj->omx_evt_cond);
1149                     pthread_mutex_unlock(&my_obj->omx_evt_lock);
1150 
1151                     /* send CB for error case */
1152                     /* If OMX can support multi encoding, it should provide a way to pass jobID.
1153                      * then we can find job by jobID from ongoing queue.
1154                      * For now, since OMX only support one job per time, we simply dequeue it. */
1155                     pthread_mutex_lock(&my_obj->job_lock);
1156                     node = mm_jpeg_queue_deq(&my_obj->ongoing_job_q);
1157                     if (NULL != node) {
1158                         job_entry = &(((mm_jpeg_job_q_node_t *)node)->entry);;
1159 
1160                         /* find job that is OMX ongoing */
1161                         job_entry->job_status = JPEG_JOB_STATUS_ERROR;
1162                         if (NULL != job_entry->job.encode_job.jpeg_cb) {
1163                             /* has callback, create a thread to send CB */
1164                             pthread_create(&job_entry->cb_pid,
1165                                            NULL,
1166                                            mm_jpeg_notify_thread,
1167                                            node);
1168 
1169                         } else {
1170                             CDBG_ERROR("%s: no cb provided, return here", __func__);
1171                             free(node);
1172                         }
1173                     }
1174                     pthread_mutex_unlock(&my_obj->job_lock);
1175 
1176                     /* Wake up jobMgr thread to work on next job if there is any */
1177                     sem_post(&my_obj->job_mgr.job_sem);
1178                 }
1179                 break;
1180             default:
1181                 break;
1182             }
1183         }
1184         break;
1185     case OMX_EventCmdComplete:
1186         {
1187             /* signal cmd complete evt */
1188             pthread_mutex_lock(&my_obj->omx_evt_lock);
1189             my_obj->omx_evt_rcvd.evt = MM_JPEG_EVENT_MASK_CMD_COMPLETE;
1190             my_obj->omx_evt_rcvd.omx_value1 = nData1;
1191             my_obj->omx_evt_rcvd.omx_value2 = nData2;
1192             pthread_cond_signal(&my_obj->omx_evt_cond);
1193             pthread_mutex_unlock(&my_obj->omx_evt_lock);
1194         }
1195         break;
1196     default:
1197         break;
1198     }
1199 
1200     return rc;
1201 }
1202 
1203 /* remove the first job from the queue with matching client handle */
mm_jpeg_queue_remove_job_by_client_id(mm_jpeg_queue_t * queue,uint32_t client_hdl)1204 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(mm_jpeg_queue_t* queue, uint32_t client_hdl)
1205 {
1206     mm_jpeg_q_node_t* node = NULL;
1207     mm_jpeg_job_q_node_t* data = NULL;
1208     mm_jpeg_job_q_node_t* job_node = NULL;
1209     struct cam_list *head = NULL;
1210     struct cam_list *pos = NULL;
1211 
1212     pthread_mutex_lock(&queue->lock);
1213     head = &queue->head.list;
1214     pos = head->next;
1215     while(pos != head) {
1216         node = member_of(pos, mm_jpeg_q_node_t, list);
1217         data = (mm_jpeg_job_q_node_t *)node->data;
1218 
1219         if (data && (data->entry.client_hdl == client_hdl)) {
1220             job_node = data;
1221             cam_list_del_node(&node->list);
1222             queue->size--;
1223             break;
1224         }
1225         pos = pos->next;
1226     }
1227 
1228     pthread_mutex_unlock(&queue->lock);
1229 
1230     return job_node;
1231 }
1232 
1233 /* remove job from the queue with matching job id */
mm_jpeg_queue_remove_job_by_job_id(mm_jpeg_queue_t * queue,uint32_t job_id)1234 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(mm_jpeg_queue_t* queue, uint32_t job_id)
1235 {
1236     mm_jpeg_q_node_t* node = NULL;
1237     mm_jpeg_job_q_node_t* data = NULL;
1238     mm_jpeg_job_q_node_t* job_node = NULL;
1239     struct cam_list *head = NULL;
1240     struct cam_list *pos = NULL;
1241 
1242     pthread_mutex_lock(&queue->lock);
1243     head = &queue->head.list;
1244     pos = head->next;
1245     while(pos != head) {
1246         node = member_of(pos, mm_jpeg_q_node_t, list);
1247         data = (mm_jpeg_job_q_node_t *)node->data;
1248 
1249         if (data && (data->entry.jobId == job_id)) {
1250             job_node = data;
1251             cam_list_del_node(&node->list);
1252             queue->size--;
1253             break;
1254         }
1255         pos = pos->next;
1256     }
1257 
1258     pthread_mutex_unlock(&queue->lock);
1259 
1260     return job_node;
1261 }
1262 
1263 /* update thumbnail dropped flag in job queue */
mm_jpeg_queue_update_flag(mm_jpeg_queue_t * queue,uint32_t job_id,uint8_t flag)1264 int32_t mm_jpeg_queue_update_flag(mm_jpeg_queue_t* queue, uint32_t job_id, uint8_t flag)
1265 {
1266     int32_t rc = 0;
1267     mm_jpeg_q_node_t* node = NULL;
1268     mm_jpeg_job_q_node_t* data = NULL;
1269     mm_jpeg_job_q_node_t* job_node = NULL;
1270     struct cam_list *head = NULL;
1271     struct cam_list *pos = NULL;
1272 
1273     pthread_mutex_lock(&queue->lock);
1274     head = &queue->head.list;
1275     pos = head->next;
1276     while(pos != head) {
1277         node = member_of(pos, mm_jpeg_q_node_t, list);
1278         data = (mm_jpeg_job_q_node_t *)node->data;
1279 
1280         if (data && (data->entry.jobId == job_id)) {
1281             job_node = data;
1282             break;
1283         }
1284         pos = pos->next;
1285     }
1286 
1287     if (job_node) {
1288         /* find matching job for its job id */
1289         job_node->entry.thumbnail_dropped = flag;
1290     } else {
1291         CDBG_ERROR("%s: No entry for jobId = %d", __func__, job_id);
1292         rc = -1;
1293     }
1294     pthread_mutex_unlock(&queue->lock);
1295 
1296     return rc;
1297 }
1298