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
);
103 player
->in
= swfdec_buffer_ref (buffer
);
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
);
150 swfdec_buffer_unref (player
->in
);
152 g_cond_signal (player
->cond
);
153 g_mutex_unlock (player
->mutex
);
157 swfdec_audio_decoder_gst_fakesink_handoff (GstElement
*fakesrc
, GstBuffer
*buf
,
158 GstPad
*pad
, SwfdecGstAudio
*player
)
160 SwfdecBuffer
*buffer
;
162 g_mutex_lock (player
->mutex
);
164 while (player
->pipeline
== NULL
&& player
->out
!= NULL
)
165 swfdec_cond_wait (player
->cond
, player
->mutex
);
166 buffer
= swfdec_buffer_new_for_data (
167 g_memdup (buf
->data
, buf
->size
), buf
->size
);
168 swfdec_buffer_queue_push (player
->out
, buffer
);
169 g_cond_signal (player
->cond
);
170 g_mutex_unlock (player
->mutex
);
174 swfdec_audio_decoder_gst_link (GstElement
*src
, GstPad
*pad
, GstElement
*sink
)
176 if (!gst_element_link (src
, sink
)) {
177 SWFDEC_ERROR ("no delayed link");
181 static GstBusSyncReply
182 swfdec_audio_decoder_gst_handle_bus (GstBus
*bus
, GstMessage
*message
, gpointer data
)
184 SwfdecGstAudio
*player
= data
;
186 switch (message
->type
) {
187 case GST_MESSAGE_EOS
:
188 case GST_MESSAGE_ERROR
:
189 g_mutex_lock (player
->mutex
);
190 g_cond_signal (player
->cond
);
192 g_mutex_unlock (player
->mutex
);
201 swfdec_audio_decoder_gst_new (SwfdecAudioCodec type
, SwfdecAudioFormat format
)
203 SwfdecGstAudio
*player
;
204 GstElement
*fakesrc
, *fakesink
, *decoder
, *convert
;
208 if (!gst_init_check (NULL
, NULL
, NULL
))
212 case SWFDEC_AUDIO_CODEC_MP3
:
213 caps
= gst_caps_from_string ("audio/mpeg, mpegversion=(int)1, layer=(int)3");
220 player
= g_slice_new0 (SwfdecGstAudio
);
221 player
->decoder
.format
= swfdec_audio_format_new (44100, 2, TRUE
);
222 player
->decoder
.pull
= swfdec_audio_decoder_gst_pull
;
223 player
->decoder
.push
= swfdec_audio_decoder_gst_push
;
224 player
->decoder
.free
= swfdec_audio_decoder_gst_free
;
225 player
->pipeline
= gst_pipeline_new ("pipeline");
226 player
->refcount
= 1;
227 g_assert (player
->pipeline
);
228 bus
= gst_element_get_bus (player
->pipeline
);
229 g_atomic_int_inc (&player
->refcount
);
230 g_object_weak_ref (G_OBJECT (bus
), swfdec_gst_audio_unref
, player
);
231 gst_bus_set_sync_handler (bus
, swfdec_audio_decoder_gst_handle_bus
, player
);
232 player
->mutex
= g_mutex_new ();
233 player
->cond
= g_cond_new ();
234 player
->out
= swfdec_buffer_queue_new ();
235 player
->srccaps
= caps
;
236 fakesrc
= gst_element_factory_make ("fakesrc", NULL
);
237 if (fakesrc
== NULL
) {
238 SWFDEC_ERROR ("failed to create fakesrc");
239 swfdec_audio_decoder_gst_free (&player
->decoder
);
242 g_object_set (fakesrc
, "signal-handoffs", TRUE
,
243 "can-activate-pull", FALSE
, NULL
);
244 g_signal_connect (fakesrc
, "handoff",
245 G_CALLBACK (swfdec_audio_decoder_gst_fakesrc_handoff
), player
);
246 g_atomic_int_inc (&player
->refcount
);
247 g_object_weak_ref (G_OBJECT (fakesrc
), swfdec_gst_audio_unref
, player
);
248 gst_bin_add (GST_BIN (player
->pipeline
), fakesrc
);
249 fakesink
= gst_element_factory_make ("fakesink", NULL
);
250 if (fakesink
== NULL
) {
251 SWFDEC_ERROR ("failed to create fakesink");
252 swfdec_audio_decoder_gst_free (&player
->decoder
);
255 g_object_set (fakesink
, "signal-handoffs", TRUE
, NULL
);
256 g_signal_connect (fakesink
, "handoff",
257 G_CALLBACK (swfdec_audio_decoder_gst_fakesink_handoff
), player
);
258 g_atomic_int_inc (&player
->refcount
);
259 g_object_weak_ref (G_OBJECT (fakesink
), swfdec_gst_audio_unref
, player
);
260 gst_bin_add (GST_BIN (player
->pipeline
), fakesink
);
261 decoder
= gst_element_factory_make ("decodebin", NULL
);
262 if (decoder
== NULL
) {
263 SWFDEC_ERROR ("failed to create decoder");
264 swfdec_audio_decoder_gst_free (&player
->decoder
);
267 gst_bin_add (GST_BIN (player
->pipeline
), decoder
);
268 convert
= gst_element_factory_make ("audioconvert", NULL
);
269 if (convert
== NULL
) {
270 SWFDEC_ERROR ("failed to create audioconvert");
271 swfdec_audio_decoder_gst_free (&player
->decoder
);
274 gst_bin_add (GST_BIN (player
->pipeline
), convert
);
275 g_signal_connect (decoder
, "pad-added",
276 G_CALLBACK (swfdec_audio_decoder_gst_link
), convert
);
278 caps
= gst_caps_from_string ("audio/x-raw-int, endianness=byte_order, signed=(boolean)true, width=16, depth=16, rate=44100, channels=2");
280 if (!gst_element_link_filtered (fakesrc
, decoder
, player
->srccaps
) ||
281 !gst_element_link_filtered (convert
, fakesink
, caps
)) {
282 SWFDEC_ERROR ("linking failed");
283 swfdec_audio_decoder_gst_free (&player
->decoder
);
286 gst_caps_unref (caps
);
287 if (gst_element_set_state (player
->pipeline
, GST_STATE_PLAYING
) == GST_STATE_CHANGE_FAILURE
) {
288 SWFDEC_ERROR ("failed to change sate");
289 swfdec_audio_decoder_gst_free (&player
->decoder
);
293 return &player
->decoder
;
298 typedef struct _SwfdecGstVideo SwfdecGstVideo
;
299 struct _SwfdecGstVideo
{
300 SwfdecVideoDecoder decoder
;
302 GMutex
* mutex
; /* mutex that blocks everything below (NB: locked by default) */
303 GCond
* cond
; /* cond used to signal when stuff below changes */
304 volatile int refcount
; /* refcount (d'oh) */
306 GstElement
* pipeline
; /* pipeline that is playing or NULL when done */
307 SwfdecBuffer
* in
; /* next input buffer or NULL */
308 GstBuffer
* out
; /* available output or NULL */
309 int width
; /* width of last output buffer */
310 int height
; /* height of last output buffer */
311 GstCaps
* srccaps
; /* caps to set on buffers */
312 gboolean out_next
; /* wether the pipeline expects input or output */
313 gboolean error
; /* we're in an error state */
317 swfdec_gst_video_unref (gpointer data
, GObject
*unused
)
319 SwfdecGstVideo
*player
= data
;
321 if (!g_atomic_int_dec_and_test (&player
->refcount
))
323 g_cond_free (player
->cond
);
324 g_mutex_free (player
->mutex
);
325 gst_caps_unref (player
->srccaps
);
327 swfdec_buffer_unref (player
->in
);
329 gst_buffer_unref (player
->out
);
330 g_slice_free (SwfdecGstVideo
, player
);
334 swfdec_video_decoder_gst_free (SwfdecVideoDecoder
*dec
)
336 SwfdecGstVideo
*player
= (SwfdecGstVideo
*) dec
;
337 GstElement
*pipeline
;
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
);
350 swfdec_video_decoder_gst_decode (SwfdecVideoDecoder
*dec
, SwfdecBuffer
*buffer
,
351 SwfdecVideoImage
*image
)
353 SwfdecGstVideo
*player
= (SwfdecGstVideo
*) dec
;
355 while (player
->in
!= NULL
&& !player
->error
) {
356 swfdec_cond_wait (player
->cond
, player
->mutex
);
358 player
->in
= swfdec_buffer_ref (buffer
);
359 g_cond_signal (player
->cond
);
361 gst_buffer_unref (player
->out
);
364 while (player
->out
== NULL
&& !player
->error
) {
365 swfdec_cond_wait (player
->cond
, player
->mutex
);
369 image
->width
= player
->width
;
370 image
->height
= player
->height
;
372 switch (swfdec_video_codec_get_format (dec
->codec
)) {
373 case SWFDEC_VIDEO_FORMAT_RGBA
:
374 image
->plane
[0] = player
->out
->data
;
375 image
->rowstride
[0] = player
->width
* 4;
377 case SWFDEC_VIDEO_FORMAT_I420
:
378 image
->plane
[0] = player
->out
->data
;
379 image
->rowstride
[0] = player
->width
;
380 image
->plane
[1] = image
->plane
[0] + player
->width
* player
->height
;
381 image
->rowstride
[1] = (player
->width
+ 1) / 2;
382 image
->plane
[2] = image
->plane
[1] + image
->rowstride
[1] * ((player
->height
+ 1) / 2);
383 image
->rowstride
[2] = image
->rowstride
[1];
384 g_assert (image
->plane
[2] + (image
->rowstride
[2] * ((player
->height
+ 1) / 2)) == image
->plane
[0] + player
->out
->size
);
391 swfdec_video_decoder_gst_fakesrc_handoff (GstElement
*fakesrc
, GstBuffer
*buf
,
392 GstPad
*pad
, SwfdecGstVideo
*player
)
394 g_mutex_lock (player
->mutex
);
395 if (player
->out_next
) {
396 player
->error
= TRUE
;
397 g_cond_signal (player
->cond
);
398 g_mutex_unlock (player
->mutex
);
401 while (player
->pipeline
!= NULL
&& player
->in
== NULL
)
402 swfdec_cond_wait (player
->cond
, player
->mutex
);
403 if (player
->pipeline
== NULL
) {
404 g_mutex_unlock (player
->mutex
);
407 buf
->data
= g_memdup (player
->in
->data
, player
->in
->length
);
408 buf
->malloc_data
= buf
->data
;
409 buf
->size
= player
->in
->length
;
410 gst_buffer_set_caps (buf
, player
->srccaps
);
411 swfdec_buffer_unref (player
->in
);
413 player
->out_next
= TRUE
;
414 g_cond_signal (player
->cond
);
415 g_mutex_unlock (player
->mutex
);
419 swfdec_video_decoder_gst_fakesink_handoff (GstElement
*fakesrc
, GstBuffer
*buf
,
420 GstPad
*pad
, SwfdecGstVideo
*player
)
424 g_mutex_lock (player
->mutex
);
425 if (!player
->out_next
) {
426 player
->error
= TRUE
;
427 g_cond_signal (player
->cond
);
428 g_mutex_unlock (player
->mutex
);
431 caps
= gst_buffer_get_caps (buf
);
433 GstStructure
*structure
= gst_caps_get_structure (caps
, 0);
434 if (!gst_structure_get_int (structure
, "width", &player
->width
) ||
435 !gst_structure_get_int (structure
, "height", &player
->height
)) {
439 gst_caps_unref (caps
);
441 if (player
->pipeline
== NULL
) {
442 g_mutex_unlock (player
->mutex
);
445 if (player
->out
!= NULL
)
446 gst_buffer_unref (player
->out
);
447 player
->out
= gst_buffer_ref (buf
);
448 player
->out_next
= FALSE
;
449 g_cond_signal (player
->cond
);
450 g_mutex_unlock (player
->mutex
);
454 swfdec_video_decoder_gst_link (GstElement
*src
, GstPad
*pad
, GstElement
*sink
)
458 caps
= g_object_get_data (G_OBJECT (sink
), "swfdec-caps");
460 if (!gst_element_link_filtered (src
, sink
, caps
)) {
461 SWFDEC_ERROR ("no delayed link");
466 swfdec_video_decoder_get_sink_caps (SwfdecVideoCodec codec
)
468 switch (swfdec_video_codec_get_format (codec
)) {
469 case SWFDEC_VIDEO_FORMAT_RGBA
:
470 #if G_BYTE_ORDER == G_BIG_ENDIAN
471 return gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
472 "red_mask=16711680, green_mask=65280, blue_mask=255");
474 return gst_caps_from_string ("video/x-raw-rgb, bpp=32, endianness=4321, depth=24, "
475 "red_mask=65280, green_mask=16711680, blue_mask=-16777216");
477 case SWFDEC_VIDEO_FORMAT_I420
:
478 return gst_caps_from_string ("video/x-raw-yuv, format=(fourcc)I420");
480 g_assert_not_reached ();
485 swfdec_video_decoder_gst_new (SwfdecVideoCodec codec
)
487 SwfdecGstVideo
*player
;
488 GstElement
*fakesrc
, *fakesink
, *decoder
;
491 if (!gst_init_check (NULL
, NULL
, NULL
))
495 case SWFDEC_VIDEO_CODEC_H263
:
496 caps
= gst_caps_from_string ("video/x-flash-video");
498 case SWFDEC_VIDEO_CODEC_VP6
:
499 caps
= gst_caps_from_string ("video/x-vp6-flash");
506 player
= g_slice_new0 (SwfdecGstVideo
);
507 player
->decoder
.decode
= swfdec_video_decoder_gst_decode
;
508 player
->decoder
.free
= swfdec_video_decoder_gst_free
;
509 player
->pipeline
= gst_pipeline_new ("pipeline");
510 player
->refcount
= 1;
511 g_assert (player
->pipeline
);
512 player
->mutex
= g_mutex_new ();
513 g_mutex_lock (player
->mutex
);
514 player
->cond
= g_cond_new ();
515 player
->srccaps
= caps
;
516 fakesrc
= gst_element_factory_make ("fakesrc", NULL
);
517 if (fakesrc
== NULL
) {
518 SWFDEC_ERROR ("failed to create fakesrc");
519 swfdec_video_decoder_gst_free (&player
->decoder
);
522 g_object_set (fakesrc
, "signal-handoffs", TRUE
,
523 "can-activate-pull", FALSE
, NULL
);
524 g_signal_connect (fakesrc
, "handoff",
525 G_CALLBACK (swfdec_video_decoder_gst_fakesrc_handoff
), player
);
526 g_atomic_int_inc (&player
->refcount
);
527 g_object_weak_ref (G_OBJECT (fakesrc
), swfdec_gst_video_unref
, player
);
528 gst_bin_add (GST_BIN (player
->pipeline
), fakesrc
);
529 fakesink
= gst_element_factory_make ("fakesink", NULL
);
530 if (fakesink
== NULL
) {
531 SWFDEC_ERROR ("failed to create fakesink");
532 swfdec_video_decoder_gst_free (&player
->decoder
);
535 g_object_set (fakesink
, "signal-handoffs", TRUE
, NULL
);
536 g_signal_connect (fakesink
, "handoff",
537 G_CALLBACK (swfdec_video_decoder_gst_fakesink_handoff
), player
);
538 caps
= swfdec_video_decoder_get_sink_caps (codec
);
540 g_object_set_data_full (G_OBJECT (fakesink
), "swfdec-caps", caps
,
541 (GDestroyNotify
) gst_caps_unref
);
542 g_atomic_int_inc (&player
->refcount
);
543 g_object_weak_ref (G_OBJECT (fakesink
), swfdec_gst_video_unref
, player
);
544 gst_bin_add (GST_BIN (player
->pipeline
), fakesink
);
545 decoder
= gst_element_factory_make ("decodebin", NULL
);
546 if (decoder
== NULL
) {
547 SWFDEC_ERROR ("failed to create decoder");
548 swfdec_video_decoder_gst_free (&player
->decoder
);
551 gst_bin_add (GST_BIN (player
->pipeline
), decoder
);
552 g_signal_connect (decoder
, "pad-added",
553 G_CALLBACK (swfdec_video_decoder_gst_link
), fakesink
);
555 if (!gst_element_link_filtered (fakesrc
, decoder
, player
->srccaps
)) {
556 SWFDEC_ERROR ("linking failed");
557 swfdec_video_decoder_gst_free (&player
->decoder
);
560 if (gst_element_set_state (player
->pipeline
, GST_STATE_PLAYING
) == GST_STATE_CHANGE_FAILURE
) {
561 SWFDEC_ERROR ("failed to change sate");
562 swfdec_video_decoder_gst_free (&player
->decoder
);
566 return &player
->decoder
;