videoconvert: make a constant of scale factor
[platform/upstream/gstreamer.git] / gst / encoding / gststreamcombiner.c
1 /* GStreamer Stream Combiner
2  * Copyright (C) 2010 Edward Hervey <edward.hervey@collabora.co.uk>
3  *           (C) 2009 Nokia Corporation
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include "gststreamcombiner.h"
26
27 static GstStaticPadTemplate src_template =
28 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
29     GST_STATIC_CAPS_ANY);
30
31 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink_%u",
32     GST_PAD_SINK,
33     GST_PAD_REQUEST,
34     GST_STATIC_CAPS_ANY);
35
36 GST_DEBUG_CATEGORY_STATIC (gst_stream_combiner_debug);
37 #define GST_CAT_DEFAULT gst_stream_combiner_debug
38
39 G_DEFINE_TYPE (GstStreamCombiner, gst_stream_combiner, GST_TYPE_ELEMENT);
40
41 #define STREAMS_LOCK(obj) (g_mutex_lock(&obj->lock))
42 #define STREAMS_UNLOCK(obj) (g_mutex_unlock(&obj->lock))
43
44 static void gst_stream_combiner_finalize (GObject * object);
45
46 static GstPad *gst_stream_combiner_request_new_pad (GstElement * element,
47     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
48 static void gst_stream_combiner_release_pad (GstElement * element,
49     GstPad * pad);
50
51 static void
52 gst_stream_combiner_class_init (GstStreamCombinerClass * klass)
53 {
54   GObjectClass *gobject_klass;
55   GstElementClass *gstelement_klass;
56
57   gobject_klass = (GObjectClass *) klass;
58   gstelement_klass = (GstElementClass *) klass;
59
60   gobject_klass->finalize = gst_stream_combiner_finalize;
61
62   GST_DEBUG_CATEGORY_INIT (gst_stream_combiner_debug, "streamcombiner", 0,
63       "Stream Combiner");
64
65   gst_element_class_add_pad_template (gstelement_klass,
66       gst_static_pad_template_get (&src_template));
67   gst_element_class_add_pad_template (gstelement_klass,
68       gst_static_pad_template_get (&sink_template));
69
70   gstelement_klass->request_new_pad =
71       GST_DEBUG_FUNCPTR (gst_stream_combiner_request_new_pad);
72   gstelement_klass->release_pad =
73       GST_DEBUG_FUNCPTR (gst_stream_combiner_release_pad);
74
75   gst_element_class_set_static_metadata (gstelement_klass,
76       "streamcombiner", "Generic",
77       "Recombines streams splitted by the streamsplitter element",
78       "Edward Hervey <edward.hervey@collabora.co.uk>");
79 }
80
81 static void
82 gst_stream_combiner_finalize (GObject * object)
83 {
84   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) object;
85
86   g_mutex_clear (&stream_combiner->lock);
87
88   G_OBJECT_CLASS (gst_stream_combiner_parent_class)->finalize (object);
89 }
90
91 static GstFlowReturn
92 gst_stream_combiner_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
93 {
94   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
95   /* FIXME : IMPLEMENT */
96
97   /* with lock taken, check if we're the active stream, if not drop */
98   return gst_pad_push (stream_combiner->srcpad, buf);
99 }
100
101 static gboolean
102 gst_stream_combiner_sink_event (GstPad * pad, GstObject * parent,
103     GstEvent * event)
104 {
105   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
106   /* FIXME : IMPLEMENT */
107
108   GST_DEBUG_OBJECT (pad, "Got event %s", GST_EVENT_TYPE_NAME (event));
109
110   switch (GST_EVENT_TYPE (event)) {
111     case GST_EVENT_CUSTOM_DOWNSTREAM:
112       if (gst_event_has_name (event, "stream-switching-eos")) {
113         gst_event_unref (event);
114         event = gst_event_new_eos ();
115       }
116       break;
117     default:
118       break;
119   }
120
121   /* SEGMENT : lock, wait for other stream to EOS, select stream, unlock, push */
122   /* EOS : lock, mark pad as unused, unlock , drop event */
123   /* CUSTOM_REAL_EOS : push EOS downstream */
124   /* FLUSH_START : lock, mark as flushing, unlock. if wasn't flushing forward */
125   /* FLUSH_STOP : lock, unmark as flushing, unlock, if was flushing forward */
126   /* OTHER : if selected pad forward */
127   return gst_pad_push_event (stream_combiner->srcpad, event);
128 }
129
130 static gboolean
131 gst_stream_combiner_sink_query (GstPad * pad, GstObject * parent,
132     GstQuery * query)
133 {
134   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
135
136   return gst_pad_peer_query (stream_combiner->srcpad, query);
137 }
138
139 static gboolean
140 gst_stream_combiner_src_event (GstPad * pad, GstObject * parent,
141     GstEvent * event)
142 {
143   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
144   GstPad *sinkpad = NULL;
145
146   STREAMS_LOCK (stream_combiner);
147   if (stream_combiner->current)
148     sinkpad = stream_combiner->current;
149   else if (stream_combiner->sinkpads)
150     sinkpad = (GstPad *) stream_combiner->sinkpads->data;
151   STREAMS_UNLOCK (stream_combiner);
152
153   if (sinkpad)
154     /* Forward upstream as is */
155     return gst_pad_push_event (sinkpad, event);
156
157   return FALSE;
158 }
159
160 static gboolean
161 gst_stream_combiner_src_query (GstPad * pad, GstObject * parent,
162     GstQuery * query)
163 {
164   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) parent;
165   GstPad *sinkpad = NULL;
166   gboolean ret = FALSE;
167
168   switch (GST_QUERY_TYPE (query)) {
169     case GST_QUERY_CAPS:
170       ret = gst_pad_query_default (pad, parent, query);
171       break;
172     default:
173       STREAMS_LOCK (stream_combiner);
174       if (stream_combiner->current)
175         sinkpad = stream_combiner->current;
176       else if (stream_combiner->sinkpads)
177         sinkpad = (GstPad *) stream_combiner->sinkpads->data;
178       STREAMS_UNLOCK (stream_combiner);
179
180       if (sinkpad)
181         /* Forward upstream as is */
182         ret = gst_pad_peer_query (sinkpad, query);
183       break;
184   }
185   return ret;
186 }
187
188 static void
189 gst_stream_combiner_init (GstStreamCombiner * stream_combiner)
190 {
191   stream_combiner->srcpad =
192       gst_pad_new_from_static_template (&src_template, "src");
193   gst_pad_set_event_function (stream_combiner->srcpad,
194       gst_stream_combiner_src_event);
195   gst_pad_set_query_function (stream_combiner->srcpad,
196       gst_stream_combiner_src_query);
197   gst_element_add_pad (GST_ELEMENT (stream_combiner), stream_combiner->srcpad);
198
199   g_mutex_init (&stream_combiner->lock);
200 }
201
202 static GstPad *
203 gst_stream_combiner_request_new_pad (GstElement * element,
204     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
205 {
206   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) element;
207   GstPad *sinkpad;
208
209   GST_DEBUG_OBJECT (element, "templ:%p, name:%s", templ, name);
210
211   sinkpad = gst_pad_new_from_static_template (&sink_template, name);
212   gst_pad_set_chain_function (sinkpad, gst_stream_combiner_chain);
213   gst_pad_set_event_function (sinkpad, gst_stream_combiner_sink_event);
214   gst_pad_set_query_function (sinkpad, gst_stream_combiner_sink_query);
215
216   STREAMS_LOCK (stream_combiner);
217   stream_combiner->sinkpads =
218       g_list_append (stream_combiner->sinkpads, sinkpad);
219   gst_pad_set_active (sinkpad, TRUE);
220   gst_element_add_pad (element, sinkpad);
221   stream_combiner->cookie++;
222   STREAMS_UNLOCK (stream_combiner);
223
224   GST_DEBUG_OBJECT (element, "Returning pad %p", sinkpad);
225
226   return sinkpad;
227 }
228
229 static void
230 gst_stream_combiner_release_pad (GstElement * element, GstPad * pad)
231 {
232   GstStreamCombiner *stream_combiner = (GstStreamCombiner *) element;
233   GList *tmp;
234
235   GST_DEBUG_OBJECT (element, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
236
237   STREAMS_LOCK (stream_combiner);
238   tmp = g_list_find (stream_combiner->sinkpads, pad);
239   if (tmp) {
240     GstPad *pad = (GstPad *) tmp->data;
241
242     stream_combiner->sinkpads =
243         g_list_delete_link (stream_combiner->sinkpads, tmp);
244     stream_combiner->cookie++;
245
246     if (pad == stream_combiner->current) {
247       /* Deactivate current flow */
248       GST_DEBUG_OBJECT (element, "Removed pad was the current one");
249       stream_combiner->current = NULL;
250     }
251     GST_DEBUG_OBJECT (element, "Removing pad from ourself");
252     gst_element_remove_pad (element, pad);
253   }
254   STREAMS_UNLOCK (stream_combiner);
255
256   return;
257 }