add blend mode tests
[swfdec.git] / swfdec / swfdec_codec_gst.c
blob4eef8d9311fa7078a77fd91dfcc9abc80893781a
1 /* Swfdec
2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23 #include <string.h>
24 #include <gst/pbutils/pbutils.h>
26 #include "swfdec_codec_gst.h"
27 #include "swfdec_debug.h"
28 #include "swfdec_internal.h"
30 /*** BUFFER ***/
32 GstBuffer *
33 swfdec_gst_buffer_new (SwfdecBuffer *buffer)
35 /* FIXME: make this a zero-copy operation */
36 GstBuffer *ret;
38 g_return_val_if_fail (buffer != NULL , NULL);
40 ret = gst_buffer_new_and_alloc (buffer->length);
41 memcpy (GST_BUFFER_DATA (ret), buffer->data, buffer->length);
42 swfdec_buffer_unref (buffer);
44 return ret;
47 /*** TYPEFINDING ***/
49 /* NB: try to mirror decodebin behavior */
50 static gboolean
51 swfdec_gst_feature_filter (GstPluginFeature *feature, gpointer caps)
53 const GList *walk;
54 const gchar *klass;
56 /* we only care about element factories */
57 if (!GST_IS_ELEMENT_FACTORY (feature))
58 return FALSE;
60 /* only decoders are interesting */
61 klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
62 if (strstr (klass, "Decoder") == NULL)
63 return FALSE;
65 /* only select elements with autoplugging rank */
66 if (gst_plugin_feature_get_rank (feature) < GST_RANK_MARGINAL)
67 return FALSE;
69 /* only care about the right sink caps */
70 for (walk = gst_element_factory_get_static_pad_templates (GST_ELEMENT_FACTORY (feature));
71 walk; walk = walk->next) {
72 GstStaticPadTemplate *template = walk->data;
73 GstCaps *intersect;
74 GstCaps *template_caps;
76 if (template->direction != GST_PAD_SINK)
77 continue;
79 template_caps = gst_static_caps_get (&template->static_caps);
80 intersect = gst_caps_intersect (caps, template_caps);
82 gst_caps_unref (template_caps);
83 if (gst_caps_is_empty (intersect)) {
84 gst_caps_unref (intersect);
85 } else {
86 gst_caps_unref (intersect);
87 return TRUE;
90 return FALSE;
93 static int
94 swfdec_gst_compare_features (gconstpointer a_, gconstpointer b_)
96 int diff;
97 GstPluginFeature *a = GST_PLUGIN_FEATURE (a_);
98 GstPluginFeature *b = GST_PLUGIN_FEATURE (b_);
100 diff = gst_plugin_feature_get_rank (b) - gst_plugin_feature_get_rank (a);
101 if (diff != 0)
102 return diff;
104 return strcmp (gst_plugin_feature_get_name (a), gst_plugin_feature_get_name (b));
107 GstElementFactory *
108 swfdec_gst_get_element_factory (GstCaps *caps)
110 GstElementFactory *ret;
111 GList *list;
113 list = gst_registry_feature_filter (gst_registry_get_default (),
114 swfdec_gst_feature_filter, FALSE, caps);
115 if (list == NULL)
116 return NULL;
118 list = g_list_sort (list, swfdec_gst_compare_features);
119 ret = list->data;
120 gst_object_ref (ret);
121 gst_plugin_feature_list_free (list);
122 return ret;
125 /*** PADS ***/
127 static GstPad *
128 swfdec_gst_connect_srcpad (GstElement *element, GstCaps *caps)
130 GstPadTemplate *tmpl;
131 GstPad *srcpad, *sinkpad;
133 sinkpad = gst_element_get_pad (element, "sink");
134 if (sinkpad == NULL)
135 return NULL;
136 gst_caps_ref (caps);
137 tmpl = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, caps);
138 srcpad = gst_pad_new_from_template (tmpl, "src");
139 g_object_unref (tmpl);
140 if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)
141 goto error;
143 gst_object_unref (sinkpad);
144 gst_pad_set_active (srcpad, TRUE);
145 return srcpad;
147 error:
148 SWFDEC_ERROR ("failed to create or link srcpad");
149 gst_object_unref (sinkpad);
150 gst_object_unref (srcpad);
151 return NULL;
154 static GstPad *
155 swfdec_gst_connect_sinkpad (GstElement *element, GstCaps *caps)
157 GstPadTemplate *tmpl;
158 GstPad *srcpad, *sinkpad;
160 srcpad = gst_element_get_pad (element, "src");
161 if (srcpad == NULL)
162 return NULL;
163 gst_caps_ref (caps);
164 tmpl = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, caps);
165 sinkpad = gst_pad_new_from_template (tmpl, "sink");
166 g_object_unref (tmpl);
167 if (gst_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK)
168 goto error;
170 gst_object_unref (srcpad);
171 gst_pad_set_active (sinkpad, TRUE);
172 return sinkpad;
174 error:
175 SWFDEC_ERROR ("failed to create or link sinkpad");
176 gst_object_unref (srcpad);
177 gst_object_unref (sinkpad);
178 return NULL;
181 /*** DECODER ***/
183 static GstFlowReturn
184 swfdec_gst_chain_func (GstPad *pad, GstBuffer *buffer)
186 GQueue *queue = g_object_get_data (G_OBJECT (pad), "swfdec-queue");
188 g_queue_push_tail (queue, buffer);
190 return GST_FLOW_OK;
193 gboolean
194 swfdec_gst_decoder_init (SwfdecGstDecoder *dec, GstCaps *srccaps, GstCaps *sinkcaps, ...)
196 va_list args;
197 GstElementFactory *factory;
198 GstElement *decoder;
199 const char *name;
201 /* create decoder */
202 factory = swfdec_gst_get_element_factory (srccaps);
203 dec->bin = gst_bin_new ("bin");
204 if (factory) {
205 decoder = gst_element_factory_create (factory, "decoder");
206 gst_object_unref (factory);
207 } else {
208 decoder = NULL;
210 if (decoder == NULL) {
211 SWFDEC_ERROR ("failed to create decoder");
212 return FALSE;
214 gst_bin_add (GST_BIN (dec->bin), decoder);
215 dec->src = swfdec_gst_connect_srcpad (decoder, srccaps);
216 if (dec->src == NULL)
217 return FALSE;
219 /* plug transform elements */
220 va_start (args, sinkcaps);
221 while ((name = va_arg (args, const char *))) {
222 GstElement *next = gst_element_factory_make (name, NULL);
223 if (next == NULL) {
224 SWFDEC_ERROR ("failed to create '%s' element", name);
225 return FALSE;
227 gst_bin_add (GST_BIN (dec->bin), next);
228 if (!gst_element_link (decoder, next)) {
229 SWFDEC_ERROR ("failed to link '%s' element to decoder", name);
230 return FALSE;
232 decoder = next;
234 va_end (args);
235 dec->sink = swfdec_gst_connect_sinkpad (decoder, sinkcaps);
236 if (dec->sink == NULL)
237 return FALSE;
238 gst_pad_set_chain_function (dec->sink, swfdec_gst_chain_func);
239 dec->queue = g_queue_new ();
240 g_object_set_data (G_OBJECT (dec->sink), "swfdec-queue", dec->queue);
241 if (!gst_element_set_state (dec->bin, GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS) {
242 SWFDEC_ERROR ("could not change element state");
243 return FALSE;
245 return TRUE;
248 void
249 swfdec_gst_decoder_finish (SwfdecGstDecoder *dec)
251 if (dec->bin) {
252 gst_element_set_state (dec->bin, GST_STATE_NULL);
253 g_object_unref (dec->bin);
254 dec->bin = NULL;
256 if (dec->src) {
257 g_object_unref (dec->src);
258 dec->src = NULL;
260 if (dec->sink) {
261 g_object_unref (dec->sink);
262 dec->sink = NULL;
264 if (dec->queue) {
265 GstBuffer *buffer;
266 while ((buffer = g_queue_pop_head (dec->queue)) != NULL) {
267 gst_buffer_unref (buffer);
269 g_queue_free (dec->queue);
270 dec->queue = NULL;
274 void
275 swfdec_gst_decoder_set_codec_data (SwfdecGstDecoder *dec,
276 GstBuffer *buffer)
278 GstCaps *caps;
280 caps = gst_pad_get_caps (dec->src);
281 caps = gst_caps_make_writable (caps);
282 if (buffer) {
283 gst_caps_set_simple (caps, "codec_data", GST_TYPE_BUFFER, buffer, NULL);
284 } else {
285 GstStructure *structure = gst_caps_get_structure (caps, 0);
286 gst_structure_remove_field (structure, "codec_data");
288 gst_pad_set_caps (dec->src, caps);
289 gst_caps_unref (caps);
292 gboolean
293 swfdec_gst_decoder_push (SwfdecGstDecoder *dec, GstBuffer *buffer)
295 GstFlowReturn ret;
296 GstCaps *caps;
298 /* set caps if none set yet */
299 caps = gst_buffer_get_caps (buffer);
300 if (caps) {
301 gst_caps_unref (caps);
302 } else {
303 caps = GST_PAD_CAPS (dec->src);
304 if (caps == NULL) {
305 caps = (GstCaps *) gst_pad_get_pad_template_caps (dec->src);
306 g_assert (gst_caps_is_fixed (caps));
307 gst_pad_set_caps (dec->src, caps);
309 gst_buffer_set_caps (buffer, GST_PAD_CAPS (dec->src));
312 ret = gst_pad_push (dec->src, buffer);
313 if (GST_FLOW_IS_SUCCESS (ret))
314 return TRUE;
315 SWFDEC_ERROR ("error %d pushing data", (int) ret);
316 return FALSE;
319 void
320 swfdec_gst_decoder_push_eos (SwfdecGstDecoder *dec)
322 gst_pad_push_event (dec->src, gst_event_new_eos ());
325 GstBuffer *
326 swfdec_gst_decoder_pull (SwfdecGstDecoder *dec)
328 return g_queue_pop_head (dec->queue);