Revert "hack for seek bug in OMX"
[gstreamer-omap:gst-openmax.git] / omx / gstomx_port.c
1 /*
2  * Copyright (C) 2006-2009 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 <string.h>
24
25 #include "gstomx_util.h"
26 #include "gstomx_port.h"
27 #include "gstomx.h"
28
29 #ifdef USE_OMXTICORE
30 #  include <OMX_TI_Common.h>
31 #  include <OMX_TI_Index.h>
32 #endif
33
34 GST_DEBUG_CATEGORY_EXTERN (gstomx_util_debug);
35
36 #ifndef OMX_BUFFERFLAG_CODECCONFIG
37 #  define OMX_BUFFERFLAG_CODECCONFIG 0x00000080 /* special nFlags field to use to indicated codec-data */
38 #endif
39
40 static OMX_BUFFERHEADERTYPE * request_buffer (GOmxPort *port);
41 static void release_buffer (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer);
42 static void setup_shared_buffer (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer);
43
44 #define DEBUG(port, fmt, args...) \
45     GST_DEBUG ("<%s:%s> "fmt, GST_OBJECT_NAME ((port)->core->object), (port)->name, ##args)
46 #define LOG(port, fmt, args...) \
47     GST_LOG ("<%s:%s> "fmt, GST_OBJECT_NAME ((port)->core->object), (port)->name, ##args)
48 #define WARNING(port, fmt, args...) \
49     GST_WARNING ("<%s:%s> "fmt, GST_OBJECT_NAME ((port)->core->object), (port)->name, ##args)
50
51 /*
52  * Port
53  */
54
55 GOmxPort *
56 g_omx_port_new (GOmxCore *core, const gchar *name, guint index)
57 {
58     GOmxPort *port = g_new0 (GOmxPort, 1);
59
60     port->core = core;
61     port->name = g_strdup_printf ("%s:%d", name, index);
62     port->port_index = index;
63     port->num_buffers = 0;
64     port->buffers = NULL;
65
66     port->enabled = TRUE;
67     port->queue = async_queue_new ();
68     port->mutex = g_mutex_new ();
69     port->n_offset = 0;
70
71     return port;
72 }
73
74 void
75 g_omx_port_free (GOmxPort *port)
76 {
77     DEBUG (port, "begin");
78
79     g_mutex_free (port->mutex);
80     async_queue_free (port->queue);
81
82     g_free (port->name);
83
84     g_free (port->buffers);
85     g_free (port);
86
87     GST_DEBUG ("end");
88 }
89
90 void
91 g_omx_port_setup (GOmxPort *port,
92                   OMX_PARAM_PORTDEFINITIONTYPE *omx_port)
93 {
94     GOmxPortType type = -1;
95
96     switch (omx_port->eDir)
97     {
98         case OMX_DirInput:
99             type = GOMX_PORT_INPUT;
100             break;
101         case OMX_DirOutput:
102             type = GOMX_PORT_OUTPUT;
103             break;
104         default:
105             break;
106     }
107
108     port->type = type;
109     /** @todo should it be nBufferCountMin? */
110     port->num_buffers = omx_port->nBufferCountActual;
111     port->port_index = omx_port->nPortIndex;
112
113     DEBUG (port, "type=%d, num_buffers=%d, port_index=%d",
114         port->type, port->num_buffers, port->port_index);
115
116     /* I don't think it is valid for buffers to be allocated at this point..
117      * if there is a case where it is, then call g_omx_port_free_buffers()
118      * here instead:
119      */
120     g_return_if_fail (!port->buffers);
121 }
122
123 static GstBuffer *
124 buffer_alloc (GOmxPort *port, gint len)
125 {
126     GstBuffer *buf = NULL;
127
128     if (port->buffer_alloc)
129         buf = port->buffer_alloc (port, len);
130
131     if (!buf)
132         buf = gst_buffer_new_and_alloc (len);
133
134     return buf;
135 }
136
137
138 /**
139  * Ensure that srcpad caps are set before beginning transition-to-idle or
140  * transition-to-loaded.  This is a bit ugly, because it requires pad-alloc'ing
141  * a buffer from the downstream element for no particular purpose other than
142  * triggering upstream caps negotiation from the sink..
143  */
144 void
145 g_omx_port_prepare (GOmxPort *port)
146 {
147     OMX_PARAM_PORTDEFINITIONTYPE param;
148     GstBuffer *buf;
149     guint size;
150
151     DEBUG (port, "begin");
152
153     G_OMX_PORT_GET_DEFINITION (port, &param);
154     size = param.nBufferSize;
155
156     buf = buffer_alloc (port, size);
157
158     if (GST_BUFFER_SIZE (buf) != size)
159     {
160         DEBUG (port, "buffer sized changed, %d->%d",
161                 size, GST_BUFFER_SIZE (buf));
162     }
163
164     /* number of buffers could have changed */
165     G_OMX_PORT_GET_DEFINITION (port, &param);
166     port->num_buffers = param.nBufferCountActual;
167
168     gst_buffer_unref (buf);
169
170 #ifdef USE_OMXTICORE
171     if (port->share_buffer)
172     {
173         OMX_TI_PARAM_BUFFERPREANNOUNCE param;
174         OMX_TI_CONFIG_BUFFERREFCOUNTNOTIFYTYPE config;
175
176         G_OMX_PORT_GET_PARAM (port, OMX_TI_IndexParamBufferPreAnnouncement, &param);
177         param.bEnabled = FALSE;
178         G_OMX_PORT_SET_PARAM (port, OMX_TI_IndexParamBufferPreAnnouncement, &param);
179
180         G_OMX_PORT_GET_CONFIG (port, OMX_TI_IndexConfigBufferRefCountNotification, &config);
181         config.bNotifyOnDecrease = TRUE;
182         config.bNotifyOnIncrease = FALSE;
183         config.nCountForNotification = 1;
184         G_OMX_PORT_SET_CONFIG (port, OMX_TI_IndexConfigBufferRefCountNotification, &config);
185     }
186 #endif
187
188     DEBUG (port, "end");
189 }
190
191 void
192 g_omx_port_allocate_buffers (GOmxPort *port)
193 {
194     OMX_PARAM_PORTDEFINITIONTYPE param;
195     guint i;
196     guint size;
197
198     if (port->buffers)
199         return;
200
201     DEBUG (port, "begin");
202
203     G_OMX_PORT_GET_DEFINITION (port, &param);
204     size = param.nBufferSize;
205
206     port->buffers = g_new0 (OMX_BUFFERHEADERTYPE *, port->num_buffers);
207
208     for (i = 0; i < port->num_buffers; i++)
209     {
210
211         if (port->omx_allocate)
212         {
213             DEBUG (port, "%d: OMX_AllocateBuffer(), size=%d", i, size);
214             OMX_AllocateBuffer (port->core->omx_handle,
215                                 &port->buffers[i],
216                                 port->port_index,
217                                 NULL,
218                                 size);
219
220             g_return_if_fail (port->buffers[i]);
221         }
222         else
223         {
224             gpointer buffer_data = NULL;
225
226             if (! port->share_buffer)
227             {
228                 buffer_data = g_malloc (size);
229             }
230
231             DEBUG (port, "%d: OMX_UseBuffer(), size=%d, share_buffer=%d", i, size, port->share_buffer);
232             OMX_UseBuffer (port->core->omx_handle,
233                            &port->buffers[i],
234                            port->port_index,
235                            NULL,
236                            size,
237                            buffer_data);
238
239             g_return_if_fail (port->buffers[i]);
240
241             if (port->share_buffer)
242             {
243                 /* we will need this later: */
244                 port->buffers[i]->nAllocLen = size;
245             }
246         }
247     }
248
249     DEBUG (port, "end");
250 }
251
252 void
253 g_omx_port_free_buffers (GOmxPort *port)
254 {
255     guint i;
256     OMX_BUFFERHEADERTYPE *omx_buffer;
257
258     if (!port->buffers)
259         return;
260
261     DEBUG (port, "begin");
262
263     for (i = 0; i < port->num_buffers; i++)
264     {
265         /* pop the buffer, to be sure that it has been returned from the
266          * OMX component, to avoid freeing a buffer that the component
267          * is still accessing:
268          */
269         omx_buffer = async_queue_pop_full (port->queue, TRUE, TRUE);
270
271 #if 0
272         /** @todo how shall we free that buffer? */
273         if (!port->omx_allocate)
274         {
275             g_free (omx_buffer->pBuffer);
276             omx_buffer->pBuffer = NULL;
277         }
278 #endif
279
280         if (omx_buffer->pAppPrivate != NULL) {
281           gst_buffer_unref (GST_BUFFER_CAST (omx_buffer->pAppPrivate));
282           omx_buffer->pAppPrivate = NULL;
283         }
284     }
285     
286     for (i = 0; i < port->num_buffers; i++)
287     {
288         omx_buffer = port->buffers[i];
289         DEBUG (port, "OMX_FreeBuffer(%p)", omx_buffer);
290         OMX_FreeBuffer (port->core->omx_handle, port->port_index, omx_buffer);
291         port->buffers[i] = NULL;
292     }
293
294     g_free (port->buffers);
295     port->buffers = NULL;
296
297     DEBUG (port, "end");
298 }
299
300 void
301 g_omx_port_start_buffers (GOmxPort *port)
302 {
303     guint i;
304
305     if (!port->enabled)
306         return;
307
308     g_return_if_fail (port->buffers);
309
310     DEBUG (port, "begin");
311
312     for (i = 0; i < port->num_buffers; i++)
313     {
314         OMX_BUFFERHEADERTYPE *omx_buffer;
315
316         omx_buffer = port->buffers[i];
317
318         /* If it's an input port we will need to fill the buffer, so put it in
319          * the queue, otherwise send to omx for processing (fill it up). */
320         if (port->type == GOMX_PORT_INPUT)
321         {
322             g_omx_core_got_buffer (port->core, port, omx_buffer);
323         }
324         else
325         {
326             setup_shared_buffer (port, omx_buffer);
327             release_buffer (port, omx_buffer);
328         }
329     }
330
331     DEBUG (port, "end");
332 }
333
334 void
335 g_omx_port_push_buffer (GOmxPort *port,
336                         OMX_BUFFERHEADERTYPE *omx_buffer)
337 {
338     async_queue_push (port->queue, omx_buffer);
339 }
340
341 static OMX_BUFFERHEADERTYPE *
342 request_buffer (GOmxPort *port)
343 {
344     LOG (port, "request buffer");
345     return async_queue_pop (port->queue);
346 }
347
348 static void
349 release_buffer (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer)
350 {
351     switch (port->type)
352     {
353         case GOMX_PORT_INPUT:
354             DEBUG (port, "ETB: omx_buffer=%p, pAppPrivate=%p, pBuffer=%p",
355                     omx_buffer, omx_buffer ? omx_buffer->pAppPrivate : 0, omx_buffer ? omx_buffer->pBuffer : 0);
356             OMX_EmptyThisBuffer (port->core->omx_handle, omx_buffer);
357             break;
358         case GOMX_PORT_OUTPUT:
359             DEBUG (port, "FTB: omx_buffer=%p, pAppPrivate=%p, pBuffer=%p",
360                     omx_buffer, omx_buffer ? omx_buffer->pAppPrivate : 0, omx_buffer ? omx_buffer->pBuffer : 0);
361             OMX_FillThisBuffer (port->core->omx_handle, omx_buffer);
362             break;
363         default:
364             break;
365     }
366 }
367
368 /* NOTE ABOUT BUFFER SHARING:
369  *
370  * Buffer sharing is a sort of "extension" to OMX to allow zero copy buffer
371  * passing between GST and OMX.
372  *
373  * There are only two cases:
374  *
375  * 1) shared_buffer is enabled, in which case we control nOffset, and use
376  *    pAppPrivate to store the reference to the original GstBuffer that
377  *    pBuffer ptr is copied from.  Note that in case of input buffers,
378  *    the DSP/coprocessor should treat the buffer as read-only so cache-
379  *    line alignment is not an issue.  For output buffers which are not
380  *    pad_alloc()d, some care may need to be taken to ensure proper buffer
381  *    alignment.
382  * 2) shared_buffer is not enabled, in which case we respect the nOffset
383  *    set by the component and pAppPrivate is NULL
384  *
385  */
386
387 static void
388 setup_shared_buffer (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer)
389 {
390     if (port->share_buffer)
391     {
392         GstBuffer *new_buf = buffer_alloc (port, omx_buffer->nAllocLen);
393
394         omx_buffer->pAppPrivate = new_buf;
395         omx_buffer->pBuffer     = GST_BUFFER_DATA (new_buf);
396         omx_buffer->nAllocLen   = GST_BUFFER_SIZE (new_buf);
397         omx_buffer->nOffset     = 0;
398         omx_buffer->nFlags      = 0;
399
400         /* special hack.. this should be removed: */
401         omx_buffer->nFlags     |= OMX_BUFFERHEADERFLAG_MODIFIED;
402     }
403     else
404     {
405         g_assert (omx_buffer->pBuffer && !omx_buffer->pAppPrivate);
406     }
407 }
408
409 typedef void (*SendPrep) (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer, gpointer obj);
410
411 static void
412 send_prep_codec_data (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer, GstBuffer *buf)
413 {
414     omx_buffer->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
415     omx_buffer->nFilledLen = GST_BUFFER_SIZE (buf);
416
417     if (port->share_buffer)
418     {
419         omx_buffer->nOffset = 0;
420         omx_buffer->pBuffer = malloc (omx_buffer->nFilledLen);
421     }
422
423     memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
424             GST_BUFFER_DATA (buf), omx_buffer->nFilledLen);
425 }
426
427 static void
428 send_prep_buffer_data (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer, GstBuffer *buf)
429 {
430     if (port->share_buffer)
431     {
432         omx_buffer->nOffset     = port->n_offset;
433         omx_buffer->pBuffer     = GST_BUFFER_DATA (buf);
434         omx_buffer->nFilledLen  = GST_BUFFER_SIZE (buf);
435         /* Temp hack to not update nAllocLen for each ETB/FTB till we
436          * find a cleaner solution to get padded width and height */
437         /* omx_buffer->nAllocLen   = GST_BUFFER_SIZE (buf); */
438         omx_buffer->pAppPrivate = gst_buffer_ref (buf);
439
440         /* special hack.. this should be removed: */
441         omx_buffer->nFlags     |= OMX_BUFFERHEADERFLAG_MODIFIED;
442     }
443     else
444     {
445         omx_buffer->nFilledLen = MIN (GST_BUFFER_SIZE (buf),
446                 omx_buffer->nAllocLen - omx_buffer->nOffset);
447         memcpy (omx_buffer->pBuffer + omx_buffer->nOffset,
448                 GST_BUFFER_DATA (buf), omx_buffer->nFilledLen);
449     }
450
451     if (port->core->use_timestamps)
452     {
453         omx_buffer->nTimeStamp = gst_util_uint64_scale_int (
454                 GST_BUFFER_TIMESTAMP (buf),
455                 OMX_TICKS_PER_SECOND, GST_SECOND);
456     }
457
458     DEBUG (port, "omx_buffer: size=%lu, len=%lu, flags=%lu, offset=%lu, timestamp=%lld",
459             omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
460             omx_buffer->nOffset, omx_buffer->nTimeStamp);
461 }
462
463 static void
464 send_prep_eos_event (GOmxPort *port, OMX_BUFFERHEADERTYPE *omx_buffer, GstEvent *evt)
465 {
466     omx_buffer->nFlags |= OMX_BUFFERFLAG_EOS;
467     omx_buffer->nFilledLen = 0;
468     if (port->share_buffer) {
469         /* OMX should not try to read from the buffer, since it is empty..
470          * but yet it complains if pBuffer is NULL.  This will get us past
471          * that check, and ensure that OMX segfaults in a debuggible way
472          * if they do something stupid like read from the empty buffer:
473          */
474         omx_buffer->pBuffer    = (OMX_U8 *)1;
475         /* TODO: Temporary hack as OMX currently complains about
476          * non-zero nAllocLen. Need to be removed once aligned with OMX.
477          */
478         /* omx_buffer->nAllocLen  = 0; */
479     }
480 }
481
482 /**
483  * Send a buffer/event to the OMX component.  This handles conversion of
484  * GST buffer, codec-data, and EOS events to the equivalent OMX buffer.
485  *
486  * This method does not take ownership of the ref to @obj
487  *
488  * Returns number of bytes sent, or negative if error
489  */
490 gint
491 g_omx_port_send (GOmxPort *port, gpointer obj)
492 {
493     SendPrep send_prep = NULL;
494
495     g_return_val_if_fail (port->type == GOMX_PORT_INPUT, -1);
496
497     if (GST_IS_BUFFER (obj))
498     {
499         if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (obj, GST_BUFFER_FLAG_IN_CAPS)))
500             send_prep = (SendPrep)send_prep_codec_data;
501         else
502             send_prep = (SendPrep)send_prep_buffer_data;
503     }
504     else if (GST_IS_EVENT (obj))
505     {
506         if (G_LIKELY (GST_EVENT_TYPE (obj) == GST_EVENT_EOS))
507             send_prep = (SendPrep)send_prep_eos_event;
508     }
509
510     if (G_LIKELY (send_prep))
511     {
512         gint ret;
513         OMX_BUFFERHEADERTYPE *omx_buffer = request_buffer (port);
514
515         if (!omx_buffer)
516         {
517             DEBUG (port, "null buffer");
518             return -1;
519         }
520
521         /* don't assume OMX component clears flags!
522          */
523         omx_buffer->nFlags = 0;
524
525         /* if buffer sharing is enabled, pAppPrivate might hold the ref to
526          * a buffer that is no longer required and should be unref'd.  We
527          * do this check here, rather than in send_prep_buffer_data() so
528          * we don't keep the reference live in case, for example, this time
529          * the buffer is used for an EOS event.
530          */
531         if (omx_buffer->pAppPrivate)
532         {
533             GstBuffer *old_buf = omx_buffer->pAppPrivate;
534             gst_buffer_unref (old_buf);
535             omx_buffer->pAppPrivate = NULL;
536             omx_buffer->pBuffer = NULL;     /* just to ease debugging */
537         }
538
539         send_prep (port, omx_buffer, obj);
540
541         ret = omx_buffer->nFilledLen;
542
543         release_buffer (port, omx_buffer);
544
545         return ret;
546     }
547
548     WARNING (port, "unknown obj type");
549     return -1;
550 }
551
552 /**
553  * Receive a buffer/event from OMX component.  This handles the conversion
554  * of OMX buffer to GST buffer, codec-data, or EOS event.
555  *
556  * Returns <code>NULL</code> if buffer could not be received.
557  */
558 gpointer
559 g_omx_port_recv (GOmxPort *port)
560 {
561     gpointer ret = NULL;
562
563     g_return_val_if_fail (port->type == GOMX_PORT_OUTPUT, NULL);
564
565     while (!ret && port->enabled)
566     {
567         OMX_BUFFERHEADERTYPE *omx_buffer = request_buffer (port);
568
569         if (G_UNLIKELY (!omx_buffer))
570         {
571             return NULL;
572         }
573
574         DEBUG (port, "omx_buffer=%p size=%lu, len=%lu, flags=%lu, offset=%lu, timestamp=%lld",
575                 omx_buffer, omx_buffer->nAllocLen, omx_buffer->nFilledLen, omx_buffer->nFlags,
576                 omx_buffer->nOffset, omx_buffer->nTimeStamp);
577
578         if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_EOS))
579         {
580             DEBUG (port, "got eos");
581             ret = gst_event_new_eos ();
582         }
583         else if (G_LIKELY (omx_buffer->nFilledLen > 0))
584         {
585             GstBuffer *buf = omx_buffer->pAppPrivate;
586
587             /* I'm not really sure if it was intentional to block zero-copy of
588              * the codec-data buffer.. this is how the original code worked,
589              * so I kept the behavior
590              */
591             if (!buf || (omx_buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG))
592             {
593                 if (buf)
594                     gst_buffer_unref (buf);
595
596                 buf = buffer_alloc (port, omx_buffer->nFilledLen);
597                 memcpy (GST_BUFFER_DATA (buf),
598                         omx_buffer->pBuffer + omx_buffer->nOffset,
599                         omx_buffer->nFilledLen);
600             }
601             else if (buf)
602             {
603                 /* don't rely on OMX having told us the correct buffer size
604                  * when we allocated the buffer.
605                  */
606                 GST_BUFFER_SIZE (buf) = omx_buffer->nFilledLen;
607             }
608
609             if (port->core->use_timestamps)
610             {
611                 GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (
612                         omx_buffer->nTimeStamp,
613                         GST_SECOND, OMX_TICKS_PER_SECOND);
614             }
615
616             if (G_UNLIKELY (omx_buffer->nFlags & OMX_BUFFERFLAG_CODECCONFIG))
617             {
618                 GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_IN_CAPS);
619             }
620
621             port->n_offset = omx_buffer->nOffset;
622
623             ret = buf;
624         }
625         else
626         {
627             GstBuffer *buf = omx_buffer->pAppPrivate;
628
629             if (buf)
630             {
631                 gst_buffer_unref (buf);
632                 omx_buffer->pAppPrivate = NULL;
633             }
634
635             DEBUG (port, "empty buffer %p", omx_buffer); /* keep looping */
636         }
637
638 #ifdef USE_OMXTICORE
639         if (omx_buffer->nFlags & OMX_TI_BUFFERFLAG_READONLY)
640         {
641             GstBuffer *buf = omx_buffer->pAppPrivate;
642
643             if (buf)
644             {
645                 /* if using buffer sharing, create an extra ref to the buffer
646                  * to account for the fact that the OMX component is still
647                  * holding a reference.  (This prevents the buffer from being
648                  * free'd while the component is still using it as, for ex, a
649                  * reference frame.)
650                  */
651                 gst_buffer_ref (buf);
652             }
653
654             DEBUG (port, "dup'd buffer %p", omx_buffer);
655
656             g_mutex_lock (port->core->omx_state_mutex);
657             omx_buffer->nFlags &= ~OMX_TI_BUFFERFLAG_READONLY;
658             g_mutex_unlock (port->core->omx_state_mutex);
659         }
660         else if (omx_buffer->nFlags & GST_BUFFERFLAG_UNREF_CHECK)
661         {
662             /* buffer has already been handled under READONLY case.. so
663              * don't return it to gst.  Just unref it, and release the omx
664              * buffer which was previously not released.
665              */
666             gst_buffer_unref(ret);
667             ret = NULL;
668
669             DEBUG (port, "unref'd buffer %p", omx_buffer);
670
671             setup_shared_buffer (port, omx_buffer);
672             release_buffer (port, omx_buffer);
673         }
674         else
675 #endif
676         {
677             setup_shared_buffer (port, omx_buffer);
678             release_buffer (port, omx_buffer);
679         }
680     }
681
682
683     return ret;
684 }
685
686 void
687 g_omx_port_resume (GOmxPort *port)
688 {
689     DEBUG (port, "resume");
690     async_queue_enable (port->queue);
691 }
692
693 void
694 g_omx_port_pause (GOmxPort *port)
695 {
696     DEBUG (port, "pause");
697     async_queue_disable (port->queue);
698 }
699
700 void
701 g_omx_port_flush (GOmxPort *port)
702 {
703     DEBUG (port, "begin");
704
705     if (port->type == GOMX_PORT_OUTPUT)
706     {
707         /* This will get rid of any buffers that we have received, but not
708          * yet processed in the output_loop.
709          */
710         OMX_BUFFERHEADERTYPE *omx_buffer;
711         while ((omx_buffer = async_queue_pop_full (port->queue, FALSE, TRUE)))
712         {
713             omx_buffer->nFilledLen = 0;
714
715 #ifdef USE_OMXTICORE
716             if (omx_buffer->nFlags & OMX_TI_BUFFERFLAG_READONLY)
717             {
718                 /* For output buffer that is marked with READONLY, we
719                    cannot release until EventHandler OMX_TI_EventBufferRefCount
720                    come. So, reset the nFlags to be released later. */
721                 DEBUG (port, "During flush encounter ReadOnly buffer %p", omx_buffer);
722                 g_mutex_lock (port->core->omx_state_mutex);
723                 omx_buffer->nFlags &= ~OMX_TI_BUFFERFLAG_READONLY;
724                 g_mutex_unlock (port->core->omx_state_mutex);
725             }
726             else
727 #endif
728             {
729                 release_buffer (port, omx_buffer);
730             }
731         }
732     }
733
734     DEBUG (port, "SendCommand(Flush, %d)", port->port_index);
735     OMX_SendCommand (port->core->omx_handle, OMX_CommandFlush, port->port_index, NULL);
736     g_sem_down (port->core->flush_sem);
737     DEBUG (port, "end");
738 }
739
740 void
741 g_omx_port_enable (GOmxPort *port)
742 {
743     if (port->enabled)
744     {
745         DEBUG (port, "already enabled");
746         return;
747     }
748
749     DEBUG (port, "begin");
750
751     g_omx_port_prepare (port);
752
753     DEBUG (port, "SendCommand(PortEnable, %d)", port->port_index);
754     OMX_SendCommand (g_omx_core_get_handle (port->core),
755             OMX_CommandPortEnable, port->port_index, NULL);
756
757     g_omx_port_allocate_buffers (port);
758
759     g_sem_down (port->core->port_sem);
760
761     port->enabled = TRUE;
762
763     if (port->core->omx_state == OMX_StateExecuting)
764         g_omx_port_start_buffers (port);
765
766     DEBUG (port, "end");
767 }
768
769 void
770 g_omx_port_disable (GOmxPort *port)
771 {
772     if (!port->enabled)
773     {
774         DEBUG (port, "already disabled");
775         return;
776     }
777
778     DEBUG (port, "begin");
779
780     port->enabled = FALSE;
781
782     DEBUG (port, "SendCommand(PortDisable, %d)", port->port_index);
783     OMX_SendCommand (g_omx_core_get_handle (port->core),
784             OMX_CommandPortDisable, port->port_index, NULL);
785
786     g_omx_port_free_buffers (port);
787
788     g_sem_down (port->core->port_sem);
789
790     DEBUG (port, "end");
791 }
792
793 void
794 g_omx_port_finish (GOmxPort *port)
795 {
796     DEBUG (port, "finish");
797     port->enabled = FALSE;
798     async_queue_disable (port->queue);
799 }
800
801
802 /*
803  * Some domain specific port related utility functions:
804  */
805
806 /* keep this list in sync GSTOMX_ALL_FORMATS */
807 static gint32 all_fourcc[] = {
808         GST_MAKE_FOURCC ('N','V','1','2'),
809         GST_MAKE_FOURCC ('I','4','2','0'),
810         GST_MAKE_FOURCC ('Y','U','Y','2'),
811         GST_MAKE_FOURCC ('U','Y','V','Y'),
812 };
813
814 #ifndef DIM  /* XXX is there a better alternative available? */
815 #  define DIM(x) (sizeof(x)/sizeof((x)[0]))
816 #endif
817
818 /**
819  * A utility function to query the port for supported color formats, and
820  * add the appropriate list of formats to @caps.  The @port can either
821  * be an input port for a video encoder, or an output port for a decoder
822  */
823 GstCaps *
824 g_omx_port_set_video_formats (GOmxPort *port, GstCaps *caps)
825 {
826     OMX_VIDEO_PARAM_PORTFORMATTYPE param;
827     int i,j;
828
829     G_OMX_PORT_GET_PARAM (port, OMX_IndexParamVideoPortFormat, &param);
830
831     caps = gst_caps_make_writable (caps);
832
833     for (i=0; i<gst_caps_get_size (caps); i++)
834     {
835         GstStructure *struc = gst_caps_get_structure (caps, i);
836         GValue formats = {0};
837
838         g_value_init (&formats, GST_TYPE_LIST);
839
840         for (j=0; j<DIM(all_fourcc); j++)
841         {
842             OMX_ERRORTYPE err;
843             GValue fourccval = {0};
844
845             g_value_init (&fourccval, GST_TYPE_FOURCC);
846
847             /* check and see if OMX supports the format:
848              */
849             param.eColorFormat = g_omx_fourcc_to_colorformat (all_fourcc[j]);
850             err = G_OMX_PORT_SET_PARAM (port, OMX_IndexParamVideoPortFormat, &param);
851
852             if( err == OMX_ErrorIncorrectStateOperation )
853             {
854                 DEBUG (port, "already executing?");
855
856                 /* if we are already executing, such as might be the case if
857                  * we get a OMX_EventPortSettingsChanged event, just take the
858                  * current format and bail:
859                  */
860                 G_OMX_PORT_GET_PARAM (port, OMX_IndexParamVideoPortFormat, &param);
861                 gst_value_set_fourcc (&fourccval,
862                         g_omx_colorformat_to_fourcc (param.eColorFormat));
863                 gst_value_list_append_value (&formats, &fourccval);
864                 break;
865             }
866             else if( err == OMX_ErrorNone )
867             {
868                 gst_value_set_fourcc (&fourccval, all_fourcc[j]);
869                 gst_value_list_append_value (&formats, &fourccval);
870             }
871         }
872
873         gst_structure_set_value (struc, "format", &formats);
874     }
875
876     return caps;
877 }
878
879     /*For avoid repeated code needs to do only one function in order to configure
880     video and images caps strure, and also maybe adding RGB color format*/
881
882 static gint32 jpeg_fourcc[] = {
883         GST_MAKE_FOURCC ('U','Y','V','Y'),
884         GST_MAKE_FOURCC ('N','V','1','2')
885 };
886
887 /**
888  * A utility function to query the port for supported color formats, and
889  * add the appropriate list of formats to @caps.  The @port can either
890  * be an input port for a image encoder, or an output port for a decoder
891  */
892 GstCaps *
893 g_omx_port_set_image_formats (GOmxPort *port, GstCaps *caps)
894 {
895     //OMX_IMAGE_PARAM_PORTFORMATTYPE param;
896     int i,j;
897
898     //G_OMX_PORT_GET_PARAM (port, OMX_IndexParamImagePortFormat, &param);
899
900     caps = gst_caps_make_writable (caps);
901
902     for (i=0; i<gst_caps_get_size (caps); i++)
903     {
904         GstStructure *struc = gst_caps_get_structure (caps, i);
905         GValue formats = {0};
906
907         g_value_init (&formats, GST_TYPE_LIST);
908
909         for (j=0; j<DIM(jpeg_fourcc); j++)
910         {
911             //OMX_ERRORTYPE err;
912             GValue fourccval = {0};
913
914             g_value_init (&fourccval, GST_TYPE_FOURCC);
915
916         /* Got error from omx jpeg component , avoiding these lines by the moment till they support it*/
917 #if 0
918             /* check and see if OMX supports the format:
919              */
920             param.eColorFormat = g_omx_fourcc_to_colorformat (all_fourcc[j]);
921             err = G_OMX_PORT_SET_PARAM (port, OMX_IndexParamImagePortFormat, &param);
922
923             if( err == OMX_ErrorIncorrectStateOperation )
924             {
925                 DEBUG (port, "already executing?");
926
927                 /* if we are already executing, such as might be the case if
928                  * we get a OMX_EventPortSettingsChanged event, just take the
929                  * current format and bail:
930                  */
931                 G_OMX_PORT_GET_PARAM (port, OMX_IndexParamImagePortFormat, &param);
932                 gst_value_set_fourcc (&fourccval,
933                         g_omx_colorformat_to_fourcc (param.eColorFormat));
934                 gst_value_list_append_value (&formats, &fourccval);
935                 break;
936             }
937             else if( err == OMX_ErrorNone )
938             {
939                 gst_value_set_fourcc (&fourccval, all_fourcc[j]);
940                 gst_value_list_append_value (&formats, &fourccval);
941             }
942 #else
943             gst_value_set_fourcc (&fourccval, jpeg_fourcc[j]);
944             gst_value_list_append_value (&formats, &fourccval);
945 #endif
946         }
947
948         gst_structure_set_value (struc, "format", &formats);
949     }
950
951     return caps;
952 }
953