1 /* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 *
28 */
29
30 #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
38 #include "mm_jpeg_dbg.h"
39 #include "mm_jpeg_interface.h"
40 #include "mm_jpeg.h"
41
42 /* define max num of supported concurrent jpeg jobs by OMX engine.
43 * Current, only one per time */
44 #define NUM_MAX_JPEG_CNCURRENT_JOBS 1
45
46 #define JOB_ID_MAGICVAL 0x1
47 #define JOB_HIST_MAX 10000
48
49 /** DUMP_TO_FILE:
50 * @filename: file name
51 * @p_addr: address of the buffer
52 * @len: buffer length
53 *
54 * dump the image to the file
55 **/
56 #define DUMP_TO_FILE(filename, p_addr, len) ({ \
57 int rc = 0; \
58 FILE *fp = fopen(filename, "w+"); \
59 if (fp) { \
60 rc = fwrite(p_addr, 1, len, fp); \
61 CDBG_ERROR("%s:%d] written size %d", __func__, __LINE__, len); \
62 fclose(fp); \
63 } else { \
64 CDBG_ERROR("%s:%d] open %s failed", __func__, __LINE__, filename); \
65 } \
66 })
67
68 /** DUMP_TO_FILE2:
69 * @filename: file name
70 * @p_addr: address of the buffer
71 * @len: buffer length
72 *
73 * dump the image to the file if the memory is non-contiguous
74 **/
75 #define DUMP_TO_FILE2(filename, p_addr1, len1, paddr2, len2) ({ \
76 int rc = 0; \
77 FILE *fp = fopen(filename, "w+"); \
78 if (fp) { \
79 rc = fwrite(p_addr1, 1, len1, fp); \
80 rc = fwrite(p_addr2, 1, len2, fp); \
81 CDBG_ERROR("%s:%d] written %d %d", __func__, __LINE__, len1, len2); \
82 fclose(fp); \
83 } else { \
84 CDBG_ERROR("%s:%d] open %s failed", __func__, __LINE__, filename); \
85 } \
86 })
87
88 /** MM_JPEG_CHK_ABORT:
89 * @p: client pointer
90 * @ret: return value
91 * @label: label to jump to
92 *
93 * check the abort failure
94 **/
95 #define MM_JPEG_CHK_ABORT(p, ret, label) ({ \
96 if (OMX_TRUE == p->abort_flag) { \
97 CDBG_ERROR("%s:%d] jpeg abort", __func__, __LINE__); \
98 ret = OMX_ErrorNone; \
99 goto label; \
100 } \
101 })
102
103 #define GET_CLIENT_IDX(x) ((x) & 0xff)
104 #define GET_SESSION_IDX(x) (((x) >> 8) & 0xff)
105 #define GET_JOB_IDX(x) (((x) >> 16) & 0xff)
106
107 OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent,
108 OMX_PTR pAppData,
109 OMX_BUFFERHEADERTYPE* pBuffer);
110 OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent,
111 OMX_PTR pAppData,
112 OMX_BUFFERHEADERTYPE* pBuffer);
113 OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent,
114 OMX_PTR pAppData,
115 OMX_EVENTTYPE eEvent,
116 OMX_U32 nData1,
117 OMX_U32 nData2,
118 OMX_PTR pEventData);
119
120 /** cirq_reset:
121 *
122 * Arguments:
123 * @q: circular queue
124 *
125 * Return:
126 * none
127 *
128 * Description:
129 * Resets the circular queue
130 *
131 **/
cirq_reset(mm_jpeg_cirq_t * q)132 static inline void cirq_reset(mm_jpeg_cirq_t *q)
133 {
134 q->front = 0;
135 q->rear = 0;
136 q->count = 0;
137 pthread_mutex_init(&q->lock, NULL);
138 }
139
140 /** cirq_empty:
141 *
142 * Arguments:
143 * @q: circular queue
144 *
145 * Return:
146 * none
147 *
148 * Description:
149 * check if the curcular queue is empty
150 *
151 **/
152 #define cirq_empty(q) (q->count == 0)
153
154 /** cirq_full:
155 *
156 * Arguments:
157 * @q: circular queue
158 *
159 * Return:
160 * none
161 *
162 * Description:
163 * check if the curcular queue is full
164 *
165 **/
166 #define cirq_full(q) (q->count == MM_JPEG_CIRQ_SIZE)
167
168 /** cirq_enqueue:
169 *
170 * Arguments:
171 * @q: circular queue
172 * @data: data to be inserted
173 *
174 * Return:
175 * true/false
176 *
177 * Description:
178 * enqueue an element into circular queue
179 *
180 **/
181 #define cirq_enqueue(q, type, data) ({ \
182 int rc = 0; \
183 pthread_mutex_lock(&q->lock); \
184 if (cirq_full(q)) { \
185 rc = -1; \
186 } else { \
187 q->type[q->rear] = data; \
188 q->rear = (q->rear + 1) % MM_JPEG_CIRQ_SIZE; \
189 q->count++; \
190 } \
191 pthread_mutex_unlock(&q->lock); \
192 rc; \
193 })
194
195 /** cirq_dequeue:
196 *
197 * Arguments:
198 * @q: circular queue
199 * @data: data to be popped
200 *
201 * Return:
202 * true/false
203 *
204 * Description:
205 * dequeue an element from the circular queue
206 *
207 **/
208 #define cirq_dequeue(q, type, data) ({ \
209 int rc = 0; \
210 pthread_mutex_lock(&q->lock); \
211 if (cirq_empty(q)) { \
212 pthread_mutex_unlock(&q->lock); \
213 rc = -1; \
214 } else { \
215 data = q->type[q->front]; \
216 q->count--; \
217 } \
218 pthread_mutex_unlock(&q->lock); \
219 rc; \
220 })
221
222 /**
223 *
224 * special queue functions for job queue
225 **/
226 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(
227 mm_jpeg_queue_t* queue, uint32_t client_hdl);
228 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(
229 mm_jpeg_queue_t* queue, uint32_t job_id);
230 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id(
231 mm_jpeg_queue_t* queue, uint32_t session_id);
232 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk(
233 mm_jpeg_queue_t* queue, uint32_t job_id);
234
235 /** mm_jpeg_pending_func_t:
236 *
237 * Intermediate function for transition change
238 **/
239 typedef OMX_ERRORTYPE (*mm_jpeg_transition_func_t)(void *);
240
241
242 /** mm_jpeg_queue_func_t:
243 *
244 * Intermediate function for queue operation
245 **/
246 typedef void (*mm_jpeg_queue_func_t)(void *);
247
248 /** mm_jpeg_session_send_buffers:
249 *
250 * Arguments:
251 * @data: job session
252 *
253 * Return:
254 * OMX error values
255 *
256 * Description:
257 * Send the buffers to OMX layer
258 *
259 **/
mm_jpeg_session_send_buffers(void * data)260 OMX_ERRORTYPE mm_jpeg_session_send_buffers(void *data)
261 {
262 uint32_t i = 0;
263 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data;
264 OMX_ERRORTYPE ret = OMX_ErrorNone;
265 QOMX_BUFFER_INFO lbuffer_info;
266 mm_jpeg_encode_params_t *p_params = &p_session->params;
267 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
268
269 memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO));
270 for (i = 0; i < p_params->num_src_bufs; i++) {
271 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
272 lbuffer_info.fd = p_params->src_main_buf[i].fd;
273 ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_in_omx_buf[i]), 0,
274 &lbuffer_info, p_params->src_main_buf[i].buf_size,
275 p_params->src_main_buf[i].buf_vaddr);
276 if (ret) {
277 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
278 return ret;
279 }
280 }
281
282 for (i = 0; i < p_params->num_tmb_bufs; i++) {
283 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
284 lbuffer_info.fd = p_params->src_thumb_buf[i].fd;
285 ret = OMX_UseBuffer(p_session->omx_handle,
286 &(p_session->p_in_omx_thumb_buf[i]), 2,
287 &lbuffer_info, p_params->src_thumb_buf[i].buf_size,
288 p_params->src_thumb_buf[i].buf_vaddr);
289 if (ret) {
290 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
291 return ret;
292 }
293 }
294
295 for (i = 0; i < p_params->num_dst_bufs; i++) {
296 CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i);
297 ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]),
298 1, NULL, p_params->dest_buf[i].buf_size,
299 p_params->dest_buf[i].buf_vaddr);
300 if (ret) {
301 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
302 return ret;
303 }
304 }
305 CDBG("%s:%d]", __func__, __LINE__);
306 return ret;
307 }
308
309 /** mm_jpeg_session_free_buffers:
310 *
311 * Arguments:
312 * @data: job session
313 *
314 * Return:
315 * OMX error values
316 *
317 * Description:
318 * Free the buffers from OMX layer
319 *
320 **/
mm_jpeg_session_free_buffers(void * data)321 OMX_ERRORTYPE mm_jpeg_session_free_buffers(void *data)
322 {
323 OMX_ERRORTYPE ret = OMX_ErrorNone;
324 uint32_t i = 0;
325 mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data;
326 mm_jpeg_encode_params_t *p_params = &p_session->params;
327 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
328
329 for (i = 0; i < p_params->num_src_bufs; i++) {
330 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
331 ret = OMX_FreeBuffer(p_session->omx_handle, 0, p_session->p_in_omx_buf[i]);
332 if (ret) {
333 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
334 return ret;
335 }
336 }
337
338 for (i = 0; i < p_params->num_tmb_bufs; i++) {
339 CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
340 ret = OMX_FreeBuffer(p_session->omx_handle, 2, p_session->p_in_omx_thumb_buf[i]);
341 if (ret) {
342 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
343 return ret;
344 }
345 }
346
347 for (i = 0; i < p_params->num_dst_bufs; i++) {
348 CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i);
349 ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]);
350 if (ret) {
351 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
352 return ret;
353 }
354 }
355 CDBG("%s:%d]", __func__, __LINE__);
356 return ret;
357 }
358
359 /** mm_jpeg_session_change_state:
360 *
361 * Arguments:
362 * @p_session: job session
363 * @new_state: new state to be transitioned to
364 * @p_exec: transition function
365 *
366 * Return:
367 * OMX error values
368 *
369 * Description:
370 * This method is used for state transition
371 *
372 **/
mm_jpeg_session_change_state(mm_jpeg_job_session_t * p_session,OMX_STATETYPE new_state,mm_jpeg_transition_func_t p_exec)373 OMX_ERRORTYPE mm_jpeg_session_change_state(mm_jpeg_job_session_t* p_session,
374 OMX_STATETYPE new_state,
375 mm_jpeg_transition_func_t p_exec)
376 {
377 OMX_ERRORTYPE ret = OMX_ErrorNone;
378 OMX_STATETYPE current_state;
379 CDBG("%s:%d] new_state %d p_exec %p", __func__, __LINE__,
380 new_state, p_exec);
381
382
383 pthread_mutex_lock(&p_session->lock);
384
385 ret = OMX_GetState(p_session->omx_handle, ¤t_state);
386
387 if (ret) {
388 pthread_mutex_unlock(&p_session->lock);
389 return ret;
390 }
391
392 if (current_state == new_state) {
393 pthread_mutex_unlock(&p_session->lock);
394 return OMX_ErrorNone;
395 }
396
397 p_session->state_change_pending = OMX_TRUE;
398 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet,
399 new_state, NULL);
400 if (ret) {
401 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
402 pthread_mutex_unlock(&p_session->lock);
403 return OMX_ErrorIncorrectStateTransition;
404 }
405 CDBG("%s:%d] ", __func__, __LINE__);
406 if (OMX_ErrorNone != p_session->error_flag) {
407 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, p_session->error_flag);
408 pthread_mutex_unlock(&p_session->lock);
409 return p_session->error_flag;
410 }
411 if (p_exec) {
412 ret = p_exec(p_session);
413 if (ret) {
414 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
415 pthread_mutex_unlock(&p_session->lock);
416 return ret;
417 }
418 }
419 CDBG("%s:%d] ", __func__, __LINE__);
420 if (p_session->state_change_pending) {
421 CDBG("%s:%d] before wait", __func__, __LINE__);
422 pthread_cond_wait(&p_session->cond, &p_session->lock);
423 CDBG("%s:%d] after wait", __func__, __LINE__);
424 }
425 pthread_mutex_unlock(&p_session->lock);
426 CDBG("%s:%d] ", __func__, __LINE__);
427 return ret;
428 }
429
430 /** mm_jpeg_session_create:
431 *
432 * Arguments:
433 * @p_session: job session
434 *
435 * Return:
436 * OMX error types
437 *
438 * Description:
439 * Create a jpeg encode session
440 *
441 **/
mm_jpeg_session_create(mm_jpeg_job_session_t * p_session)442 OMX_ERRORTYPE mm_jpeg_session_create(mm_jpeg_job_session_t* p_session)
443 {
444 OMX_ERRORTYPE rc = OMX_ErrorNone;
445 mm_jpeg_cirq_t *p_cirq = NULL;
446
447 pthread_mutex_init(&p_session->lock, NULL);
448 pthread_cond_init(&p_session->cond, NULL);
449 cirq_reset(&p_session->cb_q);
450 p_session->state_change_pending = OMX_FALSE;
451 p_session->abort_flag = OMX_FALSE;
452 p_session->error_flag = OMX_ErrorNone;
453 p_session->ebd_count = 0;
454 p_session->fbd_count = 0;
455 p_session->encode_pid = -1;
456 p_session->config = OMX_FALSE;
457
458 p_session->omx_callbacks.EmptyBufferDone = mm_jpeg_ebd;
459 p_session->omx_callbacks.FillBufferDone = mm_jpeg_fbd;
460 p_session->omx_callbacks.EventHandler = mm_jpeg_event_handler;
461 rc = OMX_GetHandle(&p_session->omx_handle,
462 "OMX.qcom.image.jpeg.encoder",
463 (void *)p_session,
464 &p_session->omx_callbacks);
465
466 if (OMX_ErrorNone != rc) {
467 CDBG_ERROR("%s:%d] OMX_GetHandle failed (%d)", __func__, __LINE__, rc);
468 return rc;
469 }
470 return rc;
471 }
472
473 /** mm_jpeg_session_destroy:
474 *
475 * Arguments:
476 * @p_session: job session
477 *
478 * Return:
479 * none
480 *
481 * Description:
482 * Destroy a jpeg encode session
483 *
484 **/
mm_jpeg_session_destroy(mm_jpeg_job_session_t * p_session)485 void mm_jpeg_session_destroy(mm_jpeg_job_session_t* p_session)
486 {
487 OMX_ERRORTYPE rc = OMX_ErrorNone;
488
489 CDBG("%s:%d] E", __func__, __LINE__);
490 if (NULL == p_session->omx_handle) {
491 CDBG_ERROR("%s:%d] invalid handle", __func__, __LINE__);
492 return;
493 }
494
495 rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL);
496 if (rc) {
497 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
498 }
499
500 rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded,
501 mm_jpeg_session_free_buffers);
502 if (rc) {
503 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
504 }
505
506 rc = OMX_FreeHandle(p_session->omx_handle);
507 if (0 != rc) {
508 CDBG_ERROR("%s:%d] OMX_FreeHandle failed (%d)", __func__, __LINE__, rc);
509 }
510 p_session->omx_handle = NULL;
511
512 rc = releaseExifEntry(&p_session->params.exif_info);
513 if (rc) {
514 CDBG_ERROR("%s:%d] Exif release failed (%d)", __func__, __LINE__, rc);
515 }
516 pthread_mutex_destroy(&p_session->lock);
517 pthread_cond_destroy(&p_session->cond);
518 CDBG("%s:%d] X", __func__, __LINE__);
519 }
520
521 /** mm_jpeg_session_config_main_buffer_offset:
522 *
523 * Arguments:
524 * @p_session: job session
525 *
526 * Return:
527 * OMX error values
528 *
529 * Description:
530 * Configure the buffer offsets
531 *
532 **/
mm_jpeg_session_config_main_buffer_offset(mm_jpeg_job_session_t * p_session)533 OMX_ERRORTYPE mm_jpeg_session_config_main_buffer_offset(
534 mm_jpeg_job_session_t* p_session)
535 {
536 OMX_ERRORTYPE rc = 0;
537 int32_t i = 0;
538 OMX_INDEXTYPE buffer_index;
539 QOMX_YUV_FRAME_INFO frame_info;
540 int32_t totalSize = 0;
541 mm_jpeg_encode_params_t *p_params = &p_session->params;
542 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
543
544 mm_jpeg_buf_t *p_src_buf =
545 &p_params->src_main_buf[p_jobparams->src_index];
546
547 memset(&frame_info, 0x0, sizeof(QOMX_YUV_FRAME_INFO));
548
549 frame_info.cbcrStartOffset[0] = p_src_buf->offset.mp[0].len;
550 frame_info.cbcrStartOffset[1] = p_src_buf->offset.mp[1].len;
551 frame_info.yOffset = p_src_buf->offset.mp[0].offset;
552 frame_info.cbcrOffset[0] = p_src_buf->offset.mp[1].offset;
553 frame_info.cbcrOffset[1] = p_src_buf->offset.mp[2].offset;
554 totalSize = p_src_buf->buf_size;
555
556 rc = OMX_GetExtensionIndex(p_session->omx_handle,
557 QOMX_IMAGE_EXT_BUFFER_OFFSET_NAME, &buffer_index);
558 if (rc != OMX_ErrorNone) {
559 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
560 return rc;
561 }
562
563 CDBG_HIGH("%s:%d] yOffset = %d, cbcrOffset = (%d %d), totalSize = %d,"
564 "cbcrStartOffset = (%d %d)", __func__, __LINE__,
565 (int)frame_info.yOffset,
566 (int)frame_info.cbcrOffset[0],
567 (int)frame_info.cbcrOffset[1],
568 totalSize,
569 (int)frame_info.cbcrStartOffset[0],
570 (int)frame_info.cbcrStartOffset[1]);
571
572 rc = OMX_SetParameter(p_session->omx_handle, buffer_index, &frame_info);
573 if (rc != OMX_ErrorNone) {
574 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
575 return rc;
576 }
577 return rc;
578 }
579
580 /** mm_jpeg_encoding_mode:
581 *
582 * Arguments:
583 * @p_session: job session
584 *
585 * Return:
586 * OMX error values
587 *
588 * Description:
589 * Configure the serial or parallel encoding
590 * mode
591 *
592 **/
mm_jpeg_encoding_mode(mm_jpeg_job_session_t * p_session)593 OMX_ERRORTYPE mm_jpeg_encoding_mode(
594 mm_jpeg_job_session_t* p_session)
595 {
596 OMX_ERRORTYPE rc = 0;
597 int32_t i = 0;
598 OMX_INDEXTYPE indextype;
599 QOMX_ENCODING_MODE encoding_mode;
600 int32_t totalSize = 0;
601 mm_jpeg_encode_params_t *p_params = &p_session->params;
602 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
603
604 rc = OMX_GetExtensionIndex(p_session->omx_handle,
605 QOMX_IMAGE_EXT_ENCODING_MODE_NAME, &indextype);
606 if (rc != OMX_ErrorNone) {
607 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
608 return rc;
609 }
610
611 CDBG_HIGH("%s:%d] OMX_Serial_Encoding = %d, OMX_Parallel_Encoding = %d ", __func__, __LINE__,
612 (int)OMX_Serial_Encoding,
613 (int)OMX_Parallel_Encoding);
614
615 encoding_mode = OMX_Serial_Encoding;
616 rc = OMX_SetParameter(p_session->omx_handle, indextype, &encoding_mode);
617 if (rc != OMX_ErrorNone) {
618 CDBG_ERROR("%s:%d] Failed", __func__, __LINE__);
619 return rc;
620 }
621 return rc;
622 }
623
624 /** map_jpeg_format:
625 *
626 * Arguments:
627 * @color_fmt: color format
628 *
629 * Return:
630 * OMX color format
631 *
632 * Description:
633 * Map mmjpeg color format to OMX color format
634 *
635 **/
map_jpeg_format(mm_jpeg_color_format color_fmt)636 int map_jpeg_format(mm_jpeg_color_format color_fmt)
637 {
638 switch (color_fmt) {
639 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V2:
640 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar;
641 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V2:
642 return (int)OMX_COLOR_FormatYUV420SemiPlanar;
643 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H2V1:
644 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar;
645 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H2V1:
646 return (int)OMX_COLOR_FormatYUV422SemiPlanar;
647 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V2:
648 return (int)OMX_QCOM_IMG_COLOR_FormatYVU422SemiPlanar_h1v2;
649 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V2:
650 return (int)OMX_QCOM_IMG_COLOR_FormatYUV422SemiPlanar_h1v2;
651 case MM_JPEG_COLOR_FORMAT_YCRCBLP_H1V1:
652 return (int)OMX_QCOM_IMG_COLOR_FormatYVU444SemiPlanar;
653 case MM_JPEG_COLOR_FORMAT_YCBCRLP_H1V1:
654 return (int)OMX_QCOM_IMG_COLOR_FormatYUV444SemiPlanar;
655 default:
656 CDBG_ERROR("%s:%d] invalid format %d", __func__, __LINE__, color_fmt);
657 return (int)OMX_QCOM_IMG_COLOR_FormatYVU420SemiPlanar;
658 }
659 }
660
661 /** mm_jpeg_session_config_port:
662 *
663 * Arguments:
664 * @p_session: job session
665 *
666 * Return:
667 * OMX error values
668 *
669 * Description:
670 * Configure OMX ports
671 *
672 **/
mm_jpeg_session_config_ports(mm_jpeg_job_session_t * p_session)673 OMX_ERRORTYPE mm_jpeg_session_config_ports(mm_jpeg_job_session_t* p_session)
674 {
675 OMX_ERRORTYPE ret = OMX_ErrorNone;
676 mm_jpeg_encode_params_t *p_params = &p_session->params;
677 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
678
679 mm_jpeg_buf_t *p_src_buf =
680 &p_params->src_main_buf[p_jobparams->src_index];
681
682 p_session->inputPort.nPortIndex = 0;
683 p_session->outputPort.nPortIndex = 1;
684 p_session->inputTmbPort.nPortIndex = 2;
685
686 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
687 &p_session->inputPort);
688 if (ret) {
689 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
690 return ret;
691 }
692
693 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
694 &p_session->inputTmbPort);
695 if (ret) {
696 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
697 return ret;
698 }
699
700 ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
701 &p_session->outputPort);
702 if (ret) {
703 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
704 return ret;
705 }
706
707 p_session->inputPort.format.image.nFrameWidth =
708 p_jobparams->main_dim.src_dim.width;
709 p_session->inputPort.format.image.nFrameHeight =
710 p_jobparams->main_dim.src_dim.height;
711 p_session->inputPort.format.image.nStride =
712 p_src_buf->offset.mp[0].stride;
713 p_session->inputPort.format.image.nSliceHeight =
714 p_src_buf->offset.mp[0].scanline;
715 p_session->inputPort.format.image.eColorFormat =
716 map_jpeg_format(p_params->color_format);
717 p_session->inputPort.nBufferSize =
718 p_params->src_main_buf[p_jobparams->src_index].buf_size;
719 p_session->inputPort.nBufferCountActual = p_params->num_src_bufs;
720 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
721 &p_session->inputPort);
722 if (ret) {
723 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
724 return ret;
725 }
726
727 p_session->inputTmbPort.format.image.nFrameWidth =
728 p_jobparams->thumb_dim.src_dim.width;
729 p_session->inputTmbPort.format.image.nFrameHeight =
730 p_jobparams->thumb_dim.src_dim.height;
731 p_session->inputTmbPort.format.image.nStride =
732 p_session->inputTmbPort.format.image.nFrameWidth;
733 p_session->inputTmbPort.format.image.nSliceHeight =
734 p_session->inputTmbPort.format.image.nFrameHeight;
735 p_session->inputTmbPort.format.image.eColorFormat =
736 map_jpeg_format(p_params->color_format);
737 p_session->inputTmbPort.nBufferSize =
738 p_params->src_thumb_buf[p_jobparams->thumb_index].buf_size;
739 p_session->inputTmbPort.nBufferCountActual = p_params->num_tmb_bufs;
740 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
741 &p_session->inputTmbPort);
742
743 if (ret) {
744 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
745 return ret;
746 }
747
748 if (p_session->params.encode_thumbnail) {
749 // Enable thumbnail port
750 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
751 p_session->inputTmbPort.nPortIndex, NULL);
752
753 if (ret) {
754 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
755 return ret;
756 }
757 } else {
758 // Disable thumbnail port
759 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable,
760 p_session->inputTmbPort.nPortIndex, NULL);
761
762 if (ret) {
763 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
764 return ret;
765 }
766 }
767
768 p_session->outputPort.nBufferSize =
769 p_params->dest_buf[p_jobparams->dst_index].buf_size;
770 p_session->outputPort.nBufferCountActual = p_params->num_dst_bufs;
771 ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
772 &p_session->outputPort);
773 if (ret) {
774 CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
775 return ret;
776 }
777
778 return ret;
779 }
780
781 /** mm_jpeg_omx_config_thumbnail:
782 *
783 * Arguments:
784 * @p_session: job session
785 *
786 * Return:
787 * OMX error values
788 *
789 * Description:
790 * Configure OMX ports
791 *
792 **/
mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t * p_session)793 OMX_ERRORTYPE mm_jpeg_session_config_thumbnail(mm_jpeg_job_session_t* p_session)
794 {
795 OMX_ERRORTYPE ret = OMX_ErrorNone;
796 QOMX_THUMBNAIL_INFO thumbnail_info;
797 OMX_INDEXTYPE thumb_indextype;
798 OMX_BOOL encode_thumbnail = OMX_FALSE;
799 mm_jpeg_encode_params_t *p_params = &p_session->params;
800 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
801 mm_jpeg_dim_t *p_thumb_dim = &p_jobparams->thumb_dim;
802 mm_jpeg_dim_t *p_main_dim = &p_jobparams->main_dim;
803 QOMX_YUV_FRAME_INFO *p_frame_info = &thumbnail_info.tmbOffset;
804 mm_jpeg_buf_t *p_tmb_buf = &p_params->src_thumb_buf[p_jobparams->thumb_index];
805
806 CDBG_HIGH("%s:%d] encode_thumbnail %d", __func__, __LINE__,
807 p_params->encode_thumbnail);
808 if (OMX_FALSE == p_params->encode_thumbnail) {
809 return ret;
810 }
811
812 if ((p_thumb_dim->dst_dim.width == 0) || (p_thumb_dim->dst_dim.height == 0)) {
813 CDBG_ERROR("%s:%d] Error invalid output dim for thumbnail",
814 __func__, __LINE__);
815 return OMX_ErrorBadParameter;
816 }
817
818 if ((p_thumb_dim->src_dim.width == 0) || (p_thumb_dim->src_dim.height == 0)) {
819 CDBG_ERROR("%s:%d] Error invalid input dim for thumbnail",
820 __func__, __LINE__);
821 return OMX_ErrorBadParameter;
822 }
823
824 if ((p_thumb_dim->crop.width == 0) || (p_thumb_dim->crop.height == 0)) {
825 p_thumb_dim->crop.width = p_thumb_dim->src_dim.width;
826 p_thumb_dim->crop.height = p_thumb_dim->src_dim.height;
827 }
828
829 /* check crop boundary */
830 if ((p_thumb_dim->crop.width + p_thumb_dim->crop.left > p_thumb_dim->src_dim.width) ||
831 (p_thumb_dim->crop.height + p_thumb_dim->crop.top > p_thumb_dim->src_dim.height)) {
832 CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) offset (%d, %d) out of (%d, %d)",
833 __func__, __LINE__,
834 p_thumb_dim->crop.width,
835 p_thumb_dim->crop.height,
836 p_thumb_dim->crop.left,
837 p_thumb_dim->crop.top,
838 p_thumb_dim->src_dim.width,
839 p_thumb_dim->src_dim.height);
840 return OMX_ErrorBadParameter;
841 }
842
843 memset(&thumbnail_info, 0x0, sizeof(QOMX_THUMBNAIL_INFO));
844 ret = OMX_GetExtensionIndex(p_session->omx_handle,
845 QOMX_IMAGE_EXT_THUMBNAIL_NAME,
846 &thumb_indextype);
847 if (ret) {
848 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
849 return ret;
850 }
851
852 /* fill thumbnail info */
853 thumbnail_info.scaling_enabled = 1;
854 thumbnail_info.input_width = p_thumb_dim->src_dim.width;
855 thumbnail_info.input_height = p_thumb_dim->src_dim.height;
856 thumbnail_info.crop_info.nWidth = p_thumb_dim->crop.width;
857 thumbnail_info.crop_info.nHeight = p_thumb_dim->crop.height;
858 thumbnail_info.crop_info.nLeft = p_thumb_dim->crop.left;
859 thumbnail_info.crop_info.nTop = p_thumb_dim->crop.top;
860
861 if ((p_main_dim->src_dim.width < p_thumb_dim->src_dim.width) ||
862 (p_main_dim->src_dim.height < p_thumb_dim->src_dim.height)) {
863 CDBG_ERROR("%s:%d] Improper thumbnail dim %dx%d resetting to %dx%d",
864 __func__, __LINE__,
865 p_thumb_dim->src_dim.width,
866 p_thumb_dim->src_dim.height,
867 p_main_dim->src_dim.width,
868 p_main_dim->src_dim.height);
869 thumbnail_info.input_width = p_main_dim->src_dim.width;
870 thumbnail_info.input_height = p_main_dim->src_dim.height;
871 if ((thumbnail_info.crop_info.nWidth > thumbnail_info.input_width)
872 || (thumbnail_info.crop_info.nHeight > thumbnail_info.input_height)) {
873 thumbnail_info.crop_info.nLeft = 0;
874 thumbnail_info.crop_info.nTop = 0;
875 thumbnail_info.crop_info.nWidth = thumbnail_info.input_width;
876 thumbnail_info.crop_info.nHeight = thumbnail_info.input_height;
877 }
878 }
879
880 if ((p_thumb_dim->dst_dim.width > p_thumb_dim->src_dim.width)
881 || (p_thumb_dim->dst_dim.height > p_thumb_dim->src_dim.height)) {
882 CDBG_ERROR("%s:%d] Incorrect thumbnail dim %dx%d resetting to %dx%d",
883 __func__, __LINE__,
884 p_thumb_dim->dst_dim.width,
885 p_thumb_dim->dst_dim.height,
886 p_thumb_dim->src_dim.width,
887 p_thumb_dim->src_dim.height);
888 thumbnail_info.output_width = p_thumb_dim->src_dim.width;
889 thumbnail_info.output_height = p_thumb_dim->src_dim.height;
890 } else {
891 thumbnail_info.output_width = p_thumb_dim->dst_dim.width;
892 thumbnail_info.output_height = p_thumb_dim->dst_dim.height;
893 }
894
895 memset(p_frame_info, 0x0, sizeof(*p_frame_info));
896
897 p_frame_info->cbcrStartOffset[0] = p_tmb_buf->offset.mp[0].len;
898 p_frame_info->cbcrStartOffset[1] = p_tmb_buf->offset.mp[1].len;
899 p_frame_info->yOffset = p_tmb_buf->offset.mp[0].offset;
900 p_frame_info->cbcrOffset[0] = p_tmb_buf->offset.mp[1].offset;
901 p_frame_info->cbcrOffset[1] = p_tmb_buf->offset.mp[2].offset;
902
903 ret = OMX_SetParameter(p_session->omx_handle, thumb_indextype,
904 &thumbnail_info);
905 if (ret) {
906 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
907 return ret;
908 }
909
910 return ret;
911 }
912
913 /** mm_jpeg_session_config_main_crop:
914 *
915 * Arguments:
916 * @p_session: job session
917 *
918 * Return:
919 * OMX error values
920 *
921 * Description:
922 * Configure main image crop
923 *
924 **/
mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t * p_session)925 OMX_ERRORTYPE mm_jpeg_session_config_main_crop(mm_jpeg_job_session_t *p_session)
926 {
927 OMX_CONFIG_RECTTYPE rect_type_in, rect_type_out;
928 OMX_ERRORTYPE ret = OMX_ErrorNone;
929 mm_jpeg_encode_params_t *p_params = &p_session->params;
930 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
931 mm_jpeg_dim_t *dim = &p_jobparams->main_dim;
932
933 if ((dim->crop.width == 0) || (dim->crop.height == 0)) {
934 dim->crop.width = dim->src_dim.width;
935 dim->crop.height = dim->src_dim.height;
936 }
937 /* error check first */
938 if ((dim->crop.width + dim->crop.left > dim->src_dim.width) ||
939 (dim->crop.height + dim->crop.top > dim->src_dim.height)) {
940 CDBG_ERROR("%s:%d] invalid crop boundary (%d, %d) out of (%d, %d)",
941 __func__, __LINE__,
942 dim->crop.width + dim->crop.left,
943 dim->crop.height + dim->crop.top,
944 dim->src_dim.width,
945 dim->src_dim.height);
946 return OMX_ErrorBadParameter;
947 }
948
949 memset(&rect_type_in, 0, sizeof(rect_type_in));
950 memset(&rect_type_out, 0, sizeof(rect_type_out));
951 rect_type_in.nPortIndex = 0;
952 rect_type_out.nPortIndex = 0;
953
954 if ((dim->src_dim.width != dim->crop.width) ||
955 (dim->src_dim.height != dim->crop.height) ||
956 (dim->src_dim.width != dim->dst_dim.width) ||
957 (dim->src_dim.height != dim->dst_dim.height)) {
958 /* Scaler information */
959 rect_type_in.nWidth = CEILING2(dim->crop.width);
960 rect_type_in.nHeight = CEILING2(dim->crop.height);
961 rect_type_in.nLeft = dim->crop.left;
962 rect_type_in.nTop = dim->crop.top;
963
964 if (dim->dst_dim.width && dim->dst_dim.height) {
965 rect_type_out.nWidth = dim->dst_dim.width;
966 rect_type_out.nHeight = dim->dst_dim.height;
967 }
968 }
969
970 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonInputCrop,
971 &rect_type_in);
972 if (OMX_ErrorNone != ret) {
973 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
974 return ret;
975 }
976
977 CDBG("%s:%d] OMX_IndexConfigCommonInputCrop w = %d, h = %d, l = %d, t = %d,"
978 " port_idx = %d", __func__, __LINE__,
979 (int)rect_type_in.nWidth, (int)rect_type_in.nHeight,
980 (int)rect_type_in.nLeft, (int)rect_type_in.nTop,
981 (int)rect_type_in.nPortIndex);
982
983 ret = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonOutputCrop,
984 &rect_type_out);
985 if (OMX_ErrorNone != ret) {
986 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
987 return ret;
988 }
989 CDBG("%s:%d] OMX_IndexConfigCommonOutputCrop w = %d, h = %d,"
990 " port_idx = %d", __func__, __LINE__,
991 (int)rect_type_out.nWidth, (int)rect_type_out.nHeight,
992 (int)rect_type_out.nPortIndex);
993
994 return ret;
995 }
996
997 /** mm_jpeg_session_config_main:
998 *
999 * Arguments:
1000 * @p_session: job session
1001 *
1002 * Return:
1003 * OMX error values
1004 *
1005 * Description:
1006 * Configure main image
1007 *
1008 **/
mm_jpeg_session_config_main(mm_jpeg_job_session_t * p_session)1009 OMX_ERRORTYPE mm_jpeg_session_config_main(mm_jpeg_job_session_t *p_session)
1010 {
1011 OMX_ERRORTYPE rc = OMX_ErrorNone;
1012 OMX_IMAGE_PARAM_QFACTORTYPE q_factor;
1013 mm_jpeg_encode_params_t *p_params = &p_session->params;
1014 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1015
1016 /* config port */
1017 CDBG("%s:%d] config port", __func__, __LINE__);
1018 rc = mm_jpeg_session_config_ports(p_session);
1019 if (OMX_ErrorNone != rc) {
1020 CDBG_ERROR("%s: config port failed", __func__);
1021 return rc;
1022 }
1023
1024 /* config buffer offset */
1025 CDBG("%s:%d] config main buf offset", __func__, __LINE__);
1026 rc = mm_jpeg_session_config_main_buffer_offset(p_session);
1027 if (OMX_ErrorNone != rc) {
1028 CDBG_ERROR("%s: config buffer offset failed", __func__);
1029 return rc;
1030 }
1031
1032 /* config crop */
1033 CDBG("%s:%d] config main crop", __func__, __LINE__);
1034 rc = mm_jpeg_session_config_main_crop(p_session);
1035 if (OMX_ErrorNone != rc) {
1036 CDBG_ERROR("%s: config crop failed", __func__);
1037 return rc;
1038 }
1039
1040 /* set quality */
1041 memset(&q_factor, 0, sizeof(q_factor));
1042 q_factor.nPortIndex = 0;
1043 q_factor.nQFactor = p_params->quality;
1044 rc = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamQFactor, &q_factor);
1045 CDBG("%s:%d] config QFactor: %d", __func__, __LINE__, (int)q_factor.nQFactor);
1046 if (OMX_ErrorNone != rc) {
1047 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1048 return rc;
1049 }
1050
1051 return rc;
1052 }
1053
1054 /** mm_jpeg_session_config_common:
1055 *
1056 * Arguments:
1057 * @p_session: job session
1058 *
1059 * Return:
1060 * OMX error values
1061 *
1062 * Description:
1063 * Configure common parameters
1064 *
1065 **/
mm_jpeg_session_config_common(mm_jpeg_job_session_t * p_session)1066 OMX_ERRORTYPE mm_jpeg_session_config_common(mm_jpeg_job_session_t *p_session)
1067 {
1068 OMX_ERRORTYPE rc = OMX_ErrorNone;
1069 int i;
1070 OMX_INDEXTYPE exif_idx;
1071 OMX_CONFIG_ROTATIONTYPE rotate;
1072 mm_jpeg_encode_params_t *p_params = &p_session->params;
1073 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1074 QOMX_EXIF_INFO exif_info;
1075
1076 /* set rotation */
1077 memset(&rotate, 0, sizeof(rotate));
1078 rotate.nPortIndex = 1;
1079 rotate.nRotation = p_jobparams->rotation;
1080 rc = OMX_SetConfig(p_session->omx_handle, OMX_IndexConfigCommonRotate,
1081 &rotate);
1082 if (OMX_ErrorNone != rc) {
1083 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1084 return rc;
1085 }
1086 CDBG("%s:%d] Set rotation to %d at port_idx = %d", __func__, __LINE__,
1087 (int)p_jobparams->rotation, (int)rotate.nPortIndex);
1088
1089 /* Set Exif data*/
1090 memset(&p_session->exif_info_all[0], 0, sizeof(p_session->exif_info_all));
1091
1092 exif_info.numOfEntries = p_params->exif_info.numOfEntries;
1093 exif_info.exif_data = &p_session->exif_info_all[0];
1094 /*If Exif data has been passed copy it*/
1095 if (p_params->exif_info.numOfEntries > 0) {
1096 CDBG("%s:%d] Num of exif entries passed from HAL: %d", __func__, __LINE__,
1097 p_params->exif_info.numOfEntries);
1098 memcpy(exif_info.exif_data, p_params->exif_info.exif_data,
1099 sizeof(QEXIF_INFO_DATA) * p_params->exif_info.numOfEntries);
1100 }
1101
1102 if (exif_info.numOfEntries > 0) {
1103 /* set exif tags */
1104 CDBG("%s:%d] Set exif tags count %d", __func__, __LINE__,
1105 (int)exif_info.numOfEntries);
1106 rc = OMX_GetExtensionIndex(p_session->omx_handle, QOMX_IMAGE_EXT_EXIF_NAME,
1107 &exif_idx);
1108 if (OMX_ErrorNone != rc) {
1109 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1110 return rc;
1111 }
1112
1113 rc = OMX_SetParameter(p_session->omx_handle, exif_idx,
1114 &exif_info);
1115 if (OMX_ErrorNone != rc) {
1116 CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, rc);
1117 return rc;
1118 }
1119 }
1120
1121 return rc;
1122 }
1123
1124 /** mm_jpeg_session_abort:
1125 *
1126 * Arguments:
1127 * @p_session: jpeg session
1128 *
1129 * Return:
1130 * OMX_BOOL
1131 *
1132 * Description:
1133 * Abort ongoing job
1134 *
1135 **/
mm_jpeg_session_abort(mm_jpeg_job_session_t * p_session)1136 OMX_BOOL mm_jpeg_session_abort(mm_jpeg_job_session_t *p_session)
1137 {
1138 OMX_ERRORTYPE ret = OMX_ErrorNone;
1139
1140 CDBG("%s:%d] E", __func__, __LINE__);
1141 pthread_mutex_lock(&p_session->lock);
1142 if (OMX_TRUE == p_session->abort_flag) {
1143 pthread_mutex_unlock(&p_session->lock);
1144 CDBG("%s:%d] **** ALREADY ABORTED", __func__, __LINE__);
1145 return 0;
1146 }
1147 p_session->abort_flag = OMX_TRUE;
1148 if (OMX_TRUE == p_session->encoding) {
1149 p_session->state_change_pending = OMX_TRUE;
1150
1151 CDBG("%s:%d] **** ABORTING", __func__, __LINE__);
1152
1153 ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandStateSet,
1154 OMX_StateIdle, NULL);
1155
1156 if (ret != OMX_ErrorNone) {
1157 CDBG("%s:%d] OMX_SendCommand returned error %d", __func__, __LINE__, ret);
1158 pthread_mutex_unlock(&p_session->lock);
1159 return 1;
1160 }
1161
1162 CDBG("%s:%d] before wait", __func__, __LINE__);
1163 pthread_cond_wait(&p_session->cond, &p_session->lock);
1164 CDBG("%s:%d] after wait", __func__, __LINE__);
1165 }
1166 pthread_mutex_unlock(&p_session->lock);
1167 CDBG("%s:%d] X", __func__, __LINE__);
1168 return 0;
1169 }
1170
1171 /** mm_jpeg_get_job_idx:
1172 *
1173 * Arguments:
1174 * @my_obj: jpeg object
1175 * @client_idx: client index
1176 *
1177 * Return:
1178 * job index
1179 *
1180 * Description:
1181 * Get job index by client id
1182 *
1183 **/
mm_jpeg_get_new_session_idx(mm_jpeg_obj * my_obj,int client_idx,mm_jpeg_job_session_t ** pp_session)1184 inline int mm_jpeg_get_new_session_idx(mm_jpeg_obj *my_obj, int client_idx,
1185 mm_jpeg_job_session_t **pp_session)
1186 {
1187 int i = 0;
1188 int index = -1;
1189 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
1190 pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
1191 if (!my_obj->clnt_mgr[client_idx].session[i].active) {
1192 *pp_session = &my_obj->clnt_mgr[client_idx].session[i];
1193 my_obj->clnt_mgr[client_idx].session[i].active = OMX_TRUE;
1194 index = i;
1195 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1196 break;
1197 }
1198 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1199 }
1200 return index;
1201 }
1202
1203 /** mm_jpeg_get_job_idx:
1204 *
1205 * Arguments:
1206 * @my_obj: jpeg object
1207 * @client_idx: client index
1208 *
1209 * Return:
1210 * job index
1211 *
1212 * Description:
1213 * Get job index by client id
1214 *
1215 **/
mm_jpeg_remove_session_idx(mm_jpeg_obj * my_obj,uint32_t job_id)1216 inline void mm_jpeg_remove_session_idx(mm_jpeg_obj *my_obj, uint32_t job_id)
1217 {
1218 int client_idx = GET_CLIENT_IDX(job_id);
1219 int session_idx= GET_SESSION_IDX(job_id);
1220 CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__,
1221 client_idx, session_idx);
1222 pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
1223 my_obj->clnt_mgr[client_idx].session[session_idx].active = OMX_FALSE;
1224 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1225 }
1226
1227 /** mm_jpeg_get_session_idx:
1228 *
1229 * Arguments:
1230 * @my_obj: jpeg object
1231 * @client_idx: client index
1232 *
1233 * Return:
1234 * job index
1235 *
1236 * Description:
1237 * Get job index by client id
1238 *
1239 **/
mm_jpeg_get_session(mm_jpeg_obj * my_obj,uint32_t job_id)1240 inline mm_jpeg_job_session_t *mm_jpeg_get_session(mm_jpeg_obj *my_obj, uint32_t job_id)
1241 {
1242 mm_jpeg_job_session_t *p_session = NULL;
1243 int client_idx = GET_CLIENT_IDX(job_id);
1244 int session_idx= GET_SESSION_IDX(job_id);
1245
1246 CDBG("%s:%d] client_idx %d session_idx %d", __func__, __LINE__,
1247 client_idx, session_idx);
1248 if ((session_idx >= MM_JPEG_MAX_SESSION) ||
1249 (client_idx >= MAX_JPEG_CLIENT_NUM)) {
1250 CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
1251 job_id);
1252 return NULL;
1253 }
1254 pthread_mutex_lock(&my_obj->clnt_mgr[client_idx].lock);
1255 p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
1256 pthread_mutex_unlock(&my_obj->clnt_mgr[client_idx].lock);
1257 return p_session;
1258 }
1259
1260 /** mm_jpeg_session_configure:
1261 *
1262 * Arguments:
1263 * @data: encode session
1264 *
1265 * Return:
1266 * none
1267 *
1268 * Description:
1269 * Configure the session
1270 *
1271 **/
mm_jpeg_session_configure(mm_jpeg_job_session_t * p_session)1272 static OMX_ERRORTYPE mm_jpeg_session_configure(mm_jpeg_job_session_t *p_session)
1273 {
1274 OMX_ERRORTYPE ret = OMX_ErrorNone;
1275 mm_jpeg_encode_params_t *p_params = &p_session->params;
1276 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1277 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
1278
1279 CDBG("%s:%d] E ", __func__, __LINE__);
1280
1281 MM_JPEG_CHK_ABORT(p_session, ret, error);
1282
1283 /* config main img */
1284 ret = mm_jpeg_session_config_main(p_session);
1285 if (OMX_ErrorNone != ret) {
1286 CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__);
1287 goto error;
1288 }
1289
1290 /* config thumbnail */
1291 ret = mm_jpeg_session_config_thumbnail(p_session);
1292 if (OMX_ErrorNone != ret) {
1293 CDBG_ERROR("%s:%d] config thumbnail img failed", __func__, __LINE__);
1294 goto error;
1295 }
1296
1297 /* config encoding mode */
1298 CDBG("%s:%d] config encoding mode", __func__, __LINE__);
1299 ret = mm_jpeg_encoding_mode(p_session);
1300 if (OMX_ErrorNone != ret) {
1301 CDBG_ERROR("%s: config encoding mode failed", __func__);
1302 return ret;
1303 }
1304
1305 /* common config */
1306 ret = mm_jpeg_session_config_common(p_session);
1307 if (OMX_ErrorNone != ret) {
1308 CDBG_ERROR("%s:%d] config common failed", __func__, __LINE__);
1309 goto error;
1310 }
1311
1312 ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle,
1313 mm_jpeg_session_send_buffers);
1314 if (ret) {
1315 CDBG_ERROR("%s:%d] change state to idle failed %d",
1316 __func__, __LINE__, ret);
1317 goto error;
1318 }
1319
1320 ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting,
1321 NULL);
1322 if (ret) {
1323 CDBG_ERROR("%s:%d] change state to executing failed %d",
1324 __func__, __LINE__, ret);
1325 goto error;
1326 }
1327
1328 error:
1329 CDBG("%s:%d] X ret %d", __func__, __LINE__, ret);
1330 return ret;
1331 }
1332
1333 /** mm_jpeg_session_encode:
1334 *
1335 * Arguments:
1336 * @p_session: encode session
1337 *
1338 * Return:
1339 * OMX_ERRORTYPE
1340 *
1341 * Description:
1342 * Start the encoding
1343 *
1344 **/
mm_jpeg_job_done(mm_jpeg_job_session_t * p_session)1345 static inline void mm_jpeg_job_done(mm_jpeg_job_session_t *p_session)
1346 {
1347 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
1348 mm_jpeg_job_q_node_t *node = NULL;
1349
1350 /*remove the job*/
1351 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q,
1352 p_session->jobId);
1353 if (node) {
1354 free(node);
1355 }
1356 p_session->encoding = OMX_FALSE;
1357
1358 /* wake up jobMgr thread to work on new job if there is any */
1359 cam_sem_post(&my_obj->job_mgr.job_sem);
1360 }
1361
1362 /** mm_jpeg_session_encode:
1363 *
1364 * Arguments:
1365 * @p_session: encode session
1366 *
1367 * Return:
1368 * OMX_ERRORTYPE
1369 *
1370 * Description:
1371 * Start the encoding
1372 *
1373 **/
mm_jpeg_session_encode(mm_jpeg_job_session_t * p_session)1374 static OMX_ERRORTYPE mm_jpeg_session_encode(mm_jpeg_job_session_t *p_session)
1375 {
1376 OMX_ERRORTYPE ret = OMX_ErrorNone;
1377 mm_jpeg_encode_params_t *p_params = &p_session->params;
1378 mm_jpeg_encode_job_t *p_jobparams = &p_session->encode_job;
1379 int dest_idx = 0;
1380 mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
1381
1382 pthread_mutex_lock(&p_session->lock);
1383 p_session->abort_flag = OMX_FALSE;
1384 p_session->encoding = OMX_FALSE;
1385 pthread_mutex_unlock(&p_session->lock);
1386
1387 if (OMX_FALSE == p_session->config) {
1388 ret = mm_jpeg_session_configure(p_session);
1389 if (ret) {
1390 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1391 goto error;
1392 }
1393 p_session->config = OMX_TRUE;
1394 }
1395
1396 pthread_mutex_lock(&p_session->lock);
1397 p_session->encoding = OMX_TRUE;
1398 pthread_mutex_unlock(&p_session->lock);
1399
1400 MM_JPEG_CHK_ABORT(p_session, ret, error);
1401
1402 #ifdef MM_JPEG_DUMP_INPUT
1403 DUMP_TO_FILE("/data/mm_jpeg_int.yuv",
1404 p_session->p_in_omx_buf[p_jobparams->src_index]->pBuffer,
1405 (int)p_session->p_in_omx_buf[p_jobparams->src_index]->nAllocLen);
1406 #endif
1407
1408 ret = OMX_EmptyThisBuffer(p_session->omx_handle,
1409 p_session->p_in_omx_buf[p_jobparams->src_index]);
1410 if (ret) {
1411 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1412 goto error;
1413 }
1414
1415 if (p_session->params.encode_thumbnail) {
1416 ret = OMX_EmptyThisBuffer(p_session->omx_handle,
1417 p_session->p_in_omx_thumb_buf[p_jobparams->thumb_index]);
1418 if (ret) {
1419 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1420 goto error;
1421 }
1422 }
1423
1424 ret = OMX_FillThisBuffer(p_session->omx_handle,
1425 p_session->p_out_omx_buf[p_jobparams->dst_index]);
1426 if (ret) {
1427 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1428 goto error;
1429 }
1430
1431 MM_JPEG_CHK_ABORT(p_session, ret, error);
1432
1433 error:
1434
1435 CDBG("%s:%d] X ", __func__, __LINE__);
1436 return ret;
1437 }
1438
1439 /** mm_jpeg_process_encoding_job:
1440 *
1441 * Arguments:
1442 * @my_obj: jpeg client
1443 * @job_node: job node
1444 *
1445 * Return:
1446 * 0 for success -1 otherwise
1447 *
1448 * Description:
1449 * Start the encoding job
1450 *
1451 **/
mm_jpeg_process_encoding_job(mm_jpeg_obj * my_obj,mm_jpeg_job_q_node_t * job_node)1452 int32_t mm_jpeg_process_encoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node)
1453 {
1454 int32_t rc = 0;
1455 OMX_ERRORTYPE ret = OMX_ErrorNone;
1456 mm_jpeg_job_session_t *p_session = NULL;
1457 mm_jpeg_job_q_node_t *node = NULL;
1458
1459 /* check if valid session */
1460 p_session = mm_jpeg_get_session(my_obj, job_node->enc_info.job_id);
1461 if (NULL == p_session) {
1462 CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
1463 job_node->enc_info.job_id);
1464 return -1;
1465 }
1466
1467 /* sent encode cmd to OMX, queue job into ongoing queue */
1468 rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, job_node);
1469 if (rc) {
1470 CDBG_ERROR("%s:%d] jpeg enqueue failed %d",
1471 __func__, __LINE__, ret);
1472 goto error;
1473 }
1474
1475 p_session->encode_job = job_node->enc_info.encode_job;
1476 p_session->jobId = job_node->enc_info.job_id;
1477 ret = mm_jpeg_session_encode(p_session);
1478 if (ret) {
1479 CDBG_ERROR("%s:%d] encode session failed", __func__, __LINE__);
1480 goto error;
1481 }
1482
1483 CDBG("%s:%d] Success X ", __func__, __LINE__);
1484 return rc;
1485
1486 error:
1487
1488 if ((OMX_ErrorNone != ret) &&
1489 (NULL != p_session->params.jpeg_cb)) {
1490 p_session->job_status = JPEG_JOB_STATUS_ERROR;
1491 CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
1492 p_session->job_status);
1493 p_session->params.jpeg_cb(p_session->job_status,
1494 p_session->client_hdl,
1495 p_session->jobId,
1496 NULL,
1497 p_session->params.userdata);
1498 }
1499
1500 /*remove the job*/
1501 mm_jpeg_job_done(p_session);
1502 CDBG("%s:%d] Error X ", __func__, __LINE__);
1503
1504 return rc;
1505 }
1506
1507 /** mm_jpeg_jobmgr_thread:
1508 *
1509 * Arguments:
1510 * @my_obj: jpeg object
1511 *
1512 * Return:
1513 * 0 for success else failure
1514 *
1515 * Description:
1516 * job manager thread main function
1517 *
1518 **/
mm_jpeg_jobmgr_thread(void * data)1519 static void *mm_jpeg_jobmgr_thread(void *data)
1520 {
1521 int rc = 0;
1522 int running = 1;
1523 uint32_t num_ongoing_jobs = 0;
1524 mm_jpeg_obj *my_obj = (mm_jpeg_obj*)data;
1525 mm_jpeg_job_cmd_thread_t *cmd_thread = &my_obj->job_mgr;
1526 mm_jpeg_job_q_node_t* node = NULL;
1527
1528 do {
1529 do {
1530 rc = cam_sem_wait(&cmd_thread->job_sem);
1531 if (rc != 0 && errno != EINVAL) {
1532 CDBG_ERROR("%s: cam_sem_wait error (%s)",
1533 __func__, strerror(errno));
1534 return NULL;
1535 }
1536 } while (rc != 0);
1537
1538 /* check ongoing q size */
1539 num_ongoing_jobs = mm_jpeg_queue_get_size(&my_obj->ongoing_job_q);
1540 if (num_ongoing_jobs >= NUM_MAX_JPEG_CNCURRENT_JOBS) {
1541 CDBG("%s:%d] ongoing job already reach max %d", __func__,
1542 __LINE__, num_ongoing_jobs);
1543 continue;
1544 }
1545
1546 pthread_mutex_lock(&my_obj->job_lock);
1547 /* can go ahead with new work */
1548 node = (mm_jpeg_job_q_node_t*)mm_jpeg_queue_deq(&cmd_thread->job_queue);
1549 if (node != NULL) {
1550 switch (node->type) {
1551 case MM_JPEG_CMD_TYPE_JOB:
1552 rc = mm_jpeg_process_encoding_job(my_obj, node);
1553 break;
1554 case MM_JPEG_CMD_TYPE_EXIT:
1555 default:
1556 /* free node */
1557 free(node);
1558 /* set running flag to false */
1559 running = 0;
1560 break;
1561 }
1562 }
1563 pthread_mutex_unlock(&my_obj->job_lock);
1564
1565 } while (running);
1566 return NULL;
1567 }
1568
1569 /** mm_jpeg_jobmgr_thread_launch:
1570 *
1571 * Arguments:
1572 * @my_obj: jpeg object
1573 *
1574 * Return:
1575 * 0 for success else failure
1576 *
1577 * Description:
1578 * launches the job manager thread
1579 *
1580 **/
mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj * my_obj)1581 int32_t mm_jpeg_jobmgr_thread_launch(mm_jpeg_obj *my_obj)
1582 {
1583 int32_t rc = 0;
1584 mm_jpeg_job_cmd_thread_t *job_mgr = &my_obj->job_mgr;
1585
1586 cam_sem_init(&job_mgr->job_sem, 0);
1587 mm_jpeg_queue_init(&job_mgr->job_queue);
1588
1589 /* launch the thread */
1590 pthread_create(&job_mgr->pid,
1591 NULL,
1592 mm_jpeg_jobmgr_thread,
1593 (void *)my_obj);
1594 return rc;
1595 }
1596
1597 /** mm_jpeg_jobmgr_thread_release:
1598 *
1599 * Arguments:
1600 * @my_obj: jpeg object
1601 *
1602 * Return:
1603 * 0 for success else failure
1604 *
1605 * Description:
1606 * Releases the job manager thread
1607 *
1608 **/
mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj)1609 int32_t mm_jpeg_jobmgr_thread_release(mm_jpeg_obj * my_obj)
1610 {
1611 int32_t rc = 0;
1612 mm_jpeg_job_cmd_thread_t * cmd_thread = &my_obj->job_mgr;
1613 mm_jpeg_job_q_node_t* node =
1614 (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
1615 if (NULL == node) {
1616 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
1617 return -1;
1618 }
1619
1620 memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
1621 node->type = MM_JPEG_CMD_TYPE_EXIT;
1622
1623 mm_jpeg_queue_enq(&cmd_thread->job_queue, node);
1624 cam_sem_post(&cmd_thread->job_sem);
1625
1626 /* wait until cmd thread exits */
1627 if (pthread_join(cmd_thread->pid, NULL) != 0) {
1628 CDBG("%s: pthread dead already", __func__);
1629 }
1630 mm_jpeg_queue_deinit(&cmd_thread->job_queue);
1631
1632 cam_sem_destroy(&cmd_thread->job_sem);
1633 memset(cmd_thread, 0, sizeof(mm_jpeg_job_cmd_thread_t));
1634 return rc;
1635 }
1636
1637 /** mm_jpeg_init:
1638 *
1639 * Arguments:
1640 * @my_obj: jpeg object
1641 *
1642 * Return:
1643 * 0 for success else failure
1644 *
1645 * Description:
1646 * Initializes the jpeg client
1647 *
1648 **/
mm_jpeg_init(mm_jpeg_obj * my_obj)1649 int32_t mm_jpeg_init(mm_jpeg_obj *my_obj)
1650 {
1651 int32_t rc = 0;
1652
1653 /* init locks */
1654 pthread_mutex_init(&my_obj->job_lock, NULL);
1655
1656 /* init ongoing job queue */
1657 rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q);
1658 if (0 != rc) {
1659 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1660 return -1;
1661 }
1662
1663 /* init job semaphore and launch jobmgr thread */
1664 CDBG("%s:%d] Launch jobmgr thread rc %d", __func__, __LINE__, rc);
1665 rc = mm_jpeg_jobmgr_thread_launch(my_obj);
1666 if (0 != rc) {
1667 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1668 return -1;
1669 }
1670
1671 /* load OMX */
1672 if (OMX_ErrorNone != OMX_Init()) {
1673 /* roll back in error case */
1674 CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc);
1675 mm_jpeg_jobmgr_thread_release(my_obj);
1676 mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1677 pthread_mutex_destroy(&my_obj->job_lock);
1678 }
1679
1680 return rc;
1681 }
1682
1683 /** mm_jpeg_deinit:
1684 *
1685 * Arguments:
1686 * @my_obj: jpeg object
1687 *
1688 * Return:
1689 * 0 for success else failure
1690 *
1691 * Description:
1692 * Deinits the jpeg client
1693 *
1694 **/
mm_jpeg_deinit(mm_jpeg_obj * my_obj)1695 int32_t mm_jpeg_deinit(mm_jpeg_obj *my_obj)
1696 {
1697 int32_t rc = 0;
1698
1699 /* release jobmgr thread */
1700 rc = mm_jpeg_jobmgr_thread_release(my_obj);
1701 if (0 != rc) {
1702 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1703 }
1704
1705 /* unload OMX engine */
1706 OMX_Deinit();
1707
1708 /* deinit ongoing job and cb queue */
1709 rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1710 if (0 != rc) {
1711 CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1712 }
1713
1714 /* destroy locks */
1715 pthread_mutex_destroy(&my_obj->job_lock);
1716
1717 return rc;
1718 }
1719
1720 /** mm_jpeg_new_client:
1721 *
1722 * Arguments:
1723 * @my_obj: jpeg object
1724 *
1725 * Return:
1726 * 0 for success else failure
1727 *
1728 * Description:
1729 * Create new jpeg client
1730 *
1731 **/
mm_jpeg_new_client(mm_jpeg_obj * my_obj)1732 uint32_t mm_jpeg_new_client(mm_jpeg_obj *my_obj)
1733 {
1734 uint32_t client_hdl = 0;
1735 uint8_t idx;
1736 int i = 0;
1737
1738 if (my_obj->num_clients >= MAX_JPEG_CLIENT_NUM) {
1739 CDBG_ERROR("%s: num of clients reached limit", __func__);
1740 return client_hdl;
1741 }
1742
1743 for (idx = 0; idx < MAX_JPEG_CLIENT_NUM; idx++) {
1744 if (0 == my_obj->clnt_mgr[idx].is_used) {
1745 break;
1746 }
1747 }
1748
1749 if (idx < MAX_JPEG_CLIENT_NUM) {
1750 /* client session avail */
1751 /* generate client handler by index */
1752 client_hdl = mm_jpeg_util_generate_handler(idx);
1753
1754 /* update client session */
1755 my_obj->clnt_mgr[idx].is_used = 1;
1756 my_obj->clnt_mgr[idx].client_handle = client_hdl;
1757
1758 pthread_mutex_init(&my_obj->clnt_mgr[idx].lock, NULL);
1759 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
1760 memset(&my_obj->clnt_mgr[idx].session[i], 0x0, sizeof(mm_jpeg_job_session_t));
1761 }
1762
1763 /* increse client count */
1764 my_obj->num_clients++;
1765 }
1766
1767 return client_hdl;
1768 }
1769
1770 /** mm_jpeg_start_job:
1771 *
1772 * Arguments:
1773 * @my_obj: jpeg object
1774 * @client_hdl: client handle
1775 * @job: pointer to encode job
1776 * @jobId: job id
1777 *
1778 * Return:
1779 * 0 for success else failure
1780 *
1781 * Description:
1782 * Start the encoding job
1783 *
1784 **/
mm_jpeg_start_job(mm_jpeg_obj * my_obj,mm_jpeg_job_t * job,uint32_t * job_id)1785 int32_t mm_jpeg_start_job(mm_jpeg_obj *my_obj,
1786 mm_jpeg_job_t *job,
1787 uint32_t *job_id)
1788 {
1789 int32_t rc = -1;
1790 uint8_t session_idx = 0;
1791 uint8_t client_idx = 0;
1792 mm_jpeg_job_q_node_t* node = NULL;
1793 mm_jpeg_job_session_t *p_session = NULL;
1794 mm_jpeg_encode_job_t *p_jobparams = &job->encode_job;
1795
1796 *job_id = 0;
1797
1798 /* check if valid session */
1799 session_idx = GET_SESSION_IDX(p_jobparams->session_id);
1800 client_idx = GET_CLIENT_IDX(p_jobparams->session_id);
1801 CDBG("%s:%d] session_idx %d client idx %d", __func__, __LINE__,
1802 session_idx, client_idx);
1803
1804 if ((session_idx >= MM_JPEG_MAX_SESSION) ||
1805 (client_idx >= MAX_JPEG_CLIENT_NUM)) {
1806 CDBG_ERROR("%s:%d] invalid session id %x", __func__, __LINE__,
1807 job->encode_job.session_id);
1808 return rc;
1809 }
1810
1811 p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
1812 if (OMX_FALSE == p_session->active) {
1813 CDBG_ERROR("%s:%d] session not active %x", __func__, __LINE__,
1814 job->encode_job.session_id);
1815 return rc;
1816 }
1817
1818 if ((p_jobparams->src_index >= p_session->params.num_src_bufs) ||
1819 (p_jobparams->dst_index >= p_session->params.num_dst_bufs)) {
1820 CDBG_ERROR("%s:%d] invalid buffer indices", __func__, __LINE__);
1821 return rc;
1822 }
1823
1824 /* enqueue new job into todo job queue */
1825 node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
1826 if (NULL == node) {
1827 CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
1828 return -1;
1829 }
1830
1831 *job_id = job->encode_job.session_id |
1832 ((p_session->job_hist++ % JOB_HIST_MAX) << 16);
1833
1834 memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
1835 node->enc_info.encode_job = job->encode_job;
1836 node->enc_info.job_id = *job_id;
1837 node->enc_info.client_handle = p_session->client_hdl;
1838 node->type = MM_JPEG_CMD_TYPE_JOB;
1839
1840 rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, node);
1841 if (0 == rc) {
1842 cam_sem_post(&my_obj->job_mgr.job_sem);
1843 }
1844
1845 return rc;
1846 }
1847
1848 /** mm_jpeg_abort_job:
1849 *
1850 * Arguments:
1851 * @my_obj: jpeg object
1852 * @client_hdl: client handle
1853 * @jobId: job id
1854 *
1855 * Return:
1856 * 0 for success else failure
1857 *
1858 * Description:
1859 * Abort the encoding session
1860 *
1861 **/
mm_jpeg_abort_job(mm_jpeg_obj * my_obj,uint32_t jobId)1862 int32_t mm_jpeg_abort_job(mm_jpeg_obj *my_obj,
1863 uint32_t jobId)
1864 {
1865 int32_t rc = -1;
1866 uint8_t clnt_idx = 0;
1867 mm_jpeg_job_q_node_t *node = NULL;
1868 OMX_BOOL ret = OMX_FALSE;
1869 mm_jpeg_job_session_t *p_session = NULL;
1870
1871 CDBG("%s:%d] ", __func__, __LINE__);
1872 pthread_mutex_lock(&my_obj->job_lock);
1873
1874 /* abort job if in todo queue */
1875 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId);
1876 if (NULL != node) {
1877 free(node);
1878 goto abort_done;
1879 }
1880
1881 /* abort job if in ongoing queue */
1882 node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId);
1883 if (NULL != node) {
1884 /* find job that is OMX ongoing, ask OMX to abort the job */
1885 p_session = mm_jpeg_get_session(my_obj, node->enc_info.job_id);
1886 if (p_session) {
1887 mm_jpeg_session_abort(p_session);
1888 } else {
1889 CDBG_ERROR("%s:%d] Invalid job id 0x%x", __func__, __LINE__,
1890 node->enc_info.job_id);
1891 }
1892 free(node);
1893 goto abort_done;
1894 }
1895
1896 abort_done:
1897 pthread_mutex_unlock(&my_obj->job_lock);
1898
1899 return rc;
1900 }
1901
1902 /** mm_jpeg_create_session:
1903 *
1904 * Arguments:
1905 * @my_obj: jpeg object
1906 * @client_hdl: client handle
1907 * @p_params: pointer to encode params
1908 * @p_session_id: session id
1909 *
1910 * Return:
1911 * 0 for success else failure
1912 *
1913 * Description:
1914 * Start the encoding session
1915 *
1916 **/
mm_jpeg_create_session(mm_jpeg_obj * my_obj,uint32_t client_hdl,mm_jpeg_encode_params_t * p_params,uint32_t * p_session_id)1917 int32_t mm_jpeg_create_session(mm_jpeg_obj *my_obj,
1918 uint32_t client_hdl,
1919 mm_jpeg_encode_params_t *p_params,
1920 uint32_t* p_session_id)
1921 {
1922 int32_t rc = 0;
1923 OMX_ERRORTYPE ret = OMX_ErrorNone;
1924 uint8_t clnt_idx = 0;
1925 int session_idx = -1;
1926 mm_jpeg_job_session_t *p_session = NULL;
1927 *p_session_id = 0;
1928
1929 /* validate the parameters */
1930 if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF)
1931 || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) {
1932 CDBG_ERROR("%s:%d] invalid num buffers", __func__, __LINE__);
1933 return -1;
1934 }
1935
1936 /* check if valid client */
1937 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
1938 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
1939 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
1940 return -1;
1941 }
1942
1943 session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session);
1944 if (session_idx < 0) {
1945 CDBG_ERROR("%s:%d] invalid session id (%d)", __func__, __LINE__, session_idx);
1946 return -1;
1947 }
1948
1949 ret = mm_jpeg_session_create(p_session);
1950 if (OMX_ErrorNone != ret) {
1951 p_session->active = OMX_FALSE;
1952 CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__);
1953 return ret;
1954 }
1955
1956 *p_session_id = (JOB_ID_MAGICVAL << 24) | (session_idx << 8) | clnt_idx;
1957
1958 /*copy the params*/
1959 p_session->params = *p_params;
1960 p_session->client_hdl = client_hdl;
1961 p_session->sessionId = *p_session_id;
1962 p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */
1963 CDBG("%s:%d] session id %x", __func__, __LINE__, *p_session_id);
1964
1965 return ret;
1966 }
1967
1968 /** mm_jpeg_destroy_session:
1969 *
1970 * Arguments:
1971 * @my_obj: jpeg object
1972 * @session_id: session index
1973 *
1974 * Return:
1975 * 0 for success else failure
1976 *
1977 * Description:
1978 * Destroy the encoding session
1979 *
1980 **/
mm_jpeg_destroy_session(mm_jpeg_obj * my_obj,mm_jpeg_job_session_t * p_session)1981 int32_t mm_jpeg_destroy_session(mm_jpeg_obj *my_obj,
1982 mm_jpeg_job_session_t *p_session)
1983 {
1984 int32_t rc = 0;
1985 uint8_t clnt_idx = 0;
1986 mm_jpeg_job_q_node_t *node = NULL;
1987 OMX_BOOL ret = OMX_FALSE;
1988 uint32_t session_id = p_session->sessionId;
1989
1990 if (NULL == p_session) {
1991 CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
1992 return rc;
1993 }
1994
1995 pthread_mutex_lock(&my_obj->job_lock);
1996
1997 /* abort job if in todo queue */
1998 CDBG("%s:%d] abort todo jobs", __func__, __LINE__);
1999 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2000 while (NULL != node) {
2001 free(node);
2002 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2003 }
2004
2005 /* abort job if in ongoing queue */
2006 CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__);
2007 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2008 while (NULL != node) {
2009 free(node);
2010 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2011 }
2012
2013 /* abort the current session */
2014 mm_jpeg_session_abort(p_session);
2015 mm_jpeg_session_destroy(p_session);
2016 mm_jpeg_remove_session_idx(my_obj, session_id);
2017 pthread_mutex_unlock(&my_obj->job_lock);
2018
2019 /* wake up jobMgr thread to work on new job if there is any */
2020 cam_sem_post(&my_obj->job_mgr.job_sem);
2021 CDBG("%s:%d] X", __func__, __LINE__);
2022
2023 return rc;
2024 }
2025
2026 /** mm_jpeg_destroy_session:
2027 *
2028 * Arguments:
2029 * @my_obj: jpeg object
2030 * @session_id: session index
2031 *
2032 * Return:
2033 * 0 for success else failure
2034 *
2035 * Description:
2036 * Destroy the encoding session
2037 *
2038 **/
mm_jpeg_destroy_session_unlocked(mm_jpeg_obj * my_obj,mm_jpeg_job_session_t * p_session)2039 int32_t mm_jpeg_destroy_session_unlocked(mm_jpeg_obj *my_obj,
2040 mm_jpeg_job_session_t *p_session)
2041 {
2042 int32_t rc = -1;
2043 uint8_t clnt_idx = 0;
2044 mm_jpeg_job_q_node_t *node = NULL;
2045 OMX_BOOL ret = OMX_FALSE;
2046 uint32_t session_id = p_session->sessionId;
2047
2048 if (NULL == p_session) {
2049 CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
2050 return rc;
2051 }
2052
2053 /* abort job if in todo queue */
2054 CDBG("%s:%d] abort todo jobs", __func__, __LINE__);
2055 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2056 while (NULL != node) {
2057 free(node);
2058 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
2059 }
2060
2061 /* abort job if in ongoing queue */
2062 CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__);
2063 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2064 while (NULL != node) {
2065 free(node);
2066 node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
2067 }
2068
2069 /* abort the current session */
2070 mm_jpeg_session_abort(p_session);
2071 mm_jpeg_remove_session_idx(my_obj, session_id);
2072
2073 return rc;
2074 }
2075
2076 /** mm_jpeg_destroy_session:
2077 *
2078 * Arguments:
2079 * @my_obj: jpeg object
2080 * @session_id: session index
2081 *
2082 * Return:
2083 * 0 for success else failure
2084 *
2085 * Description:
2086 * Destroy the encoding session
2087 *
2088 **/
mm_jpeg_destroy_session_by_id(mm_jpeg_obj * my_obj,uint32_t session_id)2089 int32_t mm_jpeg_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id)
2090 {
2091 mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id);
2092
2093 return mm_jpeg_destroy_session(my_obj, p_session);
2094 }
2095
2096 /** mm_jpeg_close:
2097 *
2098 * Arguments:
2099 * @my_obj: jpeg object
2100 * @client_hdl: client handle
2101 *
2102 * Return:
2103 * 0 for success else failure
2104 *
2105 * Description:
2106 * Close the jpeg client
2107 *
2108 **/
mm_jpeg_close(mm_jpeg_obj * my_obj,uint32_t client_hdl)2109 int32_t mm_jpeg_close(mm_jpeg_obj *my_obj, uint32_t client_hdl)
2110 {
2111 int32_t rc = -1;
2112 uint8_t clnt_idx = 0;
2113 mm_jpeg_job_q_node_t *node = NULL;
2114 OMX_BOOL ret = OMX_FALSE;
2115 int i = 0;
2116
2117 /* check if valid client */
2118 clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
2119 if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
2120 CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
2121 return rc;
2122 }
2123
2124 CDBG("%s:%d] E", __func__, __LINE__);
2125
2126 /* abort all jobs from the client */
2127 pthread_mutex_lock(&my_obj->job_lock);
2128
2129 CDBG("%s:%d] ", __func__, __LINE__);
2130
2131 for (i = 0; i < MM_JPEG_MAX_SESSION; i++) {
2132 if (OMX_TRUE == my_obj->clnt_mgr[clnt_idx].session[i].active)
2133 mm_jpeg_destroy_session_unlocked(my_obj,
2134 &my_obj->clnt_mgr[clnt_idx].session[i]);
2135 }
2136
2137 CDBG("%s:%d] ", __func__, __LINE__);
2138
2139 pthread_mutex_unlock(&my_obj->job_lock);
2140 CDBG("%s:%d] ", __func__, __LINE__);
2141
2142 /* invalidate client session */
2143 pthread_mutex_destroy(&my_obj->clnt_mgr[clnt_idx].lock);
2144 memset(&my_obj->clnt_mgr[clnt_idx], 0, sizeof(mm_jpeg_client_t));
2145
2146 rc = 0;
2147 CDBG("%s:%d] X", __func__, __LINE__);
2148 return rc;
2149 }
2150
mm_jpeg_ebd(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_BUFFERHEADERTYPE * pBuffer)2151 OMX_ERRORTYPE mm_jpeg_ebd(OMX_HANDLETYPE hComponent,
2152 OMX_PTR pAppData,
2153 OMX_BUFFERHEADERTYPE *pBuffer)
2154 {
2155 OMX_ERRORTYPE ret = OMX_ErrorNone;
2156 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2157
2158 CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->ebd_count);
2159 pthread_mutex_lock(&p_session->lock);
2160 p_session->ebd_count++;
2161 pthread_mutex_unlock(&p_session->lock);
2162 return 0;
2163 }
2164
mm_jpeg_fbd(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_BUFFERHEADERTYPE * pBuffer)2165 OMX_ERRORTYPE mm_jpeg_fbd(OMX_HANDLETYPE hComponent,
2166 OMX_PTR pAppData,
2167 OMX_BUFFERHEADERTYPE *pBuffer)
2168 {
2169 OMX_ERRORTYPE ret = OMX_ErrorNone;
2170 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2171 uint32_t i = 0;
2172 int rc = 0;
2173 mm_jpeg_output_t output_buf;
2174
2175 CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count);
2176
2177 if (OMX_TRUE == p_session->abort_flag) {
2178 pthread_cond_signal(&p_session->cond);
2179 return ret;
2180 }
2181
2182 pthread_mutex_lock(&p_session->lock);
2183 p_session->fbd_count++;
2184 if (NULL != p_session->params.jpeg_cb) {
2185 p_session->job_status = JPEG_JOB_STATUS_DONE;
2186 output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen;
2187 output_buf.buf_vaddr = pBuffer->pBuffer;
2188 output_buf.fd = 0;
2189 CDBG("%s:%d] send jpeg callback %d", __func__, __LINE__,
2190 p_session->job_status);
2191 p_session->params.jpeg_cb(p_session->job_status,
2192 p_session->client_hdl,
2193 p_session->jobId,
2194 &output_buf,
2195 p_session->params.userdata);
2196
2197 /* remove from ready queue */
2198 mm_jpeg_job_done(p_session);
2199 }
2200 pthread_mutex_unlock(&p_session->lock);
2201 CDBG("%s:%d] ", __func__, __LINE__);
2202
2203 return ret;
2204 }
2205
mm_jpeg_event_handler(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_EVENTTYPE eEvent,OMX_U32 nData1,OMX_U32 nData2,OMX_PTR pEventData)2206 OMX_ERRORTYPE mm_jpeg_event_handler(OMX_HANDLETYPE hComponent,
2207 OMX_PTR pAppData,
2208 OMX_EVENTTYPE eEvent,
2209 OMX_U32 nData1,
2210 OMX_U32 nData2,
2211 OMX_PTR pEventData)
2212 {
2213 mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
2214
2215 CDBG("%s:%d] %d %d %d", __func__, __LINE__, eEvent, (int)nData1,
2216 (int)nData2);
2217
2218 pthread_mutex_lock(&p_session->lock);
2219
2220 if (OMX_TRUE == p_session->abort_flag) {
2221 pthread_cond_signal(&p_session->cond);
2222 pthread_mutex_unlock(&p_session->lock);
2223 return OMX_ErrorNone;
2224 }
2225
2226 if (eEvent == OMX_EventError) {
2227 p_session->error_flag = OMX_ErrorHardware;
2228 if (p_session->encoding == OMX_TRUE) {
2229 CDBG("%s:%d] Error during encoding", __func__, __LINE__);
2230
2231 /* send jpeg callback */
2232 if (NULL != p_session->params.jpeg_cb) {
2233 p_session->job_status = JPEG_JOB_STATUS_ERROR;
2234 CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
2235 p_session->job_status);
2236 p_session->params.jpeg_cb(p_session->job_status,
2237 p_session->client_hdl,
2238 p_session->jobId,
2239 NULL,
2240 p_session->params.userdata);
2241 }
2242
2243 /* remove from ready queue */
2244 mm_jpeg_job_done(p_session);
2245 }
2246 pthread_cond_signal(&p_session->cond);
2247 } else if (eEvent == OMX_EventCmdComplete) {
2248 if (p_session->state_change_pending == OMX_TRUE) {
2249 p_session->state_change_pending = OMX_FALSE;
2250 pthread_cond_signal(&p_session->cond);
2251 }
2252 }
2253
2254 pthread_mutex_unlock(&p_session->lock);
2255 CDBG("%s:%d]", __func__, __LINE__);
2256 return OMX_ErrorNone;
2257 }
2258
2259 /* 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)2260 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_client_id(
2261 mm_jpeg_queue_t* queue, uint32_t client_hdl)
2262 {
2263 mm_jpeg_q_node_t* node = NULL;
2264 mm_jpeg_job_q_node_t* data = NULL;
2265 mm_jpeg_job_q_node_t* job_node = NULL;
2266 struct cam_list *head = NULL;
2267 struct cam_list *pos = NULL;
2268
2269 pthread_mutex_lock(&queue->lock);
2270 head = &queue->head.list;
2271 pos = head->next;
2272 while(pos != head) {
2273 node = member_of(pos, mm_jpeg_q_node_t, list);
2274 data = (mm_jpeg_job_q_node_t *)node->data;
2275
2276 if (data && (data->enc_info.client_handle == client_hdl)) {
2277 CDBG_ERROR("%s:%d] found matching client handle", __func__, __LINE__);
2278 job_node = data;
2279 cam_list_del_node(&node->list);
2280 queue->size--;
2281 free(node);
2282 CDBG_ERROR("%s: queue size = %d", __func__, queue->size);
2283 break;
2284 }
2285 pos = pos->next;
2286 }
2287
2288 pthread_mutex_unlock(&queue->lock);
2289
2290 return job_node;
2291 }
2292
2293 /* remove the first job from the queue with matching session id */
mm_jpeg_queue_remove_job_by_session_id(mm_jpeg_queue_t * queue,uint32_t session_id)2294 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_session_id(
2295 mm_jpeg_queue_t* queue, uint32_t session_id)
2296 {
2297 mm_jpeg_q_node_t* node = NULL;
2298 mm_jpeg_job_q_node_t* data = NULL;
2299 mm_jpeg_job_q_node_t* job_node = NULL;
2300 struct cam_list *head = NULL;
2301 struct cam_list *pos = NULL;
2302
2303 pthread_mutex_lock(&queue->lock);
2304 head = &queue->head.list;
2305 pos = head->next;
2306 while(pos != head) {
2307 node = member_of(pos, mm_jpeg_q_node_t, list);
2308 data = (mm_jpeg_job_q_node_t *)node->data;
2309
2310 if (data && (data->enc_info.encode_job.session_id == session_id)) {
2311 CDBG_ERROR("%s:%d] found matching session id", __func__, __LINE__);
2312 job_node = data;
2313 cam_list_del_node(&node->list);
2314 queue->size--;
2315 free(node);
2316 CDBG_ERROR("%s: queue size = %d", __func__, queue->size);
2317 break;
2318 }
2319 pos = pos->next;
2320 }
2321
2322 pthread_mutex_unlock(&queue->lock);
2323
2324 return job_node;
2325 }
2326
2327 /* 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)2328 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_by_job_id(
2329 mm_jpeg_queue_t* queue, uint32_t job_id)
2330 {
2331 mm_jpeg_q_node_t* node = NULL;
2332 mm_jpeg_job_q_node_t* data = NULL;
2333 mm_jpeg_job_q_node_t* job_node = NULL;
2334 struct cam_list *head = NULL;
2335 struct cam_list *pos = NULL;
2336
2337 pthread_mutex_lock(&queue->lock);
2338 head = &queue->head.list;
2339 pos = head->next;
2340 while(pos != head) {
2341 node = member_of(pos, mm_jpeg_q_node_t, list);
2342 data = (mm_jpeg_job_q_node_t *)node->data;
2343
2344 if (data && (data->enc_info.job_id == job_id)) {
2345 CDBG_ERROR("%s:%d] found matching job id", __func__, __LINE__);
2346 job_node = data;
2347 cam_list_del_node(&node->list);
2348 queue->size--;
2349 free(node);
2350 break;
2351 }
2352 pos = pos->next;
2353 }
2354
2355 pthread_mutex_unlock(&queue->lock);
2356
2357 return job_node;
2358 }
2359
2360 /* remove job from the queue with matching job id */
mm_jpeg_queue_remove_job_unlk(mm_jpeg_queue_t * queue,uint32_t job_id)2361 mm_jpeg_job_q_node_t* mm_jpeg_queue_remove_job_unlk(
2362 mm_jpeg_queue_t* queue, uint32_t job_id)
2363 {
2364 mm_jpeg_q_node_t* node = NULL;
2365 mm_jpeg_job_q_node_t* data = NULL;
2366 mm_jpeg_job_q_node_t* job_node = NULL;
2367 struct cam_list *head = NULL;
2368 struct cam_list *pos = NULL;
2369
2370 head = &queue->head.list;
2371 pos = head->next;
2372 while(pos != head) {
2373 node = member_of(pos, mm_jpeg_q_node_t, list);
2374 data = (mm_jpeg_job_q_node_t *)node->data;
2375
2376 if (data && (data->enc_info.job_id == job_id)) {
2377 job_node = data;
2378 cam_list_del_node(&node->list);
2379 queue->size--;
2380 free(node);
2381 break;
2382 }
2383 pos = pos->next;
2384 }
2385
2386 return job_node;
2387 }
2388