1/*
2Copyright (c) 2012, Code Aurora Forum. All rights reserved.
3
4Redistribution and use in source and binary forms, with or without
5modification, are permitted provided that the following conditions are
6met:
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 Code Aurora Forum, Inc. 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
17THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27IF 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
51void mm_jpeg_job_wait_for_event(mm_jpeg_obj *my_obj, uint32_t evt_mask);
52void mm_jpeg_job_wait_for_cmd_complete(mm_jpeg_obj *my_obj,
53                                       int cmd,
54                                       int status);
55OMX_ERRORTYPE mm_jpeg_etbdone(OMX_HANDLETYPE hComponent,
56                              OMX_PTR pAppData,
57                              OMX_BUFFERHEADERTYPE* pBuffer);
58OMX_ERRORTYPE mm_jpeg_ftbdone(OMX_HANDLETYPE hComponent,
59                              OMX_PTR pAppData,
60                              OMX_BUFFERHEADERTYPE* pBuffer);
61OMX_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 */
68int32_t mm_jpeg_queue_update_flag(mm_jpeg_queue_t* queue, uint32_t job_id, uint8_t flag);
69mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(mm_jpeg_queue_t* queue, uint32_t client_hdl);
70mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(mm_jpeg_queue_t* queue, uint32_t job_id);
71
72int32_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
99int32_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
108int32_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 */
139int32_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 */
192int32_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
221omx_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
254int32_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
276int32_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
340int32_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
382int32_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
420int32_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
452int32_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
496int32_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
585static 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 */
629int32_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) */
658int32_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
676static 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
729int32_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
745int32_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
773int32_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
803int32_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
824uint32_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
856int32_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
901int32_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
948abort_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
957int32_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
1018void 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
1028void 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
1042OMX_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
1050OMX_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
1103OMX_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 */
1204mm_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 */
1234mm_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 */
1264int32_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