fix jsut committed crasher by rewriting startDrag action
[swfdec.git] / libswfdec / swfdec_codec_gst.c
blobc561bcb5a3d08dfbae083a85a77440a3fa71e3cd
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/gst.h>
26 #include "swfdec_codec_audio.h"
27 #include "swfdec_codec_video.h"
28 #include "swfdec_debug.h"
29 #include "swfdec_internal.h"
31 #if 0
32 #define swfdec_cond_wait(cond, mutex) G_STMT_START { \
33 g_print ("waiting at %s\n", G_STRLOC); \
34 g_cond_wait (cond, mutex); \
35 g_print (" done at %s\n", G_STRLOC); \
36 }G_STMT_END
37 #else
38 #define swfdec_cond_wait g_cond_wait
39 #endif
41 /*** AUDIO ***/
43 typedef struct _SwfdecGstAudio SwfdecGstAudio;
44 struct _SwfdecGstAudio {
45 SwfdecAudioDecoder decoder;
47 GMutex * mutex; /* mutex that blocks everything below */
48 GCond * cond; /* cond used to signal when stuff below changes */
49 volatile int refcount; /* refcount (d'oh) */
51 GstElement * pipeline; /* pipeline that is playing or NULL when done */
52 SwfdecBuffer * in; /* next input buffer or NULL */
53 SwfdecBufferQueue * out; /* all the stored output buffers */
54 GstCaps * srccaps; /* caps to set on buffers */
55 gboolean eof; /* we've pushed EOF */
56 gboolean done; /* TRUE after decoding stopped (error or EOF) */
59 static void
60 swfdec_gst_audio_unref (gpointer data, GObject *unused)
62 SwfdecGstAudio *player = data;
64 if (!g_atomic_int_dec_and_test (&player->refcount))
65 return;
66 g_cond_free (player->cond);
67 g_mutex_free (player->mutex);
68 gst_caps_unref (player->srccaps);
69 if (player->in)
70 swfdec_buffer_unref (player->in);
71 swfdec_buffer_queue_unref (player->out);
72 g_slice_free (SwfdecGstAudio, player);
75 static void
76 swfdec_audio_decoder_gst_free (SwfdecAudioDecoder *dec)
78 SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
79 GstElement *pipeline;
81 g_mutex_lock (player->mutex);
82 pipeline = player->pipeline;
83 player->pipeline = NULL;
84 g_cond_signal (player->cond);
85 g_mutex_unlock (player->mutex);
86 gst_element_set_state (pipeline, GST_STATE_NULL);
87 g_object_unref (pipeline);
89 swfdec_gst_audio_unref (player, NULL);
92 static void
93 swfdec_audio_decoder_gst_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
95 SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
97 g_mutex_lock (player->mutex);
98 g_return_if_fail (!player->eof);
99 while (player->in != NULL && !player->done) {
100 swfdec_cond_wait (player->cond, player->mutex);
102 if (buffer) {
103 player->in = buffer;
104 } else {
105 player->eof = TRUE;
107 g_cond_signal (player->cond);
108 g_mutex_unlock (player->mutex);
111 static SwfdecBuffer *
112 swfdec_audio_decoder_gst_pull (SwfdecAudioDecoder *dec)
114 SwfdecGstAudio *player = (SwfdecGstAudio *) dec;
115 SwfdecBuffer *buffer;
117 g_mutex_lock (player->mutex);
118 if (player->eof) {
119 while (!player->done)
120 swfdec_cond_wait (player->cond, player->mutex);
122 buffer = swfdec_buffer_queue_pull_buffer (player->out);
123 g_mutex_unlock (player->mutex);
124 return buffer;
127 static void
128 swfdec_audio_decoder_gst_fakesrc_handoff (GstElement *fakesrc, GstBuffer *buf,
129 GstPad *pad, SwfdecGstAudio *player)
131 g_mutex_lock (player->mutex);
132 while (player->pipeline != NULL && player->in == NULL && player->eof == FALSE)
133 swfdec_cond_wait (player->cond, player->mutex);
134 if (player->pipeline == NULL) {
135 g_mutex_unlock (player->mutex);
136 return;
138 if (player->eof) {
139 //doesn't work: g_object_set (fakesrc, "num-buffers", 1, NULL);
140 /* HACK: just tell everyone we're done, that'll probably lose data in the
141 * gst stream, since we can't properly push EOF, but that's life... */
142 player->done = TRUE;
144 if (player->in) {
145 buf->data = g_memdup (player->in->data, player->in->length);
146 buf->malloc_data = buf->data;
147 buf->size = player->in->length;
149 gst_buffer_set_caps (buf, player->srccaps);
150 player->in = NULL;
151 g_cond_signal (player->cond);
152 g_mutex_unlock (player->mutex);
155 static void
156 swfdec_audio_decoder_gst_fakesink_handoff (GstElement *fakesrc, GstBuffer *buf,
157 GstPad *pad, SwfdecGstAudio *player)
159 SwfdecBuffer *buffer;
161 g_mutex_lock (player->mutex);
163 while (player->pipeline == NULL && player->out != NULL)
164 swfdec_cond_wait (player->cond, player->mutex);
165 buffer = swfdec_buffer_new_for_data (
166 g_memdup (buf->data, buf->size), buf->size);
167 swfdec_buffer_queue_push (player->out, buffer);
168 g_cond_signal (player->cond);
169 g_mutex_unlock (player->mutex);
172 static void
173 swfdec_audio_decoder_gst_link (GstElement *src, GstPad *pad, GstElement *sink)
175 if (!gst_element_link (src, sink)) {
176 SWFDEC_ERROR ("no delayed link");
180 static GstBusSyncReply
181 swfdec_audio_decoder_gst_handle_bus (GstBus *bus, GstMessage *message, gpointer data)
183 SwfdecGstAudio *player = data;
185 switch (message->type) {
186 case GST_MESSAGE_EOS:
187 case GST_MESSAGE_ERROR:
188 g_mutex_lock (player->mutex);
189 g_cond_signal (player->cond);
190 player->done = TRUE;
191 g_mutex_unlock (player->mutex);
192 break;
193 default:
194 break;
196 return GST_BUS_PASS;
199 SwfdecAudioDecoder *
200 swfdec_audio_decoder_gst_new (SwfdecAudioFormat type, gboolean width, SwfdecAudioOut format)
202 SwfdecGstAudio *player;
203 GstElement *fakesrc, *fakesink, *decoder, *convert;
204 GstBus *bus;
205 GstCaps *caps;
207 if (!gst_init_check (NULL, NULL, NULL))
208 return NULL;
210 switch (type) {
211 case SWFDEC_AUDIO_FORMAT_MP3:
212 caps = gst_caps_from_string ("audio/mpeg, mpegversion=(int)1, layer=(int)3");
213 break;
214 default:
215 return NULL;
217 g_assert (caps);
219 player = g_slice_new0 (SwfdecGstAudio);
220 player->decoder.out_format = SWFDEC_AUDIO_OUT_STEREO_44100;
221 player->decoder.pull = swfdec_audio_decoder_gst_pull;
222 player->decoder.push = swfdec_audio_decoder_gst_push;
223 player->decoder.free = swfdec_audio_decoder_gst_free;
224 player->pipeline = gst_pipeline_new ("pipeline");
225 player->refcount = 1;
226 g_assert (player->pipeline);
227 bus = gst_element_get_bus (player->pipeline);
228 g_atomic_int_inc (&player->refcount);
229 g_object_weak_ref (G_OBJECT (bus), swfdec_gst_audio_unref, player);
230 gst_bus_set_sync_handler (bus, swfdec_audio_decoder_gst_handle_bus, player);
231 player->mutex = g_mutex_new ();
232 player->cond = g_cond_new ();
233 player->out = swfdec_buffer_queue_new ();
234 player->srccaps = caps;
235 fakesrc = gst_element_factory_make ("fakesrc", NULL);
236 if (fakesrc == NULL) {
237 SWFDEC_ERROR ("failed to create fakesrc");
238 swfdec_audio_decoder_gst_free (&player->decoder);
239 return NULL;
241 g_object_set (fakesrc, "signal-handoffs", TRUE,
242 "can-activate-pull", FALSE, NULL);
243 g_signal_connect (fakesrc, "handoff",
244 G_CALLBACK (swfdec_audio_decoder_gst_fakesrc_handoff), player);
245 g_atomic_int_inc (&player->refcount);
246 g_object_weak_ref (G_OBJECT (fakesrc), swfdec_gst_audio_unref, player);
247 gst_bin_add (GST_BIN (player->pipeline), fakesrc);
248 fakesink = gst_element_factory_make ("fakesink", NULL);
249 if (fakesink == NULL) {
250 SWFDEC_ERROR ("failed to create fakesink");
251 swfdec_audio_decoder_gst_free (&player->decoder);
252 return NULL;
254 g_object_set (fakesink, "signal-handoffs", TRUE, NULL);
255 g_signal_connect (fakesink, "handoff",
256 G_CALLBACK (swfdec_audio_decoder_gst_fakesink_handoff), player);
257 g_atomic_int_inc (&player->refcount);
258 g_object_weak_ref (G_OBJECT (fakesink), swfdec_gst_audio_unref, player);
259 gst_bin_add (GST_BIN (player->pipeline), fakesink);
260 decoder = gst_element_factory_make ("decodebin", NULL);
261 if (decoder == NULL) {
262 SWFDEC_ERROR ("failed to create decoder");
263 swfdec_audio_decoder_gst_free (&player->decoder);
264 return NULL;
266 gst_bin_add (GST_BIN (player->pipeline), decoder);
267 convert = gst_element_factory_make ("audioconvert", NULL);
268 if (convert == NULL) {
269 SWFDEC_ERROR ("failed to create audioconvert");
270 swfdec_audio_decoder_gst_free (&player->decoder);
271 return NULL;
273 gst_bin_add (GST_BIN (player->pipeline), convert);
274 g_signal_connect (decoder, "pad-added",
275 G_CALLBACK (swfdec_audio_decoder_gst_link), convert);
277 caps = gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, rate=44100, channels=2");
278 g_assert (caps);
279 if (!gst_element_link_filtered (fakesrc, decoder, player->srccaps) ||
280 !gst_element_link_filtered (convert, fakesink, caps)) {
281 SWFDEC_ERROR ("linking failed");
282 swfdec_audio_decoder_gst_free (&player->decoder);
283 return NULL;
285 gst_caps_unref (caps);
286 if (gst_element_set_state (player->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
287 SWFDEC_ERROR ("failed to change sate");
288 swfdec_audio_decoder_gst_free (&player->decoder);
289 return NULL;
292 return &player->decoder;
295 /*** VIDEO ***/
297 typedef struct _SwfdecGstVideo SwfdecGstVideo;
298 struct _SwfdecGstVideo {
299 SwfdecVideoDecoder decoder;
301 GMutex * mutex; /* mutex that blocks everything below */
302 GCond * cond; /* cond used to signal when stuff below changes */
303 volatile int refcount; /* refcount (d'oh) */
305 GstElement * pipeline; /* pipeline that is playing or NULL when done */
306 SwfdecBuffer * in; /* next input buffer or NULL */
307 SwfdecBuffer * out; /* available output or NULL */
308 int width; /* width of last output buffer */
309 int height; /* height of last output buffer */
310 GstCaps * srccaps; /* caps to set on buffers */
311 gboolean out_next; /* wether the pipeline expects input or output */
312 gboolean error; /* we're in an error state */
315 static void
316 swfdec_gst_video_unref (gpointer data, GObject *unused)
318 SwfdecGstVideo *player = data;
320 if (!g_atomic_int_dec_and_test (&player->refcount))
321 return;
322 g_cond_free (player->cond);
323 g_mutex_free (player->mutex);
324 gst_caps_unref (player->srccaps);
325 if (player->in)
326 swfdec_buffer_unref (player->in);
327 if (player->out)
328 swfdec_buffer_unref (player->out);
329 g_slice_free (SwfdecGstVideo, player);
332 static void
333 swfdec_video_decoder_gst_free (SwfdecVideoDecoder *dec)
335 SwfdecGstVideo *player = (SwfdecGstVideo *) dec;
336 GstElement *pipeline;
338 g_mutex_lock (player->mutex);
339 pipeline = player->pipeline;
340 player->pipeline = NULL;
341 g_cond_signal (player->cond);
342 g_mutex_unlock (player->mutex);
343 gst_element_set_state (pipeline, GST_STATE_NULL);
344 g_object_unref (pipeline);
346 swfdec_gst_video_unref (player, NULL);
349 static SwfdecBuffer *
350 swfdec_video_decoder_gst_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffer,
351 guint *width, guint *height, guint *rowstride)
353 SwfdecGstVideo *player = (SwfdecGstVideo *) dec;
355 g_mutex_lock (player->mutex);
356 while (player->in != NULL && !player->error) {
357 swfdec_cond_wait (player->cond, player->mutex);
359 player->in = buffer;
360 g_cond_signal (player->cond);
361 while (player->out == NULL && !player->error) {
362 swfdec_cond_wait (player->cond, player->mutex);
364 if (player->error) {
365 g_mutex_unlock (player->mutex);
366 return NULL;
368 buffer = player->out;
369 player->out = NULL;
370 *width = player->width;
371 *height = player->height;
372 *rowstride = player->width * 4;
373 g_mutex_unlock (player->mutex);
374 return buffer;
377 static void
378 swfdec_video_decoder_gst_fakesrc_handoff (GstElement *fakesrc, GstBuffer *buf,
379 GstPad *pad, SwfdecGstVideo *player)
381 g_mutex_lock (player->mutex);
382 if (player->out_next) {
383 player->error = TRUE;
384 g_cond_signal (player->cond);
385 g_mutex_unlock (player->mutex);
386 return;
388 while (player->pipeline != NULL && player->in == NULL)
389 swfdec_cond_wait (player->cond, player->mutex);
390 if (player->pipeline == NULL) {
391 g_mutex_unlock (player->mutex);
392 return;
394 buf->data = g_memdup (player->in->data, player->in->length);
395 buf->malloc_data = buf->data;
396 buf->size = player->in->length;
397 gst_buffer_set_caps (buf, player->srccaps);
398 player->in = NULL;
399 player->out_next = TRUE;
400 g_cond_signal (player->cond);
401 g_mutex_unlock (player->mutex);
404 static void
405 swfdec_video_decoder_gst_fakesink_handoff (GstElement *fakesrc, GstBuffer *buf,
406 GstPad *pad, SwfdecGstVideo *player)
408 GstCaps *caps;
410 g_mutex_lock (player->mutex);
411 if (!player->out_next) {
412 player->error = TRUE;
413 g_cond_signal (player->cond);
414 g_mutex_unlock (player->mutex);
415 return;
417 caps = gst_buffer_get_caps (buf);
418 if (caps) {
419 GstStructure *structure = gst_caps_get_structure (caps, 0);
420 if (!gst_structure_get_int (structure, "width", &player->width) ||
421 !gst_structure_get_int (structure, "height", &player->height)) {
422 player->width = 0;
423 player->height = 0;
425 gst_caps_unref (caps);
427 while (player->pipeline != NULL && player->out != NULL)
428 swfdec_cond_wait (player->cond, player->mutex);
429 if (player->pipeline == NULL) {
430 g_mutex_unlock (player->mutex);
431 return;
433 player->out = swfdec_buffer_new_for_data (
434 g_memdup (buf->data, buf->size), buf->size);
435 player->out_next = FALSE;
436 g_cond_signal (player->cond);
437 g_mutex_unlock (player->mutex);
440 static void
441 swfdec_video_decoder_gst_link (GstElement *src, GstPad *pad, GstElement *sink)
443 if (!gst_element_link (src, sink)) {
444 SWFDEC_ERROR ("no delayed link");
448 SwfdecVideoDecoder *
449 swfdec_video_decoder_gst_new (SwfdecVideoFormat type)
451 SwfdecGstVideo *player;
452 GstElement *fakesrc, *fakesink, *decoder, *csp;
453 GstCaps *caps;
455 if (!gst_init_check (NULL, NULL, NULL))
456 return NULL;
458 switch (type) {
459 case SWFDEC_VIDEO_FORMAT_H263:
460 caps = gst_caps_from_string ("video/x-flash-video");
461 break;
462 case SWFDEC_VIDEO_FORMAT_VP6:
463 caps = gst_caps_from_string ("video/x-vp6-flash");
464 break;
465 default:
466 return NULL;
468 g_assert (caps);
470 player = g_slice_new0 (SwfdecGstVideo);
471 player->decoder.decode = swfdec_video_decoder_gst_decode;
472 player->decoder.free = swfdec_video_decoder_gst_free;
473 player->pipeline = gst_pipeline_new ("pipeline");
474 player->refcount = 1;
475 g_assert (player->pipeline);
476 player->mutex = g_mutex_new ();
477 player->cond = g_cond_new ();
478 player->srccaps = caps;
479 fakesrc = gst_element_factory_make ("fakesrc", NULL);
480 if (fakesrc == NULL) {
481 SWFDEC_ERROR ("failed to create fakesrc");
482 swfdec_video_decoder_gst_free (&player->decoder);
483 return NULL;
485 g_object_set (fakesrc, "signal-handoffs", TRUE,
486 "can-activate-pull", FALSE, NULL);
487 g_signal_connect (fakesrc, "handoff",
488 G_CALLBACK (swfdec_video_decoder_gst_fakesrc_handoff), player);
489 g_atomic_int_inc (&player->refcount);
490 g_object_weak_ref (G_OBJECT (fakesrc), swfdec_gst_video_unref, player);
491 gst_bin_add (GST_BIN (player->pipeline), fakesrc);
492 fakesink = gst_element_factory_make ("fakesink", NULL);
493 if (fakesink == NULL) {
494 SWFDEC_ERROR ("failed to create fakesink");
495 swfdec_video_decoder_gst_free (&player->decoder);
496 return NULL;
498 g_object_set (fakesink, "signal-handoffs", TRUE, NULL);
499 g_signal_connect (fakesink, "handoff",
500 G_CALLBACK (swfdec_video_decoder_gst_fakesink_handoff), player);
501 g_atomic_int_inc (&player->refcount);
502 g_object_weak_ref (G_OBJECT (fakesink), swfdec_gst_video_unref, player);
503 gst_bin_add (GST_BIN (player->pipeline), fakesink);
504 decoder = gst_element_factory_make ("decodebin", NULL);
505 if (decoder == NULL) {
506 SWFDEC_ERROR ("failed to create decoder");
507 swfdec_video_decoder_gst_free (&player->decoder);
508 return NULL;
510 gst_bin_add (GST_BIN (player->pipeline), decoder);
511 csp = gst_element_factory_make ("ffmpegcolorspace", NULL);
512 if (csp == NULL) {
513 SWFDEC_ERROR ("failed to create colorspace");
514 swfdec_video_decoder_gst_free (&player->decoder);
515 return NULL;
517 gst_bin_add (GST_BIN (player->pipeline), csp);
518 g_signal_connect (decoder, "pad-added",
519 G_CALLBACK (swfdec_video_decoder_gst_link), csp);
521 #if G_BYTE_ORDER == G_BIG_ENDIAN
522 caps = gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
523 "red_mask=16711680, green_mask=65280, blue_mask=255");
524 #else
525 caps = gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
526 "red_mask=65280, green_mask=16711680, blue_mask=-16777216");
527 #endif
528 g_assert (caps);
529 if (!gst_element_link_filtered (fakesrc, decoder, player->srccaps) ||
530 !gst_element_link_filtered (csp, fakesink, caps)) {
531 SWFDEC_ERROR ("linking failed");
532 swfdec_video_decoder_gst_free (&player->decoder);
533 return NULL;
535 gst_caps_unref (caps);
536 if (gst_element_set_state (player->pipeline, GST_STATE_PLAYING) == GST_STATE_CHANGE_FAILURE) {
537 SWFDEC_ERROR ("failed to change sate");
538 swfdec_video_decoder_gst_free (&player->decoder);
539 return NULL;
542 return &player->decoder;