bump libtool version
[swfdec.git] / libswfdec / swfdec_codec_gst.c
bloba12559830dac614f3556c79182c3b9d0e05fc5b2
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 = swfdec_buffer_ref (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 swfdec_buffer_unref (player->in);
151 player->in = NULL;
152 g_cond_signal (player->cond);
153 g_mutex_unlock (player->mutex);
156 static void
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);
173 static void
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);
191 player->done = TRUE;
192 g_mutex_unlock (player->mutex);
193 break;
194 default:
195 break;
197 return GST_BUS_PASS;
200 SwfdecAudioDecoder *
201 swfdec_audio_decoder_gst_new (SwfdecAudioCodec type, SwfdecAudioFormat format)
203 SwfdecGstAudio *player;
204 GstElement *fakesrc, *fakesink, *decoder, *convert;
205 GstBus *bus;
206 GstCaps *caps;
208 if (!gst_init_check (NULL, NULL, NULL))
209 return NULL;
211 switch (type) {
212 case SWFDEC_AUDIO_CODEC_MP3:
213 caps = gst_caps_from_string ("audio/mpeg, mpegversion=(int)1, layer=(int)3");
214 break;
215 default:
216 return NULL;
218 g_assert (caps);
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);
240 return NULL;
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);
253 return NULL;
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);
265 return NULL;
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);
272 return NULL;
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");
279 g_assert (caps);
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);
284 return NULL;
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);
290 return NULL;
293 return &player->decoder;
296 /*** VIDEO ***/
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 */
316 static void
317 swfdec_gst_video_unref (gpointer data, GObject *unused)
319 SwfdecGstVideo *player = data;
321 if (!g_atomic_int_dec_and_test (&player->refcount))
322 return;
323 g_cond_free (player->cond);
324 g_mutex_free (player->mutex);
325 gst_caps_unref (player->srccaps);
326 if (player->in)
327 swfdec_buffer_unref (player->in);
328 if (player->out)
329 gst_buffer_unref (player->out);
330 g_slice_free (SwfdecGstVideo, player);
333 static void
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);
349 static gboolean
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);
360 if (player->out) {
361 gst_buffer_unref (player->out);
362 player->out = NULL;
364 while (player->out == NULL && !player->error) {
365 swfdec_cond_wait (player->cond, player->mutex);
367 if (player->error)
368 return FALSE;
369 image->width = player->width;
370 image->height = player->height;
371 image->mask = NULL;
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;
376 break;
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);
385 break;
387 return TRUE;
390 static void
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);
399 return;
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);
405 return;
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);
412 player->in = NULL;
413 player->out_next = TRUE;
414 g_cond_signal (player->cond);
415 g_mutex_unlock (player->mutex);
418 static void
419 swfdec_video_decoder_gst_fakesink_handoff (GstElement *fakesrc, GstBuffer *buf,
420 GstPad *pad, SwfdecGstVideo *player)
422 GstCaps *caps;
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);
429 return;
431 caps = gst_buffer_get_caps (buf);
432 if (caps) {
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)) {
436 player->width = 0;
437 player->height = 0;
439 gst_caps_unref (caps);
441 if (player->pipeline == NULL) {
442 g_mutex_unlock (player->mutex);
443 return;
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);
453 static void
454 swfdec_video_decoder_gst_link (GstElement *src, GstPad *pad, GstElement *sink)
456 GstCaps *caps;
458 caps = g_object_get_data (G_OBJECT (sink), "swfdec-caps");
459 g_assert (caps);
460 if (!gst_element_link_filtered (src, sink, caps)) {
461 SWFDEC_ERROR ("no delayed link");
465 static GstCaps *
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");
473 #else
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");
476 #endif
477 case SWFDEC_VIDEO_FORMAT_I420:
478 return gst_caps_from_string ("video/x-raw-yuv, format=(fourcc)I420");
480 g_assert_not_reached ();
481 return NULL;
484 SwfdecVideoDecoder *
485 swfdec_video_decoder_gst_new (SwfdecVideoCodec codec)
487 SwfdecGstVideo *player;
488 GstElement *fakesrc, *fakesink, *decoder;
489 GstCaps *caps;
491 if (!gst_init_check (NULL, NULL, NULL))
492 return NULL;
494 switch (codec) {
495 case SWFDEC_VIDEO_CODEC_H263:
496 caps = gst_caps_from_string ("video/x-flash-video");
497 break;
498 case SWFDEC_VIDEO_CODEC_VP6:
499 caps = gst_caps_from_string ("video/x-vp6-flash");
500 break;
501 default:
502 return NULL;
504 g_assert (caps);
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);
520 return NULL;
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);
533 return NULL;
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);
539 g_assert (caps);
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);
549 return NULL;
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);
558 return NULL;
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);
563 return NULL;
566 return &player->decoder;