1 /* Copyright (c) 2015-2016, 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 // To remove
31 #include <utils/Log.h>
32
33 // System dependencies
34 #include <errno.h>
35 #include <fcntl.h>
36 #include <poll.h>
37 #include <pthread.h>
38 #include <sys/ioctl.h>
39 #include <sys/prctl.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42
43 // Camera dependencies
44 #include "img_common.h"
45 #include "img_comp.h"
46 #include "img_comp_factory.h"
47 #include "img_buffer.h"
48 #include "lib2d.h"
49 #include "mm_lib2d.h"
50 #include "img_meta.h"
51
52 /** lib2d_job_private_info
53 * @jobid: Job id of this process request
54 * @userdata: Client userdata that will be passed on callback
55 * @lib2d_client_cb: Application's callback function pointer
56 * which will be called upon completion of current job.
57 **/
58 typedef struct lib2d_job_private_info_t {
59 int jobid;
60 void *userdata;
61 lib2d_error (*lib2d_client_cb) (void *userdata, int jobid);
62 } lib2d_job_private_info;
63
64 /** img_lib_t
65 * @ptr: handle to imglib library
66 * @img_core_get_comp: function pointer for img_core_get_comp
67 * @img_wait_for_completion: function pointer for img_wait_for_completion
68 **/
69 typedef struct {
70 void *ptr;
71 int (*img_core_get_comp) (img_comp_role_t role, char *name,
72 img_core_ops_t *p_ops);
73 int (*img_wait_for_completion) (pthread_cond_t *p_cond,
74 pthread_mutex_t *p_mutex, int32_t ms);
75 } img_lib_t;
76
77 /** mm_lib2d_obj
78 * @core_ops: image core ops structure handle
79 * @comp: component structure handle
80 * @comp_mode: underlying component mode
81 * @lib2d_mode: lib2d mode requested by client
82 * @img_lib: imglib library, function ptrs handle
83 * @mutex: lib2d mutex used for synchronization
84 * @cond: librd cond used for synchronization
85 **/
86 typedef struct mm_lib2d_obj_t {
87 img_core_ops_t core_ops;
88 img_component_ops_t comp;
89 img_comp_mode_t comp_mode;
90 lib2d_mode lib2d_mode;
91 img_lib_t img_lib;
92 pthread_mutex_t mutex;
93 pthread_cond_t cond;
94 } mm_lib2d_obj;
95
96
97 /**
98 * Function: lib2d_event_handler
99 *
100 * Description: Event handler. All the component events
101 * are received here.
102 *
103 * Input parameters:
104 * p_appdata - lib2d test object
105 * p_event - pointer to the event
106 *
107 * Return values:
108 * IMG_SUCCESS
109 * IMG_ERR_INVALID_INPUT
110 *
111 * Notes: none
112 **/
lib2d_event_handler(void * p_appdata,img_event_t * p_event)113 int lib2d_event_handler(void* p_appdata, img_event_t *p_event)
114 {
115 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)p_appdata;
116
117 if ((NULL == p_event) || (NULL == p_appdata)) {
118 LOGE("invalid event");
119 return IMG_ERR_INVALID_INPUT;
120 }
121
122 LOGD("type %d", p_event->type);
123
124 switch (p_event->type) {
125 case QIMG_EVT_DONE:
126 pthread_cond_signal(&lib2d_obj->cond);
127 break;
128 default:;
129 }
130 return IMG_SUCCESS;
131 }
132
133 /**
134 * Function: lib2d_callback_handler
135 *
136 * Description: Callback handler. Registered with Component
137 * on IMG_COMP_INIT. Will be called when processing
138 * of current request is completed. If component running in
139 * async mode, this is where client will know the execution
140 * is finished for in, out frames.
141 *
142 * Input parameters:
143 * p_appdata - lib2d test object
144 * p_in_frame - pointer to input frame
145 * p_out_frame - pointer to output frame
146 * p_meta - pointer to meta data
147 *
148 * Return values:
149 * IMG_SUCCESS
150 * IMG_ERR_GENERAL
151 *
152 * Notes: none
153 **/
lib2d_callback_handler(void * userdata,img_frame_t * p_in_frame,img_frame_t * p_out_frame,img_meta_t * p_meta)154 int lib2d_callback_handler(void *userdata, img_frame_t *p_in_frame,
155 img_frame_t *p_out_frame, img_meta_t *p_meta)
156 {
157 lib2d_job_private_info *job_info = NULL;
158
159 if (NULL == userdata) {
160 LOGE("invalid event");
161 return IMG_ERR_INVALID_INPUT;
162 }
163
164 // assert(p_in_frame->private_data == p_out_frame->private_data);
165
166 job_info = (lib2d_job_private_info *)p_in_frame->private_data;
167 if (job_info->lib2d_client_cb != NULL) {
168 job_info->lib2d_client_cb(job_info->userdata, job_info->jobid);
169 }
170
171 free(p_in_frame->private_data);
172 free(p_in_frame);
173 free(p_out_frame);
174 free(p_meta);
175
176 return IMG_SUCCESS;
177 }
178
179 /**
180 * Function: lib2d_fill_img_frame
181 *
182 * Description: Setup img_frame_t for given buffer
183 *
184 * Input parameters:
185 * p_frame - pointer to img_frame_t that needs to be setup
186 * lib2d_buffer - pointer to input buffer
187 * jobid - job id
188 *
189 * Return values:
190 * MM_LIB2D_SUCCESS
191 * MM_LIB2D_ERR_GENERAL
192 *
193 * Notes: none
194 **/
lib2d_fill_img_frame(img_frame_t * p_frame,mm_lib2d_buffer * lib2d_buffer,int jobid)195 lib2d_error lib2d_fill_img_frame(img_frame_t *p_frame,
196 mm_lib2d_buffer* lib2d_buffer, int jobid)
197 {
198 // use job id for now
199 p_frame->frame_cnt = jobid;
200 p_frame->idx = jobid;
201 p_frame->frame_id = jobid;
202
203 if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_RGB) {
204 mm_lib2d_rgb_buffer *rgb_buffer = &lib2d_buffer->rgb_buffer;
205
206 p_frame->info.num_planes = 1;
207 p_frame->info.width = rgb_buffer->width;
208 p_frame->info.height = rgb_buffer->height;
209
210 p_frame->frame[0].plane_cnt = 1;
211 p_frame->frame[0].plane[0].plane_type = PLANE_ARGB;
212 p_frame->frame[0].plane[0].addr = rgb_buffer->buffer;
213 p_frame->frame[0].plane[0].stride = rgb_buffer->stride;
214 p_frame->frame[0].plane[0].length = (rgb_buffer->stride *
215 rgb_buffer->height);
216 p_frame->frame[0].plane[0].fd = rgb_buffer->fd;
217 p_frame->frame[0].plane[0].height = rgb_buffer->height;
218 p_frame->frame[0].plane[0].width = rgb_buffer->width;
219 p_frame->frame[0].plane[0].offset = 0;
220 p_frame->frame[0].plane[0].scanline = rgb_buffer->height;
221 } else if (lib2d_buffer->buffer_type == MM_LIB2D_BUFFER_TYPE_YUV) {
222 mm_lib2d_yuv_buffer *yuv_buffer = &lib2d_buffer->yuv_buffer;
223
224 p_frame->info.num_planes = 2;
225 p_frame->info.width = yuv_buffer->width;
226 p_frame->info.height = yuv_buffer->height;
227
228 p_frame->frame[0].plane_cnt = 2;
229 p_frame->frame[0].plane[0].plane_type = PLANE_Y;
230 p_frame->frame[0].plane[0].addr = yuv_buffer->plane0;
231 p_frame->frame[0].plane[0].stride = yuv_buffer->stride0;
232 p_frame->frame[0].plane[0].length = (yuv_buffer->stride0 *
233 yuv_buffer->height);
234 p_frame->frame[0].plane[0].fd = yuv_buffer->fd;
235 p_frame->frame[0].plane[0].height = yuv_buffer->height;
236 p_frame->frame[0].plane[0].width = yuv_buffer->width;
237 p_frame->frame[0].plane[0].offset = 0;
238 p_frame->frame[0].plane[0].scanline = yuv_buffer->height;
239
240 if (yuv_buffer->format == CAM_FORMAT_YUV_420_NV12) {
241 p_frame->frame[0].plane[1].plane_type = PLANE_CB_CR;
242 } else if(yuv_buffer->format == CAM_FORMAT_YUV_420_NV21) {
243 p_frame->frame[0].plane[1].plane_type = PLANE_CR_CB;
244 }
245 p_frame->frame[0].plane[1].addr = yuv_buffer->plane1;
246 p_frame->frame[0].plane[1].stride = yuv_buffer->stride1;
247 p_frame->frame[0].plane[1].length = (yuv_buffer->stride1 *
248 yuv_buffer->height / 2);
249 p_frame->frame[0].plane[1].fd = yuv_buffer->fd;
250 p_frame->frame[0].plane[1].height = yuv_buffer->height;
251 p_frame->frame[0].plane[1].width = yuv_buffer->width;
252 p_frame->frame[0].plane[1].offset = 0;
253 p_frame->frame[0].plane[1].scanline = yuv_buffer->height;
254 } else {
255 return MM_LIB2D_ERR_GENERAL;
256 }
257
258 return MM_LIB2D_SUCCESS;
259 }
260
261 /**
262 * Function: mm_lib2d_init
263 *
264 * Description: Initialization function for Lib2D. src_format, dst_format
265 * are hints to the underlying component to initialize.
266 *
267 * Input parameters:
268 * mode - Mode (sync/async) in which App wants lib2d to run.
269 * src_format - source surface format
270 * dst_format - Destination surface format
271 * my_obj - handle that will be returned on succesful Init. App has to
272 * call other lib2d functions by passing this handle.
273 *
274 * Return values:
275 * MM_LIB2D_SUCCESS
276 * MM_LIB2D_ERR_MEMORY
277 * MM_LIB2D_ERR_BAD_PARAM
278 * MM_LIB2D_ERR_GENERAL
279 *
280 * Notes: none
281 **/
282
mm_lib2d_init(lib2d_mode mode,cam_format_t src_format,cam_format_t dst_format,void ** my_obj)283 lib2d_error mm_lib2d_init(lib2d_mode mode, cam_format_t src_format,
284 cam_format_t dst_format, void **my_obj)
285 {
286 int32_t rc = IMG_SUCCESS;
287 mm_lib2d_obj *lib2d_obj = NULL;
288 img_core_ops_t *p_core_ops = NULL;
289 img_component_ops_t *p_comp = NULL;
290
291 if (my_obj == NULL) {
292 return MM_LIB2D_ERR_BAD_PARAM;
293 }
294
295 // validate src_format, dst_format to check whether we support these.
296 // Currently support NV21 to ARGB conversions only. Others not tested.
297 if ((src_format != CAM_FORMAT_YUV_420_NV21) ||
298 (dst_format != CAM_FORMAT_8888_ARGB)) {
299 LOGE("Formats conversion from %d to %d not supported",
300 src_format, dst_format);
301 }
302
303 lib2d_obj = malloc(sizeof(mm_lib2d_obj));
304 if (lib2d_obj == NULL) {
305 return MM_LIB2D_ERR_MEMORY;
306 }
307
308 // Open libmmcamera_imglib
309 lib2d_obj->img_lib.ptr = dlopen("libmmcamera_imglib.so", RTLD_NOW);
310 if (!lib2d_obj->img_lib.ptr) {
311 LOGE("ERROR: couldn't dlopen libmmcamera_imglib.so: %s",
312 dlerror());
313 goto FREE_LIB2D_OBJ;
314 }
315
316 /* Get function pointer for functions supported by C2D */
317 *(void **)&lib2d_obj->img_lib.img_core_get_comp =
318 dlsym(lib2d_obj->img_lib.ptr, "img_core_get_comp");
319 *(void **)&lib2d_obj->img_lib.img_wait_for_completion =
320 dlsym(lib2d_obj->img_lib.ptr, "img_wait_for_completion");
321
322 /* Validate function pointers */
323 if ((lib2d_obj->img_lib.img_core_get_comp == NULL) ||
324 (lib2d_obj->img_lib.img_wait_for_completion == NULL)) {
325 LOGE(" ERROR mapping symbols from libc2d2.so");
326 goto FREE_LIB2D_OBJ;
327 }
328
329 p_core_ops = &lib2d_obj->core_ops;
330 p_comp = &lib2d_obj->comp;
331
332 pthread_mutex_init(&lib2d_obj->mutex, NULL);
333 pthread_cond_init(&lib2d_obj->cond, NULL);
334
335 rc = lib2d_obj->img_lib.img_core_get_comp(IMG_COMP_LIB2D,
336 "qti.lib2d", p_core_ops);
337 if (rc != IMG_SUCCESS) {
338 LOGE("rc %d", rc);
339 goto FREE_LIB2D_OBJ;
340 }
341
342 rc = IMG_COMP_LOAD(p_core_ops, NULL);
343 if (rc != IMG_SUCCESS) {
344 LOGE("rc %d", rc);
345 goto FREE_LIB2D_OBJ;
346 }
347
348 rc = IMG_COMP_CREATE(p_core_ops, p_comp);
349 if (rc != IMG_SUCCESS) {
350 LOGE("rc %d", rc);
351 goto COMP_UNLOAD;
352 }
353
354 rc = IMG_COMP_INIT(p_comp, (void *)lib2d_obj, lib2d_callback_handler);
355 if (rc != IMG_SUCCESS) {
356 LOGE("rc %d", rc);
357 goto COMP_UNLOAD;
358 }
359
360 rc = IMG_COMP_SET_CB(p_comp, lib2d_event_handler);
361 if (rc != IMG_SUCCESS) {
362 LOGE("rc %d", rc);
363 goto COMP_DEINIT;
364 }
365
366 lib2d_obj->lib2d_mode = mode;
367 img_comp_mode_t comp_mode;
368 if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
369 comp_mode = IMG_SYNC_MODE;
370 } else {
371 comp_mode = IMG_ASYNC_MODE;
372 }
373
374 // Set source format
375 rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_SOURCE_FORMAT, (void *)&src_format);
376 if (rc != IMG_SUCCESS) {
377 LOGE("rc %d", rc);
378 goto COMP_DEINIT;
379 }
380
381 // Set destination format
382 rc = IMG_COMP_SET_PARAM(p_comp, QLIB2D_DESTINATION_FORMAT,
383 (void *)&dst_format);
384 if (rc != IMG_SUCCESS) {
385 LOGE("rc %d", rc);
386 goto COMP_DEINIT;
387 }
388
389 // Try setting the required mode.
390 rc = IMG_COMP_SET_PARAM(p_comp, QIMG_PARAM_MODE, (void *)&comp_mode);
391 if (rc != IMG_SUCCESS) {
392 LOGE("rc %d", rc);
393 goto COMP_DEINIT;
394 }
395
396 // Get the mode to make sure whether the component is really running
397 // in the mode what we set.
398 rc = IMG_COMP_GET_PARAM(p_comp, QIMG_PARAM_MODE,
399 (void *)&lib2d_obj->comp_mode);
400 if (rc != IMG_SUCCESS) {
401 LOGE("rc %d", rc);
402 goto COMP_DEINIT;
403 }
404
405 if (comp_mode != lib2d_obj->comp_mode) {
406 LOGD("Component is running in %d mode",
407 lib2d_obj->comp_mode);
408 }
409
410 *my_obj = (void *)lib2d_obj;
411
412 return MM_LIB2D_SUCCESS;
413
414 COMP_DEINIT :
415 rc = IMG_COMP_DEINIT(p_comp);
416 if (rc != IMG_SUCCESS) {
417 LOGE("rc %d", rc);
418 return MM_LIB2D_ERR_GENERAL;
419 }
420
421 COMP_UNLOAD :
422 rc = IMG_COMP_UNLOAD(p_core_ops);
423 if (rc != IMG_SUCCESS) {
424 LOGE("rc %d", rc);
425 return MM_LIB2D_ERR_GENERAL;
426 }
427
428 FREE_LIB2D_OBJ :
429 free(lib2d_obj);
430 return MM_LIB2D_ERR_GENERAL;
431 }
432
433 /**
434 * Function: mm_lib2d_deinit
435 *
436 * Description: De-Initialization function for Lib2D
437 *
438 * Input parameters:
439 * lib2d_obj_handle - handle tto the lib2d object
440 *
441 * Return values:
442 * MM_LIB2D_SUCCESS
443 * MM_LIB2D_ERR_GENERAL
444 *
445 * Notes: none
446 **/
mm_lib2d_deinit(void * lib2d_obj_handle)447 lib2d_error mm_lib2d_deinit(void *lib2d_obj_handle)
448 {
449 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)lib2d_obj_handle;
450 int rc = IMG_SUCCESS;
451 img_core_ops_t *p_core_ops = &lib2d_obj->core_ops;
452 img_component_ops_t *p_comp = &lib2d_obj->comp;
453
454 rc = IMG_COMP_DEINIT(p_comp);
455 if (rc != IMG_SUCCESS) {
456 LOGE("rc %d", rc);
457 return MM_LIB2D_ERR_GENERAL;
458 }
459
460 rc = IMG_COMP_UNLOAD(p_core_ops);
461 if (rc != IMG_SUCCESS) {
462 LOGE("rc %d", rc);
463 return MM_LIB2D_ERR_GENERAL;
464 }
465
466 dlclose(lib2d_obj->img_lib.ptr);
467 free(lib2d_obj);
468
469 return MM_LIB2D_SUCCESS;
470 }
471
472 /**
473 * Function: mm_lib2d_start_job
474 *
475 * Description: Start executing the job
476 *
477 * Input parameters:
478 * lib2d_obj_handle - handle tto the lib2d object
479 * src_buffer - pointer to the source buffer
480 * dst_buffer - pointer to the destination buffer
481 * jobid - job id of this request
482 * userdata - userdata that will be pass through callback function
483 * cb - callback function that will be called on completion of this job
484 * rotation - rotation to be applied
485 *
486 * Return values:
487 * MM_LIB2D_SUCCESS
488 * MM_LIB2D_ERR_MEMORY
489 * MM_LIB2D_ERR_GENERAL
490 *
491 * Notes: none
492 **/
mm_lib2d_start_job(void * lib2d_obj_handle,mm_lib2d_buffer * src_buffer,mm_lib2d_buffer * dst_buffer,int jobid,void * userdata,lib2d_client_cb cb,uint32_t rotation)493 lib2d_error mm_lib2d_start_job(void *lib2d_obj_handle,
494 mm_lib2d_buffer* src_buffer, mm_lib2d_buffer* dst_buffer,
495 int jobid, void *userdata, lib2d_client_cb cb, uint32_t rotation)
496 {
497 mm_lib2d_obj *lib2d_obj = (mm_lib2d_obj *)lib2d_obj_handle;
498 int rc = IMG_SUCCESS;
499 img_component_ops_t *p_comp = &lib2d_obj->comp;
500
501 img_frame_t *p_in_frame = malloc(sizeof(img_frame_t));
502 if (p_in_frame == NULL) {
503 return MM_LIB2D_ERR_MEMORY;
504 }
505
506 img_frame_t *p_out_frame = malloc(sizeof(img_frame_t));
507 if (p_out_frame == NULL) {
508 free(p_in_frame);
509 return MM_LIB2D_ERR_MEMORY;
510 }
511
512 img_meta_t *p_meta = malloc(sizeof(img_meta_t));
513 if (p_meta == NULL) {
514 free(p_in_frame);
515 free(p_out_frame);
516 return MM_LIB2D_ERR_MEMORY;
517 }
518
519 lib2d_job_private_info *p_job_info = malloc(sizeof(lib2d_job_private_info));
520 if (p_out_frame == NULL) {
521 free(p_in_frame);
522 free(p_out_frame);
523 free(p_meta);
524 return MM_LIB2D_ERR_MEMORY;
525 }
526
527 memset(p_in_frame, 0x0, sizeof(img_frame_t));
528 memset(p_out_frame, 0x0, sizeof(img_frame_t));
529 memset(p_meta, 0x0, sizeof(img_meta_t));
530 memset(p_job_info, 0x0, sizeof(lib2d_job_private_info));
531
532 // Fill up job info private data structure that can be used in callback to
533 // inform back to the client.
534 p_job_info->jobid = jobid;
535 p_job_info->userdata = userdata;
536 p_job_info->lib2d_client_cb = cb;
537
538 p_in_frame->private_data = (void *)p_job_info;
539 p_out_frame->private_data = (void *)p_job_info;
540
541 // convert the input info into component understandble data structures
542
543 // Prepare Input, output frames
544 lib2d_fill_img_frame(p_in_frame, src_buffer, jobid);
545 lib2d_fill_img_frame(p_out_frame, dst_buffer, jobid);
546
547 p_meta->frame_id = jobid;
548 p_meta->rotation.device_rotation = (int32_t)rotation;
549 p_meta->rotation.frame_rotation = (int32_t)rotation;
550
551 // call set_param to set the source, destination formats
552
553 rc = IMG_COMP_Q_BUF(p_comp, p_in_frame, IMG_IN);
554 if (rc != IMG_SUCCESS) {
555 LOGE("rc %d", rc);
556 goto ERROR;
557 }
558
559 rc = IMG_COMP_Q_BUF(p_comp, p_out_frame, IMG_OUT);
560 if (rc != IMG_SUCCESS) {
561 LOGE("rc %d", rc);
562 goto ERROR;
563 }
564
565 rc = IMG_COMP_Q_META_BUF(p_comp, p_meta);
566 if (rc != IMG_SUCCESS) {
567 LOGE("rc %d", rc);
568 goto ERROR;
569 }
570
571 rc = IMG_COMP_START(p_comp, NULL);
572 if (rc != IMG_SUCCESS) {
573 LOGE("rc %d", rc);
574 goto ERROR;
575 }
576
577 if (lib2d_obj->lib2d_mode == MM_LIB2D_SYNC_MODE) {
578 if (lib2d_obj->comp_mode == IMG_ASYNC_MODE) {
579 LOGD("before wait rc %d", rc);
580 rc = lib2d_obj->img_lib.img_wait_for_completion(&lib2d_obj->cond,
581 &lib2d_obj->mutex, 10000);
582 if (rc != IMG_SUCCESS) {
583 LOGE("rc %d", rc);
584 goto ERROR;
585 }
586 }
587 }
588
589 rc = IMG_COMP_ABORT(p_comp, NULL);
590 if (IMG_ERROR(rc)) {
591 LOGE("comp abort failed %d", rc);
592 return rc;
593 }
594
595 return MM_LIB2D_SUCCESS;
596 ERROR:
597 free(p_in_frame);
598 free(p_out_frame);
599 free(p_meta);
600 free(p_job_info);
601
602 return MM_LIB2D_ERR_GENERAL;
603 }
604
605