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.
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
26 #include "swfdec_codec_audio.h"
27 #include "swfdec_codec_video.h"
28 #include "swfdec_debug.h"
29 #include "swfdec_internal.h"
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); \
38 #define swfdec_cond_wait g_cond_wait
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) */
60 swfdec_gst_audio_unref (gpointer data
, GObject
*unused
)
62 SwfdecGstAudio
*player
= data
;
64 if (!g_atomic_int_dec_and_test (&player
->refcount
))
66 g_cond_free (player
->cond
);
67 g_mutex_free (player
->mutex
);
68 gst_caps_unref (player
->srccaps
);
70 swfdec_buffer_unref (player
->in
);
71 swfdec_buffer_queue_unref (player
->out
);
72 g_slice_free (SwfdecGstAudio
, player
);
76 swfdec_audio_decoder_gst_free (SwfdecAudioDecoder
*dec
)
78 SwfdecGstAudio
*player
= (SwfdecGstAudio
*) dec
;
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
);
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
);
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
);
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
);
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
);
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... */
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
);
151 g_cond_signal (player
->cond
);
152 g_mutex_unlock (player
->mutex
);
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
);
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
);
191 g_mutex_unlock (player
->mutex
);
200 swfdec_audio_decoder_gst_new (SwfdecAudioFormat type
, gboolean width
, SwfdecAudioOut format
)
202 SwfdecGstAudio
*player
;
203 GstElement
*fakesrc
, *fakesink
, *decoder
, *convert
;
207 if (!gst_init_check (NULL
, NULL
, NULL
))
211 case SWFDEC_AUDIO_FORMAT_MP3
:
212 caps
= gst_caps_from_string ("audio/mpeg, mpegversion=(int)1, layer=(int)3");
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
);
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
);
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
);
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
);
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");
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
);
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
);
292 return &player
->decoder
;
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 */
316 swfdec_gst_video_unref (gpointer data
, GObject
*unused
)
318 SwfdecGstVideo
*player
= data
;
320 if (!g_atomic_int_dec_and_test (&player
->refcount
))
322 g_cond_free (player
->cond
);
323 g_mutex_free (player
->mutex
);
324 gst_caps_unref (player
->srccaps
);
326 swfdec_buffer_unref (player
->in
);
328 swfdec_buffer_unref (player
->out
);
329 g_slice_free (SwfdecGstVideo
, player
);
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
);
360 g_cond_signal (player
->cond
);
361 while (player
->out
== NULL
&& !player
->error
) {
362 swfdec_cond_wait (player
->cond
, player
->mutex
);
365 g_mutex_unlock (player
->mutex
);
368 buffer
= player
->out
;
370 *width
= player
->width
;
371 *height
= player
->height
;
372 *rowstride
= player
->width
* 4;
373 g_mutex_unlock (player
->mutex
);
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
);
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
);
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
);
399 player
->out_next
= TRUE
;
400 g_cond_signal (player
->cond
);
401 g_mutex_unlock (player
->mutex
);
405 swfdec_video_decoder_gst_fakesink_handoff (GstElement
*fakesrc
, GstBuffer
*buf
,
406 GstPad
*pad
, SwfdecGstVideo
*player
)
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
);
417 caps
= gst_buffer_get_caps (buf
);
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
)) {
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
);
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
);
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");
449 swfdec_video_decoder_gst_new (SwfdecVideoFormat type
)
451 SwfdecGstVideo
*player
;
452 GstElement
*fakesrc
, *fakesink
, *decoder
, *csp
;
455 if (!gst_init_check (NULL
, NULL
, NULL
))
459 case SWFDEC_VIDEO_FORMAT_H263
:
460 caps
= gst_caps_from_string ("video/x-flash-video");
462 case SWFDEC_VIDEO_FORMAT_VP6
:
463 caps
= gst_caps_from_string ("video/x-vp6-flash");
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
);
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
);
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
);
510 gst_bin_add (GST_BIN (player
->pipeline
), decoder
);
511 csp
= gst_element_factory_make ("ffmpegcolorspace", NULL
);
513 SWFDEC_ERROR ("failed to create colorspace");
514 swfdec_video_decoder_gst_free (&player
->decoder
);
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");
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");
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
);
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
);
542 return &player
->decoder
;