• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (c) 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 #include "mm_jpeg_inlines.h"
42 
43 OMX_ERRORTYPE mm_jpegdec_ebd(OMX_HANDLETYPE hComponent,
44   OMX_PTR pAppData,
45   OMX_BUFFERHEADERTYPE *pBuffer);
46 OMX_ERRORTYPE mm_jpegdec_fbd(OMX_HANDLETYPE hComponent,
47     OMX_PTR pAppData,
48     OMX_BUFFERHEADERTYPE* pBuffer);
49 OMX_ERRORTYPE mm_jpegdec_event_handler(OMX_HANDLETYPE hComponent,
50     OMX_PTR pAppData,
51     OMX_EVENTTYPE eEvent,
52     OMX_U32 nData1,
53     OMX_U32 nData2,
54     OMX_PTR pEventData);
55 
56 
57 /** mm_jpegdec_destroy_job
58  *
59  *  Arguments:
60  *    @p_session: Session obj
61  *
62  *  Return:
63  *       0 for success else failure
64  *
65  *  Description:
66  *       Destroy the job based paramenters
67  *
68  **/
mm_jpegdec_destroy_job(mm_jpeg_job_session_t * p_session)69 static int32_t mm_jpegdec_destroy_job(mm_jpeg_job_session_t *p_session)
70 {
71   mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
72   int32_t rc = 0;
73 
74   return rc;
75 }
76 
77 /** mm_jpeg_job_done:
78  *
79  *  Arguments:
80  *    @p_session: decode session
81  *
82  *  Return:
83  *       OMX_ERRORTYPE
84  *
85  *  Description:
86  *       Finalize the job
87  *
88  **/
mm_jpegdec_job_done(mm_jpeg_job_session_t * p_session)89 static void mm_jpegdec_job_done(mm_jpeg_job_session_t *p_session)
90 {
91   mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
92   mm_jpeg_job_q_node_t *node = NULL;
93 
94   /*Destroy job related params*/
95   mm_jpegdec_destroy_job(p_session);
96 
97   /*remove the job*/
98   node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q,
99     p_session->jobId);
100   if (node) {
101     free(node);
102   }
103   p_session->encoding = OMX_FALSE;
104 
105   /* wake up jobMgr thread to work on new job if there is any */
106   cam_sem_post(&my_obj->job_mgr.job_sem);
107 }
108 
109 
110 /** mm_jpegdec_session_send_buffers:
111  *
112  *  Arguments:
113  *    @data: job session
114  *
115  *  Return:
116  *       OMX error values
117  *
118  *  Description:
119  *       Send the buffers to OMX layer
120  *
121  **/
mm_jpegdec_session_send_buffers(void * data)122 OMX_ERRORTYPE mm_jpegdec_session_send_buffers(void *data)
123 {
124   uint32_t i = 0;
125   mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data;
126   OMX_ERRORTYPE ret = OMX_ErrorNone;
127   QOMX_BUFFER_INFO lbuffer_info;
128   mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
129   mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
130 
131   memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO));
132   for (i = 0; i < p_params->num_src_bufs; i++) {
133     CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
134     lbuffer_info.fd = p_params->src_main_buf[i].fd;
135     ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_in_omx_buf[i]), 0,
136       &lbuffer_info, p_params->src_main_buf[i].buf_size,
137       p_params->src_main_buf[i].buf_vaddr);
138     if (ret) {
139       CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
140       return ret;
141     }
142   }
143 
144   CDBG("%s:%d]", __func__, __LINE__);
145   return ret;
146 }
147 
148 /** mm_jpeg_session_free_buffers:
149  *
150  *  Arguments:
151  *    @data: job session
152  *
153  *  Return:
154  *       OMX error values
155  *
156  *  Description:
157  *       Free the buffers from OMX layer
158  *
159  **/
mm_jpegdec_session_free_buffers(void * data)160 OMX_ERRORTYPE mm_jpegdec_session_free_buffers(void *data)
161 {
162   OMX_ERRORTYPE ret = OMX_ErrorNone;
163   uint32_t i = 0;
164   mm_jpeg_job_session_t* p_session = (mm_jpeg_job_session_t *)data;
165   mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
166   mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
167 
168   for (i = 0; i < p_params->num_src_bufs; i++) {
169     CDBG("%s:%d] Source buffer %d", __func__, __LINE__, i);
170     ret = OMX_FreeBuffer(p_session->omx_handle, 0, p_session->p_in_omx_buf[i]);
171     if (ret) {
172       CDBG_ERROR("%s:%d] Error %d", __func__, __LINE__, ret);
173       return ret;
174     }
175   }
176 
177   for (i = 0; i < p_params->num_dst_bufs; i++) {
178     CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i);
179     ret = OMX_FreeBuffer(p_session->omx_handle, 1, p_session->p_out_omx_buf[i]);
180     if (ret) {
181       CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
182       return ret;
183     }
184   }
185   CDBG("%s:%d]", __func__, __LINE__);
186   return ret;
187 }
188 
189 /** mm_jpegdec_session_create:
190  *
191  *  Arguments:
192  *    @p_session: job session
193  *
194  *  Return:
195  *       OMX error types
196  *
197  *  Description:
198  *       Create a jpeg encode session
199  *
200  **/
mm_jpegdec_session_create(mm_jpeg_job_session_t * p_session)201 OMX_ERRORTYPE mm_jpegdec_session_create(mm_jpeg_job_session_t* p_session)
202 {
203   OMX_ERRORTYPE rc = OMX_ErrorNone;
204   mm_jpeg_cirq_t *p_cirq = NULL;
205 
206   pthread_mutex_init(&p_session->lock, NULL);
207   pthread_cond_init(&p_session->cond, NULL);
208   cirq_reset(&p_session->cb_q);
209   p_session->state_change_pending = OMX_FALSE;
210   p_session->abort_state = MM_JPEG_ABORT_NONE;
211   p_session->error_flag = OMX_ErrorNone;
212   p_session->ebd_count = 0;
213   p_session->fbd_count = 0;
214   p_session->encode_pid = -1;
215   p_session->config = OMX_FALSE;
216 
217   p_session->omx_callbacks.EmptyBufferDone = mm_jpegdec_ebd;
218   p_session->omx_callbacks.FillBufferDone = mm_jpegdec_fbd;
219   p_session->omx_callbacks.EventHandler = mm_jpegdec_event_handler;
220   p_session->exif_count_local = 0;
221 
222   rc = OMX_GetHandle(&p_session->omx_handle,
223     "OMX.qcom.image.jpeg.decoder",
224     (void *)p_session,
225     &p_session->omx_callbacks);
226 
227   if (OMX_ErrorNone != rc) {
228     CDBG_ERROR("%s:%d] OMX_GetHandle failed (%d)", __func__, __LINE__, rc);
229     return rc;
230   }
231   return rc;
232 }
233 
234 /** mm_jpegdec_session_destroy:
235  *
236  *  Arguments:
237  *    @p_session: job session
238  *
239  *  Return:
240  *       none
241  *
242  *  Description:
243  *       Destroy a jpeg encode session
244  *
245  **/
mm_jpegdec_session_destroy(mm_jpeg_job_session_t * p_session)246 void mm_jpegdec_session_destroy(mm_jpeg_job_session_t* p_session)
247 {
248   OMX_ERRORTYPE rc = OMX_ErrorNone;
249 
250   CDBG("%s:%d] E", __func__, __LINE__);
251   if (NULL == p_session->omx_handle) {
252     CDBG_ERROR("%s:%d] invalid handle", __func__, __LINE__);
253     return;
254   }
255 
256   rc = mm_jpeg_session_change_state(p_session, OMX_StateIdle, NULL);
257   if (rc) {
258     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
259   }
260 
261   rc = mm_jpeg_session_change_state(p_session, OMX_StateLoaded,
262     mm_jpegdec_session_free_buffers);
263   if (rc) {
264     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
265   }
266 
267   rc = OMX_FreeHandle(p_session->omx_handle);
268   if (0 != rc) {
269     CDBG_ERROR("%s:%d] OMX_FreeHandle failed (%d)", __func__, __LINE__, rc);
270   }
271   p_session->omx_handle = NULL;
272 
273 
274   pthread_mutex_destroy(&p_session->lock);
275   pthread_cond_destroy(&p_session->cond);
276   CDBG("%s:%d] X", __func__, __LINE__);
277 }
278 
279 /** mm_jpeg_session_config_port:
280  *
281  *  Arguments:
282  *    @p_session: job session
283  *
284  *  Return:
285  *       OMX error values
286  *
287  *  Description:
288  *       Configure OMX ports
289  *
290  **/
mm_jpegdec_session_config_ports(mm_jpeg_job_session_t * p_session)291 OMX_ERRORTYPE mm_jpegdec_session_config_ports(mm_jpeg_job_session_t* p_session)
292 {
293   OMX_ERRORTYPE ret = OMX_ErrorNone;
294   mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
295   mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
296 
297   mm_jpeg_buf_t *p_src_buf =
298     &p_params->src_main_buf[p_jobparams->src_index];
299 
300   p_session->inputPort.nPortIndex = 0;
301   p_session->outputPort.nPortIndex = 1;
302 
303 
304   ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
305     &p_session->inputPort);
306   if (ret) {
307     CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
308     return ret;
309   }
310 
311   ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
312     &p_session->outputPort);
313   if (ret) {
314     CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
315     return ret;
316   }
317 
318   p_session->inputPort.format.image.nFrameWidth =
319     p_jobparams->main_dim.src_dim.width;
320   p_session->inputPort.format.image.nFrameHeight =
321     p_jobparams->main_dim.src_dim.height;
322   p_session->inputPort.format.image.nStride =
323     p_src_buf->offset.mp[0].stride;
324   p_session->inputPort.format.image.nSliceHeight =
325     p_src_buf->offset.mp[0].scanline;
326   p_session->inputPort.format.image.eColorFormat =
327     map_jpeg_format(p_params->color_format);
328   p_session->inputPort.nBufferSize =
329     p_params->src_main_buf[p_jobparams->src_index].buf_size;
330   p_session->inputPort.nBufferCountActual = p_params->num_src_bufs;
331   ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
332     &p_session->inputPort);
333   if (ret) {
334     CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
335     return ret;
336   }
337 
338   return ret;
339 }
340 
341 
342 /** mm_jpegdec_session_config_main:
343  *
344  *  Arguments:
345  *    @p_session: job session
346  *
347  *  Return:
348  *       OMX error values
349  *
350  *  Description:
351  *       Configure main image
352  *
353  **/
mm_jpegdec_session_config_main(mm_jpeg_job_session_t * p_session)354 OMX_ERRORTYPE mm_jpegdec_session_config_main(mm_jpeg_job_session_t *p_session)
355 {
356   OMX_ERRORTYPE rc = OMX_ErrorNone;
357   OMX_IMAGE_PARAM_QFACTORTYPE q_factor;
358   mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
359   mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
360 
361   /* config port */
362   CDBG("%s:%d] config port", __func__, __LINE__);
363   rc = mm_jpegdec_session_config_ports(p_session);
364   if (OMX_ErrorNone != rc) {
365     CDBG_ERROR("%s: config port failed", __func__);
366     return rc;
367   }
368 
369 
370   /* TODO: config crop */
371 
372   return rc;
373 }
374 
375 /** mm_jpeg_session_configure:
376  *
377  *  Arguments:
378  *    @data: encode session
379  *
380  *  Return:
381  *       none
382  *
383  *  Description:
384  *       Configure the session
385  *
386  **/
mm_jpegdec_session_configure(mm_jpeg_job_session_t * p_session)387 static OMX_ERRORTYPE mm_jpegdec_session_configure(mm_jpeg_job_session_t *p_session)
388 {
389   OMX_ERRORTYPE ret = OMX_ErrorNone;
390   mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
391   mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
392   mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
393 
394   CDBG("%s:%d] E ", __func__, __LINE__);
395 
396   MM_JPEG_CHK_ABORT(p_session, ret, error);
397 
398   /* config main img */
399   ret = mm_jpegdec_session_config_main(p_session);
400   if (OMX_ErrorNone != ret) {
401     CDBG_ERROR("%s:%d] config main img failed", __func__, __LINE__);
402     goto error;
403   }
404 
405   /* TODO: common config (if needed) */
406 
407   ret = mm_jpeg_session_change_state(p_session, OMX_StateIdle,
408     mm_jpegdec_session_send_buffers);
409   if (ret) {
410     CDBG_ERROR("%s:%d] change state to idle failed %d",
411       __func__, __LINE__, ret);
412     goto error;
413   }
414 
415   ret = mm_jpeg_session_change_state(p_session, OMX_StateExecuting,
416     NULL);
417   if (ret) {
418     CDBG_ERROR("%s:%d] change state to executing failed %d",
419       __func__, __LINE__, ret);
420     goto error;
421   }
422 
423 error:
424   CDBG("%s:%d] X ret %d", __func__, __LINE__, ret);
425   return ret;
426 }
427 
mm_jpeg_session_port_enable(mm_jpeg_job_session_t * p_session,OMX_U32 nPortIndex,OMX_BOOL wait)428 static OMX_ERRORTYPE mm_jpeg_session_port_enable(
429     mm_jpeg_job_session_t *p_session,
430     OMX_U32 nPortIndex,
431     OMX_BOOL wait)
432 {
433   OMX_ERRORTYPE ret = OMX_ErrorNone;
434   OMX_EVENTTYPE lEvent;
435 
436   pthread_mutex_lock(&p_session->lock);
437   p_session->event_pending = OMX_TRUE;
438   pthread_mutex_unlock(&p_session->lock);
439 
440   ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortEnable,
441       nPortIndex, NULL);
442 
443   if (ret) {
444     CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
445     return ret;
446   }
447 
448   if (wait == OMX_TRUE) {
449     // Wait for cmd complete
450     pthread_mutex_lock(&p_session->lock);
451     if (p_session->event_pending == OMX_TRUE) {
452       CDBG("%s:%d] before wait", __func__, __LINE__);
453       pthread_cond_wait(&p_session->cond, &p_session->lock);
454       lEvent = p_session->omxEvent;
455       CDBG("%s:%d] after wait", __func__, __LINE__);
456     }
457     lEvent = p_session->omxEvent;
458     pthread_mutex_unlock(&p_session->lock);
459 
460     if (lEvent != OMX_EventCmdComplete) {
461       CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
462       return OMX_ErrorUndefined;
463     }
464   }
465   return OMX_ErrorNone;
466 }
467 
mm_jpeg_session_port_disable(mm_jpeg_job_session_t * p_session,OMX_U32 nPortIndex,OMX_BOOL wait)468 static OMX_ERRORTYPE mm_jpeg_session_port_disable(
469     mm_jpeg_job_session_t *p_session,
470     OMX_U32 nPortIndex,
471     OMX_BOOL wait)
472 {
473   OMX_ERRORTYPE ret = OMX_ErrorNone;
474   OMX_EVENTTYPE lEvent;
475 
476   pthread_mutex_lock(&p_session->lock);
477   p_session->event_pending = OMX_TRUE;
478   pthread_mutex_unlock(&p_session->lock);
479 
480   ret = OMX_SendCommand(p_session->omx_handle, OMX_CommandPortDisable,
481       nPortIndex, NULL);
482 
483   if (ret) {
484     CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
485     return ret;
486   }
487   if (wait == OMX_TRUE) {
488     // Wait for cmd complete
489     pthread_mutex_lock(&p_session->lock);
490     if (p_session->event_pending == OMX_TRUE) {
491       CDBG("%s:%d] before wait", __func__, __LINE__);
492       pthread_cond_wait(&p_session->cond, &p_session->lock);
493 
494       CDBG("%s:%d] after wait", __func__, __LINE__);
495     }
496     lEvent = p_session->omxEvent;
497     pthread_mutex_unlock(&p_session->lock);
498 
499     if (lEvent != OMX_EventCmdComplete) {
500       CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
501       return OMX_ErrorUndefined;
502     }
503   }
504   return OMX_ErrorNone;
505 }
506 
507 
508 /** mm_jpegdec_session_decode:
509  *
510  *  Arguments:
511  *    @p_session: encode session
512  *
513  *  Return:
514  *       OMX_ERRORTYPE
515  *
516  *  Description:
517  *       Start the encoding
518  *
519  **/
mm_jpegdec_session_decode(mm_jpeg_job_session_t * p_session)520 static OMX_ERRORTYPE mm_jpegdec_session_decode(mm_jpeg_job_session_t *p_session)
521 {
522   OMX_ERRORTYPE ret = OMX_ErrorNone;
523   mm_jpeg_decode_params_t *p_params = &p_session->dec_params;
524   mm_jpeg_decode_job_t *p_jobparams = &p_session->decode_job;
525   int dest_idx = 0;
526   mm_jpeg_obj *my_obj = (mm_jpeg_obj *)p_session->jpeg_obj;
527   OMX_EVENTTYPE lEvent;
528   OMX_U32 i;
529   QOMX_BUFFER_INFO lbuffer_info;
530 
531   pthread_mutex_lock(&p_session->lock);
532   p_session->abort_state = MM_JPEG_ABORT_NONE;
533   p_session->encoding = OMX_FALSE;
534   pthread_mutex_unlock(&p_session->lock);
535 
536   if (OMX_FALSE == p_session->config) {
537     ret = mm_jpegdec_session_configure(p_session);
538     if (ret) {
539       CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
540       goto error;
541     }
542     p_session->config = OMX_TRUE;
543   }
544 
545   pthread_mutex_lock(&p_session->lock);
546   p_session->encoding = OMX_TRUE;
547   pthread_mutex_unlock(&p_session->lock);
548 
549   MM_JPEG_CHK_ABORT(p_session, ret, error);
550 
551   p_session->event_pending = OMX_TRUE;
552 
553   ret = OMX_EmptyThisBuffer(p_session->omx_handle,
554     p_session->p_in_omx_buf[p_jobparams->src_index]);
555   if (ret) {
556     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
557     goto error;
558   }
559 
560   // Wait for port settings changed
561   pthread_mutex_lock(&p_session->lock);
562   if (p_session->event_pending == OMX_TRUE) {
563     CDBG("%s:%d] before wait", __func__, __LINE__);
564     pthread_cond_wait(&p_session->cond, &p_session->lock);
565   }
566   lEvent = p_session->omxEvent;
567   CDBG("%s:%d] after wait", __func__, __LINE__);
568   pthread_mutex_unlock(&p_session->lock);
569 
570   if (lEvent != OMX_EventPortSettingsChanged) {
571     CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
572     goto error;
573   }
574 
575   // Disable output port (wait)
576   mm_jpeg_session_port_disable(p_session,
577       p_session->outputPort.nPortIndex,
578       OMX_TRUE);
579 
580   // Get port definition
581   ret = OMX_GetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
582       &p_session->outputPort);
583   if (ret) {
584     CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
585     return ret;
586   }
587 
588   // Set port definition
589   p_session->outputPort.format.image.nFrameWidth =
590     p_jobparams->main_dim.dst_dim.width;
591   p_session->outputPort.format.image.nFrameHeight =
592     p_jobparams->main_dim.dst_dim.height;
593   p_session->outputPort.format.image.eColorFormat =
594     map_jpeg_format(p_params->color_format);
595 
596   p_session->outputPort.nBufferSize =
597      p_params->dest_buf[p_jobparams->dst_index].buf_size;
598    p_session->outputPort.nBufferCountActual = p_params->num_dst_bufs;
599 
600    p_session->outputPort.format.image.nSliceHeight =
601        p_params->dest_buf[p_jobparams->dst_index].offset.mp[0].scanline;
602    p_session->outputPort.format.image.nStride =
603        p_params->dest_buf[p_jobparams->dst_index].offset.mp[0].stride;
604 
605    ret = OMX_SetParameter(p_session->omx_handle, OMX_IndexParamPortDefinition,
606      &p_session->outputPort);
607    if (ret) {
608      CDBG_ERROR("%s:%d] failed", __func__, __LINE__);
609      return ret;
610    }
611 
612   // Enable port (no wait)
613   mm_jpeg_session_port_enable(p_session,
614       p_session->outputPort.nPortIndex,
615       OMX_FALSE);
616 
617   memset(&lbuffer_info, 0x0, sizeof(QOMX_BUFFER_INFO));
618   // Use buffers
619   for (i = 0; i < p_params->num_dst_bufs; i++) {
620     lbuffer_info.fd = p_params->dest_buf[i].fd;
621     CDBG("%s:%d] Dest buffer %d", __func__, __LINE__, i);
622     ret = OMX_UseBuffer(p_session->omx_handle, &(p_session->p_out_omx_buf[i]),
623         1, &lbuffer_info, p_params->dest_buf[i].buf_size,
624         p_params->dest_buf[i].buf_vaddr);
625     if (ret) {
626       CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
627       return ret;
628     }
629   }
630 
631   // Wait for port enable completion
632   pthread_mutex_lock(&p_session->lock);
633   if (p_session->event_pending == OMX_TRUE) {
634     CDBG("%s:%d] before wait", __func__, __LINE__);
635     pthread_cond_wait(&p_session->cond, &p_session->lock);
636     lEvent = p_session->omxEvent;
637     CDBG("%s:%d] after wait", __func__, __LINE__);
638   }
639   lEvent = p_session->omxEvent;
640   pthread_mutex_unlock(&p_session->lock);
641 
642   if (lEvent != OMX_EventCmdComplete) {
643     CDBG("%s:%d] Unexpected event %d", __func__, __LINE__,lEvent);
644     goto error;
645   }
646 
647   ret = OMX_FillThisBuffer(p_session->omx_handle,
648     p_session->p_out_omx_buf[p_jobparams->dst_index]);
649   if (ret) {
650     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
651     goto error;
652   }
653 
654   MM_JPEG_CHK_ABORT(p_session, ret, error);
655 
656 error:
657 
658   CDBG("%s:%d] X ", __func__, __LINE__);
659   return ret;
660 }
661 
662 /** mm_jpegdec_process_decoding_job:
663  *
664  *  Arguments:
665  *    @my_obj: jpeg client
666  *    @job_node: job node
667  *
668  *  Return:
669  *       0 for success -1 otherwise
670  *
671  *  Description:
672  *       Start the encoding job
673  *
674  **/
mm_jpegdec_process_decoding_job(mm_jpeg_obj * my_obj,mm_jpeg_job_q_node_t * job_node)675 int32_t mm_jpegdec_process_decoding_job(mm_jpeg_obj *my_obj, mm_jpeg_job_q_node_t* job_node)
676 {
677   int32_t rc = 0;
678   OMX_ERRORTYPE ret = OMX_ErrorNone;
679   mm_jpeg_job_session_t *p_session = NULL;
680   mm_jpeg_job_q_node_t *node = NULL;
681 
682   /* check if valid session */
683   p_session = mm_jpeg_get_session(my_obj, job_node->dec_info.job_id);
684   if (NULL == p_session) {
685     CDBG_ERROR("%s:%d] invalid job id %x", __func__, __LINE__,
686       job_node->dec_info.job_id);
687     return -1;
688   }
689 
690   /* sent encode cmd to OMX, queue job into ongoing queue */
691   rc = mm_jpeg_queue_enq(&my_obj->ongoing_job_q, job_node);
692   if (rc) {
693     CDBG_ERROR("%s:%d] jpeg enqueue failed %d",
694       __func__, __LINE__, ret);
695     goto error;
696   }
697 
698   p_session->decode_job = job_node->dec_info.decode_job;
699   p_session->jobId = job_node->dec_info.job_id;
700   ret = mm_jpegdec_session_decode(p_session);
701   if (ret) {
702     CDBG_ERROR("%s:%d] encode session failed", __func__, __LINE__);
703     goto error;
704   }
705 
706   CDBG("%s:%d] Success X ", __func__, __LINE__);
707   return rc;
708 
709 error:
710 
711   if ((OMX_ErrorNone != ret) &&
712     (NULL != p_session->dec_params.jpeg_cb)) {
713     p_session->job_status = JPEG_JOB_STATUS_ERROR;
714     CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
715       p_session->job_status);
716     p_session->dec_params.jpeg_cb(p_session->job_status,
717       p_session->client_hdl,
718       p_session->jobId,
719       NULL,
720       p_session->dec_params.userdata);
721   }
722 
723   /*remove the job*/
724   mm_jpegdec_job_done(p_session);
725   CDBG("%s:%d] Error X ", __func__, __LINE__);
726 
727   return rc;
728 }
729 
730 /** mm_jpeg_start_decode_job:
731  *
732  *  Arguments:
733  *    @my_obj: jpeg object
734  *    @client_hdl: client handle
735  *    @job: pointer to encode job
736  *    @jobId: job id
737  *
738  *  Return:
739  *       0 for success else failure
740  *
741  *  Description:
742  *       Start the encoding job
743  *
744  **/
mm_jpegdec_start_decode_job(mm_jpeg_obj * my_obj,mm_jpeg_job_t * job,uint32_t * job_id)745 int32_t mm_jpegdec_start_decode_job(mm_jpeg_obj *my_obj,
746   mm_jpeg_job_t *job,
747   uint32_t *job_id)
748 {
749   int32_t rc = -1;
750   uint8_t session_idx = 0;
751   uint8_t client_idx = 0;
752   mm_jpeg_job_q_node_t* node = NULL;
753   mm_jpeg_job_session_t *p_session = NULL;
754   mm_jpeg_decode_job_t *p_jobparams  = &job->decode_job;
755 
756   *job_id = 0;
757 
758   /* check if valid session */
759   session_idx = GET_SESSION_IDX(p_jobparams->session_id);
760   client_idx = GET_CLIENT_IDX(p_jobparams->session_id);
761   CDBG("%s:%d] session_idx %d client idx %d", __func__, __LINE__,
762     session_idx, client_idx);
763 
764   if ((session_idx >= MM_JPEG_MAX_SESSION) ||
765     (client_idx >= MAX_JPEG_CLIENT_NUM)) {
766     CDBG_ERROR("%s:%d] invalid session id %x", __func__, __LINE__,
767       job->decode_job.session_id);
768     return rc;
769   }
770 
771   p_session = &my_obj->clnt_mgr[client_idx].session[session_idx];
772   if (OMX_FALSE == p_session->active) {
773     CDBG_ERROR("%s:%d] session not active %x", __func__, __LINE__,
774       job->decode_job.session_id);
775     return rc;
776   }
777 
778   if ((p_jobparams->src_index >= p_session->dec_params.num_src_bufs) ||
779     (p_jobparams->dst_index >= p_session->dec_params.num_dst_bufs)) {
780     CDBG_ERROR("%s:%d] invalid buffer indices", __func__, __LINE__);
781     return rc;
782   }
783 
784   /* enqueue new job into todo job queue */
785   node = (mm_jpeg_job_q_node_t *)malloc(sizeof(mm_jpeg_job_q_node_t));
786   if (NULL == node) {
787     CDBG_ERROR("%s: No memory for mm_jpeg_job_q_node_t", __func__);
788     return -1;
789   }
790 
791   *job_id = job->decode_job.session_id |
792     ((p_session->job_hist++ % JOB_HIST_MAX) << 16);
793 
794   memset(node, 0, sizeof(mm_jpeg_job_q_node_t));
795   node->dec_info.decode_job = job->decode_job;
796   node->dec_info.job_id = *job_id;
797   node->dec_info.client_handle = p_session->client_hdl;
798   node->type = MM_JPEG_CMD_TYPE_DECODE_JOB;
799 
800   rc = mm_jpeg_queue_enq(&my_obj->job_mgr.job_queue, node);
801   if (0 == rc) {
802     cam_sem_post(&my_obj->job_mgr.job_sem);
803   }
804 
805   return rc;
806 }
807 
808 /** mm_jpegdec_create_session:
809  *
810  *  Arguments:
811  *    @my_obj: jpeg object
812  *    @client_hdl: client handle
813  *    @p_params: pointer to encode params
814  *    @p_session_id: session id
815  *
816  *  Return:
817  *       0 for success else failure
818  *
819  *  Description:
820  *       Start the encoding session
821  *
822  **/
mm_jpegdec_create_session(mm_jpeg_obj * my_obj,uint32_t client_hdl,mm_jpeg_decode_params_t * p_params,uint32_t * p_session_id)823 int32_t mm_jpegdec_create_session(mm_jpeg_obj *my_obj,
824   uint32_t client_hdl,
825   mm_jpeg_decode_params_t *p_params,
826   uint32_t* p_session_id)
827 {
828   int32_t rc = 0;
829   OMX_ERRORTYPE ret = OMX_ErrorNone;
830   uint8_t clnt_idx = 0;
831   int session_idx = -1;
832   mm_jpeg_job_session_t *p_session = NULL;
833   *p_session_id = 0;
834 
835   /* validate the parameters */
836   if ((p_params->num_src_bufs > MM_JPEG_MAX_BUF)
837     || (p_params->num_dst_bufs > MM_JPEG_MAX_BUF)) {
838     CDBG_ERROR("%s:%d] invalid num buffers", __func__, __LINE__);
839     return rc;
840   }
841 
842   /* check if valid client */
843   clnt_idx = mm_jpeg_util_get_index_by_handler(client_hdl);
844   if (clnt_idx >= MAX_JPEG_CLIENT_NUM) {
845     CDBG_ERROR("%s: invalid client with handler (%d)", __func__, client_hdl);
846     return rc;
847   }
848 
849   session_idx = mm_jpeg_get_new_session_idx(my_obj, clnt_idx, &p_session);
850   if (session_idx < 0) {
851     CDBG_ERROR("%s:%d] invalid session id (%d)", __func__, __LINE__, session_idx);
852     return rc;
853   }
854 
855   ret = mm_jpegdec_session_create(p_session);
856   if (OMX_ErrorNone != ret) {
857     p_session->active = OMX_FALSE;
858     CDBG_ERROR("%s:%d] jpeg session create failed", __func__, __LINE__);
859     return rc;
860   }
861 
862   *p_session_id = (JOB_ID_MAGICVAL << 24) | (session_idx << 8) | clnt_idx;
863 
864   /*copy the params*/
865   p_session->dec_params = *p_params;
866   p_session->client_hdl = client_hdl;
867   p_session->sessionId = *p_session_id;
868   p_session->jpeg_obj = (void*)my_obj; /* save a ptr to jpeg_obj */
869   CDBG("%s:%d] session id %x", __func__, __LINE__, *p_session_id);
870 
871   return rc;
872 }
873 
874 /** mm_jpegdec_destroy_session:
875  *
876  *  Arguments:
877  *    @my_obj: jpeg object
878  *    @session_id: session index
879  *
880  *  Return:
881  *       0 for success else failure
882  *
883  *  Description:
884  *       Destroy the encoding session
885  *
886  **/
mm_jpegdec_destroy_session(mm_jpeg_obj * my_obj,mm_jpeg_job_session_t * p_session)887 int32_t mm_jpegdec_destroy_session(mm_jpeg_obj *my_obj,
888   mm_jpeg_job_session_t *p_session)
889 {
890   int32_t rc = 0;
891   uint8_t clnt_idx = 0;
892   mm_jpeg_job_q_node_t *node = NULL;
893   OMX_BOOL ret = OMX_FALSE;
894 
895   if (NULL == p_session) {
896     CDBG_ERROR("%s:%d] invalid session", __func__, __LINE__);
897     return rc;
898   }
899   uint32_t session_id = p_session->sessionId;
900   pthread_mutex_lock(&my_obj->job_lock);
901 
902   /* abort job if in todo queue */
903   CDBG("%s:%d] abort todo jobs", __func__, __LINE__);
904   node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
905   while (NULL != node) {
906     free(node);
907     node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->job_mgr.job_queue, session_id);
908   }
909 
910   /* abort job if in ongoing queue */
911   CDBG("%s:%d] abort ongoing jobs", __func__, __LINE__);
912   node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
913   while (NULL != node) {
914     free(node);
915     node = mm_jpeg_queue_remove_job_by_session_id(&my_obj->ongoing_job_q, session_id);
916   }
917 
918   /* abort the current session */
919   mm_jpeg_session_abort(p_session);
920   mm_jpegdec_session_destroy(p_session);
921   mm_jpeg_remove_session_idx(my_obj, session_id);
922   pthread_mutex_unlock(&my_obj->job_lock);
923 
924   /* wake up jobMgr thread to work on new job if there is any */
925   cam_sem_post(&my_obj->job_mgr.job_sem);
926   CDBG("%s:%d] X", __func__, __LINE__);
927 
928   return rc;
929 }
930 
931 /** mm_jpegdec_destroy_session_by_id:
932  *
933  *  Arguments:
934  *    @my_obj: jpeg object
935  *    @session_id: session index
936  *
937  *  Return:
938  *       0 for success else failure
939  *
940  *  Description:
941  *       Destroy the encoding session
942  *
943  **/
mm_jpegdec_destroy_session_by_id(mm_jpeg_obj * my_obj,uint32_t session_id)944 int32_t mm_jpegdec_destroy_session_by_id(mm_jpeg_obj *my_obj, uint32_t session_id)
945 {
946   int32_t rc = 0;
947   mm_jpeg_job_session_t *p_session = mm_jpeg_get_session(my_obj, session_id);
948 
949   if (NULL == p_session) {
950     CDBG_ERROR("%s:%d] session is not valid", __func__, __LINE__);
951     return rc;
952   }
953 
954   return mm_jpegdec_destroy_session(my_obj, p_session);
955 }
956 
957 
958 
mm_jpegdec_ebd(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_BUFFERHEADERTYPE * pBuffer)959 OMX_ERRORTYPE mm_jpegdec_ebd(OMX_HANDLETYPE hComponent,
960   OMX_PTR pAppData,
961   OMX_BUFFERHEADERTYPE *pBuffer)
962 {
963   OMX_ERRORTYPE ret = OMX_ErrorNone;
964   mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
965 
966   CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->ebd_count);
967   pthread_mutex_lock(&p_session->lock);
968   p_session->ebd_count++;
969   pthread_mutex_unlock(&p_session->lock);
970   return 0;
971 }
972 
mm_jpegdec_fbd(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_BUFFERHEADERTYPE * pBuffer)973 OMX_ERRORTYPE mm_jpegdec_fbd(OMX_HANDLETYPE hComponent,
974   OMX_PTR pAppData,
975   OMX_BUFFERHEADERTYPE *pBuffer)
976 {
977   OMX_ERRORTYPE ret = OMX_ErrorNone;
978   mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
979   uint32_t i = 0;
980   int rc = 0;
981   mm_jpeg_output_t output_buf;
982 
983   CDBG("%s:%d] count %d ", __func__, __LINE__, p_session->fbd_count);
984 
985   pthread_mutex_lock(&p_session->lock);
986 
987   if (MM_JPEG_ABORT_NONE != p_session->abort_state) {
988     pthread_mutex_unlock(&p_session->lock);
989     return ret;
990   }
991 
992   p_session->fbd_count++;
993   if (NULL != p_session->dec_params.jpeg_cb) {
994     p_session->job_status = JPEG_JOB_STATUS_DONE;
995     output_buf.buf_filled_len = (uint32_t)pBuffer->nFilledLen;
996     output_buf.buf_vaddr = pBuffer->pBuffer;
997     output_buf.fd = 0;
998     CDBG("%s:%d] send jpeg callback %d", __func__, __LINE__,
999       p_session->job_status);
1000     p_session->dec_params.jpeg_cb(p_session->job_status,
1001       p_session->client_hdl,
1002       p_session->jobId,
1003       &output_buf,
1004       p_session->dec_params.userdata);
1005 
1006     /* remove from ready queue */
1007     mm_jpegdec_job_done(p_session);
1008   }
1009   pthread_mutex_unlock(&p_session->lock);
1010   CDBG("%s:%d] ", __func__, __LINE__);
1011 
1012   return ret;
1013 }
1014 
mm_jpegdec_event_handler(OMX_HANDLETYPE hComponent,OMX_PTR pAppData,OMX_EVENTTYPE eEvent,OMX_U32 nData1,OMX_U32 nData2,OMX_PTR pEventData)1015 OMX_ERRORTYPE mm_jpegdec_event_handler(OMX_HANDLETYPE hComponent,
1016   OMX_PTR pAppData,
1017   OMX_EVENTTYPE eEvent,
1018   OMX_U32 nData1,
1019   OMX_U32 nData2,
1020   OMX_PTR pEventData)
1021 {
1022   mm_jpeg_job_session_t *p_session = (mm_jpeg_job_session_t *) pAppData;
1023 
1024   CDBG("%s:%d] %d %d %d state %d", __func__, __LINE__, eEvent, (int)nData1,
1025     (int)nData2, p_session->abort_state);
1026 
1027   CDBG("%s:%d] AppData=%p ", __func__, __LINE__, pAppData);
1028 
1029   pthread_mutex_lock(&p_session->lock);
1030   p_session->omxEvent = eEvent;
1031   if (MM_JPEG_ABORT_INIT == p_session->abort_state) {
1032     p_session->abort_state = MM_JPEG_ABORT_DONE;
1033     pthread_cond_signal(&p_session->cond);
1034     pthread_mutex_unlock(&p_session->lock);
1035     return OMX_ErrorNone;
1036   }
1037 
1038   if (eEvent == OMX_EventError) {
1039     if (p_session->encoding == OMX_TRUE) {
1040       CDBG("%s:%d] Error during encoding", __func__, __LINE__);
1041 
1042       /* send jpeg callback */
1043       if (NULL != p_session->dec_params.jpeg_cb) {
1044         p_session->job_status = JPEG_JOB_STATUS_ERROR;
1045         CDBG("%s:%d] send jpeg error callback %d", __func__, __LINE__,
1046           p_session->job_status);
1047         p_session->dec_params.jpeg_cb(p_session->job_status,
1048           p_session->client_hdl,
1049           p_session->jobId,
1050           NULL,
1051           p_session->dec_params.userdata);
1052       }
1053 
1054       /* remove from ready queue */
1055       mm_jpegdec_job_done(p_session);
1056     }
1057     pthread_cond_signal(&p_session->cond);
1058   } else if (eEvent == OMX_EventCmdComplete) {
1059     p_session->state_change_pending = OMX_FALSE;
1060     p_session->event_pending = OMX_FALSE;
1061     pthread_cond_signal(&p_session->cond);
1062   }  else if (eEvent == OMX_EventPortSettingsChanged) {
1063     p_session->event_pending = OMX_FALSE;
1064     pthread_cond_signal(&p_session->cond);
1065   }
1066 
1067   pthread_mutex_unlock(&p_session->lock);
1068   CDBG("%s:%d]", __func__, __LINE__);
1069   return OMX_ErrorNone;
1070 }
1071 
1072 /** mm_jpegdec_abort_job:
1073  *
1074  *  Arguments:
1075  *    @my_obj: jpeg object
1076  *    @client_hdl: client handle
1077  *    @jobId: job id
1078  *
1079  *  Return:
1080  *       0 for success else failure
1081  *
1082  *  Description:
1083  *       Abort the encoding session
1084  *
1085  **/
mm_jpegdec_abort_job(mm_jpeg_obj * my_obj,uint32_t jobId)1086 int32_t mm_jpegdec_abort_job(mm_jpeg_obj *my_obj,
1087   uint32_t jobId)
1088 {
1089   int32_t rc = -1;
1090   uint8_t clnt_idx = 0;
1091   mm_jpeg_job_q_node_t *node = NULL;
1092   OMX_BOOL ret = OMX_FALSE;
1093   mm_jpeg_job_session_t *p_session = NULL;
1094 
1095   CDBG("%s:%d] ", __func__, __LINE__);
1096   pthread_mutex_lock(&my_obj->job_lock);
1097 
1098   /* abort job if in todo queue */
1099   node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->job_mgr.job_queue, jobId);
1100   if (NULL != node) {
1101     free(node);
1102     goto abort_done;
1103   }
1104 
1105   /* abort job if in ongoing queue */
1106   node = mm_jpeg_queue_remove_job_by_job_id(&my_obj->ongoing_job_q, jobId);
1107   if (NULL != node) {
1108     /* find job that is OMX ongoing, ask OMX to abort the job */
1109     p_session = mm_jpeg_get_session(my_obj, node->dec_info.job_id);
1110     if (p_session) {
1111       mm_jpeg_session_abort(p_session);
1112     } else {
1113       CDBG_ERROR("%s:%d] Invalid job id 0x%x", __func__, __LINE__,
1114         node->dec_info.job_id);
1115     }
1116     free(node);
1117     goto abort_done;
1118   }
1119 
1120 abort_done:
1121   pthread_mutex_unlock(&my_obj->job_lock);
1122 
1123   return rc;
1124 }
1125 /** mm_jpegdec_init:
1126  *
1127  *  Arguments:
1128  *    @my_obj: jpeg object
1129  *
1130  *  Return:
1131  *       0 for success else failure
1132  *
1133  *  Description:
1134  *       Initializes the jpeg client
1135  *
1136  **/
mm_jpegdec_init(mm_jpeg_obj * my_obj)1137 int32_t mm_jpegdec_init(mm_jpeg_obj *my_obj)
1138 {
1139   int32_t rc = 0;
1140 
1141   /* init locks */
1142   pthread_mutex_init(&my_obj->job_lock, NULL);
1143 
1144   /* init ongoing job queue */
1145   rc = mm_jpeg_queue_init(&my_obj->ongoing_job_q);
1146   if (0 != rc) {
1147     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1148     return -1;
1149   }
1150 
1151   /* init job semaphore and launch jobmgr thread */
1152   CDBG("%s:%d] Launch jobmgr thread rc %d", __func__, __LINE__, rc);
1153   rc = mm_jpeg_jobmgr_thread_launch(my_obj);
1154   if (0 != rc) {
1155     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1156     return -1;
1157   }
1158 
1159   /* load OMX */
1160   if (OMX_ErrorNone != OMX_Init()) {
1161     /* roll back in error case */
1162     CDBG_ERROR("%s:%d] OMX_Init failed (%d)", __func__, __LINE__, rc);
1163     mm_jpeg_jobmgr_thread_release(my_obj);
1164     mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1165     pthread_mutex_destroy(&my_obj->job_lock);
1166   }
1167 
1168   return rc;
1169 }
1170 
1171 /** mm_jpegdec_deinit:
1172  *
1173  *  Arguments:
1174  *    @my_obj: jpeg object
1175  *
1176  *  Return:
1177  *       0 for success else failure
1178  *
1179  *  Description:
1180  *       Deinits the jpeg client
1181  *
1182  **/
mm_jpegdec_deinit(mm_jpeg_obj * my_obj)1183 int32_t mm_jpegdec_deinit(mm_jpeg_obj *my_obj)
1184 {
1185   int32_t rc = 0;
1186 
1187   /* release jobmgr thread */
1188   rc = mm_jpeg_jobmgr_thread_release(my_obj);
1189   if (0 != rc) {
1190     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1191   }
1192 
1193   /* unload OMX engine */
1194   OMX_Deinit();
1195 
1196   /* deinit ongoing job and cb queue */
1197   rc = mm_jpeg_queue_deinit(&my_obj->ongoing_job_q);
1198   if (0 != rc) {
1199     CDBG_ERROR("%s:%d] Error", __func__, __LINE__);
1200   }
1201 
1202   /* destroy locks */
1203   pthread_mutex_destroy(&my_obj->job_lock);
1204 
1205   return rc;
1206 }
1207