base_filter: flush when switching to pause
[gstreamer-omap:gst-openmax.git] / omx / gstomx_base_filter.c
1 /*
2  * Copyright (C) 2007-2009 Nokia Corporation.
3  *
4  * Author: Felipe Contreras <felipe.contreras@nokia.com>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation
9  * version 2.1 of the License.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include "gstomx_base_filter.h"
23 #include "gstomx.h"
24 #include "gstomx_interface.h"
25
26 enum
27 {
28     ARG_0,
29     ARG_COMPONENT_ROLE,
30     ARG_COMPONENT_NAME,
31     ARG_LIBRARY_NAME,
32     ARG_USE_TIMESTAMPS,
33     ARG_NUM_INPUT_BUFFERS,
34     ARG_NUM_OUTPUT_BUFFERS,
35 };
36
37 static void init_interfaces (GType type);
38 GSTOMX_BOILERPLATE_FULL (GstOmxBaseFilter, gst_omx_base_filter, GstElement, GST_TYPE_ELEMENT, init_interfaces);
39
40
41 static GstFlowReturn push_buffer (GstOmxBaseFilter *self, GstBuffer *buf);
42 static GstFlowReturn pad_chain (GstPad *pad, GstBuffer *buf);
43 static gboolean pad_event (GstPad *pad, GstEvent *event);
44
45
46 static void
47 setup_ports (GstOmxBaseFilter *self)
48 {
49     OMX_PARAM_PORTDEFINITIONTYPE param;
50
51     /* Input port configuration. */
52
53     G_OMX_PORT_GET_DEFINITION (self->in_port, &param);
54     g_omx_port_setup (self->in_port, &param);
55     gst_pad_set_element_private (self->sinkpad, self->in_port);
56
57     /* Output port configuration. */
58
59     G_OMX_PORT_GET_DEFINITION (self->out_port, &param);
60     g_omx_port_setup (self->out_port, &param);
61     gst_pad_set_element_private (self->srcpad, self->out_port);
62
63     if (g_getenv ("OMX_ALLOCATE_ON"))
64     {
65         GST_DEBUG_OBJECT (self, "OMX_ALLOCATE_ON");
66         self->in_port->omx_allocate = TRUE;
67         self->out_port->omx_allocate = TRUE;
68         self->in_port->share_buffer = FALSE;
69         self->out_port->share_buffer = FALSE;
70     }
71     else if (g_getenv ("OMX_SHARE_HACK_ON"))
72     {
73         GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_ON");
74         self->in_port->share_buffer = TRUE;
75         self->out_port->share_buffer = TRUE;
76     }
77     else if (g_getenv ("OMX_SHARE_HACK_OFF"))
78     {
79         GST_DEBUG_OBJECT (self, "OMX_SHARE_HACK_OFF");
80         self->in_port->share_buffer = FALSE;
81         self->out_port->share_buffer = FALSE;
82     }
83
84     GST_DEBUG_OBJECT (self, "in_port->omx_allocate=%d, out_port->omx_allocate=%d",
85             self->in_port->omx_allocate, self->out_port->omx_allocate);
86     GST_DEBUG_OBJECT (self, "in_port->share_buffer=%d, out_port->share_buffer=%d",
87             self->in_port->share_buffer, self->out_port->share_buffer);
88 }
89
90 static void
91 inject_codec_data (GstOmxBaseFilter * self)
92 {
93     /* send buffer with codec data flag */
94     if (self->codec_data)
95     {
96         GST_BUFFER_FLAG_SET (self->codec_data, GST_BUFFER_FLAG_IN_CAPS);  /* just in case */
97         g_omx_port_send (self->in_port, self->codec_data);
98     }
99 }
100
101 static GstStateChangeReturn
102 change_state (GstElement *element,
103               GstStateChange transition)
104 {
105     GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
106     GstOmxBaseFilter *self;
107     GOmxCore *core;
108
109     self = GST_OMX_BASE_FILTER (element);
110     core = self->gomx;
111
112     GST_INFO_OBJECT (self, "begin: changing state %s -> %s",
113                      gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
114                      gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
115
116     switch (transition)
117     {
118         case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
119             g_mutex_lock (self->ready_lock);
120             if (self->ready)
121             {
122                 g_omx_core_flush_start (core);
123                 g_omx_core_flush_stop (core);
124             }
125             g_mutex_unlock (self->ready_lock);
126             break;
127         case GST_STATE_CHANGE_NULL_TO_READY:
128             g_omx_core_init (core);
129             if (core->omx_state != OMX_StateLoaded)
130             {
131                 ret = GST_STATE_CHANGE_FAILURE;
132                 goto leave;
133             }
134             break;
135         case GST_STATE_CHANGE_READY_TO_PAUSED:
136             self->in_port->enabled = TRUE;
137             g_omx_port_resume (self->in_port);
138             self->out_port->enabled = TRUE;
139             g_omx_port_resume (self->out_port);
140             break;            
141         default:
142             break;
143     }
144
145     ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
146
147     if (ret == GST_STATE_CHANGE_FAILURE)
148         goto leave;
149
150     switch (transition)
151     {
152         case GST_STATE_CHANGE_PAUSED_TO_READY:
153             g_mutex_lock (self->ready_lock);
154             if (self->ready)
155             {
156                 /* unlock */
157                 g_omx_port_finish (self->in_port);
158                 g_omx_port_finish (self->out_port);
159
160                 g_omx_core_stop (core);
161                 g_omx_core_unload (core);
162                 self->ready = FALSE;
163             }
164             g_mutex_unlock (self->ready_lock);
165             if (core->omx_state != OMX_StateLoaded &&
166                 core->omx_state != OMX_StateInvalid)
167             {
168                 ret = GST_STATE_CHANGE_FAILURE;
169                 goto leave;
170             }
171             break;
172
173         case GST_STATE_CHANGE_READY_TO_NULL:
174         {
175             gboolean in_allocate, in_share, out_allocate, out_share;
176             GstBuffer * (*out_alloc)(GOmxPort *port, gint len);
177
178             /* g_omx_core_deinit deallocates ports, so we need to save and
179              * restore state */
180             in_allocate = self->in_port->omx_allocate;
181             in_share = self->in_port->share_buffer;
182             out_allocate = self->out_port->omx_allocate;
183             out_share = self->out_port->share_buffer;
184             out_alloc = self->out_port->buffer_alloc;
185
186             g_omx_core_deinit (core);
187
188             self->in_port = g_omx_core_get_port (self->gomx, "in", 0);
189             self->in_port->omx_allocate = in_allocate;
190             self->in_port->share_buffer = in_share;
191
192             self->out_port = g_omx_core_get_port (self->gomx, "out", 1);
193             self->out_port->omx_allocate = out_allocate;
194             self->out_port->share_buffer = out_share;
195             self->out_port->buffer_alloc = out_alloc;
196
197             break;
198         }
199
200         default:
201             break;
202     }
203
204 leave:
205     GST_LOG_OBJECT (self, "end");
206
207     return ret;
208 }
209
210 static void
211 finalize (GObject *obj)
212 {
213     GstOmxBaseFilter *self;
214
215     self = GST_OMX_BASE_FILTER (obj);
216
217     if (self->codec_data)
218     {
219         gst_buffer_unref (self->codec_data);
220         self->codec_data = NULL;
221     }
222
223     g_omx_core_free (self->gomx);
224
225     g_free (self->omx_role);
226     g_free (self->omx_component);
227     g_free (self->omx_library);
228
229     g_mutex_free (self->ready_lock);
230
231     G_OBJECT_CLASS (parent_class)->finalize (obj);
232 }
233
234 static void
235 set_property (GObject *obj,
236               guint prop_id,
237               const GValue *value,
238               GParamSpec *pspec)
239 {
240     GstOmxBaseFilter *self;
241
242     self = GST_OMX_BASE_FILTER (obj);
243
244     switch (prop_id)
245     {
246         case ARG_COMPONENT_ROLE:
247             g_free (self->omx_role);
248             self->omx_role = g_value_dup_string (value);
249             break;
250         case ARG_COMPONENT_NAME:
251             g_free (self->omx_component);
252             self->omx_component = g_value_dup_string (value);
253             break;
254         case ARG_LIBRARY_NAME:
255             g_free (self->omx_library);
256             self->omx_library = g_value_dup_string (value);
257             break;
258         case ARG_USE_TIMESTAMPS:
259             self->gomx->use_timestamps = g_value_get_boolean (value);
260             break;
261         case ARG_NUM_INPUT_BUFFERS:
262         case ARG_NUM_OUTPUT_BUFFERS:
263             {
264                 OMX_PARAM_PORTDEFINITIONTYPE param;
265                 OMX_U32 nBufferCountActual = g_value_get_uint (value);
266                 GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
267                         self->in_port : self->out_port;
268
269                 G_OMX_PORT_GET_DEFINITION (port, &param);
270
271                 g_return_if_fail (nBufferCountActual >= param.nBufferCountMin);
272                 param.nBufferCountActual = nBufferCountActual;
273
274                 G_OMX_PORT_SET_DEFINITION (port, &param);
275             }
276             break;
277         default:
278             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
279             break;
280     }
281 }
282
283 static void
284 get_property (GObject *obj,
285               guint prop_id,
286               GValue *value,
287               GParamSpec *pspec)
288 {
289     GstOmxBaseFilter *self;
290
291     self = GST_OMX_BASE_FILTER (obj);
292
293     switch (prop_id)
294     {
295         case ARG_COMPONENT_ROLE:
296             g_value_set_string (value, self->omx_role);
297             break;
298         case ARG_COMPONENT_NAME:
299             g_value_set_string (value, self->omx_component);
300             break;
301         case ARG_LIBRARY_NAME:
302             g_value_set_string (value, self->omx_library);
303             break;
304         case ARG_USE_TIMESTAMPS:
305             g_value_set_boolean (value, self->gomx->use_timestamps);
306             break;
307         case ARG_NUM_INPUT_BUFFERS:
308         case ARG_NUM_OUTPUT_BUFFERS:
309             {
310                 OMX_PARAM_PORTDEFINITIONTYPE param;
311                 GOmxPort *port = (prop_id == ARG_NUM_INPUT_BUFFERS) ?
312                         self->in_port : self->out_port;
313
314                 G_OMX_PORT_GET_DEFINITION (port, &param);
315
316                 g_value_set_uint (value, param.nBufferCountActual);
317             }
318             break;
319         default:
320             G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
321             break;
322     }
323 }
324
325 static void
326 type_base_init (gpointer g_class)
327 {
328 }
329
330 static void
331 type_class_init (gpointer g_class,
332                  gpointer class_data)
333 {
334     GObjectClass *gobject_class;
335     GstElementClass *gstelement_class;
336     GstOmxBaseFilterClass *bclass;
337
338     gobject_class = G_OBJECT_CLASS (g_class);
339     gstelement_class = GST_ELEMENT_CLASS (g_class);
340     bclass = GST_OMX_BASE_FILTER_CLASS (g_class);
341
342     gobject_class->finalize = finalize;
343     gstelement_class->change_state = change_state;
344     bclass->push_buffer = push_buffer;
345     bclass->pad_chain = pad_chain;
346     bclass->pad_event = pad_event;
347
348     /* Properties stuff */
349     {
350         gobject_class->set_property = set_property;
351         gobject_class->get_property = get_property;
352
353         g_object_class_install_property (gobject_class, ARG_COMPONENT_ROLE,
354                                          g_param_spec_string ("component-role", "Component role",
355                                                               "Role of the OpenMAX IL component",
356                                                               NULL, G_PARAM_READWRITE));
357
358         g_object_class_install_property (gobject_class, ARG_COMPONENT_NAME,
359                                          g_param_spec_string ("component-name", "Component name",
360                                                               "Name of the OpenMAX IL component to use",
361                                                               NULL, G_PARAM_READWRITE));
362
363         g_object_class_install_property (gobject_class, ARG_LIBRARY_NAME,
364                                          g_param_spec_string ("library-name", "Library name",
365                                                               "Name of the OpenMAX IL implementation library to use",
366                                                               NULL, G_PARAM_READWRITE));
367
368         g_object_class_install_property (gobject_class, ARG_USE_TIMESTAMPS,
369                                          g_param_spec_boolean ("use-timestamps", "Use timestamps",
370                                                                "Whether or not to use timestamps",
371                                                                TRUE, G_PARAM_READWRITE));
372
373         /* note: the default values for these are just a guess.. since we wouldn't know
374          * until the OMX component is constructed.  But that is ok, these properties are
375          * only for debugging
376          */
377         g_object_class_install_property (gobject_class, ARG_NUM_INPUT_BUFFERS,
378                                          g_param_spec_uint ("input-buffers", "Input buffers",
379                                                             "The number of OMX input buffers",
380                                                             1, 10, 4, G_PARAM_READWRITE));
381         g_object_class_install_property (gobject_class, ARG_NUM_OUTPUT_BUFFERS,
382                                          g_param_spec_uint ("output-buffers", "Output buffers",
383                                                             "The number of OMX output buffers",
384                                                             1, 10, 4, G_PARAM_READWRITE));
385     }
386 }
387
388 static GstFlowReturn
389 push_buffer (GstOmxBaseFilter *self,
390              GstBuffer *buf)
391 {
392     GstFlowReturn ret;
393
394     GST_BUFFER_DURATION (buf) = self->duration;
395
396     PRINT_BUFFER (self, buf);
397
398     /** @todo check if tainted */
399     GST_LOG_OBJECT (self, "begin");
400     ret = gst_pad_push (self->srcpad, buf);
401     GST_LOG_OBJECT (self, "end");
402
403     return ret;
404 }
405
406 static void
407 output_loop (gpointer data)
408 {
409     GstPad *pad;
410     GOmxCore *gomx;
411     GOmxPort *out_port;
412     GstOmxBaseFilter *self;
413     GstFlowReturn ret = GST_FLOW_OK;
414     GstOmxBaseFilterClass *bclass;
415
416     pad = data;
417     self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
418     gomx = self->gomx;
419
420     bclass = GST_OMX_BASE_FILTER_GET_CLASS (self);
421
422     GST_LOG_OBJECT (self, "begin");
423
424     if (!self->ready)
425     {
426         g_error ("not ready");
427         return;
428     }
429
430     out_port = self->out_port;
431
432     if (G_LIKELY (out_port->enabled))
433     {
434         gpointer obj = g_omx_port_recv (out_port);
435
436         if (G_UNLIKELY (!obj))
437         {
438             GST_WARNING_OBJECT (self, "null buffer: leaving");
439             ret = GST_FLOW_WRONG_STATE;
440             goto leave;
441         }
442
443         if (G_LIKELY (GST_IS_BUFFER (obj)))
444         {
445             if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (obj, GST_BUFFER_FLAG_IN_CAPS)))
446             {
447                 GstCaps *caps = NULL;
448                 GstStructure *structure;
449                 GValue value = { 0 };
450
451                 caps = gst_pad_get_negotiated_caps (self->srcpad);
452                 caps = gst_caps_make_writable (caps);
453                 structure = gst_caps_get_structure (caps, 0);
454
455                 g_value_init (&value, GST_TYPE_BUFFER);
456                 gst_value_set_buffer (&value, obj);
457                 gst_buffer_unref (obj);
458                 gst_structure_set_value (structure, "codec_data", &value);
459                 g_value_unset (&value);
460
461                 gst_pad_set_caps (self->srcpad, caps);
462             }
463             else
464             {
465                 GstBuffer *buf = GST_BUFFER (obj);
466                 ret = bclass->push_buffer (self, buf);
467                 GST_DEBUG_OBJECT (self, "ret=%s", gst_flow_get_name (ret));
468             }
469         }
470         else if (GST_IS_EVENT (obj))
471         {
472             GST_DEBUG_OBJECT (self, "got eos");
473             gst_pad_push_event (self->srcpad, obj);
474             ret = GST_FLOW_UNEXPECTED;
475             goto leave;
476         }
477
478     }
479
480 leave:
481
482     self->last_pad_push_return = ret;
483
484     if (gomx->omx_error != OMX_ErrorNone)
485     {
486         GST_DEBUG_OBJECT (self, "omx_error=%s", g_omx_error_to_str (gomx->omx_error));
487         ret = GST_FLOW_ERROR;
488     }
489
490     if (ret != GST_FLOW_OK)
491     {
492         GST_INFO_OBJECT (self, "pause task, reason:  %s",
493                          gst_flow_get_name (ret));
494         gst_pad_pause_task (self->srcpad);
495     }
496
497     GST_LOG_OBJECT (self, "end");
498
499     gst_object_unref (self);
500 }
501
502 static GstFlowReturn
503 pad_chain (GstPad *pad,
504            GstBuffer *buf)
505 {
506     GOmxCore *gomx;
507     GOmxPort *in_port;
508     GstOmxBaseFilter *self;
509     GstFlowReturn ret = GST_FLOW_OK;
510
511     self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
512
513     PRINT_BUFFER (self, buf);
514
515     gomx = self->gomx;
516
517     GST_LOG_OBJECT (self, "begin: size=%u, state=%d", GST_BUFFER_SIZE (buf), gomx->omx_state);
518
519     if (G_UNLIKELY (gomx->omx_state == OMX_StateLoaded))
520     {
521         g_mutex_lock (self->ready_lock);
522
523         GST_INFO_OBJECT (self, "omx: prepare");
524
525         /** @todo this should probably go after doing preparations. */
526         if (self->omx_setup)
527         {
528             self->omx_setup (self);
529         }
530
531         setup_ports (self);
532
533         g_omx_core_prepare (self->gomx);
534
535         if (gomx->omx_state == OMX_StateIdle)
536         {
537             self->ready = TRUE;
538             gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
539         }
540
541         g_mutex_unlock (self->ready_lock);
542
543         if (gomx->omx_state != OMX_StateIdle)
544             goto out_flushing;
545     }
546
547     in_port = self->in_port;
548
549     if (G_LIKELY (in_port->enabled))
550     {
551         if (G_UNLIKELY (gomx->omx_state == OMX_StateIdle))
552         {
553             GST_INFO_OBJECT (self, "omx: play");
554             g_omx_core_start (gomx);
555
556             if (gomx->omx_state != OMX_StateExecuting)
557                 goto out_flushing;
558
559             if (self->inject_codec_data)
560               self->inject_codec_data (self);
561         }
562
563         if (G_UNLIKELY (gomx->omx_state != OMX_StateExecuting))
564         {
565             GST_ERROR_OBJECT (self, "Whoa! very wrong");
566         }
567
568         while (TRUE)
569         {
570             gint sent;
571
572             if (self->last_pad_push_return != GST_FLOW_OK ||
573                 !(gomx->omx_state == OMX_StateExecuting ||
574                   gomx->omx_state == OMX_StatePause))
575             {
576                 GST_DEBUG_OBJECT (self, "last_pad_push_return=%d", self->last_pad_push_return);
577                 goto out_flushing;
578             }
579
580             sent = g_omx_port_send (in_port, buf);
581
582             if (G_UNLIKELY (sent < 0))
583             {
584                 ret = GST_FLOW_WRONG_STATE;
585                 goto out_flushing;
586             }
587             else if (sent < GST_BUFFER_SIZE (buf))
588             {
589                 GstBuffer *subbuf = gst_buffer_create_sub (buf, sent,
590                         GST_BUFFER_SIZE (buf) - sent);
591                 gst_buffer_unref (buf);
592                 buf = subbuf;
593             }
594             else
595             {
596                 gst_buffer_unref (buf);
597                 break;
598             }
599         }
600     }
601     else
602     {
603         GST_WARNING_OBJECT (self, "done");
604         ret = GST_FLOW_UNEXPECTED;
605     }
606
607 leave:
608
609     GST_LOG_OBJECT (self, "end");
610
611     return ret;
612
613     /* special conditions */
614 out_flushing:
615     {
616         const gchar *error_msg = NULL;
617
618         if (gomx->omx_error)
619         {
620             error_msg = "Error from OpenMAX component";
621         }
622         else if (gomx->omx_state != OMX_StateExecuting &&
623                  gomx->omx_state != OMX_StatePause)
624         {
625             error_msg = "OpenMAX component in wrong state";
626         }
627
628         if (error_msg)
629         {
630             GST_ELEMENT_ERROR (self, STREAM, FAILED, (NULL), (error_msg));
631             ret = GST_FLOW_ERROR;
632         }
633
634         gst_buffer_unref (buf);
635
636         goto leave;
637     }
638 }
639
640 static gboolean
641 pad_event (GstPad *pad,
642            GstEvent *event)
643 {
644     GstOmxBaseFilter *self;
645     GOmxCore *gomx;
646     gboolean ret = TRUE;
647
648     self = GST_OMX_BASE_FILTER (GST_OBJECT_PARENT (pad));
649     gomx = self->gomx;
650
651     GST_INFO_OBJECT (self, "begin: event=%s", GST_EVENT_TYPE_NAME (event));
652
653     switch (GST_EVENT_TYPE (event))
654     {
655         case GST_EVENT_EOS:
656             /* if we are init'ed, and there is a running loop; then
657              * if we get a buffer to inform it of EOS, let it handle the rest
658              * in any other case, we send EOS */
659             if (self->ready && self->last_pad_push_return == GST_FLOW_OK)
660             {
661                 if (g_omx_port_send (self->in_port, event) >= 0)
662                 {
663                     gst_event_unref (event);
664                     break;
665                 }
666             }
667
668             /* we tried, but it's up to us here */
669             ret = gst_pad_push_event (self->srcpad, event);
670             break;
671
672         case GST_EVENT_FLUSH_START:
673             gst_pad_push_event (self->srcpad, event);
674             self->last_pad_push_return = GST_FLOW_WRONG_STATE;
675
676             g_omx_core_flush_start (gomx);
677
678             gst_pad_pause_task (self->srcpad);
679
680             ret = TRUE;
681             break;
682
683         case GST_EVENT_FLUSH_STOP:
684             gst_pad_push_event (self->srcpad, event);
685             self->last_pad_push_return = GST_FLOW_OK;
686
687             g_omx_core_flush_stop (gomx);
688
689             if (self->ready)
690                 gst_pad_start_task (self->srcpad, output_loop, self->srcpad);
691
692             ret = TRUE;
693             break;
694
695         case GST_EVENT_NEWSEGMENT:
696             ret = gst_pad_push_event (self->srcpad, event);
697             break;
698
699         default:
700             ret = gst_pad_push_event (self->srcpad, event);
701             break;
702     }
703
704     GST_LOG_OBJECT (self, "end");
705
706     return ret;
707 }
708
709 static gboolean
710 activate_push (GstPad *pad,
711                gboolean active)
712 {
713     gboolean result = TRUE;
714     GstOmxBaseFilter *self;
715
716     self = GST_OMX_BASE_FILTER (gst_pad_get_parent (pad));
717
718     if (active)
719     {
720         GST_DEBUG_OBJECT (self, "activate");
721         self->last_pad_push_return = GST_FLOW_OK;
722
723         /* we do not start the task yet if the pad is not connected */
724         if (gst_pad_is_linked (pad))
725         {
726             if (self->ready)
727             {
728                 /** @todo link callback function also needed */
729                 g_omx_port_resume (self->in_port);
730                 g_omx_port_resume (self->out_port);
731
732                 result = gst_pad_start_task (pad, output_loop, pad);
733             }
734         }
735     }
736     else
737     {
738         GST_DEBUG_OBJECT (self, "deactivate");
739
740         if (self->ready)
741         {
742             /** @todo disable this until we properly reinitialize the buffers. */
743 #if 0
744             /* flush all buffers */
745             OMX_SendCommand (self->gomx->omx_handle, OMX_CommandFlush, OMX_ALL, NULL);
746 #endif
747
748             /* unlock loops */
749             g_omx_port_pause (self->in_port);
750             g_omx_port_pause (self->out_port);
751         }
752
753         /* make sure streaming finishes */
754         result = gst_pad_stop_task (pad);
755     }
756
757     gst_object_unref (self);
758
759     return result;
760 }
761
762 /**
763  * overrides the default buffer allocation for output port to allow
764  * pad_alloc'ing from the srcpad
765  */
766 static GstBuffer *
767 buffer_alloc (GOmxPort *port, gint len)
768 {
769     GstOmxBaseFilter *self = port->core->object;
770     GstBuffer *buf;
771     GstFlowReturn ret;
772
773 #if 1
774     /** @todo remove this check */
775     if (G_LIKELY (self->in_port->enabled))
776     {
777         GstCaps *caps = NULL;
778
779         caps = gst_pad_get_negotiated_caps (self->srcpad);
780
781         if (!caps)
782         {
783             /** @todo We shouldn't be doing this. */
784             GOmxCore *gomx = self->gomx;
785             GST_WARNING_OBJECT (self, "faking settings changed notification");
786             if (gomx->settings_changed_cb)
787                 gomx->settings_changed_cb (gomx);
788         }
789         else
790         {
791             GST_LOG_OBJECT (self, "caps already fixed: %" GST_PTR_FORMAT, caps);
792             gst_caps_unref (caps);
793         }
794     }
795 #endif
796
797     ret = gst_pad_alloc_buffer_and_set_caps (
798             self->srcpad, GST_BUFFER_OFFSET_NONE,
799             len, GST_PAD_CAPS (self->srcpad), &buf);
800
801     if (ret == GST_FLOW_OK) return buf;
802
803     return NULL;
804 }
805
806 static void
807 type_instance_init (GTypeInstance *instance,
808                     gpointer g_class)
809 {
810     GstOmxBaseFilter *self;
811     GstElementClass *element_class;
812     GstOmxBaseFilterClass *bclass;
813
814     element_class = GST_ELEMENT_CLASS (g_class);
815     bclass = GST_OMX_BASE_FILTER_CLASS (g_class);
816
817     self = GST_OMX_BASE_FILTER (instance);
818
819     GST_LOG_OBJECT (self, "begin");
820
821     /* GOmx */
822     self->gomx = g_omx_core_new (self, g_class);
823     self->in_port = g_omx_core_get_port (self->gomx, "in", 0);
824     self->out_port = g_omx_core_get_port (self->gomx, "out", 1);
825
826     self->out_port->buffer_alloc = buffer_alloc;
827
828     self->in_port->omx_allocate = TRUE;
829     self->out_port->omx_allocate = TRUE;
830     self->in_port->share_buffer = FALSE;
831     self->out_port->share_buffer = FALSE;
832
833     self->ready_lock = g_mutex_new ();
834
835     self->sinkpad =
836         gst_pad_new_from_template (gst_element_class_get_pad_template (element_class, "sink"), "sink");
837
838     gst_pad_set_chain_function (self->sinkpad, bclass->pad_chain);
839     gst_pad_set_event_function (self->sinkpad, bclass->pad_event);
840
841     self->srcpad =
842         gst_pad_new_from_template (gst_element_class_get_pad_template (element_class, "src"), "src");
843
844     gst_pad_set_activatepush_function (self->srcpad, activate_push);
845
846     gst_pad_use_fixed_caps (self->srcpad);
847
848     gst_element_add_pad (GST_ELEMENT (self), self->sinkpad);
849     gst_element_add_pad (GST_ELEMENT (self), self->srcpad);
850
851     self->duration = GST_CLOCK_TIME_NONE;
852     self->inject_codec_data = inject_codec_data;
853
854     GST_LOG_OBJECT (self, "end");
855 }
856
857 static void
858 omx_interface_init (GstImplementsInterfaceClass *klass)
859 {
860 }
861
862 static gboolean
863 interface_supported (GstImplementsInterface *iface,
864                      GType type)
865 {
866     g_assert (type == GST_TYPE_OMX);
867     return TRUE;
868 }
869
870 static void
871 interface_init (GstImplementsInterfaceClass *klass)
872 {
873     klass->supported = interface_supported;
874 }
875
876 static void
877 init_interfaces (GType type)
878 {
879     GInterfaceInfo *iface_info;
880     GInterfaceInfo *omx_info;
881
882
883     iface_info = g_new0 (GInterfaceInfo, 1);
884     iface_info->interface_init = (GInterfaceInitFunc) interface_init;
885
886     g_type_add_interface_static (type, GST_TYPE_IMPLEMENTS_INTERFACE, iface_info);
887     g_free (iface_info);
888
889     omx_info = g_new0 (GInterfaceInfo, 1);
890     omx_info->interface_init = (GInterfaceInitFunc) omx_interface_init;
891
892     g_type_add_interface_static (type, GST_TYPE_OMX, omx_info);
893     g_free (omx_info);
894 }
895