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