diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/sdl/Makefile.am | 19 | ||||
-rw-r--r-- | ext/sdl/gstsdl.c | 45 | ||||
-rw-r--r-- | ext/sdl/sdlaudiosink.c | 484 | ||||
-rw-r--r-- | ext/sdl/sdlaudiosink.h | 65 | ||||
-rw-r--r-- | ext/sdl/sdlvideosink.c | 22 |
5 files changed, 611 insertions, 24 deletions
diff --git a/ext/sdl/Makefile.am b/ext/sdl/Makefile.am index c183ee80..24e6d985 100644 --- a/ext/sdl/Makefile.am +++ b/ext/sdl/Makefile.am @@ -1,8 +1,19 @@ plugin_LTLIBRARIES = libgstsdlvideosink.la -libgstsdlvideosink_la_SOURCES = sdlvideosink.c -libgstsdlvideosink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(SDL_CFLAGS) -libgstsdlvideosink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) -lgstinterfaces-$(GST_MAJORMINOR) $(SDL_LIBS) +libgstsdlvideosink_la_SOURCES = gstsdl.c \ + sdlvideosink.c \ + sdlaudiosink.c + +libgstsdlvideosink_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \ + $(SDL_CFLAGS) + +libgstsdlvideosink_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \ + -lgstvideo-$(GST_MAJORMINOR) \ + -lgstaudio-@GST_MAJORMINOR@ \ + -lgstinterfaces-$(GST_MAJORMINOR) \ + $(SDL_LIBS) + libgstsdlvideosink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -noinst_HEADERS = sdlvideosink.h +noinst_HEADERS = sdlvideosink.h \ + sdlaudiosink.h diff --git a/ext/sdl/gstsdl.c b/ext/sdl/gstsdl.c new file mode 100644 index 00000000..bf5d7da9 --- /dev/null +++ b/ext/sdl/gstsdl.c @@ -0,0 +1,45 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sdlvideosink.h" +#include "sdlaudiosink.h" + + +GST_DEBUG_CATEGORY (sdl_debug); + +static gboolean +plugin_init (GstPlugin * plugin) +{ + + if (!gst_element_register (plugin, "sdlvideosink", GST_RANK_NONE, + GST_TYPE_SDLVIDEOSINK) || + !gst_element_register (plugin, "sdlaudiosink", GST_RANK_NONE, + GST_TYPE_SDLAUDIOSINK)) { + return FALSE; + } + + GST_DEBUG_CATEGORY_INIT (sdl_debug, "sdl", 0, "SDL elements"); + + return TRUE; +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + "sdl", + "SDL (Simple DirectMedia Layer) support for GStreamer", + plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN) diff --git a/ext/sdl/sdlaudiosink.c b/ext/sdl/sdlaudiosink.c new file mode 100644 index 00000000..4465a529 --- /dev/null +++ b/ext/sdl/sdlaudiosink.c @@ -0,0 +1,484 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "sdlaudiosink.h" + +#include <SDL_byteorder.h> +#include <string.h> + +#include <unistd.h> + +GST_DEBUG_CATEGORY_EXTERN (sdl_debug); +#define GST_CAT_DEFAULT sdl_debug + +/* elementfactory information */ +static GstElementDetails gst_sdlaudio_sink_details = +GST_ELEMENT_DETAILS ("Audio Sink (SDLAUDIO)", + "Sink/Audio", + "Output to a sound card via SDLAUDIO", + "Edgard Lima <edgard.lima@indt.org.br>"); + +static void gst_sdlaudio_sink_base_init (gpointer g_class); +static void gst_sdlaudio_sink_class_init (GstSDLAudioSinkClass * klass); +static void gst_sdlaudio_sink_init (GstSDLAudioSink * sdlaudiosink); +static void gst_sdlaudio_sink_dispose (GObject * object); + +static void gst_sdlaudio_sink_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static void gst_sdlaudio_sink_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); + +static GstCaps *gst_sdlaudio_sink_getcaps (GstBaseSink * bsink); + +static gboolean gst_sdlaudio_sink_open (GstAudioSink * asink); +static gboolean gst_sdlaudio_sink_close (GstAudioSink * asink); +static gboolean gst_sdlaudio_sink_prepare (GstAudioSink * asink, + GstRingBufferSpec * spec); +static gboolean gst_sdlaudio_sink_unprepare (GstAudioSink * asink); +static guint gst_sdlaudio_sink_write (GstAudioSink * asink, gpointer data, + guint length); + +#if 0 +static guint gst_sdlaudio_sink_delay (GstAudioSink * asink); +static void gst_sdlaudio_sink_reset (GstAudioSink * asink); +#endif + + +/* SdlaudioSink signals and args */ +enum +{ + LAST_SIGNAL +}; + +#define SEMAPHORE_INIT(s,f) \ + do { \ + s.cond = g_cond_new(); \ + s.mutex = g_mutex_new(); \ + s.mutexflag = f; \ + } while(0) + +#define SEMAPHORE_CLOSE(s) \ + do { \ + if ( s.cond ) { \ + g_cond_free(s.cond); \ + s.cond = NULL; \ + } \ + if ( s.mutex ) { \ + g_mutex_free(s.mutex); \ + s.mutex = NULL; \ + } \ + } while(0) + +#define SEMAPHORE_UP(s) \ + do \ + { \ + g_mutex_lock(s.mutex); \ + s.mutexflag = TRUE; \ + g_mutex_unlock(s.mutex); \ + g_cond_signal(s.cond); \ + } while(0) + +#define SEMAPHORE_DOWN(s, e) \ + do \ + { \ + while (1) { \ + g_mutex_lock(s.mutex); \ + if (!s.mutexflag) { \ + if ( e ) { \ + g_mutex_unlock(s.mutex); \ + break; \ + } \ + g_cond_wait(s.cond,s.mutex); \ + } \ + else { \ + s.mutexflag = FALSE; \ + g_mutex_unlock(s.mutex); \ + break; \ + } \ + g_mutex_unlock(s.mutex); \ + } \ + } while(0) + + +static GstStaticPadTemplate sdlaudiosink_sink_factory = + GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("audio/x-raw-int, " + "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE, FALSE }, " + "width = (int) 16, " + "depth = (int) 16, " + "rate = (int) [ 1, MAX ], " + "channels = (int) [ 1, 2 ]; " + "audio/x-raw-int, " + "endianness = (int) { " G_STRINGIFY (G_BYTE_ORDER) " }, " + "signed = (boolean) { TRUE, FALSE }, " + "width = (int) 8, " + "depth = (int) 8, " + "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]") + ); + +static GstElementClass *parent_class = NULL; + +GType +gst_sdlaudio_sink_get_type (void) +{ + static GType sdlaudiosink_type = 0; + + if (!sdlaudiosink_type) { + static const GTypeInfo sdlaudiosink_info = { + sizeof (GstSDLAudioSinkClass), + gst_sdlaudio_sink_base_init, + NULL, + (GClassInitFunc) gst_sdlaudio_sink_class_init, + NULL, + NULL, + sizeof (GstSDLAudioSink), + 0, + (GInstanceInitFunc) gst_sdlaudio_sink_init, + }; + + sdlaudiosink_type = + g_type_register_static (GST_TYPE_AUDIO_SINK, "GstSDLAudioSink", + &sdlaudiosink_info, 0); + } + + return sdlaudiosink_type; +} + +static void +gst_sdlaudio_sink_dispose (GObject * object) +{ + GstSDLAudioSink *sdlaudiosink = GST_SDLAUDIOSINK (object); + + SEMAPHORE_CLOSE (sdlaudiosink->semB); + + SEMAPHORE_CLOSE (sdlaudiosink->semA); + + if (sdlaudiosink->buffer) { + g_free (sdlaudiosink->buffer); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gst_sdlaudio_sink_base_init (gpointer g_class) +{ + GstElementClass *element_class = GST_ELEMENT_CLASS (g_class); + + gst_element_class_set_details (element_class, &gst_sdlaudio_sink_details); + + gst_element_class_add_pad_template (element_class, + gst_static_pad_template_get (&sdlaudiosink_sink_factory)); +} +static void +gst_sdlaudio_sink_class_init (GstSDLAudioSinkClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + GstBaseSinkClass *gstbasesink_class; + GstBaseAudioSinkClass *gstbaseaudiosink_class; + GstAudioSinkClass *gstaudiosink_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + gstbasesink_class = (GstBaseSinkClass *) klass; + gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass; + gstaudiosink_class = (GstAudioSinkClass *) klass; + + parent_class = g_type_class_ref (GST_TYPE_BASE_AUDIO_SINK); + + gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_dispose); + + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_getcaps); + + gstaudiosink_class->open = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_open); + gstaudiosink_class->close = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_close); + gstaudiosink_class->prepare = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_prepare); + gstaudiosink_class->unprepare = + GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_unprepare); + gstaudiosink_class->write = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_write); + +#if 0 + gstaudiosink_class->delay = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_delay); + gstaudiosink_class->reset = GST_DEBUG_FUNCPTR (gst_sdlaudio_sink_reset); +#endif + +} + +static void +gst_sdlaudio_sink_init (GstSDLAudioSink * sdlaudiosink) +{ + GST_DEBUG ("initializing sdlaudiosink"); + + memset (&sdlaudiosink->fmt, 0, sizeof (SDL_AudioSpec)); + + sdlaudiosink->buffer = NULL; + sdlaudiosink->eos = FALSE; + + SEMAPHORE_INIT (sdlaudiosink->semA, TRUE); + + SEMAPHORE_INIT (sdlaudiosink->semB, TRUE); + +} + +static GstCaps * +gst_sdlaudio_sink_getcaps (GstBaseSink * bsink) +{ + GstSDLAudioSink *sdlaudiosink; + GstCaps *caps = NULL; + + sdlaudiosink = GST_SDLAUDIOSINK (bsink); + + caps = gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD + (bsink))); + return caps; +} + +static gint +gst_sdlaudio_sink_get_format (GstBufferFormat fmt) +{ + gint result = GST_UNKNOWN; + + switch (fmt) { + case GST_U8: + result = AUDIO_U8; + break; + case GST_S8: + result = AUDIO_S8; + break; + case GST_S16_LE: + result = AUDIO_S16LSB; + break; + case GST_S16_BE: + result = AUDIO_S16MSB; + break; + case GST_U16_LE: + result = AUDIO_U16LSB; + break; + case GST_U16_BE: + result = AUDIO_U16MSB; + break; + default: + break; + } + return result; +} + +static gboolean +gst_sdlaudio_sink_open (GstAudioSink * asink) +{ + GstSDLAudioSink *sdlaudio; + int mode; + + sdlaudio = GST_SDLAUDIOSINK (asink); + + if (SDL_Init (SDL_INIT_AUDIO) < 0) { + goto open_failed; + } + + return TRUE; + +open_failed: + { + GST_ELEMENT_ERROR (sdlaudio, LIBRARY, INIT, + ("Unable to init SDL: %s\n", SDL_GetError ()), (NULL)); + return FALSE; + } +} + +static gboolean +gst_sdlaudio_sink_close (GstAudioSink * asink) +{ + GstSDLAudioSink *sdlaudio = GST_SDLAUDIOSINK (asink); + + sdlaudio->eos = TRUE; + SEMAPHORE_UP (sdlaudio->semA); + SEMAPHORE_UP (sdlaudio->semB); + SDL_Quit (); + return TRUE; +} + +static guint +gst_sdlaudio_sink_write (GstAudioSink * asink, gpointer data, guint length) +{ + GstSDLAudioSink *sdlaudio = GST_SDLAUDIOSINK (asink); + + if (sdlaudio->fmt.size != length) { + GST_ERROR ("ring buffer segment lenght (%u) != sdl buffer len", length, + sdlaudio->fmt.size); + } + + SEMAPHORE_DOWN (sdlaudio->semA, sdlaudio->eos); + + if (!sdlaudio->eos) + memcpy (sdlaudio->buffer, data, length); + + SEMAPHORE_UP (sdlaudio->semB); + + return sdlaudio->fmt.size; +} + + +void +mixaudio (void *unused, Uint8 * stream, int len) +{ + GstSDLAudioSink *sdlaudio; + + sdlaudio = GST_SDLAUDIOSINK (unused); + + if (sdlaudio->fmt.size != len) { + GST_ERROR ("fmt buffer len (%u) != sdl callback len (%d)", + sdlaudio->fmt.size, len); + } + + SEMAPHORE_DOWN (sdlaudio->semB, sdlaudio->eos); + + if (!sdlaudio->eos) + SDL_MixAudio (stream, sdlaudio->buffer, sdlaudio->fmt.size, + SDL_MIX_MAXVOLUME); + + SEMAPHORE_UP (sdlaudio->semA); + +} + +static gboolean +gst_sdlaudio_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec) +{ + GstSDLAudioSink *sdlaudio; + gint power2 = -1; + + sdlaudio = GST_SDLAUDIOSINK (asink); + + sdlaudio->fmt.format = gst_sdlaudio_sink_get_format (spec->format); + if (sdlaudio->fmt.format == 0) + goto wrong_format; + + if (spec->width != 16 && spec->width != 8) + goto dodgy_width; + + sdlaudio->fmt.freq = spec->rate; + sdlaudio->fmt.channels = spec->channels; + sdlaudio->fmt.samples = + spec->segsize / (spec->channels * ((sdlaudio->fmt.format & 0xFF) >> 3)); + sdlaudio->fmt.callback = mixaudio; + sdlaudio->fmt.userdata = sdlaudio; + + GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize, + spec->segtotal, sdlaudio->fmt.samples); + + while (sdlaudio->fmt.samples) { + sdlaudio->fmt.samples >>= 1; + ++power2; + } + + sdlaudio->fmt.samples = 1; + sdlaudio->fmt.samples <<= power2; + + GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize, + spec->segtotal, sdlaudio->fmt.samples); + + if (SDL_OpenAudio (&sdlaudio->fmt, NULL) < 0) { + goto unable_open; + } + + spec->segsize = sdlaudio->fmt.size; + + sdlaudio->buffer = g_malloc (sdlaudio->fmt.size); + memset (sdlaudio->buffer, sdlaudio->fmt.silence, sdlaudio->fmt.size); + + GST_DEBUG ("set segsize: %d, segtotal: %d, samples: %d", spec->segsize, + spec->segtotal, sdlaudio->fmt.samples); + + spec->bytes_per_sample = + spec->channels * ((sdlaudio->fmt.format & 0xFF) >> 3); + memset (spec->silence_sample, sdlaudio->fmt.silence, spec->bytes_per_sample); + + SDL_PauseAudio (0); + + return TRUE; + +unable_open: + { + GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ, + ("Unable to open audio: %s", SDL_GetError ()), NULL); + return FALSE; + } +wrong_format: + { + GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ, + ("Unable to get format %d", spec->format), NULL); + return FALSE; + } +dodgy_width: + { + GST_ELEMENT_ERROR (sdlaudio, RESOURCE, OPEN_READ, + ("unexpected width %d", spec->width), NULL); + return FALSE; + } +} + +static gboolean +gst_sdlaudio_sink_unprepare (GstAudioSink * asink) +{ + + SDL_CloseAudio (); + + return TRUE; + +#if 0 + if (!gst_sdlaudio_sink_close (asink)) + goto couldnt_close; + + if (!gst_sdlaudio_sink_open (asink)) + goto couldnt_reopen; + + return TRUE; + +couldnt_close: + { + GST_DEBUG ("Could not close the audio device"); + return FALSE; + } +couldnt_reopen: + { + GST_DEBUG ("Could not reopen the audio device"); + return FALSE; + } +#endif + +} + +#if 0 +static guint +gst_sdlaudio_sink_delay (GstAudioSink * asink) +{ + GstSDLAudioSink *sdlaudio; + + sdlaudio = GST_SDLAUDIOSINK (asink); + + return 0; +} + +static void +gst_sdlaudio_sink_reset (GstAudioSink * asink) +{ +} +#endif diff --git a/ext/sdl/sdlaudiosink.h b/ext/sdl/sdlaudiosink.h new file mode 100644 index 00000000..646a7747 --- /dev/null +++ b/ext/sdl/sdlaudiosink.h @@ -0,0 +1,65 @@ +/* GStreamer + * Copyright (C) <2005> Edgard Lima <edgard.lima@indt.org.br> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more + */ + +#ifndef __GST_SDLAUDIOSINK_H__ +#define __GST_SDLAUDIOSINK_H__ + + +#include <gst/gst.h> +#include <gst/audio/gstaudiosink.h> + +#include <SDL.h> +#include <SDL_audio.h> + +G_BEGIN_DECLS + +#define GST_TYPE_SDLAUDIOSINK (gst_sdlaudio_sink_get_type()) +#define GST_SDLAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SDLAUDIOSINK,GstSDLAudioSink)) +#define GST_SDLAUDIOSINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SDLAUDIOSINK,GstSDLAudioSinkClass)) +#define GST_IS_SDLAUDIOSINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SDLAUDIOSINK)) +#define GST_IS_SDLAUDIOSINK_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SDLAUDIOSINK)) + +typedef struct _GstSDLAudioSink GstSDLAudioSink; +typedef struct _GstSDLAudioSinkClass GstSDLAudioSinkClass; + +typedef struct _gstsdl_semaphore { + GCond *cond; + GMutex *mutex; + gboolean mutexflag; + +} gstsdl_semaphore; + +struct _GstSDLAudioSink { + GstAudioSink sink; + + SDL_AudioSpec fmt; + guint8 *buffer; + + gstsdl_semaphore semA; + + gstsdl_semaphore semB; + + gboolean eos; + +}; + +struct _GstSDLAudioSinkClass { + GstAudioSinkClass parent_class; +}; + +GType gst_sdlaudio_sink_get_type(void); + +G_END_DECLS + +#endif /* __GST_SDLAUDIOSINK_H__ */ diff --git a/ext/sdl/sdlvideosink.c b/ext/sdl/sdlvideosink.c index 4f99835d..6d4688fb 100644 --- a/ext/sdl/sdlvideosink.c +++ b/ext/sdl/sdlvideosink.c @@ -32,8 +32,8 @@ #include "sdlvideosink.h" -GST_DEBUG_CATEGORY_STATIC (sdlvideosink_debug); -#define GST_CAT_DEFAULT sdlvideosink_debug +GST_DEBUG_CATEGORY_EXTERN (sdl_debug); +#define GST_CAT_DEFAULT sdl_debug /* These macros are adapted from videotestsrc.c * and/or gst-plugins/gst/games/gstvideoimage.c */ @@ -173,8 +173,6 @@ gst_sdlvideosink_base_init (gpointer g_class) gst_element_class_add_pad_template (element_class, sink_template); gst_element_class_set_details (element_class, &gst_sdlvideosink_details); - GST_DEBUG_CATEGORY_INIT (sdlvideosink_debug, "sdlvideosink", 0, - "SDL video sink element"); } static void @@ -844,19 +842,3 @@ init_failed: return GST_STATE_CHANGE_FAILURE; } } - - -static gboolean -plugin_init (GstPlugin * plugin) -{ - if (!gst_element_register (plugin, "sdlvideosink", GST_RANK_NONE, - GST_TYPE_SDLVIDEOSINK)) - return FALSE; - - return TRUE; -} - -GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, - GST_VERSION_MINOR, - "sdlvideosink", - "SDL Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE, GST_ORIGIN) |