Initialize Tizen 2.3
[framework/multimedia/gst-openmax.git] / wearable / omx / gstomx_util.c
1 /*
2  * Copyright (C) 2006-2007 Texas Instruments, Incorporated
3  * Copyright (C) 2007-2009 Nokia Corporation.
4  *
5  * Author: Felipe Contreras <felipe.contreras@nokia.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation
10  * version 2.1 of the License.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  *
21  */
22
23 #include "gstomx_util.h"
24 #include <dlfcn.h>
25
26 #include "gstomx.h"
27
28 GST_DEBUG_CATEGORY (gstomx_util_debug);
29
30 /*
31  * Forward declarations
32  */
33
34 static inline void change_state (GOmxCore * core, OMX_STATETYPE state);
35
36 static inline void wait_for_state (GOmxCore * core, OMX_STATETYPE state);
37
38 static inline void
39 in_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer);
40
41 static inline void
42 out_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer);
43
44 static inline void
45 got_buffer (GOmxCore * core,
46     GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer);
47
48 static OMX_ERRORTYPE
49 EventHandler (OMX_HANDLETYPE omx_handle,
50     OMX_PTR app_data,
51     OMX_EVENTTYPE event, OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data);
52
53 static OMX_ERRORTYPE
54 EmptyBufferDone (OMX_HANDLETYPE omx_handle,
55     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer);
56
57 static OMX_ERRORTYPE
58 FillBufferDone (OMX_HANDLETYPE omx_handle,
59     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer);
60
61 static inline const char *omx_state_to_str (OMX_STATETYPE omx_state);
62
63 static inline const char *omx_error_to_str (OMX_ERRORTYPE omx_error);
64
65 static inline GOmxPort *get_port (GOmxCore * core, guint index);
66
67 static void core_deinit (GOmxCore * core);
68
69 static inline void port_free_buffers (GOmxPort * port);
70
71 static inline void port_allocate_buffers (GOmxPort * port);
72
73 static inline void port_start_buffers (GOmxPort * port);
74
75 static void PostCommand (gpointer data);
76
77 static OMX_CALLBACKTYPE callbacks =
78     { EventHandler, EmptyBufferDone, FillBufferDone };
79
80 /* protect implementations hash_table */
81 static GMutex *imp_mutex;
82 static GHashTable *implementations;
83 static gboolean initialized;
84
85 /* Modification: calculate plane */
86 /* this is for S.LSI */
87 static int calc_plane(int width, int height) /* for h.264 */
88 {
89     int mbX, mbY;
90
91     mbX = ALIGN(width, S5P_FIMV_NV12MT_HALIGN);
92     mbY = ALIGN(height, S5P_FIMV_NV12MT_VALIGN);
93
94     return ALIGN(mbX * mbY, S5P_FIMV_DEC_BUF_ALIGN);
95 }
96
97
98 static int calc_yplane(int width, int height)
99 {
100     int mbX, mbY;
101
102     mbX = ALIGN(width + 24, S5P_FIMV_NV12MT_HALIGN);
103     mbY = ALIGN(height + 16, S5P_FIMV_NV12MT_VALIGN);
104
105     return ALIGN(mbX * mbY, S5P_FIMV_DEC_BUF_ALIGN);
106 }
107
108 static int calc_uvplane(int width, int height)
109 {
110     int mbX, mbY;
111
112     mbX = ALIGN(width + 16, S5P_FIMV_NV12MT_HALIGN);
113     mbY = ALIGN(height + 4, S5P_FIMV_NV12MT_VALIGN);
114
115     return ALIGN(mbX * mbY, S5P_FIMV_DEC_BUF_ALIGN);
116 }
117
118 static void calc_align_size(GOmxPort * port, int width, int height, guint* y_size, guint* uv_size)
119 {
120   if (port->core->compression_format == OMX_VIDEO_CodingAVC) {
121     *y_size = calc_plane(width, height);
122     *uv_size = calc_plane(width, height /2);
123   } else {
124     *y_size = calc_yplane(width, height);
125     *uv_size = calc_uvplane(width, height /2);
126   }
127 }
128
129 /*
130  * Util
131  */
132
133 static void
134 g_ptr_array_clear (GPtrArray * array)
135 {
136   guint index;
137   for (index = 0; index < array->len; index++)
138     array->pdata[index] = NULL;
139 }
140
141 static void
142 g_ptr_array_insert (GPtrArray * array, guint index, gpointer data)
143 {
144   if (index + 1 > array->len) {
145     g_ptr_array_set_size (array, index + 1);
146   }
147
148   array->pdata[index] = data;
149 }
150
151 typedef void (*GOmxPortFunc) (GOmxPort * port);
152
153 static inline void
154 core_for_each_port (GOmxCore * core, GOmxPortFunc func)
155 {
156   guint index;
157
158   for (index = 0; index < core->ports->len; index++) {
159     GOmxPort *port;
160
161     port = get_port (core, index);
162
163     if (port)
164       func (port);
165   }
166 }
167
168 /*
169  * Main
170  */
171
172 static GOmxImp *imp_new (const gchar * name);
173 static void imp_free (GOmxImp * imp);
174
175 static GOmxImp *
176 imp_new (const gchar * name)
177 {
178   GOmxImp *imp;
179
180   imp = g_new0 (GOmxImp, 1);
181
182   /* Load the OpenMAX IL symbols */
183   {
184     void *handle;
185
186     GST_DEBUG ("loading: %s", name);
187
188     imp->dl_handle = handle = dlopen (name, RTLD_LAZY);
189
190     GST_DEBUG ("dlopen(%s) -> %p", name, handle);
191
192     if (!handle) {
193       g_warning ("%s\n", dlerror ());
194       g_free (imp);
195       return NULL;
196     }
197
198     imp->mutex = g_mutex_new ();
199     imp->sym_table.init = dlsym (handle, "OMX_Init");
200     imp->sym_table.deinit = dlsym (handle, "OMX_Deinit");
201     imp->sym_table.get_handle = dlsym (handle, "OMX_GetHandle");
202     imp->sym_table.free_handle = dlsym (handle, "OMX_FreeHandle");
203   }
204
205   return imp;
206 }
207
208 static void
209 imp_free (GOmxImp * imp)
210 {
211   if (imp->dl_handle) {
212     dlclose (imp->dl_handle);
213   }
214   g_mutex_free (imp->mutex);
215   g_free (imp);
216 }
217
218 static inline GOmxImp *
219 request_imp (const gchar * name)
220 {
221   GOmxImp *imp = NULL;
222
223   g_mutex_lock (imp_mutex);
224   imp = g_hash_table_lookup (implementations, name);
225   if (!imp) {
226     imp = imp_new (name);
227     if (imp)
228       g_hash_table_insert (implementations, g_strdup (name), imp);
229   }
230   g_mutex_unlock (imp_mutex);
231
232   if (!imp)
233     return NULL;
234
235   g_mutex_lock (imp->mutex);
236   if (imp->client_count == 0) {
237     OMX_ERRORTYPE omx_error;
238     omx_error = imp->sym_table.init ();
239     if (omx_error) {
240       g_mutex_unlock (imp->mutex);
241       return NULL;
242     }
243   }
244   imp->client_count++;
245   g_mutex_unlock (imp->mutex);
246
247   return imp;
248 }
249
250 static inline void
251 release_imp (GOmxImp * imp)
252 {
253   g_mutex_lock (imp->mutex);
254   imp->client_count--;
255   if (imp->client_count == 0) {
256     imp->sym_table.deinit ();
257   }
258   g_mutex_unlock (imp->mutex);
259 }
260
261 void
262 g_omx_init (void)
263 {
264   if (!initialized) {
265     /* safe as plugin_init is safe */
266     imp_mutex = g_mutex_new ();
267     implementations = g_hash_table_new_full (g_str_hash,
268         g_str_equal, g_free, (GDestroyNotify) imp_free);
269     initialized = TRUE;
270   }
271 }
272
273 void
274 g_omx_deinit (void)
275 {
276   if (initialized) {
277     g_hash_table_destroy (implementations);
278     g_mutex_free (imp_mutex);
279     initialized = FALSE;
280   }
281 }
282
283 /*
284  * Core
285  */
286
287 GOmxCore *
288 g_omx_core_new (void *object)
289 {
290   GOmxCore *core;
291
292   core = g_new0 (GOmxCore, 1);
293
294   core->object = object;
295   core->ports = g_ptr_array_new ();
296
297   core->omx_state_condition = g_cond_new ();
298   core->omx_state_mutex = g_mutex_new ();
299
300   core->done_sem = g_sem_new ();
301   core->flush_sem = g_sem_new ();
302   core->port_sem = g_sem_new ();
303
304   core->cmd.cmd_queue = async_queue_new ();
305   core->cmd.cmd_queue_enabled = TRUE;
306
307   g_static_rec_mutex_init (&core->cmd.cmd_mutex);
308
309   GST_WARNING ("gst_task_create for PostCommand");
310   core->cmd.cmd_task = gst_task_create (PostCommand, core);
311   gst_task_set_lock (core->cmd.cmd_task, &core->cmd.cmd_mutex);
312
313   core->omx_state = OMX_StateInvalid;
314
315   return core;
316 }
317
318 void
319 g_omx_core_free (GOmxCore * core)
320 {
321   GST_WARNING ("g_omx_core_free enter");
322   core_deinit (core);
323
324   g_sem_free (core->port_sem);
325   g_sem_free (core->flush_sem);
326   g_sem_free (core->done_sem);
327
328   g_mutex_free (core->omx_state_mutex);
329   g_cond_free (core->omx_state_condition);
330
331   g_mutex_free (core->drc_lock);
332   g_cond_free (core->drc_cond);
333
334   gst_task_stop (core->cmd.cmd_task);
335   gst_task_join(core->cmd.cmd_task);
336   gst_object_unref(core->cmd.cmd_task);
337
338   g_ptr_array_free (core->ports, TRUE);
339
340   g_free (core);
341   core = NULL;
342   GST_WARNING ("g_omx_core_free leave");
343 }
344
345 void
346 g_omx_core_init (GOmxCore * core)
347 {
348   GST_DEBUG_OBJECT (core->object, "loading: %s %s (%s)",
349       core->component_name,
350       core->component_role ? core->component_role : "", core->library_name);
351
352   core->imp = request_imp (core->library_name);
353
354   if (!core->imp)
355     return;
356
357   core->omx_error = core->imp->sym_table.get_handle (&core->omx_handle,
358       (char *) core->component_name, core, &callbacks);
359
360   GST_DEBUG_OBJECT (core->object, "OMX_GetHandle(&%p) -> %d",
361       core->omx_handle, core->omx_error);
362
363   if (!core->omx_error) {
364     core->omx_state = OMX_StateLoaded;
365
366     if (core->component_role) {
367       OMX_PARAM_COMPONENTROLETYPE param;
368
369       GST_DEBUG_OBJECT (core->object, "setting component role: %s",
370           core->component_role);
371
372       G_OMX_INIT_PARAM (param);
373
374       strncpy ((char *) param.cRole, core->component_role,
375           OMX_MAX_STRINGNAME_SIZE - 1);
376
377       OMX_SetParameter (core->omx_handle, OMX_IndexParamStandardComponentRole,
378           &param);
379     }
380
381     /* MODIFICATION: Add_component_vendor */
382     if (strncmp(core->component_name+4, "SEC", 3) == 0)
383     {
384       core->component_vendor = GOMX_VENDOR_SLSI_SEC;
385     }
386     else if (strncmp(core->component_name+4, "Exynos", 6) == 0)
387     {
388       core->component_vendor = GOMX_VENDOR_SLSI_EXYNOS;
389     }
390     else
391     {
392       core->component_vendor = GOMX_VENDOR_DEFAULT;
393     }
394   }
395 }
396
397 static void
398 core_deinit (GOmxCore * core)
399 {
400   if (!core->imp)
401     return;
402
403   if (core->omx_state == OMX_StateLoaded || core->omx_state == OMX_StateInvalid) {
404     if (core->omx_handle) {
405       core->omx_error = core->imp->sym_table.free_handle (core->omx_handle);
406       GST_DEBUG_OBJECT (core->object, "OMX_FreeHandle(%p) -> %d",
407           core->omx_handle, core->omx_error);
408     }
409   } else {
410     GST_WARNING_OBJECT (core->object, "Incorrect state: %s",
411         omx_state_to_str (core->omx_state));
412   }
413
414   g_free (core->library_name);
415   g_free (core->component_name);
416   g_free (core->component_role);
417   core->library_name = NULL;
418   core->component_name = NULL;
419   core->component_role = NULL;
420
421   release_imp (core->imp);
422   core->imp = NULL;
423 }
424
425 void
426 g_omx_core_prepare (GOmxCore * core)
427 {
428   change_state (core, OMX_StateIdle);
429
430   /* Allocate buffers. */
431   core_for_each_port (core, port_allocate_buffers);
432
433   wait_for_state (core, OMX_StateIdle);
434 }
435
436 void
437 g_omx_core_start (GOmxCore * core)
438 {
439   change_state (core, OMX_StateExecuting);
440   wait_for_state (core, OMX_StateExecuting);
441
442   if (gst_task_start (core->cmd.cmd_task) == FALSE) {
443     GST_ERROR ("Could not start PostCommand task");
444   }
445
446   if (core->omx_state == OMX_StateExecuting)
447     core_for_each_port (core, port_start_buffers);
448 }
449
450 void
451 g_omx_core_stop (GOmxCore * core)
452 {
453   if (core->omx_state == OMX_StateExecuting ||
454       core->omx_state == OMX_StatePause) {
455     change_state (core, OMX_StateIdle);
456     wait_for_state (core, OMX_StateIdle);
457   }
458 }
459
460 void
461 g_omx_core_pause (GOmxCore * core)
462 {
463   change_state (core, OMX_StatePause);
464   wait_for_state (core, OMX_StatePause);
465 }
466
467 void
468 g_omx_core_unload (GOmxCore * core)
469 {
470   if (core->omx_state == OMX_StateIdle ||
471       core->omx_state == OMX_StateWaitForResources ||
472       core->omx_state == OMX_StateInvalid) {
473     if (core->omx_state != OMX_StateInvalid)
474       change_state (core, OMX_StateLoaded);
475
476     core_for_each_port (core, port_free_buffers);
477
478     if (core->omx_state != OMX_StateInvalid)
479       wait_for_state (core, OMX_StateLoaded);
480   }
481 }
482
483 void
484 g_omx_port_clear (GOmxCore * core)
485 {
486   core_for_each_port (core, g_omx_port_free);
487   g_ptr_array_clear (core->ports);
488
489   GST_WARNING_OBJECT (core->object, "free command queue");
490   async_queue_free (core->cmd.cmd_queue);
491 }
492
493 static inline GOmxPort *
494 get_port (GOmxCore * core, guint index)
495 {
496   if (G_LIKELY (index < core->ports->len)) {
497     return g_ptr_array_index (core->ports, index);
498   }
499
500   return NULL;
501 }
502
503 GOmxPort *
504 g_omx_core_new_port (GOmxCore * core, guint index)
505 {
506   GOmxPort *port = get_port (core, index);
507
508   if (port) {
509     GST_WARNING_OBJECT (core->object, "port %d already exists", index);
510     return port;
511   }
512
513   port = g_omx_port_new (core, index);
514   g_ptr_array_insert (core->ports, index, port);
515
516   return port;
517 }
518
519 void
520 g_omx_core_set_done (GOmxCore * core)
521 {
522   g_sem_up (core->done_sem);
523 }
524
525 void
526 g_omx_core_wait_for_done (GOmxCore * core)
527 {
528   g_sem_down (core->done_sem);
529 }
530
531 void
532 g_omx_core_flush_start (GOmxCore * core)
533 {
534   core_for_each_port (core, g_omx_port_pause);
535 }
536
537 void
538 g_omx_core_flush_stop (GOmxCore * core)
539 {
540   core_for_each_port (core, g_omx_port_flush);
541   core_for_each_port (core, g_omx_port_resume);
542 }
543
544 /*
545  * Port
546  */
547
548 gboolean
549 gst_omx_drm_init(GOmxPort * port)
550 {
551   Display *dpy;
552   int eventBase = 0;
553   int errorBase = 0;
554   int dri2Major = 0;
555   int dri2Minor = 0;
556   char *driverName = NULL;
557   char *deviceName = NULL;
558   struct drm_auth auth_arg = {0};
559
560   port->drm_fd = -1;
561
562   GST_INFO_OBJECT (port->core->object, "gst_omx_drm_init enter");
563
564   dpy = XOpenDisplay(0);
565
566   /* DRI2 */
567   if (!DRI2QueryExtension(dpy, &eventBase, &errorBase)) {
568     GST_ERROR_OBJECT (port->core->object, "failed to DRI2QueryExtension()");
569     goto ERROR_CASE;
570   }
571
572   if (!DRI2QueryVersion(dpy, &dri2Major, &dri2Minor)) {
573     GST_ERROR_OBJECT (port->core->object, "failed to DRI2QueryVersion");
574     goto ERROR_CASE;
575   }
576
577   if (!DRI2Connect(dpy, RootWindow(dpy, DefaultScreen(dpy)), &driverName, &deviceName)) {
578     GST_ERROR_OBJECT(port->core->object,"failed to DRI2Connect");
579     goto ERROR_CASE;
580   }
581
582   /* get the drm_fd though opening the deviceName */
583   port->drm_fd = open(deviceName, O_RDWR);
584   if (port->drm_fd < 0) {
585     GST_ERROR_OBJECT(port->core->object,"cannot open drm device (%s)", deviceName);
586     goto ERROR_CASE;
587   }
588   GST_INFO("Open drm device : %s, fd(%d)", deviceName, port->drm_fd);
589
590   /* get magic from drm to authentication */
591   if (ioctl(port->drm_fd, DRM_IOCTL_GET_MAGIC, &auth_arg)) {
592     GST_ERROR_OBJECT(port->core->object,"cannot get drm auth magic");
593     close(port->drm_fd);
594     port->drm_fd = -1;
595     goto ERROR_CASE;
596   }
597
598   if (!DRI2Authenticate(dpy, RootWindow(dpy, DefaultScreen(dpy)), auth_arg.magic)) {
599     GST_ERROR_OBJECT(port->core->object,"cannot get drm authentication from X");
600     close(port->drm_fd);
601     port->drm_fd = -1;
602     goto ERROR_CASE;
603   }
604
605     /* drm slp buffer manager init */
606     port->bufmgr = tbm_bufmgr_init (port->drm_fd);
607     if (!port->bufmgr)
608     {
609         GST_ERROR_OBJECT (port->core->object, "fail to init buffer manager");
610         close (port->drm_fd);
611         port->drm_fd = -1;
612         goto  ERROR_CASE;
613     }
614
615   XCloseDisplay(dpy);
616   free(driverName);
617   free(deviceName);
618
619   GST_INFO_OBJECT(port->core->object, "gst_omx_drm_init leave");
620   return TRUE;
621
622 ERROR_CASE:
623   XCloseDisplay(dpy);
624   if (!driverName) {
625     free(driverName);
626   }
627
628   if (!deviceName) {
629     free(deviceName);
630   }
631
632   return FALSE;
633 }
634
635 void
636 gst_omx_drm_close(GOmxPort * port)
637 {
638   if (port->bufmgr) {
639     GST_LOG_OBJECT (port->core->object, "drm_slp_bufmgr_destroy");
640     tbm_bufmgr_deinit (port->bufmgr);
641     port->bufmgr = NULL;
642   }
643
644   if (port->drm_fd != -1) {
645     GST_LOG_OBJECT (port->core->object, "close drm fd");
646     close (port->drm_fd);
647     port->drm_fd = -1;
648   }
649 }
650
651 gboolean
652 gst_omx_drm_alloc_buffer(GOmxPort * port, guint width, guint height, guint buffer_index)
653 {
654   int flag = 0;
655   guint y_size = 0, uv_size = 0;
656   tbm_bo_handle handle_vaddr;
657   tbm_bo_handle handle_fd;
658
659   if (!port->drm_fd) {
660     GST_ERROR("drm_fd is NULL");
661     return FALSE;
662   }
663
664   if (port->core->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
665     calc_align_size(port, width, height, &y_size, &uv_size);
666     flag = TBM_BO_WC;
667   }
668
669   /* alloc Y plane*/
670   port->bo[buffer_index].bo_y = tbm_bo_alloc (port->bufmgr, y_size, flag);
671   if (!port->bo[buffer_index].bo_y) {
672     GST_ERROR("failed to tbm_bo_alloc (y plane) size = %d", y_size);
673     return FALSE;
674   }
675
676   GST_INFO_OBJECT (port->core->object, "buf[%d] Y plane - bo: %p", buffer_index, port->bo[buffer_index].bo_y);
677
678   /* for sending BO to XvImgSink(QC)*/
679   port->scmn_out[buffer_index].bo[0] = port->bo[buffer_index].bo_y;
680
681   handle_fd = tbm_bo_get_handle (port->bo[buffer_index].bo_y, TBM_DEVICE_MM);
682   port->scmn_out[buffer_index].fd[0] = handle_fd.u32;
683
684   GST_DEBUG_OBJECT (port->core->object, "  buf[%d] Y plane - fd[0]: %d", buffer_index, port->scmn_out[buffer_index].fd[0]);
685   handle_vaddr= tbm_bo_get_handle (port->bo[buffer_index].bo_y, TBM_DEVICE_CPU);
686
687   if (port->buffer_type==GOMX_BUFFER_GEM_VDEC_OUTPUT)
688     port->scmn_out[buffer_index].a[0] = handle_vaddr.ptr;
689
690   GST_DEBUG_OBJECT (port->core->object, "  buf[%d] Y plane -  a[0]: %p", buffer_index, port->scmn_out[buffer_index].a[0]);
691
692   /* alloc CbCr plane*/
693   port->bo[buffer_index].bo_uv = tbm_bo_alloc (port->bufmgr, uv_size, flag);
694
695   if (!port->bo[buffer_index].bo_uv) {
696     GST_ERROR("failed to tbm_bo_alloc (cbcr plane), size = %d", uv_size);
697     return FALSE;
698   }
699
700   GST_INFO_OBJECT (port->core->object, "buf[%d] CbCr plane - bo: %p", buffer_index, port->bo[buffer_index].bo_uv);
701
702   /* for sending BO to XvImgSink(S.LSI)*/
703   port->scmn_out[buffer_index].bo[1] = port->bo[buffer_index].bo_uv;
704
705   handle_fd = tbm_bo_get_handle (port->bo[buffer_index].bo_uv, TBM_DEVICE_MM);
706   port->scmn_out[buffer_index].fd[1] = handle_fd.u32;
707   GST_DEBUG_OBJECT (port->core->object, "  buf[%d] CbCr plane - fd[1]: %d", buffer_index, port->scmn_out[buffer_index].fd[1]);
708
709   handle_vaddr= tbm_bo_get_handle (port->bo[buffer_index].bo_uv, TBM_DEVICE_CPU);
710   port->scmn_out[buffer_index].a[1] = handle_vaddr.ptr;
711   GST_DEBUG_OBJECT (port->core->object, "  buf[%d] CbCr plane -  a[1]: %p\n", buffer_index, port->scmn_out[buffer_index].a[1]);
712
713   return TRUE;
714 }
715
716 /**
717  * note: this is not intended to be called directly by elements (which should
718  * instead use g_omx_core_new_port())
719  */
720 GOmxPort *
721 g_omx_port_new (GOmxCore * core, guint index)
722 {
723   GOmxPort *port;
724   port = g_new0 (GOmxPort, 1);
725
726   port->core = core;
727   port->port_index = index;
728   port->num_buffers = 0;
729   port->buffer_size = 0;
730   port->buffers = NULL;
731   port->shared_buffer = FALSE;
732
733   port->enabled = TRUE;
734   port->flushing = FALSE;
735   port->queue = async_queue_new ();
736   port->mutex = g_mutex_new ();
737 #ifdef GEM_BUFFER
738   port->bufmgr = NULL;
739   port->tzmem_fd = -1;
740   port->buffer_type = GOMX_BUFFER_DEFAULT;
741 #endif
742   port->output_color_format = OMX_VIDEO_CodingUnused;
743
744   return port;
745 }
746
747 void
748 g_omx_port_free (GOmxPort * port)
749 {
750   g_mutex_free (port->mutex);
751   async_queue_free (port->queue);
752
753   g_free (port->buffers);
754   port->buffers = NULL;
755   g_free (port);
756   port = NULL;
757 }
758
759 void
760 g_omx_port_setup (GOmxPort * port)
761 {
762   GOmxPortType type = -1;
763   OMX_PARAM_PORTDEFINITIONTYPE param;
764
765   G_OMX_INIT_PARAM (param);
766
767   param.nPortIndex = port->port_index;
768   OMX_GetParameter (port->core->omx_handle, OMX_IndexParamPortDefinition,
769       &param);
770
771   switch (param.eDir) {
772     case OMX_DirInput:
773       type = GOMX_PORT_INPUT;
774       break;
775     case OMX_DirOutput:
776       type = GOMX_PORT_OUTPUT;
777       break;
778     default:
779       break;
780   }
781
782   port->type = type;
783     /** @todo should it be nBufferCountMin? */
784   port->num_buffers = param.nBufferCountActual;
785   port->buffer_size = param.nBufferSize;
786
787   GST_DEBUG_OBJECT(port->core->object, "width:%d, height:%d, buffer size:%d", param.format.video.nFrameWidth, param.format.video.nFrameHeight, port->buffer_size);
788   if (port->type == GOMX_PORT_OUTPUT) {
789       if (port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
790         GST_DEBUG_OBJECT (port->core->object, "gst_omx_drm_init");
791         gst_omx_drm_init(port);
792       }
793   }
794
795   GST_DEBUG_OBJECT (port->core->object,
796       "type=%d, num_buffers=%d, buffer_size=%ld, port_index=%d",
797       port->type, port->num_buffers, port->buffer_size, port->port_index);
798
799   g_free (port->buffers);
800   port->buffers = g_new0 (OMX_BUFFERHEADERTYPE *, port->num_buffers);
801 }
802
803 static void
804 port_allocate_buffers (GOmxPort * port)
805 {
806   guint buf_idx;
807   gsize size;
808   OMX_PARAM_PORTDEFINITIONTYPE param;
809   guint width, height;
810
811   G_OMX_INIT_PARAM (param);
812   param.nPortIndex = port->port_index;
813   OMX_GetParameter (port->core->omx_handle, OMX_IndexParamPortDefinition, &param);
814
815   width = param.format.video.nFrameWidth;
816   height = param.format.video.nFrameHeight;
817
818   port->num_buffers = param.nBufferCountActual;
819   port->buffer_size = param.nBufferSize;
820   size = port->buffer_size;
821
822   GST_DEBUG_OBJECT (port->core->object,"port index: %d, num_buffer:%d, buffer_size :%d",
823       port->port_index, port->num_buffers, port->buffer_size);
824
825   if(port->buffers != NULL) {
826     g_free (port->buffers);
827     port->buffers = NULL;
828   }
829   GST_DEBUG_OBJECT (port->core->object,"make new OMX_BUFFERHEADERTYPE.");
830   port->buffers = g_new0 (OMX_BUFFERHEADERTYPE *, port->num_buffers);
831
832   /* MODIFICATION: allocate buffer for SLSI Exynos components*/
833   if (port->core->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
834
835     for (buf_idx = 0; buf_idx < port->num_buffers; buf_idx++) {
836       if (port->omx_allocate) {
837         /* OMX_AllocateBuffer with normal buffer */
838         GST_DEBUG_OBJECT (port->core->object, "%d: OMX_AllocateBuffer(), size=%" G_GSIZE_FORMAT, buf_idx, size);
839
840         OMX_AllocateBuffer (port->core->omx_handle, &port->buffers[buf_idx], port->port_index, NULL, size);
841       } else {
842         /* OMX_UseBuffer with gem or TZ*/
843         if (port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
844           gpointer buffer_data = NULL;
845           gpointer pAppPrivate = NULL;
846
847           if(!gst_omx_drm_alloc_buffer(port, width, height, buf_idx))
848             GST_ERROR_OBJECT (port->core->object,"gst_omx_drm_alloc_buffer failed");
849
850           buffer_data = &(port->scmn_out[buf_idx]);
851           size = sizeof(SCMN_IMGB);
852
853           GST_DEBUG_OBJECT (port->core->object, "%d: OMX_UseBuffer(), (GEM) size=%" G_GSIZE_FORMAT" (%p)",
854               buf_idx, size, buffer_data);
855
856           OMX_UseBuffer (port->core->omx_handle, &port->buffers[buf_idx], port->port_index, pAppPrivate, size, buffer_data);
857         } else {
858           /* OMX_UseBuffer with  normal buffer */
859           gpointer buffer_data;
860           buffer_data = g_malloc (size);
861           GST_DEBUG_OBJECT (port->core->object, "%d: OMX_UseBuffer(), size=%" G_GSIZE_FORMAT" (%p)", buf_idx, size, buffer_data);
862           OMX_UseBuffer (port->core->omx_handle, &port->buffers[buf_idx], port->port_index, NULL, size, buffer_data);
863
864           if (port->type == GOMX_PORT_INPUT && port->shared_buffer == TRUE) {
865             port->initial_pbuffer[buf_idx] = buffer_data;
866             GST_DEBUG_OBJECT (port->core->object, "alloc initial pbuffer. (%d): p= %p", buf_idx, port->initial_pbuffer[buf_idx]);
867           }
868         }
869
870       }
871     }
872   }
873   else {
874     /* allocate buffer for other components */
875     for (buf_idx = 0; buf_idx < port->num_buffers; buf_idx++) {
876       if (port->omx_allocate) {
877         GST_DEBUG_OBJECT (port->core->object,
878             "%d: OMX_AllocateBuffer(), size=%" G_GSIZE_FORMAT, buf_idx, size);
879         OMX_AllocateBuffer (port->core->omx_handle, &port->buffers[buf_idx],
880             port->port_index, NULL, size);
881       } else {
882         gpointer buffer_data;
883         buffer_data = g_malloc (size);
884         GST_DEBUG_OBJECT (port->core->object,
885             "%d: OMX_UseBuffer(), size=%" G_GSIZE_FORMAT" (%p)", buf_idx, size, buffer_data);
886         OMX_UseBuffer (port->core->omx_handle, &port->buffers[buf_idx],
887             port->port_index, NULL, size, buffer_data);
888
889         if (port->type == GOMX_PORT_INPUT && port->shared_buffer == TRUE) {
890           port->initial_pbuffer[buf_idx] = buffer_data;
891           GST_DEBUG_OBJECT (port->core->object,
892             "     alloc initial pbuffer. (%d): p= %p", buf_idx, port->initial_pbuffer[buf_idx]);
893         }
894       }
895     }
896   }
897 }
898
899 static void
900 port_free_buffers (GOmxPort * port)
901 {
902   guint i = 0;
903
904   if (port->type == GOMX_PORT_INPUT) {
905     GST_WARNING_OBJECT(port->core->object, "Input port free buffers.port->num_buffers = %d", port->num_buffers);
906   } else {
907     GST_WARNING_OBJECT(port->core->object, "Output port free buffers. port->num_buffers = %d", port->num_buffers);
908   }
909
910   for (i = 0; i < port->num_buffers; i++) {
911     OMX_BUFFERHEADERTYPE *omx_buffer;
912     omx_buffer = port->buffers[i];
913     /* Exynos case */
914     if (port->core->component_vendor == GOMX_VENDOR_SLSI_EXYNOS) {
915       if(port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
916         GST_WARNING_OBJECT(port->core->object, "gem buffer free. port %d: bo[%d] Y: %p, UV: %p",port->type, i, port->bo[i].bo_y, port->bo[i].bo_uv);
917         tbm_bo_unref(port->bo[i].bo_y);
918         port->bo[i].bo_y = NULL;
919         tbm_bo_unref(port->bo[i].bo_uv);
920         port->bo[i].bo_uv = NULL;
921       }
922
923       /* this is for input buffer share case. we need to free initial buffers (decoder input) */
924       if (port->shared_buffer && port->type == GOMX_PORT_INPUT && port->initial_pbuffer[i] != NULL) {
925         GST_DEBUG_OBJECT(port->core->object, " %d: g_free shared input initial buffer (pBuffer) %p", i, port->initial_pbuffer[i]);
926         g_free (port->initial_pbuffer[i]);
927         port->initial_pbuffer[i] = NULL;
928       }
929
930     /* other vendor case */
931     }else {
932       if (omx_buffer) {
933         if (port->shared_buffer) {
934           /* Modification: free pAppPrivate when input/output buffer is shared */
935           if (port->type == GOMX_PORT_INPUT && port->initial_pbuffer[i] != NULL) {
936             GST_DEBUG_OBJECT(port->core->object,
937             " %d: g_free shared input initial buffer (pBuffer) %p", i, port->initial_pbuffer[i]);
938             g_free (port->initial_pbuffer[i]);
939             port->initial_pbuffer[i] = NULL;
940           }
941
942           if (!omx_buffer->pAppPrivate && port->type == GOMX_PORT_OUTPUT && omx_buffer->pBuffer) {
943             GST_DEBUG_OBJECT(port->core->object,
944             " %d: g_free shared buffer (pBuffer) %p", i, omx_buffer->pBuffer);
945             g_free (omx_buffer->pBuffer);
946             omx_buffer->pBuffer = NULL;
947           }
948
949           if (omx_buffer->pAppPrivate) {
950             GST_DEBUG_OBJECT(port->core->object,
951                 " %d: unref shared buffer (pAppPrivate) %p", i, omx_buffer->pAppPrivate);
952             gst_buffer_unref(omx_buffer->pAppPrivate);
953             omx_buffer->pAppPrivate = NULL;
954           }
955         } else {
956           /* this is not shared buffer */
957           if (!port->omx_allocate) {
958             /* Modification: free pBuffer allocated in plugin when OMX_UseBuffer.
959              * the component shall free only buffer header if it allocated only buffer header.*/
960             GST_DEBUG_OBJECT(port->core->object,
961                 " %d: free buffer (pBuffer) %p", i, omx_buffer->pBuffer);
962             if (omx_buffer->pBuffer) {
963               g_free (omx_buffer->pBuffer);
964               omx_buffer->pBuffer = NULL;
965             }
966           }
967         }
968       } else {
969         GST_ERROR_OBJECT(port->core->object, "omx_buffer is NULL. port->buffers[%d]", i);
970       }
971     }
972
973     if (omx_buffer) {
974       GST_DEBUG_OBJECT(port->core->object, "OMX_FreeBuffer");
975       OMX_FreeBuffer (port->core->omx_handle, port->port_index, omx_buffer);
976       port->buffers[i] = NULL;
977     }
978
979   }
980
981   if(port->buffers != NULL) {
982     g_free (port->buffers); /* need to check */
983     port->buffers = NULL;
984   }
985
986   if (port->type == GOMX_PORT_OUTPUT) {
987       if (port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
988         GST_DEBUG_OBJECT (port->core->object, "gst_omx_drm_close");
989         gst_omx_drm_close(port);
990       }
991   }
992 }
993
994 static void
995 port_start_buffers (GOmxPort * port)
996 {
997   guint i;
998
999   for (i = 0; i < port->num_buffers; i++) {
1000     OMX_BUFFERHEADERTYPE *omx_buffer;
1001
1002     omx_buffer = port->buffers[i];
1003
1004     /* If it's an input port we will need to fill the buffer, so put it in
1005      * the queue, otherwise send to omx for processing (fill it up). */
1006     if (port->type == GOMX_PORT_INPUT){
1007       got_buffer (port->core, port, omx_buffer);
1008     } else {
1009       GST_DEBUG_OBJECT(port->core->object, "index %d FillThisBuffer. omx_buffer= %p",i, omx_buffer);
1010       g_omx_port_release_buffer (port, omx_buffer);
1011     }
1012   }
1013 }
1014
1015 void
1016 g_omx_port_push_buffer (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
1017 {
1018   async_queue_push (port->queue, omx_buffer);
1019 }
1020
1021 OMX_BUFFERHEADERTYPE *
1022 g_omx_port_request_buffer (GOmxPort * port)
1023 {
1024   return async_queue_pop (port->queue);
1025 }
1026
1027 void
1028 g_omx_port_release_buffer (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
1029 {
1030   switch (port->type) {
1031     case GOMX_PORT_INPUT:
1032       if (port->core->input_log_count < MAX_DEBUG_FRAME_CNT) {
1033         GST_WARNING_OBJECT(port->core->object, "[EmptyThisBuffer] omx_buf=%p  pBuf= %p, nFill= %d",
1034           omx_buffer, omx_buffer->pBuffer, omx_buffer->nFilledLen);
1035       } else {
1036         GST_LOG_OBJECT(port->core->object, "[EmptyThisBuffer] omx_buf=%p  pBuf= %p, nFill= %d",
1037           omx_buffer, omx_buffer->pBuffer, omx_buffer->nFilledLen);
1038       }
1039       OMX_EmptyThisBuffer (port->core->omx_handle, omx_buffer);
1040       break;
1041     case GOMX_PORT_OUTPUT:
1042       if (port->core->output_log_count < MAX_DEBUG_FRAME_CNT) {
1043         GST_WARNING_OBJECT(port->core->object, "[FillThisBuffer] omx_buf=%p  pBuf= %p, nAlloc= %d, nFill= %d",
1044           omx_buffer, omx_buffer->pBuffer, omx_buffer->nAllocLen, omx_buffer->nFilledLen);
1045       } else {
1046         GST_LOG_OBJECT(port->core->object, "[FillThisBuffer] omx_buf=%p  pBuf= %p, nAlloc= %d, nFill= %d",
1047           omx_buffer, omx_buffer->pBuffer, omx_buffer->nAllocLen, omx_buffer->nFilledLen);
1048       }
1049       OMX_FillThisBuffer (port->core->omx_handle, omx_buffer);
1050       break;
1051     default:
1052       break;
1053   }
1054 }
1055
1056 void
1057 g_omx_port_resume (GOmxPort * port)
1058 {
1059   async_queue_enable (port->queue);
1060 }
1061
1062 void
1063 g_omx_port_pause (GOmxPort * port)
1064 {
1065   async_queue_disable (port->queue);
1066 }
1067
1068 /* MODIFICATION: clean queue for DRC */
1069 void
1070 g_omx_port_clean (GOmxPort * port)
1071 {
1072   OMX_BUFFERHEADERTYPE *omx_buffer;
1073
1074   if (port->type != GOMX_PORT_OUTPUT) {
1075     GST_ERROR("g_omx_port_clean is only for output port");
1076     return;
1077   }
1078
1079   while ((omx_buffer = async_queue_pop_forced (port->queue))) {
1080     omx_buffer->nFilledLen = 0;
1081     GST_LOG_OBJECT(port->core->object, "pop and free buffers from the client queue. omx_buffer= %p", omx_buffer);
1082
1083     if ((port->core->reconfiguring == GOMX_RECONF_STATE_START||
1084       port->core->reconfiguring == GOMX_RECONF_STATE_PENDING)&&
1085         (port->enabled == FALSE)) {
1086         SCMN_IMGB * buffer = NULL;
1087
1088         if (port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
1089             {
1090                 buffer = (SCMN_IMGB*)omx_buffer->pBuffer;
1091             }
1092
1093         if (buffer != NULL) {
1094           int i = 0;
1095           for(i = 0; i < port->num_buffers ; i ++) {
1096
1097             if (buffer->fd[0] == port->scmn_out[i].fd[0]) {
1098               GST_INFO_OBJECT(port->core->object, "tbm_bo_unref: bo[%d] Y plane: %p", i, port->bo[i].bo_y);
1099               tbm_bo_unref(port->bo[i].bo_y);
1100               port->bo[i].bo_y = NULL;
1101
1102               GST_INFO_OBJECT(port->core->object, "tbm_bo_unref: bo[%d] UV plane: %p", i, port->bo[i].bo_uv);
1103               tbm_bo_unref(port->bo[i].bo_uv);
1104               port->bo[i].bo_uv = NULL;
1105               break;
1106             }
1107           }
1108         } else {
1109           GST_ERROR("pBuffer is NULL!! at omx_buffer= %p", omx_buffer);
1110         }
1111       }
1112       GST_INFO_OBJECT (port->core->object, "send OMX_FreeBuffer");
1113       OMX_FreeBuffer (port->core->omx_handle, port->port_index, omx_buffer);
1114     }
1115   } 
1116 }
1117
1118 void
1119 g_omx_port_flush (GOmxPort * port)
1120 {
1121   if (port->type == GOMX_PORT_OUTPUT) {
1122     port->flushing = TRUE; /* to modify seek issue */
1123   }
1124
1125   GST_WARNING ("send OMX_CommandFlush. port: %d", port->type);
1126   OMX_SendCommand (port->core->omx_handle, OMX_CommandFlush, port->port_index, NULL);
1127   g_sem_down (port->core->flush_sem);
1128 }
1129
1130 void
1131 g_omx_port_enable (GOmxPort * port)
1132 {
1133   GOmxCore *core;
1134
1135   core = port->core;
1136
1137   OMX_SendCommand (core->omx_handle, OMX_CommandPortEnable, port->port_index,
1138       NULL);
1139   port_allocate_buffers (port);
1140   if (core->omx_state != OMX_StateLoaded)
1141     port_start_buffers (port);
1142   g_omx_port_resume (port);
1143
1144   g_sem_down (core->port_sem);
1145 }
1146
1147 void
1148 g_omx_port_disable (GOmxPort * port)
1149 {
1150   GOmxCore *core;
1151
1152   core = port->core;
1153
1154   OMX_SendCommand (core->omx_handle, OMX_CommandPortDisable, port->port_index,
1155       NULL);
1156   g_omx_port_pause (port);
1157   g_omx_port_flush (port);
1158   port_free_buffers (port);
1159
1160   g_sem_down (core->port_sem);
1161 }
1162
1163 void
1164 g_omx_port_finish (GOmxPort * port)
1165 {
1166   port->enabled = FALSE;
1167   async_queue_disable (port->queue);
1168 }
1169
1170 void
1171 g_omx_cmd_queue_finish (GOmxCore * core)
1172 {
1173   GST_WARNING ("disable command queue");
1174   core->cmd.cmd_queue_enabled = FALSE;
1175   async_queue_disable (core->cmd.cmd_queue);
1176 }
1177
1178 /*
1179  * Helper functions.
1180  */
1181
1182 static inline void
1183 change_state (GOmxCore * core, OMX_STATETYPE state)
1184 {
1185   GST_DEBUG_OBJECT (core->object, "state=%d", state);
1186   OMX_SendCommand (core->omx_handle, OMX_CommandStateSet, state, NULL);
1187 }
1188
1189 static inline void
1190 complete_change_state (GOmxCore * core, OMX_STATETYPE state)
1191 {
1192   g_mutex_lock (core->omx_state_mutex);
1193
1194   core->omx_state = state;
1195   g_cond_signal (core->omx_state_condition);
1196   GST_DEBUG_OBJECT (core->object, "state=%d", state);
1197
1198   g_mutex_unlock (core->omx_state_mutex);
1199 }
1200
1201 static inline void
1202 wait_for_state (GOmxCore * core, OMX_STATETYPE state)
1203 {
1204   GTimeVal tv;
1205   gboolean signaled;
1206
1207   g_mutex_lock (core->omx_state_mutex);
1208   if (core->omx_error != OMX_ErrorNone) {
1209     /* MODIFICATION: ignore init fail to stop. */
1210     if ((core->component_vendor == GOMX_VENDOR_SLSI_EXYNOS ||
1211       core->component_vendor == GOMX_VENDOR_SLSI_SEC) &&
1212         core->omx_error == OMX_ErrorMFCInit) {
1213       GST_LOG_OBJECT (core->object, "ignore init fail when going to stop");
1214     } else {
1215       GST_ERROR_OBJECT (core->object, "there is error %s (0x%lx). but we will wait state change", omx_error_to_str (core->omx_error), core->omx_error);
1216     }
1217   }
1218
1219   g_get_current_time (&tv);
1220   g_time_val_add (&tv, OMX_STATE_CHANGE_TIMEOUT * G_USEC_PER_SEC);
1221
1222   /* try once */
1223   if (core->omx_state != state) {
1224     signaled =
1225         g_cond_timed_wait (core->omx_state_condition, core->omx_state_mutex,
1226         &tv);
1227
1228     if (!signaled) {
1229       GST_ERROR_OBJECT (core->object, "timed out switching from '%s' to '%s'",
1230           omx_state_to_str (core->omx_state), omx_state_to_str (state));
1231     }
1232   }
1233
1234   if (core->omx_error != OMX_ErrorNone)
1235     goto leave;
1236
1237   if (core->omx_state != state) {
1238     GST_ERROR_OBJECT (core->object,
1239         "wrong state received: state=%d, expected=%d", core->omx_state, state);
1240   }
1241
1242 leave:
1243   g_mutex_unlock (core->omx_state_mutex);
1244 }
1245
1246 /*
1247  * Callbacks
1248  */
1249
1250 static inline void
1251 in_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
1252 {
1253     /** @todo remove this */
1254
1255   if (!port->enabled)
1256     return;
1257 }
1258
1259 static inline void
1260 out_port_cb (GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
1261 {
1262     /** @todo remove this */
1263
1264   if (!port->enabled)
1265     return;
1266
1267 #if 0
1268   if (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) {
1269     g_omx_port_set_done (port);
1270     return;
1271   }
1272 #endif
1273 }
1274
1275 static inline void
1276 got_buffer (GOmxCore * core, GOmxPort * port, OMX_BUFFERHEADERTYPE * omx_buffer)
1277 {
1278   if (G_UNLIKELY (!omx_buffer)) {
1279     return;
1280   }
1281
1282   if (G_LIKELY (port)) {
1283     g_omx_port_push_buffer (port, omx_buffer);
1284
1285     switch (port->type) {
1286       case GOMX_PORT_INPUT:
1287         in_port_cb (port, omx_buffer);
1288         break;
1289       case GOMX_PORT_OUTPUT:
1290         out_port_cb (port, omx_buffer);
1291         break;
1292       default:
1293         break;
1294     }
1295   }
1296 }
1297
1298 /* MODIFICATION: Port setting changed */
1299 static void
1300 PortSettingsChanged(GOmxCore * core, OMX_U32 port_index)
1301 {
1302   GOmxPort *port;
1303   GstOmxSendCmdQueue *gomx_cmd = NULL;
1304
1305   GST_LOG_OBJECT (core->object, "PortSettingsChanged enter");
1306
1307   if (core->component_vendor == GOMX_VENDOR_SLSI_SEC) {
1308     GST_WARNING_OBJECT (core->object, "sec omx component does not handle PortSettingChanged Event. return");
1309     return;
1310   }
1311
1312   if (core->omx_state != OMX_StateExecuting) {
1313     GST_WARNING_OBJECT (core->object, "we got PortSettingsChanged Event not in Executing state. state = %d", core->omx_state);
1314     return;
1315   }
1316
1317   if (core->reconfiguring == GOMX_RECONF_STATE_PENDING) {
1318     GST_WARNING_OBJECT (core->object, "output_port_settingchanged_pending is true. return");
1319     return;
1320   }
1321
1322   port = get_port (core, port_index);
1323   if (port == NULL) {
1324     GST_ERROR_OBJECT (core->object, "get_port (output port) returned NULL");
1325     return;
1326   }
1327
1328   if (port->enabled != TRUE) { /* FIX ME: need to change port enable checking sequence */
1329     core->reconfiguring = GOMX_RECONF_STATE_PENDING;
1330     GST_WARNING_OBJECT (core->object, "output port is not enabled. set output_port_settingchanged_pending and return");
1331     return;
1332   }
1333
1334   core->reconfiguring = GOMX_RECONF_STATE_START;
1335   port->enabled = FALSE;
1336   g_omx_port_pause(port);
1337
1338   /* post OMX_CommandPortDisable */
1339   gomx_cmd = g_malloc(sizeof(GstOmxSendCmdQueue));
1340   gomx_cmd->type = GSTOMX_COMMAND_PORT_DISABLE;
1341   gomx_cmd->port = port->port_index;
1342   async_queue_push (core->cmd.cmd_queue, gomx_cmd);
1343
1344   GST_LOG_OBJECT (core->object, "PortSettingsChanged leave.");
1345 }
1346
1347
1348 static void
1349 PostCommand (gpointer data)
1350 {
1351   GOmxCore *core = (GOmxCore *) data;
1352   GOmxPort *port;
1353   GstOmxSendCmdQueue *gomx_cmd = NULL;
1354
1355   if (data == NULL) {
1356     GST_ERROR ("core is NULL!");
1357     return;
1358   }
1359
1360   gomx_cmd = (GstOmxSendCmdQueue*)async_queue_pop (core->cmd.cmd_queue);
1361   if (core->cmd.cmd_queue_enabled == FALSE) {
1362     GST_WARNING ("command queue is disable. goto leave.");
1363     goto pause;
1364   }
1365
1366   if (gomx_cmd == NULL) {
1367     GST_ERROR ("gomx_cmd is NULL.");
1368     goto leave;
1369   }
1370
1371   GST_INFO_OBJECT (core->object, "we got SendCommand. cmd: %d, port: %d", gomx_cmd->type, gomx_cmd->port);
1372   port = get_port (core, gomx_cmd->port);
1373
1374   if (port == NULL) {
1375     GST_ERROR ("port is NULL!");
1376     goto leave;
1377   }
1378
1379   switch (gomx_cmd->type) {
1380     case GSTOMX_COMMAND_PORT_DISABLE:
1381       GST_WARNING_OBJECT (core->object, "send OMX_CommandPortDisable (port: %d)", port->port_index);
1382       OMX_SendCommand (core->omx_handle, OMX_CommandPortDisable, port->port_index, NULL);
1383
1384       /* MODIFICATION: for DRC */
1385       if (port->type == GOMX_PORT_OUTPUT) {
1386         g_omx_port_clean (port);
1387       }
1388       break;
1389
1390     case GSTOMX_COMMAND_PORT_ENABLE:
1391       GST_WARNING_OBJECT (core->object, "send OMX_CommandPortEnable (port: %d)", port->port_index);
1392       OMX_SendCommand (core->omx_handle, OMX_CommandPortEnable, port->port_index, NULL);
1393
1394       GST_INFO_OBJECT (core->object, "port_allocate_buffers (port idx: %d)", port->port_index);
1395       port_allocate_buffers (port);
1396       break;
1397
1398     case GSTOMX_COMMAND_FREE_BUFFER: /* this case comes from fillbufferdone */
1399       GST_WARNING_OBJECT (core->object, "OMX_FreeBuffer (port: %d, omx_buffer = %p)", port->port_index, gomx_cmd->omx_buffer);
1400       if (gomx_cmd->omx_buffer) {
1401         OMX_FreeBuffer (core->omx_handle, port->port_index, gomx_cmd->omx_buffer);
1402       } else {
1403         GST_ERROR_OBJECT (core->object, "GSTOMX_COMMAND_FREE_BUFFER fail. omx_buffer is NULL");
1404       }
1405       break;
1406
1407     default:
1408       break;
1409   }
1410
1411   if(gomx_cmd) {
1412     g_free(gomx_cmd);
1413     gomx_cmd = NULL;
1414   }
1415
1416
1417 leave:
1418   GST_LOG_OBJECT (core->object, "SendCommand leave");
1419   return;
1420
1421 pause:
1422   gst_task_pause(core->cmd.cmd_task);
1423   GST_WARNING_OBJECT (core->object, "SendCommand leave. paused command task.");
1424   return;
1425 }
1426
1427 /*
1428  * OpenMAX IL callbacks.
1429  */
1430
1431 static OMX_ERRORTYPE
1432 EventHandler (OMX_HANDLETYPE omx_handle,
1433     OMX_PTR app_data,
1434     OMX_EVENTTYPE event, OMX_U32 data_1, OMX_U32 data_2, OMX_PTR event_data)
1435 {
1436   GOmxCore *core;
1437   GstOmxSendCmdQueue *gomx_cmd = NULL;
1438
1439   core = (GOmxCore *) app_data;
1440
1441   switch (event) {
1442     case OMX_EventCmdComplete:
1443     {
1444       OMX_COMMANDTYPE cmd;
1445
1446       cmd = (OMX_COMMANDTYPE) data_1;
1447
1448       GST_DEBUG_OBJECT (core->object, "OMX_EventCmdComplete: %d", cmd);
1449
1450       switch (cmd) {
1451         case OMX_CommandStateSet:
1452           complete_change_state (core, data_2);
1453           break;
1454         case OMX_CommandFlush:
1455         { /* MODIFICATION */
1456           OMX_U32 port_index = (OMX_U32)data_2;
1457           GOmxPort *port = get_port (core, port_index);
1458
1459           GST_WARNING_OBJECT (core->object, "we got OMX_CommandFlush complete event (port idx: %d)", port_index);
1460
1461           port->enabled = TRUE;
1462
1463           if (port->type == GOMX_PORT_OUTPUT && core->reconfiguring == GOMX_RECONF_STATE_PENDING) {
1464             GST_INFO_OBJECT (core->object, "we already have outport port settingchanged pending. do it now");
1465             PortSettingsChanged(core, port_index);
1466           } else {
1467             if (port->type == GOMX_PORT_OUTPUT) {
1468               OMX_BUFFERHEADERTYPE *omx_buffer;
1469               gint cnt = 0;
1470               GST_WARNING_OBJECT (core->object, "before async_queue_pop_forced. queue_len= %d", port->queue->length);
1471               while ((omx_buffer = async_queue_pop_forced (port->queue))) {
1472                 omx_buffer->nFilledLen = 0;
1473                 g_omx_port_release_buffer (port, omx_buffer);
1474                 GST_INFO_OBJECT (core->object, "send FIllThisBuffer (%d)  omx_buffer = %p", cnt, omx_buffer);
1475                 cnt++;
1476               }
1477               port->flushing = FALSE;
1478             }
1479             g_sem_up (core->flush_sem);
1480           }
1481           break;
1482         }
1483         case OMX_CommandPortDisable:
1484         { /* MODIFICATION */
1485           OMX_U32 port_index = (OMX_U32)data_2;
1486           GOmxPort *port = get_port (core, port_index);
1487
1488           GST_WARNING_OBJECT (core->object, "we got OMX_CommandPortDisable complete event (port idx: %d)", port_index);
1489
1490           port->enabled = FALSE;
1491
1492           if (port->type == GOMX_PORT_OUTPUT && core->reconfiguring == GOMX_RECONF_STATE_START) {
1493             gomx_cmd = g_malloc(sizeof(GstOmxSendCmdQueue));
1494             gomx_cmd->type = GSTOMX_COMMAND_PORT_ENABLE;
1495             gomx_cmd->port = port->port_index;
1496             async_queue_push (core->cmd.cmd_queue, gomx_cmd);
1497           } else {
1498             g_sem_up (core->port_sem);
1499           }
1500           break;
1501         }
1502         case OMX_CommandPortEnable:
1503         { /* MODIFICATION */
1504           OMX_U32 port_index = (OMX_U32)data_2;
1505           GOmxPort *port = get_port (core, port_index);
1506
1507           port->enabled = TRUE;
1508
1509           GST_WARNING_OBJECT (core->object, "we got OMX_CommandPortEnable complete event (port idx: %d)", port_index);
1510
1511           if (port->type == GOMX_PORT_OUTPUT && core->reconfiguring == GOMX_RECONF_STATE_START) {
1512             GST_INFO_OBJECT (core->object, "Reconfiguring is done. resume all port");
1513             if (core->omx_state == OMX_StateExecuting) {
1514               port_start_buffers (port);
1515             }
1516             /* First flush the queue and then enable it. This will ensure queue variables are reset */
1517             async_queue_flush (port->queue);
1518             g_omx_port_resume(port);
1519
1520             core->reconfiguring = GOMX_RECONF_STATE_DONE;
1521             GST_WARNING_OBJECT (core->object, "after drc port enable, send signal DRC done to output_loop task.");
1522             g_cond_signal(core->drc_cond);
1523           } else {
1524             g_sem_up (core->port_sem);
1525           }
1526           break;
1527         }
1528         default:
1529           break;
1530       }
1531       break;
1532     }
1533     case OMX_EventBufferFlag:
1534     {
1535       GST_DEBUG_OBJECT (core->object, "OMX_EventBufferFlag");
1536       if (data_2 & OMX_BUFFERFLAG_EOS) {
1537         g_omx_core_set_done (core);
1538       }
1539       break;
1540     }
1541     case OMX_EventPortSettingsChanged:
1542     {
1543       GST_WARNING_OBJECT (core->object, "we got OMX_EventPortSettingsChanged. (in state = %d)", core->omx_state);
1544                 /** @todo only on the relevant port. */
1545       /* MODIFICATION */
1546       if (data_2 == 0 || data_2 == OMX_IndexParamPortDefinition) {
1547         OMX_U32 port_index = (OMX_U32)data_1;
1548         GOmxPort *port = get_port (core, port_index);
1549
1550         GST_WARNING_OBJECT (core->object, "start reconfiguring for output port");
1551
1552         if (port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
1553           PortSettingsChanged(core, port_index);
1554         }
1555       } else if (data_2 == OMX_IndexConfigCommonOutputCrop) {
1556         core->crop_changed = TRUE;
1557         GST_WARNING_OBJECT (core->object, "we got only OMX_IndexConfigCommonOutputCrop");
1558       }
1559
1560       if (core->settings_changed_cb) {
1561         core->settings_changed_cb (core);
1562       }
1563       break;
1564     }
1565     case OMX_EventError:
1566     {
1567       core->omx_error = data_1;
1568       GST_ERROR_OBJECT (core->object, "unrecoverable error: %s (0x%lx)",
1569           omx_error_to_str (data_1), data_1);
1570       /* component might leave us waiting for buffers, unblock */
1571       g_omx_core_flush_start (core);
1572       /* unlock wait_for_state */
1573       g_mutex_lock (core->omx_state_mutex);
1574       /* MODIFICATION: set to ignore condition signal to stop. */
1575       if ((core->component_vendor == GOMX_VENDOR_SLSI_EXYNOS ||
1576         core->component_vendor == GOMX_VENDOR_SLSI_SEC) &&
1577           core->omx_error == OMX_ErrorMFCInit) {
1578         GST_WARNING_OBJECT (core->object, "do not send g_cond_signal when MFC init fail. (%d)",
1579             core->omx_unrecover_err_cnt);
1580         if (core->omx_unrecover_err_cnt == 0) {
1581           if (core->post_gst_element_error == FALSE) {
1582             GST_ERROR_OBJECT (core->object, "post GST_ELEMENT_ERROR as Error from OpenMAX component");
1583             GST_ELEMENT_ERROR (core->object, STREAM, FAILED, (NULL), ("%s", "Error from OpenMAX component"));
1584             core->post_gst_element_error = TRUE;
1585           } else {
1586             GST_ERROR_OBJECT (core->object, "GST_ELEMENT_ERROR is already posted. skip this (Error from OpenMAX component)");
1587           }
1588         }
1589         core->omx_unrecover_err_cnt++;
1590       } else {
1591         g_cond_signal (core->omx_state_condition);
1592       }
1593       g_mutex_unlock (core->omx_state_mutex);
1594       if (core->omx_unrecover_err_cnt >= OMX_UNRECOVERABLE_ERROR_MAX_COUNT) {
1595         GST_WARNING_OBJECT (core->object, "got unrecoverable error too much. go to omx pause state");
1596         g_omx_core_pause(core);
1597         core->omx_unrecover_err_cnt = 0;
1598       }
1599       break;
1600     }
1601     default:
1602       break;
1603   }
1604
1605   return OMX_ErrorNone;
1606 }
1607
1608 static OMX_ERRORTYPE
1609 EmptyBufferDone (OMX_HANDLETYPE omx_handle,
1610     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer)
1611 {
1612   GOmxCore *core;
1613   GOmxPort *port;
1614   private_data *pAppPrivate;
1615
1616   core = (GOmxCore *) app_data;
1617   port = get_port (core, omx_buffer->nInputPortIndex);
1618   pAppPrivate = (private_data*)omx_buffer->pAppPrivate;
1619
1620   GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer = %p",
1621       omx_buffer);
1622
1623   if (pAppPrivate) {
1624         if (core->input_log_count < MAX_DEBUG_FRAME_CNT) {
1625           GST_CAT_WARNING_OBJECT (gstomx_util_debug, core->object, "unref pAppPrivate. gst_buf= %p", pAppPrivate);
1626         } else {
1627           GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "unref pAppPrivate. gst_buf= %p", pAppPrivate);
1628         }
1629         gst_buffer_unref ((GstBuffer *)pAppPrivate);
1630
1631         pAppPrivate = NULL;
1632     }
1633
1634   /* MODIFICATION: enc input buffer unref after EBD. */
1635   if (omx_buffer->nFlags == OMX_BUFFERFLAG_EOS && core->codec_type == GSTOMX_CODECTYPE_VIDEO_ENC) {
1636     if (omx_buffer->pBuffer != NULL) {
1637       GST_CAT_WARNING_OBJECT (gstomx_util_debug, core->object, "g_free eos omx_buffer->pBuffer. p = %p", omx_buffer->pBuffer);
1638       g_free(omx_buffer->pBuffer);
1639       omx_buffer->pBuffer = NULL;
1640     }
1641   }
1642
1643   omx_buffer->nFlags = 0x00000000;
1644   got_buffer (core, port, omx_buffer);
1645
1646   return OMX_ErrorNone;
1647 }
1648
1649 static OMX_ERRORTYPE
1650 FillBufferDone (OMX_HANDLETYPE omx_handle,
1651     OMX_PTR app_data, OMX_BUFFERHEADERTYPE * omx_buffer)
1652 {
1653   GOmxCore *core;
1654   GOmxPort *port;
1655   OMX_PARAM_PORTDEFINITIONTYPE param;
1656
1657   G_OMX_INIT_PARAM (param);
1658
1659   core = (GOmxCore *) app_data;
1660   port = get_port (core, omx_buffer->nOutputPortIndex);
1661
1662   if (core->output_log_count < MAX_DEBUG_FRAME_CNT) {
1663       GST_CAT_WARNING_OBJECT (gstomx_util_debug, core->object, "omx_buffer= %p  pBuf= %p nFill= %d state= %d",
1664       omx_buffer, omx_buffer->pBuffer, omx_buffer->nFilledLen, core->omx_state);
1665   }
1666   else
1667   {
1668       GST_CAT_LOG_OBJECT (gstomx_util_debug, core->object, "omx_buffer= %p  pBuf= %p nFill= %d state= %d",
1669       omx_buffer, omx_buffer->pBuffer, omx_buffer->nFilledLen, core->omx_state);
1670   }
1671
1672
1673   /* MODIFICATION: for DRC */
1674   if ((core->reconfiguring == GOMX_RECONF_STATE_START||
1675     core->reconfiguring == GOMX_RECONF_STATE_PENDING)&&
1676       (port->enabled == FALSE)) {
1677     GstOmxSendCmdQueue *gomx_cmd = NULL;
1678     SCMN_IMGB * buffer = NULL;
1679
1680     buffer = (SCMN_IMGB*)omx_buffer->pBuffer;
1681
1682     GST_WARNING_OBJECT (core->object, "this FBD is flush response. do not queue.");
1683
1684     if (core->omx_state != OMX_StateExecuting) {
1685       GST_ERROR_OBJECT (core->object, "OMX_EventPortSettingsChanged but not executing. do not free buffer now.");
1686       goto queue_push;
1687     }
1688
1689     /* send OMX_FreeBuffer */
1690     gomx_cmd = g_malloc(sizeof(GstOmxSendCmdQueue));
1691     gomx_cmd->type = GSTOMX_COMMAND_FREE_BUFFER;
1692     gomx_cmd->port = port->port_index;
1693     gomx_cmd->omx_buffer = omx_buffer;
1694     async_queue_push (core->cmd.cmd_queue, gomx_cmd);
1695
1696     if (port->buffer_type == GOMX_BUFFER_GEM_VDEC_OUTPUT) {
1697       gint i = 0;
1698       for(i = 0; i < port->num_buffers ; i ++) {
1699         if (buffer->fd[0] == port->scmn_out[i].fd[0]) {
1700           GST_INFO_OBJECT(port->core->object, "tbm_bo_unref: bo[%d] Y plane: %p", i, port->bo[i].bo_y);
1701           tbm_bo_unref(port->bo[i].bo_y);
1702           port->bo[i].bo_y = NULL;
1703
1704           GST_INFO_OBJECT(port->core->object, "tbm_bo_unref: bo[%d] UV plane: %p", i, port->bo[i].bo_uv);
1705           tbm_bo_unref(port->bo[i].bo_uv);
1706           port->bo[i].bo_uv = NULL;
1707           break;
1708         }
1709       }
1710     }
1711     goto exit;
1712   }
1713
1714
1715 queue_push:
1716   got_buffer (core, port, omx_buffer);
1717
1718 exit:
1719   return OMX_ErrorNone;
1720 }
1721
1722 static inline const char *
1723 omx_state_to_str (OMX_STATETYPE omx_state)
1724 {
1725   switch (omx_state) {
1726     case OMX_StateInvalid:
1727       return "invalid";
1728     case OMX_StateLoaded:
1729       return "loaded";
1730     case OMX_StateIdle:
1731       return "idle";
1732     case OMX_StateExecuting:
1733       return "executing";
1734     case OMX_StatePause:
1735       return "pause";
1736     case OMX_StateWaitForResources:
1737       return "wait for resources";
1738     default:
1739       return "unknown";
1740   }
1741 }
1742
1743 static inline const char *
1744 omx_error_to_str (OMX_ERRORTYPE omx_error)
1745 {
1746   switch (omx_error) {
1747     case OMX_ErrorNone:
1748       return "None";
1749
1750     case OMX_ErrorInsufficientResources:
1751       return
1752           "There were insufficient resources to perform the requested operation";
1753
1754     case OMX_ErrorUndefined:
1755       return "The cause of the error could not be determined";
1756
1757     case OMX_ErrorInvalidComponentName:
1758       return "The component name string was not valid";
1759
1760     case OMX_ErrorComponentNotFound:
1761       return "No component with the specified name string was found";
1762
1763     case OMX_ErrorInvalidComponent:
1764       return "The component specified did not have an entry point";
1765
1766     case OMX_ErrorBadParameter:
1767       return "One or more parameters were not valid";
1768
1769     case OMX_ErrorNotImplemented:
1770       return "The requested function is not implemented";
1771
1772     case OMX_ErrorUnderflow:
1773       return "The buffer was emptied before the next buffer was ready";
1774
1775     case OMX_ErrorOverflow:
1776       return "The buffer was not available when it was needed";
1777
1778     case OMX_ErrorHardware:
1779       return "The hardware failed to respond as expected";
1780
1781     case OMX_ErrorInvalidState:
1782       return "The component is in invalid state";
1783
1784     case OMX_ErrorStreamCorrupt:
1785       return "Stream is found to be corrupt";
1786
1787     case OMX_ErrorPortsNotCompatible:
1788       return "Ports being connected are not compatible";
1789
1790     case OMX_ErrorResourcesLost:
1791       return "Resources allocated to an idle component have been lost";
1792
1793     case OMX_ErrorNoMore:
1794       return "No more indices can be enumerated";
1795
1796     case OMX_ErrorVersionMismatch:
1797       return "The component detected a version mismatch";
1798
1799     case OMX_ErrorNotReady:
1800       return "The component is not ready to return data at this time";
1801
1802     case OMX_ErrorTimeout:
1803       return "There was a timeout that occurred";
1804
1805     case OMX_ErrorSameState:
1806       return
1807           "This error occurs when trying to transition into the state you are already in";
1808
1809     case OMX_ErrorResourcesPreempted:
1810       return
1811           "Resources allocated to an executing or paused component have been preempted";
1812
1813     case OMX_ErrorPortUnresponsiveDuringAllocation:
1814       return
1815           "Waited an unusually long time for the supplier to allocate buffers";
1816
1817     case OMX_ErrorPortUnresponsiveDuringDeallocation:
1818       return
1819           "Waited an unusually long time for the supplier to de-allocate buffers";
1820
1821     case OMX_ErrorPortUnresponsiveDuringStop:
1822       return
1823           "Waited an unusually long time for the non-supplier to return a buffer during stop";
1824
1825     case OMX_ErrorIncorrectStateTransition:
1826       return "Attempting a state transition that is not allowed";
1827
1828     case OMX_ErrorIncorrectStateOperation:
1829       return
1830           "Attempting a command that is not allowed during the present state";
1831
1832     case OMX_ErrorUnsupportedSetting:
1833       return
1834           "The values encapsulated in the parameter or config structure are not supported";
1835
1836     case OMX_ErrorUnsupportedIndex:
1837       return
1838           "The parameter or config indicated by the given index is not supported";
1839
1840     case OMX_ErrorBadPortIndex:
1841       return "The port index supplied is incorrect";
1842
1843     case OMX_ErrorPortUnpopulated:
1844       return
1845           "The port has lost one or more of its buffers and it thus unpopulated";
1846
1847     case OMX_ErrorComponentSuspended:
1848       return "Component suspended due to temporary loss of resources";
1849
1850     case OMX_ErrorDynamicResourcesUnavailable:
1851       return
1852           "Component suspended due to an inability to acquire dynamic resources";
1853
1854     case OMX_ErrorMbErrorsInFrame:
1855       return "Frame generated macroblock error";
1856
1857     case OMX_ErrorFormatNotDetected:
1858       return "Cannot parse or determine the format of an input stream";
1859
1860     case OMX_ErrorContentPipeOpenFailed:
1861       return "The content open operation failed";
1862
1863     case OMX_ErrorContentPipeCreationFailed:
1864       return "The content creation operation failed";
1865
1866     case OMX_ErrorSeperateTablesUsed:
1867       return "Separate table information is being used";
1868
1869     case OMX_ErrorTunnelingUnsupported:
1870       return "Tunneling is unsupported by the component";
1871
1872     default:
1873       return "Unknown error";
1874   }
1875 }