summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/directsound/gstdirectsoundsink.c367
-rw-r--r--sys/directsound/gstdirectsoundsink.h9
-rw-r--r--sys/oss/gstosshelper.c37
-rw-r--r--sys/oss/gstossmixer.h14
-rw-r--r--sys/oss/gstosssink.c27
-rw-r--r--sys/oss/gstosssrc.c28
-rw-r--r--sys/oss4/oss4-audio.c4
-rw-r--r--sys/oss4/oss4-mixer-slider.c4
-rw-r--r--sys/oss4/oss4-mixer.c27
-rw-r--r--sys/oss4/oss4-sink.c3
-rw-r--r--sys/oss4/oss4-source.c15
-rw-r--r--sys/osxaudio/gstosxaudioelement.c8
-rw-r--r--sys/osxaudio/gstosxaudiosink.c3
-rw-r--r--sys/osxaudio/gstosxaudiosrc.c3
-rw-r--r--sys/osxvideo/osxvideosink.m4
-rw-r--r--sys/sunaudio/gstsunaudiomixerctrl.h20
-rw-r--r--sys/sunaudio/gstsunaudiosink.c4
-rw-r--r--sys/sunaudio/gstsunaudiosrc.c4
-rw-r--r--sys/v4l2/Makefile.am13
-rw-r--r--sys/v4l2/gstv4l2.c8
-rw-r--r--sys/v4l2/gstv4l2bufferpool.c1378
-rw-r--r--sys/v4l2/gstv4l2bufferpool.h92
-rw-r--r--sys/v4l2/gstv4l2colorbalance.c14
-rw-r--r--sys/v4l2/gstv4l2colorbalance.h19
-rw-r--r--sys/v4l2/gstv4l2object.c904
-rw-r--r--sys/v4l2/gstv4l2object.h83
-rw-r--r--sys/v4l2/gstv4l2radio.c126
-rw-r--r--sys/v4l2/gstv4l2sink.c535
-rw-r--r--sys/v4l2/gstv4l2sink.h6
-rw-r--r--sys/v4l2/gstv4l2src.c692
-rw-r--r--sys/v4l2/gstv4l2src.h21
-rw-r--r--sys/v4l2/gstv4l2tuner.c1
-rw-r--r--sys/v4l2/gstv4l2tuner.h20
-rw-r--r--sys/v4l2/gstv4l2videooverlay.c (renamed from sys/v4l2/gstv4l2xoverlay.c)90
-rw-r--r--sys/v4l2/gstv4l2videooverlay.h (renamed from sys/v4l2/gstv4l2xoverlay.h)39
-rw-r--r--sys/v4l2/gstv4l2vidorient.c3
-rw-r--r--sys/v4l2/gstv4l2vidorient.h22
-rw-r--r--sys/v4l2/v4l2_calls.c7
-rw-r--r--sys/v4l2/v4l2_calls.h8
-rw-r--r--sys/v4l2/v4l2src_calls.c434
-rw-r--r--sys/v4l2/v4l2src_calls.h46
-rw-r--r--sys/waveform/gstwaveformsink.c113
-rw-r--r--sys/ximage/Makefile.am2
-rw-r--r--sys/ximage/gstximagesrc.c215
-rw-r--r--sys/ximage/gstximagesrc.h6
-rw-r--r--sys/ximage/ximageutil.c190
-rw-r--r--sys/ximage/ximageutil.h31
47 files changed, 2715 insertions, 2984 deletions
diff --git a/sys/directsound/gstdirectsoundsink.c b/sys/directsound/gstdirectsoundsink.c
index 2f9a04c65b..49f2afa8ae 100644
--- a/sys/directsound/gstdirectsoundsink.c
+++ b/sys/directsound/gstdirectsoundsink.c
@@ -52,6 +52,8 @@
#include "config.h"
#endif
+#include <gst/base/gstbasesink.h>
+#include <gst/audio/streamvolume.h>
#include "gstdirectsoundsink.h"
#include <math.h>
@@ -63,228 +65,85 @@
#endif
#endif
+#define DEFAULT_MUTE FALSE
+
GST_DEBUG_CATEGORY_STATIC (directsoundsink_debug);
#define GST_CAT_DEFAULT directsoundsink_debug
-static void gst_directsound_sink_finalise (GObject * object);
+static void gst_directsound_sink_finalize (GObject * object);
static void gst_directsound_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_directsound_sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-static GstCaps *gst_directsound_sink_getcaps (GstBaseSink * bsink);
+static GstCaps *gst_directsound_sink_getcaps (GstBaseSink * bsink,
+ GstCaps * filter);
static gboolean gst_directsound_sink_prepare (GstAudioSink * asink,
- GstRingBufferSpec * spec);
+ GstAudioRingBufferSpec * spec);
static gboolean gst_directsound_sink_unprepare (GstAudioSink * asink);
-
static gboolean gst_directsound_sink_open (GstAudioSink * asink);
static gboolean gst_directsound_sink_close (GstAudioSink * asink);
-static guint gst_directsound_sink_write (GstAudioSink * asink, gpointer data,
- guint length);
+static gint gst_directsound_sink_write (GstAudioSink * asink,
+ gpointer data, guint length);
static guint gst_directsound_sink_delay (GstAudioSink * asink);
static void gst_directsound_sink_reset (GstAudioSink * asink);
static GstCaps *gst_directsound_probe_supported_formats (GstDirectSoundSink *
dsoundsink, const GstCaps * template_caps);
-/* interfaces */
-static void gst_directsound_sink_interfaces_init (GType type);
-static void
-gst_directsound_sink_implements_interface_init (GstImplementsInterfaceClass *
- iface);
-static void gst_directsound_sink_mixer_interface_init (GstMixerClass * iface);
+static void gst_directsound_sink_set_volume (GstDirectSoundSink * sink,
+ gdouble volume, gboolean store);
+static gdouble gst_directsound_sink_get_volume (GstDirectSoundSink * sink);
+static void gst_directsound_sink_set_mute (GstDirectSoundSink * sink,
+ gboolean mute);
+static gboolean gst_directsound_sink_get_mute (GstDirectSoundSink * sink);
static GstStaticPadTemplate directsoundsink_sink_factory =
GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-raw-int, "
- "signed = (boolean) TRUE, "
- "width = (int) 16, "
- "depth = (int) 16, "
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) S16LE, "
+ "layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
- "audio/x-raw-int, "
- "signed = (boolean) FALSE, "
- "width = (int) 8, "
- "depth = (int) 8, "
+ "audio/x-raw, "
+ "format = (string) S8, "
+ "layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ];"
"audio/x-iec958"));
enum
{
PROP_0,
- PROP_VOLUME
+ PROP_VOLUME,
+ PROP_MUTE
};
-GST_BOILERPLATE_FULL (GstDirectSoundSink, gst_directsound_sink, GstAudioSink,
- GST_TYPE_AUDIO_SINK, gst_directsound_sink_interfaces_init);
-
-/* interfaces stuff */
-static void
-gst_directsound_sink_interfaces_init (GType type)
-{
- static const GInterfaceInfo implements_interface_info = {
- (GInterfaceInitFunc) gst_directsound_sink_implements_interface_init,
- NULL,
- NULL,
- };
-
- static const GInterfaceInfo mixer_interface_info = {
- (GInterfaceInitFunc) gst_directsound_sink_mixer_interface_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type,
- GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info);
- g_type_add_interface_static (type, GST_TYPE_MIXER, &mixer_interface_info);
-}
-
-static gboolean
-gst_directsound_sink_interface_supported (GstImplementsInterface * iface,
- GType iface_type)
-{
- g_return_val_if_fail (iface_type == GST_TYPE_MIXER, FALSE);
-
- /* for the sake of this example, we'll always support it. However, normally,
- * you would check whether the device you've opened supports mixers. */
- return TRUE;
-}
-
-static void
-gst_directsound_sink_implements_interface_init (GstImplementsInterfaceClass *
- iface)
-{
- iface->supported = gst_directsound_sink_interface_supported;
-}
-
-/*
- * This function returns the list of support tracks (inputs, outputs)
- * on this element instance. Elements usually build this list during
- * _init () or when going from NULL to READY.
- */
-
-static const GList *
-gst_directsound_sink_mixer_list_tracks (GstMixer * mixer)
-{
- GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer);
-
- return dsoundsink->tracks;
-}
-
-static void
-gst_directsound_sink_set_volume (GstDirectSoundSink * dsoundsink)
-{
- if (dsoundsink->pDSBSecondary) {
- /* DirectSound controls volume using units of 100th of a decibel,
- * ranging from -10000 to 0. We use a linear scale of 0 - 100
- * here, so remap.
- */
- long dsVolume;
- if (dsoundsink->volume == 0)
- dsVolume = -10000;
- else
- dsVolume = 100 * (long) (20 * log10 ((double) dsoundsink->volume / 100.));
- dsVolume = CLAMP (dsVolume, -10000, 0);
-
- GST_DEBUG_OBJECT (dsoundsink,
- "Setting volume on secondary buffer to %d from %d", (int) dsVolume,
- (int) dsoundsink->volume);
- IDirectSoundBuffer_SetVolume (dsoundsink->pDSBSecondary, dsVolume);
- }
-}
-
-/*
- * Set volume. volumes is an array of size track->num_channels, and
- * each value in the array gives the wanted volume for one channel
- * on the track.
- */
-
-static void
-gst_directsound_sink_mixer_set_volume (GstMixer * mixer,
- GstMixerTrack * track, gint * volumes)
-{
- GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer);
-
- if (volumes[0] != dsoundsink->volume) {
- dsoundsink->volume = volumes[0];
-
- gst_directsound_sink_set_volume (dsoundsink);
- }
-}
-
-static void
-gst_directsound_sink_mixer_get_volume (GstMixer * mixer,
- GstMixerTrack * track, gint * volumes)
-{
- GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (mixer);
-
- volumes[0] = dsoundsink->volume;
-}
+#define gst_directsound_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstDirectSoundSink, gst_directsound_sink,
+ GST_TYPE_AUDIO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_STREAM_VOLUME, NULL)
+ );
static void
-gst_directsound_sink_mixer_interface_init (GstMixerClass * iface)
+gst_directsound_sink_finalize (GObject * object)
{
- /* the mixer interface requires a definition of the mixer type:
- * hardware or software? */
- GST_MIXER_TYPE (iface) = GST_MIXER_SOFTWARE;
-
- /* virtual function pointers */
- iface->list_tracks = gst_directsound_sink_mixer_list_tracks;
- iface->set_volume = gst_directsound_sink_mixer_set_volume;
- iface->get_volume = gst_directsound_sink_mixer_get_volume;
-}
-
-static void
-gst_directsound_sink_finalise (GObject * object)
-{
- GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (object);
-
- g_mutex_free (dsoundsink->dsound_lock);
-
- if (dsoundsink->tracks) {
- g_list_foreach (dsoundsink->tracks, (GFunc) g_object_unref, NULL);
- g_list_free (dsoundsink->tracks);
- dsoundsink->tracks = NULL;
- }
-
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
-gst_directsound_sink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class,
- "Direct Sound Audio Sink", "Sink/Audio",
- "Output to a sound card via Direct Sound",
- "Sebastien Moutte <sebastien@moutte.net>");
- gst_element_class_add_static_pad_template (element_class,
- &directsoundsink_sink_factory);
-}
-
-static void
gst_directsound_sink_class_init (GstDirectSoundSinkClass * 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;
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GstBaseSinkClass *gstbasesink_class = GST_BASE_SINK_CLASS (klass);
+ GstAudioSinkClass *gstaudiosink_class = GST_AUDIO_SINK_CLASS (klass);
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
GST_DEBUG_CATEGORY_INIT (directsoundsink_debug, "directsoundsink", 0,
"DirectSound sink");
parent_class = g_type_class_peek_parent (klass);
- gobject_class->finalize = gst_directsound_sink_finalise;
+ gobject_class->finalize = gst_directsound_sink_finalize;
gobject_class->set_property = gst_directsound_sink_set_property;
gobject_class->get_property = gst_directsound_sink_get_property;
@@ -306,23 +165,27 @@ gst_directsound_sink_class_init (GstDirectSoundSinkClass * klass)
g_param_spec_double ("volume", "Volume",
"Volume of this stream", 0.0, 1.0, 1.0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class,
+ PROP_MUTE,
+ g_param_spec_boolean ("mute", "Mute",
+ "Mute state of this stream", DEFAULT_MUTE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_set_details_simple (element_class,
+ "Direct Sound Audio Sink", "Sink/Audio",
+ "Output to a sound card via Direct Sound",
+ "Sebastien Moutte <sebastien@moutte.net>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&directsoundsink_sink_factory));
}
static void
-gst_directsound_sink_init (GstDirectSoundSink * dsoundsink,
- GstDirectSoundSinkClass * g_class)
+gst_directsound_sink_init (GstDirectSoundSink * dsoundsink)
{
- GstMixerTrack *track = NULL;
-
- dsoundsink->tracks = NULL;
- track = g_object_new (GST_TYPE_MIXER_TRACK, NULL);
- track->label = g_strdup ("DSoundTrack");
- track->num_channels = 2;
- track->min_volume = 0;
- track->max_volume = 100;
- track->flags = GST_MIXER_TRACK_OUTPUT;
- dsoundsink->tracks = g_list_append (dsoundsink->tracks, track);
-
+ dsoundsink->volume = 100;
+ dsoundsink->mute = FALSE;
dsoundsink->pDS = NULL;
dsoundsink->cached_caps = NULL;
dsoundsink->pDSBSecondary = NULL;
@@ -341,8 +204,10 @@ gst_directsound_sink_set_property (GObject * object,
switch (prop_id) {
case PROP_VOLUME:
- sink->volume = (int) (g_value_get_double (value) * 100);
- gst_directsound_sink_set_volume (sink);
+ gst_directsound_sink_set_volume (sink, g_value_get_double (value), TRUE);
+ break;
+ case PROP_MUTE:
+ gst_directsound_sink_set_mute (sink, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -358,7 +223,10 @@ gst_directsound_sink_get_property (GObject * object,
switch (prop_id) {
case PROP_VOLUME:
- g_value_set_double (value, (double) sink->volume / 100.);
+ g_value_set_double (value, gst_directsound_sink_get_volume (sink));
+ break;
+ case PROP_MUTE:
+ g_value_set_boolean (value, gst_directsound_sink_get_mute (sink));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -367,7 +235,7 @@ gst_directsound_sink_get_property (GObject * object,
}
static GstCaps *
-gst_directsound_sink_getcaps (GstBaseSink * bsink)
+gst_directsound_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
GstElementClass *element_class;
GstPadTemplate *pad_template;
@@ -409,9 +277,11 @@ gst_directsound_sink_getcaps (GstBaseSink * bsink)
static gboolean
gst_directsound_sink_open (GstAudioSink * asink)
{
- GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (asink);
+ GstDirectSoundSink *dsoundsink;
HRESULT hRes;
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
/* create and initialize a DirecSound object */
if (FAILED (hRes = DirectSoundCreate (NULL, &dsoundsink->pDS, NULL))) {
GST_ELEMENT_ERROR (dsoundsink, RESOURCE, OPEN_READ,
@@ -432,47 +302,50 @@ gst_directsound_sink_open (GstAudioSink * asink)
}
static gboolean
-gst_directsound_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
+gst_directsound_sink_prepare (GstAudioSink * asink,
+ GstAudioRingBufferSpec * spec)
{
- GstDirectSoundSink *dsoundsink = GST_DIRECTSOUND_SINK (asink);
+ GstDirectSoundSink *dsoundsink;
HRESULT hRes;
DSBUFFERDESC descSecondary;
WAVEFORMATEX wfx;
+ dsoundsink = GST_DIRECTSOUND_SINK (asink);
+
/*save number of bytes per sample and buffer format */
- dsoundsink->bytes_per_sample = spec->bytes_per_sample;
- dsoundsink->buffer_format = spec->format;
+ dsoundsink->bytes_per_sample = spec->info.bpf;
+ dsoundsink->type = spec->type;
/* fill the WAVEFORMATEX structure with spec params */
memset (&wfx, 0, sizeof (wfx));
- if (spec->format != GST_IEC958) {
+ if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958) {
wfx.cbSize = sizeof (wfx);
wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nChannels = spec->channels;
- wfx.nSamplesPerSec = spec->rate;
- wfx.wBitsPerSample = (spec->bytes_per_sample * 8) / wfx.nChannels;
- wfx.nBlockAlign = spec->bytes_per_sample;
+ wfx.nChannels = spec->info.channels;
+ wfx.nSamplesPerSec = spec->info.rate;
+ wfx.wBitsPerSample = (spec->info.bpf * 8) / wfx.nChannels;
+ wfx.nBlockAlign = spec->info.bpf;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
- /* Create directsound buffer with size based on our configured
+ /* Create directsound buffer with size based on our configured
* buffer_size (which is 200 ms by default) */
dsoundsink->buffer_size =
gst_util_uint64_scale_int (wfx.nAvgBytesPerSec, spec->buffer_time,
GST_MSECOND);
/* Make sure we make those numbers multiple of our sample size in bytes */
- dsoundsink->buffer_size += dsoundsink->buffer_size % spec->bytes_per_sample;
+ dsoundsink->buffer_size += dsoundsink->buffer_size % spec->info.bpf;
spec->segsize =
gst_util_uint64_scale_int (wfx.nAvgBytesPerSec, spec->latency_time,
GST_MSECOND);
- spec->segsize += spec->segsize % spec->bytes_per_sample;
+ spec->segsize += spec->segsize % spec->info.bpf;
spec->segtotal = dsoundsink->buffer_size / spec->segsize;
} else {
#ifdef WAVE_FORMAT_DOLBY_AC3_SPDIF
wfx.cbSize = 0;
wfx.wFormatTag = WAVE_FORMAT_DOLBY_AC3_SPDIF;
wfx.nChannels = 2;
- wfx.nSamplesPerSec = spec->rate;
+ wfx.nSamplesPerSec = spec->info.rate;
wfx.wBitsPerSample = 16;
wfx.nBlockAlign = wfx.wBitsPerSample / 8 * wfx.nChannels;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
@@ -490,15 +363,15 @@ gst_directsound_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
GST_INFO_OBJECT (dsoundsink,
"GstRingBufferSpec->channels: %d, GstRingBufferSpec->rate: %d, GstRingBufferSpec->bytes_per_sample: %d\n"
"WAVEFORMATEX.nSamplesPerSec: %ld, WAVEFORMATEX.wBitsPerSample: %d, WAVEFORMATEX.nBlockAlign: %d, WAVEFORMATEX.nAvgBytesPerSec: %ld\n"
- "Size of dsound circular buffer=>%d\n", spec->channels, spec->rate,
- spec->bytes_per_sample, wfx.nSamplesPerSec, wfx.wBitsPerSample,
+ "Size of dsound circular buffer=>%d\n", spec->info.channels,
+ spec->info.rate, spec->info.bpf, wfx.nSamplesPerSec, wfx.wBitsPerSample,
wfx.nBlockAlign, wfx.nAvgBytesPerSec, dsoundsink->buffer_size);
/* create a secondary directsound buffer */
memset (&descSecondary, 0, sizeof (DSBUFFERDESC));
descSecondary.dwSize = sizeof (DSBUFFERDESC);
descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
- if (spec->format != GST_IEC958)
+ if (spec->type != GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958)
descSecondary.dwFlags |= DSBCAPS_CTRLVOLUME;
descSecondary.dwBufferBytes = dsoundsink->buffer_size;
@@ -513,7 +386,7 @@ gst_directsound_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
return FALSE;
}
- gst_directsound_sink_set_volume (dsoundsink);
+ gst_directsound_sink_set_volume (dsoundsink, dsoundsink->volume, FALSE);
return TRUE;
}
@@ -551,7 +424,7 @@ gst_directsound_sink_close (GstAudioSink * asink)
return TRUE;
}
-static guint
+static gint
gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length)
{
GstDirectSoundSink *dsoundsink;
@@ -564,7 +437,7 @@ gst_directsound_sink_write (GstAudioSink * asink, gpointer data, guint length)
dsoundsink = GST_DIRECTSOUND_SINK (asink);
/* Fix endianness */
- if (dsoundsink->buffer_format == GST_IEC958)
+ if (dsoundsink->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958)
_swab (data, data, length);
GST_DSOUND_LOCK (dsoundsink);
@@ -719,12 +592,12 @@ gst_directsound_sink_reset (GstAudioSink * asink)
GST_DSOUND_UNLOCK (dsoundsink);
}
-/*
- * gst_directsound_probe_supported_formats:
- *
- * Takes the template caps and returns the subset which is actually
- * supported by this device.
- *
+/*
+ * gst_directsound_probe_supported_formats:
+ *
+ * Takes the template caps and returns the subset which is actually
+ * supported by this device.
+ *
*/
static GstCaps *
@@ -738,8 +611,8 @@ gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink,
caps = gst_caps_copy (template_caps);
- /*
- * Check availability of digital output by trying to create an SPDIF buffer
+ /*
+ * Check availability of digital output by trying to create an SPDIF buffer
*/
#ifdef WAVE_FORMAT_DOLBY_AC3_SPDIF
@@ -753,7 +626,7 @@ gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink,
wfx.nBlockAlign = 4;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
- // create a secondary directsound buffer
+ // create a secondary directsound buffer
memset (&descSecondary, 0, sizeof (DSBUFFERDESC));
descSecondary.dwSize = sizeof (DSBUFFERDESC);
descSecondary.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
@@ -767,7 +640,7 @@ gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink,
"(IDirectSound_CreateSoundBuffer returned: %s)\n",
DXGetErrorString9 (hRes));
caps =
- gst_caps_subtract (caps, gst_caps_new_simple ("audio/x-iec958", NULL));
+ gst_caps_subtract (caps, gst_caps_new_empty_simple ("audio/x-iec958"));
} else {
GST_INFO_OBJECT (dsoundsink, "AC3 passthrough supported");
hRes = IDirectSoundBuffer_Release (dsoundsink->pDSBSecondary);
@@ -783,3 +656,53 @@ gst_directsound_probe_supported_formats (GstDirectSoundSink * dsoundsink,
return caps;
}
+
+static void
+gst_directsound_sink_set_volume (GstDirectSoundSink * dsoundsink,
+ gdouble dvolume, gboolean store)
+{
+ glong volume;
+
+ volume = dvolume * 100;
+ if (store)
+ dsoundsink->volume = volume;
+
+ if (dsoundsink->pDSBSecondary) {
+ /* DirectSound controls volume using units of 100th of a decibel,
+ * ranging from -10000 to 0. We use a linear scale of 0 - 100
+ * here, so remap.
+ */
+ long dsVolume;
+ if (dsoundsink->volume == 0)
+ dsVolume = -10000;
+ else
+ dsVolume = 100 * (long) (20 * log10 ((double) dsoundsink->volume / 100.));
+ dsVolume = CLAMP (dsVolume, -10000, 0);
+
+ GST_DEBUG_OBJECT (dsoundsink,
+ "Setting volume on secondary buffer to %d from %d", (int) dsVolume,
+ (int) dsoundsink->volume);
+ IDirectSoundBuffer_SetVolume (dsoundsink->pDSBSecondary, dsVolume);
+ }
+}
+
+gdouble
+gst_directsound_sink_get_volume (GstDirectSoundSink * dsoundsink)
+{
+ return (gdouble) dsoundsink->volume / 100;
+}
+
+static void
+gst_directsound_sink_set_mute (GstDirectSoundSink * dsoundsink, gboolean mute)
+{
+ if (mute)
+ gst_directsound_sink_set_volume (dsoundsink, 0, FALSE);
+ else
+ gst_directsound_sink_set_volume (dsoundsink, dsoundsink->volume, FALSE);
+}
+
+static gboolean
+gst_directsound_sink_get_mute (GstDirectSoundSink * dsoundsink)
+{
+ return FALSE;
+}
diff --git a/sys/directsound/gstdirectsoundsink.h b/sys/directsound/gstdirectsoundsink.h
index 8bb10bf34d..5e23f19342 100644
--- a/sys/directsound/gstdirectsoundsink.h
+++ b/sys/directsound/gstdirectsoundsink.h
@@ -31,7 +31,6 @@
#include <gst/gst.h>
#include <gst/audio/gstaudiosink.h>
-#include <gst/interfaces/mixer.h>
#include <windows.h>
#include <dxerr9.h>
@@ -56,6 +55,7 @@ struct _GstDirectSoundSink
{
GstAudioSink sink;
+
/* directsound object interface pointer */
LPDIRECTSOUND pDS;
@@ -72,18 +72,15 @@ struct _GstDirectSoundSink
/* current volume setup by mixer interface */
glong volume;
-
- /* tracks list of our mixer interface implementation */
- GList *tracks;
+ gboolean mute;
GstCaps *cached_caps;
-
/* lock used to protect writes and resets */
GMutex *dsound_lock;
gboolean first_buffer_after_reset;
- GstBufferFormat buffer_format;
+ GstAudioRingBufferFormatType type;
};
struct _GstDirectSoundSinkClass
diff --git a/sys/oss/gstosshelper.c b/sys/oss/gstosshelper.c
index 6d7e6bd3e1..639ee9d8f4 100644
--- a/sys/oss/gstosshelper.c
+++ b/sys/oss/gstosshelper.c
@@ -169,53 +169,34 @@ static GstStructure *
gst_oss_helper_get_format_structure (unsigned int format_bit)
{
GstStructure *structure;
- int endianness;
- gboolean sign;
- int width;
+ const gchar *format;
switch (format_bit) {
case AFMT_U8:
- endianness = 0;
- sign = FALSE;
- width = 8;
+ format = "U8";
break;
case AFMT_S16_LE:
- endianness = G_LITTLE_ENDIAN;
- sign = TRUE;
- width = 16;
+ format = "S16_LE";
break;
case AFMT_S16_BE:
- endianness = G_BIG_ENDIAN;
- sign = TRUE;
- width = 16;
+ format = "S16_BE";
break;
case AFMT_S8:
- endianness = 0;
- sign = TRUE;
- width = 8;
+ format = "S8";
break;
case AFMT_U16_LE:
- endianness = G_LITTLE_ENDIAN;
- sign = FALSE;
- width = 16;
+ format = "U16_LE";
break;
case AFMT_U16_BE:
- endianness = G_BIG_ENDIAN;
- sign = FALSE;
- width = 16;
+ format = "U16_BE";
break;
default:
g_assert_not_reached ();
return NULL;
}
- structure = gst_structure_new ("audio/x-raw-int",
- "width", G_TYPE_INT, width,
- "depth", G_TYPE_INT, width, "signed", G_TYPE_BOOLEAN, sign, NULL);
-
- if (endianness) {
- gst_structure_set (structure, "endianness", G_TYPE_INT, endianness, NULL);
- }
+ structure = gst_structure_new ("audio/x-raw",
+ "format", G_TYPE_STRING, format, NULL);
return structure;
}
diff --git a/sys/oss/gstossmixer.h b/sys/oss/gstossmixer.h
index d2e06fed92..4ae888aba7 100644
--- a/sys/oss/gstossmixer.h
+++ b/sys/oss/gstossmixer.h
@@ -152,16 +152,16 @@ interface_as_function ## _set_mute (GstMixer * mixer, GstMixerTrack * track,
} \
\
static void \
-interface_as_function ## _interface_init (GstMixerClass * klass) \
+interface_as_function ## _interface_init (GstMixerInterface * iface) \
{ \
- GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \
+ GST_MIXER_TYPE (iface) = GST_MIXER_HARDWARE; \
\
/* set up the interface hooks */ \
- klass->list_tracks = interface_as_function ## _list_tracks; \
- klass->set_volume = interface_as_function ## _set_volume; \
- klass->get_volume = interface_as_function ## _get_volume; \
- klass->set_mute = interface_as_function ## _set_mute; \
- klass->set_record = interface_as_function ## _set_record; \
+ iface->list_tracks = interface_as_function ## _list_tracks; \
+ iface->set_volume = interface_as_function ## _set_volume; \
+ iface->get_volume = interface_as_function ## _get_volume; \
+ iface->set_mute = interface_as_function ## _set_mute; \
+ iface->set_record = interface_as_function ## _set_record; \
}
diff --git a/sys/oss/gstosssink.c b/sys/oss/gstosssink.c
index a604d9c3a8..67813476b2 100644
--- a/sys/oss/gstosssink.c
+++ b/sys/oss/gstosssink.c
@@ -110,21 +110,22 @@ enum
PROP_DEVICE,
};
+#define FORMATS "{" GST_AUDIO_NE(S16)","GST_AUDIO_NE(U16)", S8, U8 }"
+
static GstStaticPadTemplate osssink_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, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 8, "
- "depth = (int) 8, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) " FORMATS ", "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) 1; "
+ "audio/x-raw, "
+ "format = (string) " FORMATS ", "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
);
static GstElementClass *parent_class = NULL;
@@ -181,8 +182,8 @@ gst_oss_sink_base_init (gpointer g_class)
"Erik Walthinsen <omega@cse.ogi.edu>, "
"Wim Taymans <wim.taymans@chello.be>");
- gst_element_class_add_static_pad_template (element_class,
- &osssink_sink_factory);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&osssink_sink_factory));
}
static void
diff --git a/sys/oss/gstosssrc.c b/sys/oss/gstosssrc.c
index 2bd931b1bc..f8ac8a93bf 100644
--- a/sys/oss/gstosssrc.c
+++ b/sys/oss/gstosssrc.c
@@ -101,25 +101,23 @@ static guint gst_oss_src_read (GstAudioSrc * asrc, gpointer data, guint length);
static guint gst_oss_src_delay (GstAudioSrc * asrc);
static void gst_oss_src_reset (GstAudioSrc * asrc);
-
+#define FORMATS "{" GST_AUDIO_NE(S16)","GST_AUDIO_NE(U16)", S8, U8 }"
static GstStaticPadTemplate osssrc_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
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, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 8, "
- "depth = (int) 8, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]")
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) " FORMATS ", "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) 1; "
+ "audio/x-raw, "
+ "format = (string) " FORMATS ", "
+ "layout = (string) interleaved, "
+ "rate = (int) [ 1, MAX ], "
+ "channels = (int) 2, " "channel-mask = (bitmask) 0x3")
);
-
static void
gst_oss_src_dispose (GObject * object)
{
@@ -136,8 +134,8 @@ gst_oss_src_base_init (gpointer g_class)
"Capture from a sound card via OSS",
"Erik Walthinsen <omega@cse.ogi.edu>, " "Wim Taymans <wim@fluendo.com>");
- gst_element_class_add_static_pad_template (element_class,
- &osssrc_src_factory);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&osssrc_src_factory));
}
static void
diff --git a/sys/oss4/oss4-audio.c b/sys/oss4/oss4-audio.c
index 6317400dc5..c788a13807 100644
--- a/sys/oss4/oss4-audio.c
+++ b/sys/oss4/oss4-audio.c
@@ -458,7 +458,7 @@ gst_oss4_audio_probe_caps (GstObject * obj, int fd)
}
}
- gst_caps_do_simplify (caps);
+ caps = gst_caps_do_simplify (caps);
GST_LOG_OBJECT (obj, "formats: %" GST_PTR_FORMAT, caps);
if (!gst_oss4_audio_detect_rates (obj, &ai, caps))
@@ -505,7 +505,7 @@ gst_oss4_audio_get_template_caps (void)
gst_oss4_append_format_to_caps (&fmt_map[i], caps);
}
- gst_caps_do_simplify (caps);
+ caps = gst_caps_do_simplify (caps);
for (i = 0; i < gst_caps_get_size (caps); ++i) {
GstStructure *s;
diff --git a/sys/oss4/oss4-mixer-slider.c b/sys/oss4/oss4-mixer-slider.c
index ea2bc8cb2a..e71d1348fe 100644
--- a/sys/oss4/oss4-mixer-slider.c
+++ b/sys/oss4/oss4-mixer-slider.c
@@ -219,7 +219,7 @@ gst_oss4_mixer_slider_set_mute (GstOss4MixerSlider * s, gboolean mute)
}
ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc, volume);
} else {
- ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc->mute, ! !mute);
+ ret = gst_oss4_mixer_set_control_val (s->mixer, s->mc->mute, !!mute);
}
if (mute) {
@@ -286,7 +286,7 @@ gst_oss4_mixer_slider_process_change_unlocked (GstMixerTrack * track)
if (s->mc->mute != NULL && s->mc->mute->changed) {
gst_mixer_mute_toggled (GST_MIXER (s->mixer), track,
- ! !s->mc->mute->last_val);
+ !!s->mc->mute->last_val);
} else {
/* nothing to do here, since we don't/can't easily implement the record
* flag */
diff --git a/sys/oss4/oss4-mixer.c b/sys/oss4/oss4-mixer.c
index 03e2d9d729..49da03ceb1 100644
--- a/sys/oss4/oss4-mixer.c
+++ b/sys/oss4/oss4-mixer.c
@@ -542,13 +542,8 @@ gst_oss4_mixer_start_watch_task (GstOss4Mixer * mixer)
mixer->watch_cond = g_cond_new ();
mixer->watch_shutdown = FALSE;
-#if !GLIB_CHECK_VERSION (2, 31, 0)
- mixer->watch_thread = g_thread_create (gst_oss4_mixer_watch_thread,
- gst_object_ref (mixer), TRUE, &err);
-#else
mixer->watch_thread = g_thread_try_new ("oss4-mixer-thread",
gst_oss4_mixer_watch_thread, gst_object_ref (mixer), &err);
-#endif
if (mixer->watch_thread == NULL) {
GST_ERROR_OBJECT (mixer, "Could not create watch thread: %s", err->message);
@@ -1806,18 +1801,18 @@ gst_oss4_mixer_get_mixer_flags (GstMixer * mixer)
}
static void
-gst_oss4_mixer_interface_init (GstMixerClass * klass)
+gst_oss4_mixer_interface_init (GstMixerInterface * iface)
{
- GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE;
-
- klass->list_tracks = gst_oss4_mixer_list_tracks;
- klass->set_volume = gst_oss4_mixer_set_volume;
- klass->get_volume = gst_oss4_mixer_get_volume;
- klass->set_mute = gst_oss4_mixer_set_mute;
- klass->set_record = gst_oss4_mixer_set_record;
- klass->set_option = gst_oss4_mixer_set_option;
- klass->get_option = gst_oss4_mixer_get_option;
- klass->get_mixer_flags = gst_oss4_mixer_get_mixer_flags;
+ GST_MIXER_TYPE (iface) = GST_MIXER_HARDWARE;
+
+ iface->list_tracks = gst_oss4_mixer_list_tracks;
+ iface->set_volume = gst_oss4_mixer_set_volume;
+ iface->get_volume = gst_oss4_mixer_get_volume;
+ iface->set_mute = gst_oss4_mixer_set_mute;
+ iface->set_record = gst_oss4_mixer_set_record;
+ iface->set_option = gst_oss4_mixer_set_option;
+ iface->get_option = gst_oss4_mixer_get_option;
+ iface->get_mixer_flags = gst_oss4_mixer_get_mixer_flags;
}
/* Implement the horror that is GstImplementsInterface */
diff --git a/sys/oss4/oss4-sink.c b/sys/oss4/oss4-sink.c
index 54e95b9f9e..81f8d2af28 100644
--- a/sys/oss4/oss4-sink.c
+++ b/sys/oss4/oss4-sink.c
@@ -134,7 +134,6 @@ gst_oss4_sink_base_init (gpointer g_class)
templ = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
gst_oss4_audio_get_template_caps ());
gst_element_class_add_pad_template (element_class, templ);
- gst_object_unref (templ);
}
static void
@@ -477,7 +476,7 @@ gst_oss4_sink_open (GstAudioSink * asink, gboolean silent_errors)
if (ioctl (oss->fd, SNDCTL_DSP_GET_PLAYTGT_NAMES, &routings) != -1) {
GST_LOG_OBJECT (oss, "%u output routings (static list: %d)",
- routings.nvalues, !!(routings.version == 0));
+ routings.nvalues, ! !(routings.version == 0));
for (i = 0; i < routings.nvalues; ++i) {
GST_LOG_OBJECT (oss, " output routing %d: %s", i,
&routings.strings[routings.strindex[i]]);
diff --git a/sys/oss4/oss4-source.c b/sys/oss4/oss4-source.c
index eadb4c5e31..b80f9b7707 100644
--- a/sys/oss4/oss4-source.c
+++ b/sys/oss4/oss4-source.c
@@ -115,7 +115,6 @@ gst_oss4_source_base_init (gpointer g_class)
templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
gst_oss4_audio_get_template_caps ());
gst_element_class_add_pad_template (element_class, templ);
- gst_object_unref (templ);
}
static void
@@ -936,15 +935,15 @@ gst_oss4_source_mixer_set_mute (GstMixer * mixer, GstMixerTrack * track,
}
static void
-gst_oss4_source_mixer_interface_init (GstMixerClass * klass)
+gst_oss4_source_mixer_interface_init (GstMixerInterface * iface)
{
- GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE;
+ GST_MIXER_TYPE (iface) = GST_MIXER_HARDWARE;
- klass->list_tracks = gst_oss4_source_mixer_list_tracks;
- klass->set_volume = gst_oss4_source_mixer_set_volume;
- klass->get_volume = gst_oss4_source_mixer_get_volume;
- klass->set_mute = gst_oss4_source_mixer_set_mute;
- klass->set_record = gst_oss4_source_mixer_set_record;
+ iface->list_tracks = gst_oss4_source_mixer_list_tracks;
+ iface->set_volume = gst_oss4_source_mixer_set_volume;
+ iface->get_volume = gst_oss4_source_mixer_get_volume;
+ iface->set_mute = gst_oss4_source_mixer_set_mute;
+ iface->set_record = gst_oss4_source_mixer_set_record;
}
/* Implement the horror that is GstImplementsInterface */
diff --git a/sys/osxaudio/gstosxaudioelement.c b/sys/osxaudio/gstosxaudioelement.c
index a41f4b8772..16cee0fd07 100644
--- a/sys/osxaudio/gstosxaudioelement.c
+++ b/sys/osxaudio/gstosxaudioelement.c
@@ -50,7 +50,7 @@
#include "gstosxaudioelement.h"
static void
-gst_osx_audio_element_class_init (GstOsxAudioElementInterface * klass);
+gst_osx_audio_element_interface_init (GstOsxAudioElementInterface * iface);
GType
gst_osx_audio_element_get_type (void)
@@ -60,7 +60,7 @@ gst_osx_audio_element_get_type (void)
if (!gst_osxaudioelement_type) {
static const GTypeInfo gst_osxaudioelement_info = {
sizeof (GstOsxAudioElementInterface),
- (GBaseInitFunc) gst_osx_audio_element_class_init,
+ (GBaseInitFunc) gst_osx_audio_element_interface_init,
NULL,
NULL,
NULL,
@@ -79,7 +79,7 @@ gst_osx_audio_element_get_type (void)
}
static void
-gst_osx_audio_element_class_init (GstOsxAudioElementInterface * klass)
+gst_osx_audio_element_interface_init (GstOsxAudioElementInterface * iface)
{
static gboolean initialized = FALSE;
@@ -88,5 +88,5 @@ gst_osx_audio_element_class_init (GstOsxAudioElementInterface * klass)
}
/* default virtual functions */
- klass->io_proc = NULL;
+ iface->io_proc = NULL;
}
diff --git a/sys/osxaudio/gstosxaudiosink.c b/sys/osxaudio/gstosxaudiosink.c
index cd456e5973..e3ade70110 100644
--- a/sys/osxaudio/gstosxaudiosink.c
+++ b/sys/osxaudio/gstosxaudiosink.c
@@ -142,7 +142,8 @@ gst_osx_audio_sink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- gst_element_class_add_static_pad_template (element_class, &sink_factory);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&sink_factory));
gst_element_class_set_details_simple (element_class, "Audio Sink (OSX)",
"Sink/Audio",
diff --git a/sys/osxaudio/gstosxaudiosrc.c b/sys/osxaudio/gstosxaudiosrc.c
index 7e9ad245bd..2bb21a79ba 100644
--- a/sys/osxaudio/gstosxaudiosrc.c
+++ b/sys/osxaudio/gstosxaudiosrc.c
@@ -133,7 +133,8 @@ gst_osx_audio_src_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- gst_element_class_add_static_pad_template (element_class, &src_factory);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&src_factory));
gst_element_class_set_details_simple (element_class, "Audio Source (OSX)",
"Source/Audio",
diff --git a/sys/osxvideo/osxvideosink.m b/sys/osxvideo/osxvideosink.m
index 59145503e1..4c325278fc 100644
--- a/sys/osxvideo/osxvideosink.m
+++ b/sys/osxvideo/osxvideosink.m
@@ -354,8 +354,8 @@ gst_osx_video_sink_base_init (gpointer g_class)
"Sink/Video", "OSX native videosink",
"Zaheer Abbas Merali <zaheerabbas at merali dot org>");
- gst_element_class_add_static_pad_template (element_class,
- &gst_osx_video_sink_sink_template_factory);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_osx_video_sink_sink_template_factory));
}
static void
diff --git a/sys/sunaudio/gstsunaudiomixerctrl.h b/sys/sunaudio/gstsunaudiomixerctrl.h
index d38f02f25d..2ca17f0ed3 100644
--- a/sys/sunaudio/gstsunaudiomixerctrl.h
+++ b/sys/sunaudio/gstsunaudiomixerctrl.h
@@ -169,19 +169,19 @@ interface_as_function ## _get_mixer_flags (GstMixer * mixer)
} \
\
static void \
-interface_as_function ## _interface_init (GstMixerClass * klass) \
+interface_as_function ## _interface_init (GstMixerInterface * iface) \
{ \
- GST_MIXER_TYPE (klass) = GST_MIXER_HARDWARE; \
+ GST_MIXER_TYPE (iface) = GST_MIXER_HARDWARE; \
\
/* set up the interface hooks */ \
- klass->list_tracks = interface_as_function ## _list_tracks; \
- klass->set_volume = interface_as_function ## _set_volume; \
- klass->get_volume = interface_as_function ## _get_volume; \
- klass->set_mute = interface_as_function ## _set_mute; \
- klass->set_record = interface_as_function ## _set_record; \
- klass->get_option = interface_as_function ## _get_option; \
- klass->set_option = interface_as_function ## _set_option; \
- klass->get_mixer_flags = interface_as_function ## _get_mixer_flags; \
+ iface->list_tracks = interface_as_function ## _list_tracks; \
+ iface->set_volume = interface_as_function ## _set_volume; \
+ iface->get_volume = interface_as_function ## _get_volume; \
+ iface->set_mute = interface_as_function ## _set_mute; \
+ iface->set_record = interface_as_function ## _set_record; \
+ iface->get_option = interface_as_function ## _get_option; \
+ iface->set_option = interface_as_function ## _set_option; \
+ iface->get_mixer_flags = interface_as_function ## _get_mixer_flags; \
}
G_END_DECLS
diff --git a/sys/sunaudio/gstsunaudiosink.c b/sys/sunaudio/gstsunaudiosink.c
index 2a3cf19284..0110b26fab 100644
--- a/sys/sunaudio/gstsunaudiosink.c
+++ b/sys/sunaudio/gstsunaudiosink.c
@@ -146,8 +146,8 @@ gst_sunaudiosink_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- gst_element_class_add_static_pad_template (element_class,
- &gst_sunaudiosink_factory);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_sunaudiosink_factory));
gst_element_class_set_details_simple (element_class, "Sun Audio Sink",
"Sink/Audio",
"Audio sink for Sun Audio devices",
diff --git a/sys/sunaudio/gstsunaudiosrc.c b/sys/sunaudio/gstsunaudiosrc.c
index 08282cf02b..f0529be932 100644
--- a/sys/sunaudio/gstsunaudiosrc.c
+++ b/sys/sunaudio/gstsunaudiosrc.c
@@ -108,8 +108,8 @@ gst_sunaudiosrc_base_init (gpointer g_class)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- gst_element_class_add_static_pad_template (element_class,
- &gst_sunaudiosrc_factory);
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_sunaudiosrc_factory));
gst_element_class_set_details_simple (element_class, "Sun Audio Source",
"Source/Audio",
"Audio source for Sun Audio devices",
diff --git a/sys/v4l2/Makefile.am b/sys/v4l2/Makefile.am
index a7a99dea31..86f4fd2d08 100644
--- a/sys/v4l2/Makefile.am
+++ b/sys/v4l2/Makefile.am
@@ -1,7 +1,7 @@
plugin_LTLIBRARIES = libgstvideo4linux2.la
if USE_XVIDEO
-xv_source = gstv4l2xoverlay.c
+xv_source = gstv4l2videooverlay.c
xv_libs = $(X_LIBS) $(XVIDEO_LIBS)
else
xv_source =
@@ -17,16 +17,11 @@ libgstvideo4linux2_la_SOURCES = gstv4l2.c \
gstv4l2tuner.c \
gstv4l2vidorient.c \
v4l2_calls.c \
- v4l2src_calls.c \
$(xv_source)
-
-if BUILD_EXPERIMENTAL
libgstvideo4linux2_la_SOURCES += gstv4l2sink.c
-endif
libgstvideo4linux2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) \
$(GST_BASE_CFLAGS) \
- $(GST_CONTROLLER_CFLAGS) \
$(GST_CFLAGS) \
$(X_CFLAGS) \
$(LIBV4L2_CFLAGS) \
@@ -37,7 +32,6 @@ libgstvideo4linux2_la_LIBTOOLFLAGS = --tag=disable-static
libgstvideo4linux2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) \
$(GST_BASE_LIBS) \
- $(GST_CONTROLLER_LIBS) \
$(GST_PLUGINS_BASE_LIBS) \
-lgstvideo-$(GST_MAJORMINOR) \
-lgstinterfaces-$(GST_MAJORMINOR) \
@@ -55,6 +49,5 @@ noinst_HEADERS = \
gstv4l2radio.h \
gstv4l2tuner.h \
gstv4l2vidorient.h \
- gstv4l2xoverlay.h \
- v4l2_calls.h \
- v4l2src_calls.h
+ gstv4l2videooverlay.h \
+ v4l2_calls.h
diff --git a/sys/v4l2/gstv4l2.c b/sys/v4l2/gstv4l2.c
index 95f64db785..22959c6635 100644
--- a/sys/v4l2/gstv4l2.c
+++ b/sys/v4l2/gstv4l2.c
@@ -28,13 +28,10 @@
#include "gst/gst-i18n-plugin.h"
#include <gst/gst.h>
-#include <gst/controller/gstcontroller.h>
#include "gstv4l2object.h"
#include "gstv4l2src.h"
-#ifdef HAVE_EXPERIMENTAL
#include "gstv4l2sink.h"
-#endif
#include "gstv4l2radio.h"
/* #include "gstv4l2jpegsrc.h" */
/* #include "gstv4l2mjpegsrc.h" */
@@ -50,15 +47,10 @@ plugin_init (GstPlugin * plugin)
GST_DEBUG_CATEGORY_INIT (v4l2_debug, "v4l2", 0, "V4L2 API calls");
GST_DEBUG_CATEGORY_GET (GST_CAT_PERFORMANCE, "GST_PERFORMANCE");
- /* initialize gst controller library */
- gst_controller_init (NULL, NULL);
-
if (!gst_element_register (plugin, "v4l2src", GST_RANK_PRIMARY,
GST_TYPE_V4L2SRC) ||
-#ifdef HAVE_EXPERIMENTAL
!gst_element_register (plugin, "v4l2sink", GST_RANK_NONE,
GST_TYPE_V4L2SINK) ||
-#endif
!gst_element_register (plugin, "v4l2radio", GST_RANK_NONE,
GST_TYPE_V4L2RADIO) ||
/* !gst_element_register (plugin, "v4l2jpegsrc", */
diff --git a/sys/v4l2/gstv4l2bufferpool.c b/sys/v4l2/gstv4l2bufferpool.c
index a0b4c842aa..306814717c 100644
--- a/sys/v4l2/gstv4l2bufferpool.c
+++ b/sys/v4l2/gstv4l2bufferpool.c
@@ -31,12 +31,13 @@
#include <unistd.h>
#include "gst/video/video.h"
+#include "gst/video/gstvideometa.h"
+#include "gst/video/gstvideopool.h"
#include <gstv4l2bufferpool.h>
+
#include "gstv4l2src.h"
-#ifdef HAVE_EXPERIMENTAL
#include "gstv4l2sink.h"
-#endif
#include "v4l2_calls.h"
#include "gst/gst-i18n-plugin.h"
#include <gst/glib-compat-private.h>
@@ -53,153 +54,167 @@
GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
#define GST_CAT_DEFAULT v4l2_debug
-
/*
* GstV4l2Buffer:
*/
-
-static GstBufferClass *v4l2buffer_parent_class = NULL;
-
-static void
-gst_v4l2_buffer_finalize (GstV4l2Buffer * buffer)
+GType
+gst_v4l2_meta_api_get_type (void)
{
- GstV4l2BufferPool *pool;
- gboolean resuscitated = FALSE;
- gint index;
-
- pool = buffer->pool;
-
- index = buffer->vbuffer.index;
-
- GST_LOG_OBJECT (pool->v4l2elem, "finalizing buffer %p %d", buffer, index);
-
- GST_V4L2_BUFFER_POOL_LOCK (pool);
- if (pool->running) {
- if (pool->requeuebuf) {
- if (!gst_v4l2_buffer_pool_qbuf (pool, buffer)) {
- GST_WARNING ("could not requeue buffer %p %d", buffer, index);
- } else {
- resuscitated = TRUE;
- }
- } else {
- resuscitated = TRUE;
- /* XXX double check this... I think it is ok to not synchronize this
- * w.r.t. destruction of the pool, since the buffer is still live and
- * the buffer holds a ref to the pool..
- */
- g_async_queue_push (pool->avail_buffers, buffer);
- }
- } else {
- GST_LOG_OBJECT (pool->v4l2elem, "the pool is shutting down");
- }
+ static volatile GType type;
+ static const gchar *tags[] = { "memory", NULL };
- if (resuscitated) {
- /* FIXME: check that the caps didn't change */
- GST_LOG_OBJECT (pool->v4l2elem, "reviving buffer %p, %d", buffer, index);
- gst_buffer_ref (GST_BUFFER (buffer));
- GST_BUFFER_SIZE (buffer) = 0;
- GST_BUFFER_FLAG_UNSET (buffer, GST_BUFFER_FLAG_DISCONT);
- pool->buffers[index] = buffer;
- }
-
- GST_V4L2_BUFFER_POOL_UNLOCK (pool);
-
- if (!resuscitated) {
- GST_LOG_OBJECT (pool->v4l2elem,
- "buffer %p (data %p, len %u) not recovered, unmapping",
- buffer, GST_BUFFER_DATA (buffer), buffer->mmap_length);
- gst_mini_object_unref (GST_MINI_OBJECT (pool));
- v4l2_munmap ((void *) GST_BUFFER_DATA (buffer), buffer->mmap_length);
-
- GST_MINI_OBJECT_CLASS (v4l2buffer_parent_class)->finalize (GST_MINI_OBJECT
- (buffer));
+ if (g_once_init_enter (&type)) {
+ GType _type = gst_meta_api_type_register ("GstV4l2MetaAPI", tags);
+ g_once_init_leave (&type, _type);
}
+ return type;
}
-static void
-gst_v4l2_buffer_class_init (gpointer g_class, gpointer class_data)
+const GstMetaInfo *
+gst_v4l2_meta_get_info (void)
{
- GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+ static const GstMetaInfo *meta_info = NULL;
- v4l2buffer_parent_class = g_type_class_peek_parent (g_class);
-
- mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
- gst_v4l2_buffer_finalize;
-}
-
-GType
-gst_v4l2_buffer_get_type (void)
-{
- static GType _gst_v4l2_buffer_type;
-
- if (G_UNLIKELY (_gst_v4l2_buffer_type == 0)) {
- static const GTypeInfo v4l2_buffer_info = {
- sizeof (GstBufferClass),
- NULL,
- NULL,
- gst_v4l2_buffer_class_init,
- NULL,
- NULL,
- sizeof (GstV4l2Buffer),
- 0,
- NULL,
- NULL
- };
- _gst_v4l2_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
- "GstV4l2Buffer", &v4l2_buffer_info, 0);
- }
- return _gst_v4l2_buffer_type;
+ if (meta_info == NULL) {
+ meta_info =
+ gst_meta_register (gst_v4l2_meta_api_get_type (), "GstV4l2Meta",
+ sizeof (GstV4l2Meta), (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL);
+ }
+ return meta_info;
}
-static GstV4l2Buffer *
-gst_v4l2_buffer_new (GstV4l2BufferPool * pool, guint index, GstCaps * caps)
-{
- GstV4l2Buffer *ret;
- guint8 *data;
-
- ret = (GstV4l2Buffer *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER);
+/*
+ * GstV4l2BufferPool:
+ */
+#define gst_v4l2_buffer_pool_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2BufferPool, gst_v4l2_buffer_pool, GST_TYPE_BUFFER_POOL);
- GST_LOG_OBJECT (pool->v4l2elem, "creating buffer %u, %p in pool %p", index,
- ret, pool);
+static void gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool,
+ GstBuffer * buffer);
- ret->pool =
- (GstV4l2BufferPool *) gst_mini_object_ref (GST_MINI_OBJECT (pool));
+static void
+gst_v4l2_buffer_pool_free_buffer (GstBufferPool * bpool, GstBuffer * buffer)
+{
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ GstV4l2Object *obj;
- ret->vbuffer.index = index;
- ret->vbuffer.type = pool->type;
- ret->vbuffer.memory = V4L2_MEMORY_MMAP;
+ obj = pool->obj;
- if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &ret->vbuffer) < 0)
- goto querybuf_failed;
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ break;
+ case GST_V4L2_IO_MMAP:
+ {
+ GstV4l2Meta *meta;
+ gint index;
- GST_LOG_OBJECT (pool->v4l2elem, " index: %u", ret->vbuffer.index);
- GST_LOG_OBJECT (pool->v4l2elem, " type: %d", ret->vbuffer.type);
- GST_LOG_OBJECT (pool->v4l2elem, " bytesused: %u", ret->vbuffer.bytesused);
- GST_LOG_OBJECT (pool->v4l2elem, " flags: %08x", ret->vbuffer.flags);
- GST_LOG_OBJECT (pool->v4l2elem, " field: %d", ret->vbuffer.field);
- GST_LOG_OBJECT (pool->v4l2elem, " memory: %d", ret->vbuffer.memory);
- if (ret->vbuffer.memory == V4L2_MEMORY_MMAP)
- GST_LOG_OBJECT (pool->v4l2elem, " MMAP offset: %u",
- ret->vbuffer.m.offset);
- GST_LOG_OBJECT (pool->v4l2elem, " length: %u", ret->vbuffer.length);
- GST_LOG_OBJECT (pool->v4l2elem, " input: %u", ret->vbuffer.input);
+ meta = GST_V4L2_META_GET (buffer);
+ g_assert (meta != NULL);
- ret->mmap_length = ret->vbuffer.length;
- data = (guint8 *) v4l2_mmap (0, ret->vbuffer.length,
- PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd,
- ret->vbuffer.m.offset);
+ index = meta->vbuffer.index;
+ GST_LOG_OBJECT (pool,
+ "mmap buffer %p idx %d (data %p, len %u) freed, unmapping", buffer,
+ index, meta->mem, meta->vbuffer.length);
- if (data == MAP_FAILED)
- goto mmap_failed;
+ v4l2_munmap (meta->mem, meta->vbuffer.length);
+ pool->buffers[index] = NULL;
+ break;
+ }
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ gst_buffer_unref (buffer);
+}
- GST_BUFFER_DATA (ret) = data;
- GST_BUFFER_SIZE (ret) = ret->vbuffer.length;
+static GstFlowReturn
+gst_v4l2_buffer_pool_alloc_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
+ GstBufferPoolAcquireParams * params)
+{
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ GstBuffer *newbuf;
+ GstV4l2Meta *meta;
+ GstV4l2Object *obj;
+ GstVideoInfo *info;
+ guint index;
+
+ obj = pool->obj;
+ info = &obj->info;
+
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ {
+ newbuf =
+ gst_buffer_new_allocate (pool->allocator, pool->size, &pool->params);
+ break;
+ }
+ case GST_V4L2_IO_MMAP:
+ {
+ newbuf = gst_buffer_new ();
+ meta = GST_V4L2_META_ADD (newbuf);
+
+ index = pool->num_allocated;
+
+ GST_LOG_OBJECT (pool, "creating buffer %u, %p", index, newbuf);
+
+ meta->vbuffer.index = index;
+ meta->vbuffer.type = obj->type;
+ meta->vbuffer.memory = V4L2_MEMORY_MMAP;
+
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_QUERYBUF, &meta->vbuffer) < 0)
+ goto querybuf_failed;
+
+ GST_LOG_OBJECT (pool, " index: %u", meta->vbuffer.index);
+ GST_LOG_OBJECT (pool, " type: %d", meta->vbuffer.type);
+ GST_LOG_OBJECT (pool, " bytesused: %u", meta->vbuffer.bytesused);
+ GST_LOG_OBJECT (pool, " flags: %08x", meta->vbuffer.flags);
+ GST_LOG_OBJECT (pool, " field: %d", meta->vbuffer.field);
+ GST_LOG_OBJECT (pool, " memory: %d", meta->vbuffer.memory);
+ if (meta->vbuffer.memory == V4L2_MEMORY_MMAP)
+ GST_LOG_OBJECT (pool, " MMAP offset: %u", meta->vbuffer.m.offset);
+ GST_LOG_OBJECT (pool, " length: %u", meta->vbuffer.length);
+ GST_LOG_OBJECT (pool, " input: %u", meta->vbuffer.input);
+
+ meta->mem = v4l2_mmap (0, meta->vbuffer.length,
+ PROT_READ | PROT_WRITE, MAP_SHARED, pool->video_fd,
+ meta->vbuffer.m.offset);
+ if (meta->mem == MAP_FAILED)
+ goto mmap_failed;
+
+ gst_buffer_take_memory (newbuf, -1,
+ gst_memory_new_wrapped (0,
+ meta->mem, meta->vbuffer.length, 0, meta->vbuffer.length, NULL,
+ NULL));
+
+ /* add metadata to raw video buffers */
+ if (pool->add_videometa && info->finfo) {
+ gsize offset[GST_VIDEO_MAX_PLANES];
+ gint stride[GST_VIDEO_MAX_PLANES];
+
+ offset[0] = 0;
+ stride[0] = obj->bytesperline;
+
+ GST_DEBUG_OBJECT (pool, "adding video meta, stride %d", stride[0]);
+ gst_buffer_add_video_meta_full (newbuf, info->flags,
+ GST_VIDEO_INFO_FORMAT (info), GST_VIDEO_INFO_WIDTH (info),
+ GST_VIDEO_INFO_HEIGHT (info), GST_VIDEO_INFO_N_PLANES (info),
+ offset, stride);
+ }
+ break;
+ }
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
- GST_BUFFER_FLAG_SET (ret, GST_BUFFER_FLAG_READONLY);
+ pool->num_allocated++;
- gst_buffer_set_caps (GST_BUFFER (ret), caps);
+ *buffer = newbuf;
- return ret;
+ return GST_FLOW_OK;
/* ERRORS */
querybuf_failed:
@@ -207,448 +222,909 @@ querybuf_failed:
gint errnosave = errno;
GST_WARNING ("Failed QUERYBUF: %s", g_strerror (errnosave));
- gst_buffer_unref (GST_BUFFER (ret));
+ gst_buffer_unref (newbuf);
errno = errnosave;
- return NULL;
+ return GST_FLOW_ERROR;
}
mmap_failed:
{
gint errnosave = errno;
GST_WARNING ("Failed to mmap: %s", g_strerror (errnosave));
- gst_buffer_unref (GST_BUFFER (ret));
+ gst_buffer_unref (newbuf);
errno = errnosave;
- return NULL;
+ return GST_FLOW_ERROR;
}
}
+static gboolean
+gst_v4l2_buffer_pool_set_config (GstBufferPool * bpool, GstStructure * config)
+{
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ GstV4l2Object *obj = pool->obj;
+ const GstCaps *caps;
+ guint size, min_buffers, max_buffers;
+ GstAllocator *allocator;
+ GstAllocationParams params;
-/*
- * GstV4l2BufferPool:
- */
+ GST_DEBUG_OBJECT (pool, "set config");
-static GstMiniObjectClass *buffer_pool_parent_class = NULL;
+ pool->add_videometa =
+ gst_buffer_pool_config_has_option (config,
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
-static void
-gst_v4l2_buffer_pool_finalize (GstV4l2BufferPool * pool)
-{
- g_mutex_free (pool->lock);
- pool->lock = NULL;
+ if (!pool->add_videometa) {
+ gint stride;
- g_async_queue_unref (pool->avail_buffers);
- pool->avail_buffers = NULL;
+ /* we don't have video metadata, see if the strides are compatible */
+ stride = GST_VIDEO_INFO_PLANE_STRIDE (&obj->info, 0);
- if (pool->video_fd >= 0)
- v4l2_close (pool->video_fd);
+ GST_DEBUG_OBJECT (pool, "no videometadata, checking strides %d and %u",
+ stride, obj->bytesperline);
- if (pool->buffers) {
- g_free (pool->buffers);
- pool->buffers = NULL;
+ if (stride != obj->bytesperline)
+ goto missing_video_api;
}
- GST_MINI_OBJECT_CLASS (buffer_pool_parent_class)->finalize (GST_MINI_OBJECT
- (pool));
-}
+ /* parse the config and keep around */
+ if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
+ &max_buffers))
+ goto wrong_config;
-static void
-gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool, gpointer g_class)
-{
- pool->lock = g_mutex_new ();
- pool->running = FALSE;
- pool->num_live_buffers = 0;
-}
+ if (!gst_buffer_pool_config_get_allocator (config, &allocator, &params))
+ goto wrong_config;
-static void
-gst_v4l2_buffer_pool_class_init (gpointer g_class, gpointer class_data)
-{
- GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
+ GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config);
- buffer_pool_parent_class = g_type_class_peek_parent (g_class);
+ pool->size = size;
+ pool->max_buffers = MAX (min_buffers, max_buffers);
+ pool->min_buffers = MIN (pool->max_buffers, min_buffers);
+ pool->params = params;
- mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
- gst_v4l2_buffer_pool_finalize;
-}
+ gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
+ max_buffers);
-GType
-gst_v4l2_buffer_pool_get_type (void)
-{
- static GType _gst_v4l2_buffer_pool_type;
-
- if (G_UNLIKELY (_gst_v4l2_buffer_pool_type == 0)) {
- static const GTypeInfo v4l2_buffer_pool_info = {
- sizeof (GstMiniObjectClass),
- NULL,
- NULL,
- gst_v4l2_buffer_pool_class_init,
- NULL,
- NULL,
- sizeof (GstV4l2BufferPool),
- 0,
- (GInstanceInitFunc) gst_v4l2_buffer_pool_init,
- NULL
- };
- _gst_v4l2_buffer_pool_type = g_type_register_static (GST_TYPE_MINI_OBJECT,
- "GstV4l2BufferPool", &v4l2_buffer_pool_info, 0);
- }
- return _gst_v4l2_buffer_pool_type;
-}
+ return GST_BUFFER_POOL_CLASS (parent_class)->set_config (bpool, config);
+ /* ERRORS */
+missing_video_api:
+ {
+ GST_ERROR_OBJECT (pool, "missing GstMetaVideo API in config, "
+ "default stride: %d, wanted stride %u",
+ GST_VIDEO_INFO_PLANE_STRIDE (&obj->info, 0), obj->bytesperline);
+ return FALSE;
+ }
+wrong_config:
+ {
+ GST_ERROR_OBJECT (pool, "invalid config %" GST_PTR_FORMAT, config);
+ return FALSE;
+ }
+}
-/* this is somewhat of a hack.. but better to keep the hack in
- * one place than copy/pasting it around..
- */
-static GstV4l2Object *
-get_v4l2_object (GstElement * v4l2elem)
+static gboolean
+start_streaming (GstV4l2BufferPool * pool)
{
- GstV4l2Object *v4l2object = NULL;
- if (GST_IS_V4L2SRC (v4l2elem)) {
- v4l2object = (GST_V4L2SRC (v4l2elem))->v4l2object;
-#ifdef HAVE_EXPERIMENTAL
- } else if (GST_IS_V4L2SINK (v4l2elem)) {
- v4l2object = (GST_V4L2SINK (v4l2elem))->v4l2object;
-#endif
- } else {
- GST_ERROR_OBJECT (v4l2elem, "unknown v4l2 element");
+ GstV4l2Object *obj = pool->obj;
+
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ break;
+ case GST_V4L2_IO_MMAP:
+ case GST_V4L2_IO_USERPTR:
+ GST_DEBUG_OBJECT (pool, "STREAMON");
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMON, &obj->type) < 0)
+ goto start_failed;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
}
- return v4l2object;
-}
+ pool->streaming = TRUE;
+ return TRUE;
-/**
- * gst_v4l2_buffer_pool_new:
- * @v4l2elem: the v4l2 element (src or sink) that owns this pool
- * @fd: the video device file descriptor
- * @num_buffers: the requested number of buffers in the pool
- * @caps: the caps to set on the buffer
- * @requeuebuf: if %TRUE, and if the pool is still in the running state, a
- * buffer with no remaining references is immediately passed back to v4l2
- * (VIDIOC_QBUF), otherwise it is returned to the pool of available buffers
- * (which can be accessed via gst_v4l2_buffer_pool_get().
- *
- * Construct a new buffer pool.
- *
- * Returns: the new pool, use gst_v4l2_buffer_pool_destroy() to free resources
- */
-GstV4l2BufferPool *
-gst_v4l2_buffer_pool_new (GstElement * v4l2elem, gint fd, gint num_buffers,
- GstCaps * caps, gboolean requeuebuf, enum v4l2_buf_type type)
+ /* ERRORS */
+start_failed:
+ {
+ GST_ERROR_OBJECT (pool, "error with STREAMON %d (%s)", errno,
+ g_strerror (errno));
+ return FALSE;
+ }
+}
+
+static gboolean
+gst_v4l2_buffer_pool_start (GstBufferPool * bpool)
{
- GstV4l2BufferPool *pool;
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ GstV4l2Object *obj = pool->obj;
gint n;
struct v4l2_requestbuffers breq;
+ gint min_buffers, max_buffers;
- pool = (GstV4l2BufferPool *) gst_mini_object_new (GST_TYPE_V4L2_BUFFER_POOL);
-
- pool->video_fd = v4l2_dup (fd);
- if (pool->video_fd < 0)
- goto dup_failed;
+ min_buffers = pool->min_buffers;
+ max_buffers = pool->max_buffers;
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ {
+ break;
+ }
+ case GST_V4L2_IO_MMAP:
+ {
+ /* first, lets request buffers, and see how many we can get: */
+ GST_DEBUG_OBJECT (pool, "starting, requesting %d MMAP buffers",
+ max_buffers);
- /* first, lets request buffers, and see how many we can get: */
- GST_DEBUG_OBJECT (v4l2elem, "STREAMING, requesting %d MMAP buffers",
- num_buffers);
+ if (max_buffers == 0)
+ max_buffers = 4;
- memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
- breq.type = type;
- breq.count = num_buffers;
- breq.memory = V4L2_MEMORY_MMAP;
+ memset (&breq, 0, sizeof (struct v4l2_requestbuffers));
+ breq.type = obj->type;
+ breq.count = max_buffers;
+ breq.memory = V4L2_MEMORY_MMAP;
- if (v4l2_ioctl (fd, VIDIOC_REQBUFS, &breq) < 0)
- goto reqbufs_failed;
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_REQBUFS, &breq) < 0)
+ goto reqbufs_failed;
- GST_LOG_OBJECT (v4l2elem, " count: %u", breq.count);
- GST_LOG_OBJECT (v4l2elem, " type: %d", breq.type);
- GST_LOG_OBJECT (v4l2elem, " memory: %d", breq.memory);
+ GST_LOG_OBJECT (pool, " count: %u", breq.count);
+ GST_LOG_OBJECT (pool, " type: %d", breq.type);
+ GST_LOG_OBJECT (pool, " memory: %d", breq.memory);
- if (breq.count < GST_V4L2_MIN_BUFFERS)
- goto no_buffers;
+ if (breq.count < GST_V4L2_MIN_BUFFERS)
+ goto no_buffers;
- if (num_buffers != breq.count) {
- GST_WARNING_OBJECT (v4l2elem, "using %u buffers instead", breq.count);
- num_buffers = breq.count;
+ if (max_buffers != breq.count) {
+ GST_WARNING_OBJECT (pool, "using %u buffers instead", breq.count);
+ max_buffers = breq.count;
+ }
+ break;
+ }
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
}
- pool->v4l2elem = v4l2elem;
- pool->requeuebuf = requeuebuf;
- pool->type = type;
- pool->buffer_count = num_buffers;
- pool->buffers = g_new0 (GstV4l2Buffer *, num_buffers);
- pool->avail_buffers = g_async_queue_new ();
+ pool->obj = obj;
+ pool->max_buffers = max_buffers;
+ pool->buffers = g_new0 (GstBuffer *, max_buffers);
+ pool->num_allocated = 0;
+
+ /* now, allocate the buffers: */
+ for (n = 0; n < min_buffers; n++) {
+ GstBuffer *buffer;
- /* now, map the buffers: */
- for (n = 0; n < num_buffers; n++) {
- pool->buffers[n] = gst_v4l2_buffer_new (pool, n, caps);
- if (!pool->buffers[n])
+ if (gst_v4l2_buffer_pool_alloc_buffer (bpool, &buffer, NULL) != GST_FLOW_OK)
goto buffer_new_failed;
- pool->num_live_buffers++;
- g_async_queue_push (pool->avail_buffers, pool->buffers[n]);
- }
- return pool;
+ gst_v4l2_buffer_pool_release_buffer (bpool, buffer);
+ }
- /* ERRORS */
-dup_failed:
- {
- gint errnosave = errno;
+ /* we can start capturing now, we wait for the playback case until we queued
+ * the first buffer */
+ if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (!start_streaming (pool))
+ goto start_failed;
- gst_mini_object_unref (GST_MINI_OBJECT (pool));
+ gst_poll_set_flushing (obj->poll, FALSE);
- errno = errnosave;
+ return TRUE;
- return NULL;
- }
+ /* ERRORS */
reqbufs_failed:
{
- GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem);
- GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ,
- (_("Could not get buffers from device '%s'."),
- v4l2object->videodev),
- ("error requesting %d buffers: %s", num_buffers, g_strerror (errno)));
- return NULL;
+ GST_ERROR_OBJECT (pool,
+ "error requesting %d buffers: %s", max_buffers, g_strerror (errno));
+ return FALSE;
}
no_buffers:
{
- GstV4l2Object *v4l2object = get_v4l2_object (v4l2elem);
- GST_ELEMENT_ERROR (v4l2elem, RESOURCE, READ,
- (_("Could not get enough buffers from device '%s'."),
- v4l2object->videodev),
- ("we received %d from device '%s', we want at least %d",
- breq.count, v4l2object->videodev, GST_V4L2_MIN_BUFFERS));
- return NULL;
+ GST_ERROR_OBJECT (pool,
+ "we received %d from device '%s', we want at least %d",
+ breq.count, obj->videodev, GST_V4L2_MIN_BUFFERS);
+ return FALSE;
}
buffer_new_failed:
{
- gint errnosave = errno;
+ GST_ERROR_OBJECT (pool, "failed to create a buffer");
+ return FALSE;
+ }
+start_failed:
+ {
+ GST_ERROR_OBJECT (pool, "failed to start streaming");
+ return FALSE;
+ }
+}
- gst_v4l2_buffer_pool_destroy (pool);
+static gboolean
+gst_v4l2_buffer_pool_stop (GstBufferPool * bpool)
+{
+ gboolean ret;
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ GstV4l2Object *obj = pool->obj;
+ guint n;
+
+ GST_DEBUG_OBJECT (pool, "stopping pool");
+
+ gst_poll_set_flushing (obj->poll, TRUE);
+
+ if (pool->streaming) {
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ break;
+ case GST_V4L2_IO_MMAP:
+ case GST_V4L2_IO_USERPTR:
+ /* we actually need to sync on all queued buffers but not
+ * on the non-queued ones */
+ GST_DEBUG_OBJECT (pool, "STREAMOFF");
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_STREAMOFF, &obj->type) < 0)
+ goto stop_failed;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ pool->streaming = FALSE;
+ }
- errno = errnosave;
+ /* first free the buffers in the queue */
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->stop (bpool);
- return NULL;
+ /* then free the remaining buffers */
+ for (n = 0; n < pool->num_allocated; n++) {
+ if (pool->buffers[n])
+ gst_v4l2_buffer_pool_free_buffer (bpool, pool->buffers[n]);
+ }
+ g_free (pool->buffers);
+ pool->buffers = NULL;
+
+ return ret;
+
+ /* ERRORS */
+stop_failed:
+ {
+ GST_ERROR_OBJECT (pool, "error with STREAMOFF %d (%s)", errno,
+ g_strerror (errno));
+ return FALSE;
}
}
-/**
- * gst_v4l2_buffer_pool_destroy:
- * @pool: the pool
- *
- * Free all resources in the pool and the pool itself.
- */
-void
-gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool)
+static GstFlowReturn
+gst_v4l2_object_poll (GstV4l2Object * v4l2object)
{
- gint n;
+ gint ret;
+
+ if (v4l2object->can_poll_device) {
+ GST_LOG_OBJECT (v4l2object->element, "polling device");
+ ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
+ if (G_UNLIKELY (ret < 0)) {
+ if (errno == EBUSY)
+ goto stopped;
+ if (errno == ENXIO) {
+ GST_WARNING_OBJECT (v4l2object->element,
+ "v4l2 device doesn't support polling. Disabling");
+ v4l2object->can_poll_device = FALSE;
+ } else {
+ if (errno != EAGAIN && errno != EINTR)
+ goto select_error;
+ }
+ }
+ }
+ return GST_FLOW_OK;
- GST_V4L2_BUFFER_POOL_LOCK (pool);
- pool->running = FALSE;
- GST_V4L2_BUFFER_POOL_UNLOCK (pool);
+ /* ERRORS */
+stopped:
+ {
+ GST_DEBUG ("stop called");
+ return GST_FLOW_FLUSHING;
+ }
+select_error:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ, (NULL),
+ ("poll error %d: %s (%d)", ret, g_strerror (errno), errno));
+ return GST_FLOW_ERROR;
+ }
+}
- GST_DEBUG_OBJECT (pool->v4l2elem, "destroy pool");
+static GstFlowReturn
+gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstBuffer * buf)
+{
+ GstV4l2Meta *meta;
+ gint index;
- /* after this point, no more buffers will be queued or dequeued; no buffer
- * from pool->buffers that is NULL will be set to a buffer, and no buffer that
- * is not NULL will be pushed out. */
+ meta = GST_V4L2_META_GET (buf);
+ g_assert (meta != NULL);
- /* miniobjects have no dispose, so they can't break ref-cycles, as buffers ref
- * the pool, we need to unref the buffer to properly finalize te pool */
- for (n = 0; n < pool->buffer_count; n++) {
- GstBuffer *buf;
+ index = meta->vbuffer.index;
- GST_V4L2_BUFFER_POOL_LOCK (pool);
- buf = GST_BUFFER (pool->buffers[n]);
- GST_V4L2_BUFFER_POOL_UNLOCK (pool);
+ GST_LOG_OBJECT (pool, "enqueue buffer %p, index:%d, queued:%d", buf,
+ index, pool->num_queued);
- if (buf)
- /* we own the ref if the buffer is in pool->buffers; drop it. */
- gst_buffer_unref (buf);
- }
+ if (pool->buffers[index] != NULL)
+ goto already_queued;
- gst_mini_object_unref (GST_MINI_OBJECT (pool));
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &meta->vbuffer) < 0)
+ goto queue_failed;
+
+ pool->buffers[index] = buf;
+ pool->num_queued++;
+
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+already_queued:
+ {
+ GST_WARNING_OBJECT (pool, "the buffer was already queued");
+ return GST_FLOW_ERROR;
+ }
+queue_failed:
+ {
+ GST_WARNING_OBJECT (pool, "could not queue a buffer %d (%s)", errno,
+ g_strerror (errno));
+ return GST_FLOW_ERROR;
+ }
}
-/**
- * gst_v4l2_buffer_pool_get:
- * @pool: the "this" object
- * @blocking: should this call suspend until there is a buffer available
- * in the buffer pool?
- *
- * Get an available buffer in the pool
- */
-GstV4l2Buffer *
-gst_v4l2_buffer_pool_get (GstV4l2BufferPool * pool, gboolean blocking)
+static GstFlowReturn
+gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool, GstBuffer ** buffer)
{
- GstV4l2Buffer *buf;
+ GstFlowReturn res;
+ GstBuffer *outbuf;
+ struct v4l2_buffer vbuffer;
+ GstV4l2Object *obj = pool->obj;
+
+ if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ /* select works for input devices when data is available. According to the
+ * specs we can also poll to find out when a frame has been displayed but
+ * that just seems to lock up here */
+ if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
+ goto poll_error;
+ }
- if (blocking) {
- buf = g_async_queue_pop (pool->avail_buffers);
- } else {
- buf = g_async_queue_try_pop (pool->avail_buffers);
+ memset (&vbuffer, 0x00, sizeof (vbuffer));
+ vbuffer.type = obj->type;
+ vbuffer.memory = V4L2_MEMORY_MMAP;
+
+ GST_LOG_OBJECT (pool, "doing DQBUF");
+ if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &vbuffer) < 0)
+ goto error;
+
+ /* get our GstBuffer with that index from the pool, if the buffer was
+ * outstanding we have a serious problem.
+ */
+ outbuf = pool->buffers[vbuffer.index];
+ if (outbuf == NULL)
+ goto no_buffer;
+
+ /* mark the buffer outstanding */
+ pool->buffers[vbuffer.index] = NULL;
+ pool->num_queued--;
+
+ GST_LOG_OBJECT (pool,
+ "dequeued buffer %p seq:%d (ix=%d), used %d, flags %08x, pool-queued=%d, buffer=%p",
+ outbuf, vbuffer.sequence, vbuffer.index, vbuffer.bytesused, vbuffer.flags,
+ pool->num_queued, outbuf);
+
+ /* set top/bottom field first if v4l2_buffer has the information */
+ if (vbuffer.field == V4L2_FIELD_INTERLACED_TB) {
+ GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+ GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
}
+ if (vbuffer.field == V4L2_FIELD_INTERLACED_BT) {
+ GST_BUFFER_FLAG_UNSET (outbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+ GST_BUFFER_FLAG_SET (outbuf, GST_VIDEO_BUFFER_FLAG_INTERLACED);
+ }
+
+ /* this can change at every frame, esp. with jpeg */
+ if (obj->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ gst_buffer_resize (outbuf, 0, vbuffer.bytesused);
+ else
+ gst_buffer_resize (outbuf, 0, vbuffer.length);
+
+ *buffer = outbuf;
- if (buf) {
- GST_V4L2_BUFFER_POOL_LOCK (pool);
- GST_BUFFER_SIZE (buf) = buf->vbuffer.length;
- GST_BUFFER_FLAG_UNSET (buf, 0xffffffff);
- GST_V4L2_BUFFER_POOL_UNLOCK (pool);
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+poll_error:
+ {
+ GST_DEBUG_OBJECT (pool, "poll error %s", gst_flow_get_name (res));
+ return res;
+ }
+error:
+ {
+ GST_WARNING_OBJECT (pool,
+ "problem dequeuing frame %d (ix=%d), pool-ct=%d, buf.flags=%d",
+ vbuffer.sequence, vbuffer.index,
+ GST_MINI_OBJECT_REFCOUNT (pool), vbuffer.flags);
+
+ switch (errno) {
+ case EAGAIN:
+ GST_WARNING_OBJECT (pool,
+ "Non-blocking I/O has been selected using O_NONBLOCK and"
+ " no buffer was in the outgoing queue. device %s", obj->videodev);
+ break;
+ case EINVAL:
+ GST_ERROR_OBJECT (pool,
+ "The buffer type is not supported, or the index is out of bounds, "
+ "or no buffers have been allocated yet, or the userptr "
+ "or length are invalid. device %s", obj->videodev);
+ break;
+ case ENOMEM:
+ GST_ERROR_OBJECT (pool,
+ "insufficient memory to enqueue a user pointer buffer");
+ break;
+ case EIO:
+ GST_INFO_OBJECT (pool,
+ "VIDIOC_DQBUF failed due to an internal error."
+ " Can also indicate temporary problems like signal loss."
+ " Note the driver might dequeue an (empty) buffer despite"
+ " returning an error, or even stop capturing."
+ " device %s", obj->videodev);
+ /* have we de-queued a buffer ? */
+ if (!(vbuffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) {
+ GST_DEBUG_OBJECT (pool, "reenqueing buffer");
+ /* FIXME ... should we do something here? */
+ }
+ break;
+ case EINTR:
+ GST_WARNING_OBJECT (pool,
+ "could not sync on a buffer on device %s", obj->videodev);
+ break;
+ default:
+ GST_WARNING_OBJECT (pool,
+ "Grabbing frame got interrupted on %s unexpectedly. %d: %s.",
+ obj->videodev, errno, g_strerror (errno));
+ break;
+ }
+ return GST_FLOW_ERROR;
}
+no_buffer:
+ {
+ GST_ERROR_OBJECT (pool, "No free buffer found in the pool at index %d.",
+ vbuffer.index);
+ return GST_FLOW_ERROR;
+ }
+}
- pool->running = TRUE;
+static GstFlowReturn
+gst_v4l2_buffer_pool_acquire_buffer (GstBufferPool * bpool, GstBuffer ** buffer,
+ GstBufferPoolAcquireParams * params)
+{
+ GstFlowReturn ret;
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ GstV4l2Object *obj = pool->obj;
+
+ GST_DEBUG_OBJECT (pool, "acquire");
+
+ if (GST_BUFFER_POOL_IS_FLUSHING (bpool))
+ goto flushing;
+
+ switch (obj->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* capture, This function should return a buffer with new captured data */
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ /* take empty buffer from the pool */
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
+ buffer, params);
+ break;
+
+ case GST_V4L2_IO_MMAP:
+ /* just dequeue a buffer, we basically use the queue of v4l2 as the
+ * storage for our buffers. This function does poll first so we can
+ * interrupt it fine. */
+ ret = gst_v4l2_buffer_pool_dqbuf (pool, buffer);
+ break;
+
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ /* playback, This function should return an empty buffer */
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ /* get an empty buffer */
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
+ buffer, params);
+ break;
+
+ case GST_V4L2_IO_MMAP:
+ /* get a free unqueued buffer */
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
+ buffer, params);
+ break;
+
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
- return buf;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ return ret;
+
+ /* ERRORS */
+flushing:
+ {
+ GST_DEBUG_OBJECT (pool, "We are flushing");
+ return GST_FLOW_FLUSHING;
+ }
}
+static void
+gst_v4l2_buffer_pool_release_buffer (GstBufferPool * bpool, GstBuffer * buffer)
+{
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (bpool);
+ GstV4l2Object *obj = pool->obj;
+
+ GST_DEBUG_OBJECT (pool, "release buffer %p", buffer);
+
+ switch (obj->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* capture, put the buffer back in the queue so that we can refill it
+ * later. */
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ /* release back in the pool */
+ GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
+ break;
+
+ case GST_V4L2_IO_MMAP:
+ /* queue back in the device */
+ gst_v4l2_buffer_pool_qbuf (pool, buffer);
+ break;
+
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
-/**
- * gst_v4l2_buffer_pool_qbuf:
- * @pool: the pool
- * @buf: the buffer to queue
- *
- * Queue a buffer to the driver
- *
- * Returns: %TRUE for success
- */
-gboolean
-gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool * pool, GstV4l2Buffer * buf)
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ /* release back in the pool */
+ GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool, buffer);
+ break;
+
+ case GST_V4L2_IO_MMAP:
+ {
+ GstV4l2Meta *meta;
+
+ meta = GST_V4L2_META_GET (buffer);
+ g_assert (meta != NULL);
+
+ if (pool->buffers[meta->vbuffer.index] == NULL) {
+ GST_LOG_OBJECT (pool, "buffer not queued, putting on free list");
+ /* playback, put the buffer back in the queue to refill later. */
+ GST_BUFFER_POOL_CLASS (parent_class)->release_buffer (bpool,
+ buffer);
+ } else {
+ /* the buffer is queued in the device but maybe not played yet. We just
+ * leave it there and not make it available for future calls to acquire
+ * for now. The buffer will be dequeued and reused later. */
+ GST_LOG_OBJECT (pool, "buffer is queued");
+ }
+ break;
+ }
+
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+static void
+gst_v4l2_buffer_pool_finalize (GObject * object)
{
- GST_LOG_OBJECT (pool->v4l2elem, "enqueue pool buffer %d", buf->vbuffer.index);
+ GstV4l2BufferPool *pool = GST_V4L2_BUFFER_POOL (object);
- if (v4l2_ioctl (pool->video_fd, VIDIOC_QBUF, &buf->vbuffer) < 0)
- return FALSE;
+ if (pool->video_fd >= 0)
+ v4l2_close (pool->video_fd);
- pool->num_live_buffers--;
- GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers--: %d",
- pool->num_live_buffers);
+ g_free (pool->buffers);
- return TRUE;
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_v4l2_buffer_pool_init (GstV4l2BufferPool * pool)
+{
+}
+
+static void
+gst_v4l2_buffer_pool_class_init (GstV4l2BufferPoolClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GstBufferPoolClass *bufferpool_class = GST_BUFFER_POOL_CLASS (klass);
+
+ object_class->finalize = gst_v4l2_buffer_pool_finalize;
+
+ bufferpool_class->start = gst_v4l2_buffer_pool_start;
+ bufferpool_class->stop = gst_v4l2_buffer_pool_stop;
+ bufferpool_class->set_config = gst_v4l2_buffer_pool_set_config;
+ bufferpool_class->alloc_buffer = gst_v4l2_buffer_pool_alloc_buffer;
+ bufferpool_class->acquire_buffer = gst_v4l2_buffer_pool_acquire_buffer;
+ bufferpool_class->release_buffer = gst_v4l2_buffer_pool_release_buffer;
+ bufferpool_class->free_buffer = gst_v4l2_buffer_pool_free_buffer;
}
/**
- * gst_v4l2_buffer_pool_dqbuf:
- * @pool: the pool
+ * gst_v4l2_buffer_pool_new:
+ * @obj: the v4l2 object owning the pool
*
- * Dequeue a buffer from the driver. Some generic error handling is done in
- * this function, but any error handling specific to v4l2src (capture) or
- * v4l2sink (output) can be done outside this function by checking 'errno'
+ * Construct a new buffer pool.
*
- * Returns: a buffer
+ * Returns: the new pool, use gst_object_unref() to free resources
*/
-GstV4l2Buffer *
-gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool * pool)
+GstBufferPool *
+gst_v4l2_buffer_pool_new (GstV4l2Object * obj, GstCaps * caps)
{
- GstV4l2Object *v4l2object = get_v4l2_object (pool->v4l2elem);
- GstV4l2Buffer *pool_buffer;
- struct v4l2_buffer buffer;
+ GstV4l2BufferPool *pool;
+ GstStructure *s;
+ gint fd;
- memset (&buffer, 0x00, sizeof (buffer));
- buffer.type = pool->type;
- buffer.memory = V4L2_MEMORY_MMAP;
+ fd = v4l2_dup (obj->video_fd);
+ if (fd < 0)
+ goto dup_failed;
+ pool = (GstV4l2BufferPool *) g_object_new (GST_TYPE_V4L2_BUFFER_POOL, NULL);
+ pool->video_fd = fd;
+ pool->obj = obj;
- if (v4l2_ioctl (pool->video_fd, VIDIOC_DQBUF, &buffer) >= 0) {
+ s = gst_buffer_pool_get_config (GST_BUFFER_POOL_CAST (pool));
+ gst_buffer_pool_config_set_params (s, caps, obj->sizeimage, 2, 0);
+ gst_buffer_pool_set_config (GST_BUFFER_POOL_CAST (pool), s);
- GST_V4L2_BUFFER_POOL_LOCK (pool);
+ return GST_BUFFER_POOL (pool);
- /* get our GstBuffer with that index from the pool, if the buffer was
- * outstanding we have a serious problem.
- */
- pool_buffer = pool->buffers[buffer.index];
+ /* ERRORS */
+dup_failed:
+ {
+ GST_DEBUG ("failed to dup fd %d (%s)", errno, g_strerror (errno));
+ return NULL;
+ }
+}
- if (pool_buffer == NULL) {
- GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
- (_("Failed trying to get video frames from device '%s'."),
- v4l2object->videodev),
- (_("No free buffers found in the pool at index %d."), buffer.index));
- GST_V4L2_BUFFER_POOL_UNLOCK (pool);
- return NULL;
- }
+static GstFlowReturn
+gst_v4l2_do_read (GstV4l2BufferPool * pool, GstBuffer * buf)
+{
+ GstFlowReturn res;
+ GstV4l2Object *obj = pool->obj;
+ gint amount;
+ GstMapInfo map;
+ gint toread;
- GST_LOG_OBJECT (pool->v4l2elem,
- "grabbed frame %d (ix=%d), flags %08x, pool-ct=%d, buffer=%p",
- buffer.sequence, buffer.index, buffer.flags, pool->num_live_buffers,
- pool_buffer);
+ toread = obj->sizeimage;
- pool->num_live_buffers++;
- GST_DEBUG_OBJECT (pool->v4l2elem, "num_live_buffers++: %d",
- pool->num_live_buffers);
+ GST_LOG_OBJECT (pool, "reading %d bytes into buffer %p", toread, buf);
- /* set top/bottom field first if v4l2_buffer has the information */
- if (buffer.field == V4L2_FIELD_INTERLACED_TB)
- GST_BUFFER_FLAG_SET (pool_buffer, GST_VIDEO_BUFFER_TFF);
- if (buffer.field == V4L2_FIELD_INTERLACED_BT)
- GST_BUFFER_FLAG_UNSET (pool_buffer, GST_VIDEO_BUFFER_TFF);
+ gst_buffer_map (buf, &map, GST_MAP_WRITE);
- /* this can change at every frame, esp. with jpeg */
- GST_BUFFER_SIZE (pool_buffer) = buffer.bytesused;
+ do {
+ if ((res = gst_v4l2_object_poll (obj)) != GST_FLOW_OK)
+ goto poll_error;
- GST_V4L2_BUFFER_POOL_UNLOCK (pool);
+ amount = v4l2_read (obj->video_fd, map.data, toread);
- return pool_buffer;
- }
+ if (amount == toread) {
+ break;
+ } else if (amount == -1) {
+ if (errno == EAGAIN || errno == EINTR) {
+ continue;
+ } else
+ goto read_error;
+ } else {
+ /* short reads can happen if a signal interrupts the read */
+ continue;
+ }
+ } while (TRUE);
+ GST_LOG_OBJECT (pool, "read %d bytes", amount);
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_resize (buf, 0, amount);
- GST_WARNING_OBJECT (pool->v4l2elem,
- "problem grabbing frame %d (ix=%d), pool-ct=%d, buf.flags=%d",
- buffer.sequence, buffer.index,
- GST_MINI_OBJECT_REFCOUNT (pool), buffer.flags);
+ return GST_FLOW_OK;
- switch (errno) {
- case EAGAIN:
- GST_WARNING_OBJECT (pool->v4l2elem,
- "Non-blocking I/O has been selected using O_NONBLOCK and"
- " no buffer was in the outgoing queue. device %s",
- v4l2object->videodev);
- break;
- case EINVAL:
- GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
- (_("Failed trying to get video frames from device '%s'."),
- v4l2object->videodev),
- (_("The buffer type is not supported, or the index is out of bounds,"
- " or no buffers have been allocated yet, or the userptr"
- " or length are invalid. device %s"), v4l2object->videodev));
- break;
- case ENOMEM:
- GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
- (_("Failed trying to get video frames from device '%s'. Not enough memory."), v4l2object->videodev), (_("insufficient memory to enqueue a user pointer buffer. device %s."), v4l2object->videodev));
- break;
- case EIO:
- GST_INFO_OBJECT (pool->v4l2elem,
- "VIDIOC_DQBUF failed due to an internal error."
- " Can also indicate temporary problems like signal loss."
- " Note the driver might dequeue an (empty) buffer despite"
- " returning an error, or even stop capturing."
- " device %s", v4l2object->videodev);
- /* have we de-queued a buffer ? */
- if (!(buffer.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))) {
- GST_DEBUG_OBJECT (pool->v4l2elem, "reenqueing buffer");
- /* FIXME ... should we do something here? */
- }
- break;
- case EINTR:
- GST_WARNING_OBJECT (pool->v4l2elem,
- "could not sync on a buffer on device %s", v4l2object->videodev);
- break;
- default:
- GST_WARNING_OBJECT (pool->v4l2elem,
- "Grabbing frame got interrupted on %s unexpectedly. %d: %s.",
- v4l2object->videodev, errno, g_strerror (errno));
- break;
+ /* ERRORS */
+poll_error:
+ {
+ GST_DEBUG ("poll error %s", gst_flow_get_name (res));
+ goto cleanup;
+ }
+read_error:
+ {
+ GST_ELEMENT_ERROR (obj->element, RESOURCE, READ,
+ (_("Error reading %d bytes from device '%s'."),
+ toread, obj->videodev), GST_ERROR_SYSTEM);
+ res = GST_FLOW_ERROR;
+ goto cleanup;
+ }
+cleanup:
+ {
+ gst_buffer_unmap (buf, &map);
+ gst_buffer_resize (buf, 0, 0);
+ return res;
}
-
- return NULL;
}
/**
- * gst_v4l2_buffer_pool_available_buffers:
- * @pool: the pool
+ * gst_v4l2_buffer_pool_process:
+ * @bpool: a #GstBufferPool
+ * @buf: a #GstBuffer
*
- * Check the number of buffers available to the driver, ie. buffers that
- * have been QBUF'd but not yet DQBUF'd.
+ * Process @buf in @bpool. For capture devices, this functions fills @buf with
+ * data from the device. For output devices, this functions send the contents of
+ * @buf to the device for playback.
*
- * Returns: the number of buffers available.
+ * Returns: %GST_FLOW_OK on success.
*/
-gint
-gst_v4l2_buffer_pool_available_buffers (GstV4l2BufferPool * pool)
+GstFlowReturn
+gst_v4l2_buffer_pool_process (GstV4l2BufferPool * pool, GstBuffer * buf)
{
- return pool->buffer_count - pool->num_live_buffers;
+ GstFlowReturn ret = GST_FLOW_OK;
+ GstBufferPool *bpool = GST_BUFFER_POOL_CAST (pool);
+ GstV4l2Object *obj = pool->obj;
+
+ GST_DEBUG_OBJECT (pool, "process buffer %p", buf);
+
+ switch (obj->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ /* capture */
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ /* capture into the buffer */
+ ret = gst_v4l2_do_read (pool, buf);
+ break;
+
+ case GST_V4L2_IO_MMAP:
+ {
+ GstBuffer *tmp;
+
+ if (buf->pool == bpool)
+ /* nothing, data was inside the buffer when we did _acquire() */
+ goto done;
+
+ /* buffer not from our pool, grab a frame and copy it into the target */
+ if ((ret = gst_v4l2_buffer_pool_dqbuf (pool, &tmp)) != GST_FLOW_OK)
+ goto done;
+
+ if (!gst_v4l2_object_copy (obj, buf, tmp))
+ goto copy_failed;
+
+ /* an queue the buffer again after the copy */
+ if ((ret = gst_v4l2_buffer_pool_qbuf (pool, tmp)) != GST_FLOW_OK)
+ goto done;
+ break;
+ }
+
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ /* playback */
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ /* FIXME, do write() */
+ GST_WARNING_OBJECT (pool, "implement write()");
+ break;
+
+ case GST_V4L2_IO_MMAP:
+ {
+ GstBuffer *to_queue;
+
+ if (buf->pool == bpool) {
+ /* nothing, we can queue directly */
+ to_queue = buf;
+ GST_LOG_OBJECT (pool, "processing buffer from our pool");
+ } else {
+ GST_LOG_OBJECT (pool, "alloc buffer from our pool");
+ if (!gst_buffer_pool_is_active (bpool)) {
+ GstStructure *config;
+
+ /* this pool was not activated, configure and activate */
+ GST_DEBUG_OBJECT (pool, "activating pool");
+
+ config = gst_buffer_pool_get_config (bpool);
+ gst_buffer_pool_config_add_option (config,
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
+ gst_buffer_pool_set_config (bpool, config);
+
+ if (!gst_buffer_pool_set_active (bpool, TRUE))
+ goto activate_failed;
+ }
+
+ /* this can block if all buffers are outstanding which would be
+ * strange because we would expect the upstream element to have
+ * allocated them and returned to us.. */
+ ret = GST_BUFFER_POOL_CLASS (parent_class)->acquire_buffer (bpool,
+ &to_queue, NULL);
+ if (ret != GST_FLOW_OK)
+ goto acquire_failed;
+
+ /* copy into it and queue */
+ if (!gst_v4l2_object_copy (obj, to_queue, buf))
+ goto copy_failed;
+ }
+
+ if ((ret = gst_v4l2_buffer_pool_qbuf (pool, to_queue)) != GST_FLOW_OK)
+ goto done;
+
+ /* if we are not streaming yet (this is the first buffer, start
+ * streaming now */
+ if (!pool->streaming)
+ if (!start_streaming (pool))
+ goto start_failed;
+
+ if (pool->num_queued == pool->num_allocated) {
+ /* all buffers are queued, try to dequeue one and release it back
+ * into the pool so that _acquire can get to it again. */
+ ret = gst_v4l2_buffer_pool_dqbuf (pool, &to_queue);
+ if (ret != GST_FLOW_OK)
+ goto done;
+
+ /* release the rendered buffer back into the pool. This wakes up any
+ * thread waiting for a buffer in _acquire() */
+ gst_v4l2_buffer_pool_release_buffer (bpool, to_queue);
+ }
+ break;
+ }
+
+ case GST_V4L2_IO_USERPTR:
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+done:
+ return ret;
+
+ /* ERRORS */
+activate_failed:
+ {
+ GST_ERROR_OBJECT (obj->element, "failed to activate pool");
+ return GST_FLOW_ERROR;
+ }
+acquire_failed:
+ {
+ GST_WARNING_OBJECT (obj->element, "failed to acquire a buffer: %s",
+ gst_flow_get_name (ret));
+ return ret;
+ }
+copy_failed:
+ {
+ GST_ERROR_OBJECT (obj->element, "failed to copy data");
+ return GST_FLOW_ERROR;
+ }
+start_failed:
+ {
+ GST_ERROR_OBJECT (obj->element, "failed to start streaming");
+ return GST_FLOW_ERROR;
+ }
}
diff --git a/sys/v4l2/gstv4l2bufferpool.h b/sys/v4l2/gstv4l2bufferpool.h
index 36ea3233a6..532a39b0c9 100644
--- a/sys/v4l2/gstv4l2bufferpool.h
+++ b/sys/v4l2/gstv4l2bufferpool.h
@@ -22,79 +22,73 @@
* Boston, MA 02111-1307, USA.
*/
-#ifndef __GSTV4L2BUFFER_H__
-#define __GSTV4L2BUFFER_H__
+#ifndef __GST_V4L2_BUFFER_POOL_H__
+#define __GST_V4L2_BUFFER_POOL_H__
#include <gst/gst.h>
-#include "v4l2_calls.h"
+
+typedef struct _GstV4l2BufferPool GstV4l2BufferPool;
+typedef struct _GstV4l2BufferPoolClass GstV4l2BufferPoolClass;
+typedef struct _GstV4l2Meta GstV4l2Meta;
+
+#include "gstv4l2object.h"
+//#include "v4l2_calls.h"
GST_DEBUG_CATEGORY_EXTERN (v4l2buffer_debug);
G_BEGIN_DECLS
-GType gst_v4l2_buffer_get_type (void);
-#define GST_TYPE_V4L2_BUFFER (gst_v4l2_buffer_get_type())
-#define GST_IS_V4L2_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER))
-#define GST_V4L2_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER, GstV4l2Buffer))
+#define GST_TYPE_V4L2_BUFFER_POOL (gst_v4l2_buffer_pool_get_type())
+#define GST_IS_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER_POOL))
+#define GST_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool))
+#define GST_V4L2_BUFFER_POOL_CAST(obj) ((GstV4l2BufferPool*)(obj))
-GType gst_v4l2_buffer_pool_get_type (void);
-#define GST_TYPE_V4L2_BUFFER_POOL (gst_v4l2_buffer_pool_get_type())
-#define GST_IS_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_V4L2_BUFFER_POOL))
-#define GST_V4L2_BUFFER_POOL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_V4L2_BUFFER_POOL, GstV4l2BufferPool))
+struct _GstV4l2BufferPool
+{
+ GstBufferPool parent;
+ GstV4l2Object *obj; /* the v4l2 object */
+ gint video_fd; /* a dup(2) of the v4l2object's video_fd */
+ GstAllocator *allocator;
+ GstAllocationParams params;
+ guint size;
+ guint min_buffers;
+ guint max_buffers;
+ gboolean add_videometa;
-typedef struct _GstV4l2BufferPool GstV4l2BufferPool;
-typedef struct _GstV4l2Buffer GstV4l2Buffer;
+ guint num_allocated; /* number of buffers allocated by the driver */
+ guint num_queued; /* number of buffers queued in the driver */
+ gboolean streaming;
-struct _GstV4l2BufferPool
-{
- GstMiniObject parent;
-
- GstElement *v4l2elem; /* the v4l2 src/sink that owns us.. maybe we should be owned by v4l2object? */
- gboolean requeuebuf; /* if true, unusued buffers are automatically re-QBUF'd */
- enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */
+ GstBuffer **buffers;
+};
- GMutex *lock;
- gboolean running; /* with lock */
- gint num_live_buffers; /* number of buffers not with driver */
- GAsyncQueue* avail_buffers;/* pool of available buffers, not with the driver and which aren't held outside the bufferpool */
- gint video_fd; /* a dup(2) of the v4l2object's video_fd */
- guint buffer_count;
- GstV4l2Buffer **buffers;
+struct _GstV4l2BufferPoolClass
+{
+ GstBufferPoolClass parent_class;
};
-struct _GstV4l2Buffer {
- GstBuffer buffer;
+struct _GstV4l2Meta {
+ GstMeta meta;
+ gpointer mem;
struct v4l2_buffer vbuffer;
- /* warning: the size of mmap buffer and
- * the actual frame-buffer can be different. */
- size_t mmap_length;
-
- /* FIXME: have GstV4l2Src* instead, as this has GstV4l2BufferPool* */
- /* FIXME: do we really want to fix this if GstV4l2Buffer/Pool is shared
- * between v4l2src and v4l2sink??
- */
- GstV4l2BufferPool *pool;
};
-void gst_v4l2_buffer_pool_destroy (GstV4l2BufferPool * pool);
-GstV4l2BufferPool *gst_v4l2_buffer_pool_new (GstElement *v4l2elem, gint fd, gint num_buffers, GstCaps * caps, gboolean requeuebuf, enum v4l2_buf_type type);
-
+GType gst_v4l2_meta_api_get_type (void);
+const GstMetaInfo * gst_v4l2_meta_get_info (void);
+#define GST_V4L2_META_GET(buf) ((GstV4l2Meta *)gst_buffer_get_meta(buf,gst_v4l2_meta_api_get_type()))
+#define GST_V4L2_META_ADD(buf) ((GstV4l2Meta *)gst_buffer_add_meta(buf,gst_v4l2_meta_get_info(),NULL))
-GstV4l2Buffer *gst_v4l2_buffer_pool_get (GstV4l2BufferPool *pool, gboolean blocking);
-gboolean gst_v4l2_buffer_pool_qbuf (GstV4l2BufferPool *pool, GstV4l2Buffer *buf);
-GstV4l2Buffer *gst_v4l2_buffer_pool_dqbuf (GstV4l2BufferPool *pool);
-
-gint gst_v4l2_buffer_pool_available_buffers (GstV4l2BufferPool *pool);
+GType gst_v4l2_buffer_pool_get_type (void);
+GstBufferPool * gst_v4l2_buffer_pool_new (GstV4l2Object *obj, GstCaps *caps);
-#define GST_V4L2_BUFFER_POOL_LOCK(pool) g_mutex_lock ((pool)->lock)
-#define GST_V4L2_BUFFER_POOL_UNLOCK(pool) g_mutex_unlock ((pool)->lock)
+GstFlowReturn gst_v4l2_buffer_pool_process (GstV4l2BufferPool * bpool, GstBuffer * buf);
G_END_DECLS
-#endif /* __GSTV4L2BUFFER_H__ */
+#endif /*__GST_V4L2_BUFFER_POOL_H__ */
diff --git a/sys/v4l2/gstv4l2colorbalance.c b/sys/v4l2/gstv4l2colorbalance.c
index f5cde096f4..a07c9be316 100644
--- a/sys/v4l2/gstv4l2colorbalance.c
+++ b/sys/v4l2/gstv4l2colorbalance.c
@@ -29,14 +29,9 @@
#include "gstv4l2colorbalance.h"
#include "gstv4l2object.h"
-GST_BOILERPLATE (GstV4l2ColorBalanceChannel,
- gst_v4l2_color_balance_channel,
- GstColorBalanceChannel, GST_TYPE_COLOR_BALANCE_CHANNEL);
-
-static void
-gst_v4l2_color_balance_channel_base_init (gpointer g_class)
-{
-}
+#define gst_v4l2_color_balance_channel_parent_class parent_class
+G_DEFINE_TYPE (GstV4l2ColorBalanceChannel,
+ gst_v4l2_color_balance_channel, GST_TYPE_COLOR_BALANCE_CHANNEL);
static void
gst_v4l2_color_balance_channel_class_init (GstV4l2ColorBalanceChannelClass *
@@ -45,8 +40,7 @@ gst_v4l2_color_balance_channel_class_init (GstV4l2ColorBalanceChannelClass *
}
static void
-gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel * channel,
- GstV4l2ColorBalanceChannelClass * klass)
+gst_v4l2_color_balance_channel_init (GstV4l2ColorBalanceChannel * channel)
{
channel->id = (guint32) - 1;
}
diff --git a/sys/v4l2/gstv4l2colorbalance.h b/sys/v4l2/gstv4l2colorbalance.h
index 9e183f0144..7bf47e1fb4 100644
--- a/sys/v4l2/gstv4l2colorbalance.h
+++ b/sys/v4l2/gstv4l2colorbalance.h
@@ -25,7 +25,7 @@
#define __GST_V4L2_COLOR_BALANCE_H__
#include <gst/gst.h>
-#include <gst/interfaces/colorbalance.h>
+#include <gst/video/colorbalance.h>
#include "v4l2_calls.h"
G_BEGIN_DECLS
@@ -90,15 +90,20 @@ interface_as_function ## _color_balance_get_value (GstColorBalance * balance,
return gst_v4l2_color_balance_get_value(this->v4l2object, channel); \
} \
\
-static void \
-interface_as_function ## _color_balance_interface_init (GstColorBalanceClass * klass) \
+static GstColorBalanceType \
+interface_as_function ## _color_balance_get_balance_type (GstColorBalance * balance) \
{ \
- GST_COLOR_BALANCE_TYPE (klass) = GST_COLOR_BALANCE_HARDWARE; \
+ return GST_COLOR_BALANCE_HARDWARE; \
+} \
\
+static void \
+interface_as_function ## _color_balance_interface_init (GstColorBalanceInterface * iface) \
+{ \
/* default virtual functions */ \
- klass->list_channels = interface_as_function ## _color_balance_list_channels; \
- klass->set_value = interface_as_function ## _color_balance_set_value; \
- klass->get_value = interface_as_function ## _color_balance_get_value; \
+ iface->list_channels = interface_as_function ## _color_balance_list_channels; \
+ iface->set_value = interface_as_function ## _color_balance_set_value; \
+ iface->get_value = interface_as_function ## _color_balance_get_value; \
+ iface->get_balance_type = interface_as_function ## _color_balance_get_balance_type; \
} \
#endif /* __GST_V4L2_COLOR_BALANCE_H__ */
diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c
index 6ff5ab4a47..6bcbf16b89 100644
--- a/sys/v4l2/gstv4l2object.c
+++ b/sys/v4l2/gstv4l2object.c
@@ -39,12 +39,14 @@
#include "v4l2_calls.h"
#include "gstv4l2tuner.h"
#ifdef HAVE_XVIDEO
-#include "gstv4l2xoverlay.h"
+#include "gstv4l2videooverlay.h"
#endif
#include "gstv4l2colorbalance.h"
#include "gst/gst-i18n-plugin.h"
+#include <gst/video/video.h>
+
/* videodev2.h is not versioned and we can't easily check for the presence
* of enum values at compile time, but the V4L2_CAP_VIDEO_OUTPUT_OVERLAY define
* was added in the same commit as V4L2_FIELD_INTERLACED_{TB,BT} (b2787845) */
@@ -54,15 +56,16 @@
#endif
GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
+GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
#define GST_CAT_DEFAULT v4l2_debug
-
#define DEFAULT_PROP_DEVICE_NAME NULL
#define DEFAULT_PROP_DEVICE_FD -1
#define DEFAULT_PROP_FLAGS 0
#define DEFAULT_PROP_TV_NORM 0
#define DEFAULT_PROP_CHANNEL NULL
#define DEFAULT_PROP_FREQUENCY 0
+#define DEFAULT_PROP_IO_MODE GST_V4L2_IO_AUTO
enum
{
@@ -70,6 +73,7 @@ enum
V4L2_STD_OBJECT_PROPS,
};
+#if 0
G_LOCK_DEFINE_STATIC (probe_lock);
const GList *
@@ -78,8 +82,6 @@ gst_v4l2_probe_get_properties (GstPropertyProbe * probe)
GObjectClass *klass = G_OBJECT_GET_CLASS (probe);
static GList *list = NULL;
- /* well, not perfect, but better than no locking at all.
- * In the worst case we leak a list node, so who cares? */
G_LOCK (probe_lock);
if (!list) {
@@ -293,6 +295,7 @@ gst_v4l2_probe_get_values (GstPropertyProbe * probe,
return array;
}
+#endif
#define GST_TYPE_V4L2_DEVICE_FLAGS (gst_v4l2_device_get_type ())
static GType
@@ -374,6 +377,26 @@ gst_v4l2_tv_norm_get_type (void)
return v4l2_tv_norm;
}
+#define GST_TYPE_V4L2_IO_MODE (gst_v4l2_io_mode_get_type ())
+static GType
+gst_v4l2_io_mode_get_type (void)
+{
+ static GType v4l2_io_mode = 0;
+
+ if (!v4l2_io_mode) {
+ static const GEnumValue io_modes[] = {
+ {GST_V4L2_IO_AUTO, "GST_V4L2_IO_AUTO", "auto"},
+ {GST_V4L2_IO_RW, "GST_V4L2_IO_RW", "rw"},
+ {GST_V4L2_IO_MMAP, "GST_V4L2_IO_MMAP", "mmap"},
+ {GST_V4L2_IO_USERPTR, "GST_V4L2_IO_USERPTR", "userptr"},
+
+ {0, NULL, NULL}
+ };
+ v4l2_io_mode = g_enum_register_static ("GstV4l2IOMode", io_modes);
+ }
+ return v4l2_io_mode;
+}
+
void
gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
const char *default_device)
@@ -455,6 +478,17 @@ gst_v4l2_object_install_properties_helper (GObjectClass * gobject_class,
"video standard",
GST_TYPE_V4L2_TV_NORM, DEFAULT_PROP_TV_NORM,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ /**
+ * GstV4l2Src:io-mode
+ *
+ * IO Mode
+ */
+ g_object_class_install_property (gobject_class, PROP_IO_MODE,
+ g_param_spec_enum ("io-mode", "IO mode",
+ "I/O mode",
+ GST_TYPE_V4L2_IO_MODE, DEFAULT_PROP_IO_MODE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
}
GstV4l2Object *
@@ -482,7 +516,7 @@ gst_v4l2_object_new (GstElement * element,
v4l2object->video_fd = -1;
v4l2object->poll = gst_poll_new (TRUE);
- v4l2object->buffer = NULL;
+ v4l2object->active = FALSE;
v4l2object->videodev = g_strdup (default_device);
v4l2object->norms = NULL;
@@ -616,6 +650,9 @@ gst_v4l2_object_set_property_helper (GstV4l2Object * v4l2object,
}
break;
#endif
+ case PROP_IO_MODE:
+ v4l2object->req_mode = g_value_get_enum (value);
+ break;
default:
return FALSE;
break;
@@ -689,6 +726,9 @@ gst_v4l2_object_get_property_helper (GstV4l2Object * v4l2object,
case PROP_TV_NORM:
g_value_set_enum (value, v4l2object->tv_norm);
break;
+ case PROP_IO_MODE:
+ g_value_set_enum (value, v4l2object->req_mode);
+ break;
default:
return FALSE;
break;
@@ -755,7 +795,7 @@ gst_v4l2_set_defaults (GstV4l2Object * v4l2object)
}
gboolean
-gst_v4l2_object_start (GstV4l2Object * v4l2object)
+gst_v4l2_object_open (GstV4l2Object * v4l2object)
{
if (gst_v4l2_open (v4l2object))
gst_v4l2_set_defaults (v4l2object);
@@ -763,17 +803,17 @@ gst_v4l2_object_start (GstV4l2Object * v4l2object)
return FALSE;
#ifdef HAVE_XVIDEO
- gst_v4l2_xoverlay_start (v4l2object);
+ gst_v4l2_video_overlay_start (v4l2object);
#endif
return TRUE;
}
gboolean
-gst_v4l2_object_stop (GstV4l2Object * v4l2object)
+gst_v4l2_object_close (GstV4l2Object * v4l2object)
{
#ifdef HAVE_XVIDEO
- gst_v4l2_xoverlay_stop (v4l2object);
+ gst_v4l2_video_overlay_stop (v4l2object);
#endif
if (!gst_v4l2_close (v4l2object))
@@ -1153,99 +1193,24 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
case V4L2_PIX_FMT_PJPG: /* Progressive-JPEG */
#endif
case V4L2_PIX_FMT_JPEG: /* JFIF JPEG */
- structure = gst_structure_new ("image/jpeg", NULL);
+ structure = gst_structure_new_empty ("image/jpeg");
+ break;
+ case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
+ case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
+ /* FIXME: get correct fourccs here */
break;
case V4L2_PIX_FMT_RGB332:
- case V4L2_PIX_FMT_RGB555:
case V4L2_PIX_FMT_RGB555X:
- case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
+ /* FIXME: get correct fourccs here */
+ break;
+ case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
+ case V4L2_PIX_FMT_RGB555:
+ case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB24:
case V4L2_PIX_FMT_BGR24:
case V4L2_PIX_FMT_RGB32:
- case V4L2_PIX_FMT_BGR32:{
- guint depth = 0, bpp = 0;
-
- gint endianness = 0;
-
- guint32 r_mask = 0, b_mask = 0, g_mask = 0;
-
- switch (fourcc) {
- case V4L2_PIX_FMT_RGB332:
- bpp = depth = 8;
- endianness = G_BYTE_ORDER; /* 'like, whatever' */
- r_mask = 0xe0;
- g_mask = 0x1c;
- b_mask = 0x03;
- break;
- case V4L2_PIX_FMT_RGB555:
- case V4L2_PIX_FMT_RGB555X:
- bpp = 16;
- depth = 15;
- endianness =
- fourcc == V4L2_PIX_FMT_RGB555X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
- r_mask = 0x7c00;
- g_mask = 0x03e0;
- b_mask = 0x001f;
- break;
- case V4L2_PIX_FMT_RGB565:
- case V4L2_PIX_FMT_RGB565X:
- bpp = depth = 16;
- endianness =
- fourcc == V4L2_PIX_FMT_RGB565X ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
- r_mask = 0xf800;
- g_mask = 0x07e0;
- b_mask = 0x001f;
- break;
- case V4L2_PIX_FMT_RGB24:
- bpp = depth = 24;
- endianness = G_BIG_ENDIAN;
- r_mask = 0xff0000;
- g_mask = 0x00ff00;
- b_mask = 0x0000ff;
- break;
- case V4L2_PIX_FMT_BGR24:
- bpp = depth = 24;
- endianness = G_BIG_ENDIAN;
- r_mask = 0x0000ff;
- g_mask = 0x00ff00;
- b_mask = 0xff0000;
- break;
- case V4L2_PIX_FMT_RGB32:
- bpp = depth = 32;
- endianness = G_BIG_ENDIAN;
- r_mask = 0xff000000;
- g_mask = 0x00ff0000;
- b_mask = 0x0000ff00;
- break;
- case V4L2_PIX_FMT_BGR32:
- bpp = depth = 32;
- endianness = G_BIG_ENDIAN;
- r_mask = 0x000000ff;
- g_mask = 0x0000ff00;
- b_mask = 0x00ff0000;
- break;
- default:
- g_assert_not_reached ();
- break;
- }
- structure = gst_structure_new ("video/x-raw-rgb",
- "bpp", G_TYPE_INT, bpp,
- "depth", G_TYPE_INT, depth,
- "red_mask", G_TYPE_INT, r_mask,
- "green_mask", G_TYPE_INT, g_mask,
- "blue_mask", G_TYPE_INT, b_mask,
- "endianness", G_TYPE_INT, endianness, NULL);
- break;
- }
- case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
- structure = gst_structure_new ("video/x-raw-gray",
- "bpp", G_TYPE_INT, 8, NULL);
- break;
- case V4L2_PIX_FMT_YYUV: /* 16 YUV 4:2:2 */
- case V4L2_PIX_FMT_HI240: /* 8 8-bit color */
- /* FIXME: get correct fourccs here */
- break;
+ case V4L2_PIX_FMT_BGR32:
case V4L2_PIX_FMT_NV12: /* 12 Y/CbCr 4:2:0 */
case V4L2_PIX_FMT_NV21: /* 12 Y/CrCb 4:2:0 */
case V4L2_PIX_FMT_YVU410:
@@ -1254,59 +1219,84 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_UYVY:
+#if 0
case V4L2_PIX_FMT_Y41P:
+#endif
case V4L2_PIX_FMT_YUV422P:
#ifdef V4L2_PIX_FMT_YVYU
case V4L2_PIX_FMT_YVYU:
#endif
case V4L2_PIX_FMT_YUV411P:{
- guint32 fcc = 0;
+ GstVideoFormat format;
switch (fourcc) {
+ case V4L2_PIX_FMT_GREY: /* 8 Greyscale */
+ format = GST_VIDEO_FORMAT_GRAY8;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ format = GST_VIDEO_FORMAT_RGB15;
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ format = GST_VIDEO_FORMAT_RGB16;
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ format = GST_VIDEO_FORMAT_RGB;
+ break;
+ case V4L2_PIX_FMT_BGR24:
+ format = GST_VIDEO_FORMAT_BGR;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ format = GST_VIDEO_FORMAT_RGBx;
+ break;
+ case V4L2_PIX_FMT_BGR32:
+ format = GST_VIDEO_FORMAT_BGRx;
+ break;
case V4L2_PIX_FMT_NV12:
- fcc = GST_MAKE_FOURCC ('N', 'V', '1', '2');
+ format = GST_VIDEO_FORMAT_NV12;
break;
case V4L2_PIX_FMT_NV21:
- fcc = GST_MAKE_FOURCC ('N', 'V', '2', '1');
+ format = GST_VIDEO_FORMAT_NV21;
break;
case V4L2_PIX_FMT_YVU410:
- fcc = GST_MAKE_FOURCC ('Y', 'V', 'U', '9');
+ format = GST_VIDEO_FORMAT_YVU9;
break;
case V4L2_PIX_FMT_YUV410:
- fcc = GST_MAKE_FOURCC ('Y', 'U', 'V', '9');
+ format = GST_VIDEO_FORMAT_YUV9;
break;
case V4L2_PIX_FMT_YUV420:
- fcc = GST_MAKE_FOURCC ('I', '4', '2', '0');
+ format = GST_VIDEO_FORMAT_I420;
break;
case V4L2_PIX_FMT_YUYV:
- fcc = GST_MAKE_FOURCC ('Y', 'U', 'Y', '2');
+ format = GST_VIDEO_FORMAT_YUY2;
break;
case V4L2_PIX_FMT_YVU420:
- fcc = GST_MAKE_FOURCC ('Y', 'V', '1', '2');
+ format = GST_VIDEO_FORMAT_YV12;
break;
case V4L2_PIX_FMT_UYVY:
- fcc = GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y');
+ format = GST_VIDEO_FORMAT_UYVY;
break;
+#if 0
case V4L2_PIX_FMT_Y41P:
- fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'P');
+ format = GST_VIDEO_FORMAT_Y41P;
break;
+#endif
case V4L2_PIX_FMT_YUV411P:
- fcc = GST_MAKE_FOURCC ('Y', '4', '1', 'B');
+ format = GST_VIDEO_FORMAT_Y41B;
break;
case V4L2_PIX_FMT_YUV422P:
- fcc = GST_MAKE_FOURCC ('Y', '4', '2', 'B');
+ format = GST_VIDEO_FORMAT_Y42B;
break;
#ifdef V4L2_PIX_FMT_YVYU
case V4L2_PIX_FMT_YVYU:
- fcc = GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U');
+ format = GST_VIDEO_FORMAT_YVYU;
break;
#endif
default:
g_assert_not_reached ();
break;
}
- structure = gst_structure_new ("video/x-raw-yuv",
- "format", GST_TYPE_FOURCC, fcc, NULL);
+ structure = gst_structure_new ("video/x-raw",
+ "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
break;
}
case V4L2_PIX_FMT_DV:
@@ -1315,28 +1305,28 @@ gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc)
NULL);
break;
case V4L2_PIX_FMT_MPEG: /* MPEG */
- structure = gst_structure_new ("video/mpegts", NULL);
+ structure = gst_structure_new_empty ("video/mpegts");
break;
case V4L2_PIX_FMT_WNVA: /* Winnov hw compres */
break;
#ifdef V4L2_PIX_FMT_SBGGR8
case V4L2_PIX_FMT_SBGGR8:
- structure = gst_structure_new ("video/x-raw-bayer", NULL);
+ structure = gst_structure_new_empty ("video/x-bayer");
break;
#endif
#ifdef V4L2_PIX_FMT_SN9C10X
case V4L2_PIX_FMT_SN9C10X:
- structure = gst_structure_new ("video/x-sonix", NULL);
+ structure = gst_structure_new_empty ("video/x-sonix");
break;
#endif
#ifdef V4L2_PIX_FMT_PWC1
case V4L2_PIX_FMT_PWC1:
- structure = gst_structure_new ("video/x-pwc1", NULL);
+ structure = gst_structure_new_empty ("video/x-pwc1");
break;
#endif
#ifdef V4L2_PIX_FMT_PWC2
case V4L2_PIX_FMT_PWC2:
- structure = gst_structure_new ("video/x-pwc2", NULL);
+ structure = gst_structure_new_empty ("video/x-pwc2");
break;
#endif
default:
@@ -1387,160 +1377,181 @@ gst_v4l2_object_get_all_caps (void)
* @fps_n/@fps_d: location for framerate
* @size: location for expected size of the frame or 0 if unknown
*/
-gboolean
+static gboolean
gst_v4l2_object_get_caps_info (GstV4l2Object * v4l2object, GstCaps * caps,
- struct v4l2_fmtdesc ** format, gint * w, gint * h,
- gboolean * interlaced, guint * fps_n, guint * fps_d, guint * size)
+ struct v4l2_fmtdesc **format, GstVideoInfo * info)
{
GstStructure *structure;
- const GValue *framerate;
guint32 fourcc;
const gchar *mimetype;
- guint outsize;
+ struct v4l2_fmtdesc *fmt;
/* default unknown values */
fourcc = 0;
- outsize = 0;
structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure);
- if (strcmp (mimetype, "video/mpegts") == 0) {
- fourcc = V4L2_PIX_FMT_MPEG;
- *fps_n = 0;
- *fps_d = 1;
- goto done;
- }
-
- if (!gst_structure_get_int (structure, "width", w))
- return FALSE;
-
- if (!gst_structure_get_int (structure, "height", h))
- return FALSE;
-
- if (!gst_structure_get_boolean (structure, "interlaced", interlaced))
- *interlaced = FALSE;
+ if (g_str_equal (mimetype, "video/x-raw")) {
+ /* raw caps, parse into video info */
+ if (!gst_video_info_from_caps (info, caps))
+ goto invalid_format;
- framerate = gst_structure_get_value (structure, "framerate");
- if (!framerate)
- return FALSE;
-
- *fps_n = gst_value_get_fraction_numerator (framerate);
- *fps_d = gst_value_get_fraction_denominator (framerate);
-
- if (!strcmp (mimetype, "video/x-raw-yuv")) {
- gst_structure_get_fourcc (structure, "format", &fourcc);
-
- switch (fourcc) {
- case GST_MAKE_FOURCC ('I', '4', '2', '0'):
- case GST_MAKE_FOURCC ('I', 'Y', 'U', 'V'):
+ switch (GST_VIDEO_INFO_FORMAT (info)) {
+ case GST_VIDEO_FORMAT_I420:
fourcc = V4L2_PIX_FMT_YUV420;
- outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
- outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
break;
- case GST_MAKE_FOURCC ('Y', 'U', 'Y', '2'):
+ case GST_VIDEO_FORMAT_YUY2:
fourcc = V4L2_PIX_FMT_YUYV;
- outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
break;
- case GST_MAKE_FOURCC ('Y', '4', '1', 'P'):
+#if 0
+ case GST_VIDEO_FORMAT_Y41P:
fourcc = V4L2_PIX_FMT_Y41P;
- outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
break;
- case GST_MAKE_FOURCC ('U', 'Y', 'V', 'Y'):
+#endif
+ case GST_VIDEO_FORMAT_UYVY:
fourcc = V4L2_PIX_FMT_UYVY;
- outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
break;
- case GST_MAKE_FOURCC ('Y', 'V', '1', '2'):
+ case GST_VIDEO_FORMAT_YV12:
fourcc = V4L2_PIX_FMT_YVU420;
- outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
- outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * (GST_ROUND_UP_2 (*h) / 2));
break;
- case GST_MAKE_FOURCC ('Y', '4', '1', 'B'):
+ case GST_VIDEO_FORMAT_Y41B:
fourcc = V4L2_PIX_FMT_YUV411P;
- outsize = GST_ROUND_UP_4 (*w) * *h;
- outsize += 2 * ((GST_ROUND_UP_8 (*w) / 4) * *h);
break;
- case GST_MAKE_FOURCC ('Y', '4', '2', 'B'):
+ case GST_VIDEO_FORMAT_Y42B:
fourcc = V4L2_PIX_FMT_YUV422P;
- outsize = GST_ROUND_UP_4 (*w) * *h;
- outsize += 2 * ((GST_ROUND_UP_8 (*w) / 2) * *h);
break;
- case GST_MAKE_FOURCC ('N', 'V', '1', '2'):
+ case GST_VIDEO_FORMAT_NV12:
fourcc = V4L2_PIX_FMT_NV12;
- outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
- outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
break;
- case GST_MAKE_FOURCC ('N', 'V', '2', '1'):
+ case GST_VIDEO_FORMAT_NV21:
fourcc = V4L2_PIX_FMT_NV21;
- outsize = GST_ROUND_UP_4 (*w) * GST_ROUND_UP_2 (*h);
- outsize += (GST_ROUND_UP_4 (*w) * *h) / 2;
break;
#ifdef V4L2_PIX_FMT_YVYU
- case GST_MAKE_FOURCC ('Y', 'V', 'Y', 'U'):
+ case GST_VIDEO_FORMAT_YVYU:
fourcc = V4L2_PIX_FMT_YVYU;
- outsize = (GST_ROUND_UP_2 (*w) * 2) * *h;
break;
#endif
- }
- } else if (!strcmp (mimetype, "video/x-raw-rgb")) {
- gint depth, endianness, r_mask;
-
- gst_structure_get_int (structure, "depth", &depth);
- gst_structure_get_int (structure, "endianness", &endianness);
- gst_structure_get_int (structure, "red_mask", &r_mask);
-
- switch (depth) {
- case 8:
- fourcc = V4L2_PIX_FMT_RGB332;
+ case GST_VIDEO_FORMAT_RGB15:
+ fourcc = V4L2_PIX_FMT_RGB555;
+ break;
+ case GST_VIDEO_FORMAT_RGB16:
+ fourcc = V4L2_PIX_FMT_RGB565;
break;
- case 15:
- fourcc = (endianness == G_LITTLE_ENDIAN) ?
- V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB555X;
+ case GST_VIDEO_FORMAT_RGB:
+ fourcc = V4L2_PIX_FMT_RGB24;
break;
- case 16:
- fourcc = (endianness == G_LITTLE_ENDIAN) ?
- V4L2_PIX_FMT_RGB565 : V4L2_PIX_FMT_RGB565X;
+ case GST_VIDEO_FORMAT_BGR:
+ fourcc = V4L2_PIX_FMT_BGR24;
break;
- case 24:
- fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR24 : V4L2_PIX_FMT_RGB24;
+ case GST_VIDEO_FORMAT_RGBx:
+ case GST_VIDEO_FORMAT_RGBA:
+ fourcc = V4L2_PIX_FMT_RGB32;
break;
- case 32:
- fourcc = (r_mask == 0xFF) ? V4L2_PIX_FMT_BGR32 : V4L2_PIX_FMT_RGB32;
+ case GST_VIDEO_FORMAT_BGRx:
+ case GST_VIDEO_FORMAT_BGRA:
+ fourcc = V4L2_PIX_FMT_BGR32;
+ break;
+ case GST_VIDEO_FORMAT_GRAY8:
+ fourcc = V4L2_PIX_FMT_GREY;
+ default:
break;
}
- } else if (strcmp (mimetype, "video/x-dv") == 0) {
- fourcc = V4L2_PIX_FMT_DV;
- } else if (strcmp (mimetype, "image/jpeg") == 0) {
- fourcc = V4L2_PIX_FMT_JPEG;
+ } else {
+ gboolean dimensions = TRUE;
+
+ /* no video caps, construct videoinfo ourselves */
+ gst_video_info_init (info);
+
+ if (g_str_equal (mimetype, "video/mpegts")) {
+ fourcc = V4L2_PIX_FMT_MPEG;
+ dimensions = FALSE;
+ } else if (g_str_equal (mimetype, "video/x-dv")) {
+ fourcc = V4L2_PIX_FMT_DV;
+ } else if (g_str_equal (mimetype, "image/jpeg")) {
+ fourcc = V4L2_PIX_FMT_JPEG;
#ifdef V4L2_PIX_FMT_SBGGR8
- } else if (strcmp (mimetype, "video/x-raw-bayer") == 0) {
- fourcc = V4L2_PIX_FMT_SBGGR8;
+ } else if (g_str_equal (mimetype, "video/x-bayer")) {
+ fourcc = V4L2_PIX_FMT_SBGGR8;
#endif
#ifdef V4L2_PIX_FMT_SN9C10X
- } else if (strcmp (mimetype, "video/x-sonix") == 0) {
- fourcc = V4L2_PIX_FMT_SN9C10X;
+ } else if (g_str_equal (mimetype, "video/x-sonix")) {
+ fourcc = V4L2_PIX_FMT_SN9C10X;
#endif
#ifdef V4L2_PIX_FMT_PWC1
- } else if (strcmp (mimetype, "video/x-pwc1") == 0) {
- fourcc = V4L2_PIX_FMT_PWC1;
+ } else if (g_str_equal (mimetype, "video/x-pwc1")) {
+ fourcc = V4L2_PIX_FMT_PWC1;
#endif
#ifdef V4L2_PIX_FMT_PWC2
- } else if (strcmp (mimetype, "video/x-pwc2") == 0) {
- fourcc = V4L2_PIX_FMT_PWC2;
+ } else if (g_str_equal (mimetype, "video/x-pwc2")) {
+ fourcc = V4L2_PIX_FMT_PWC2;
+ }
#endif
- } else if (strcmp (mimetype, "video/x-raw-gray") == 0) {
- fourcc = V4L2_PIX_FMT_GREY;
+
+ if (dimensions) {
+ const gchar *interlace_mode;
+
+ if (!gst_structure_get_int (structure, "width", &info->width))
+ goto no_width;
+
+ if (!gst_structure_get_int (structure, "height", &info->height))
+ goto no_height;
+
+ interlace_mode = gst_structure_get_string (structure, "interlace-mode");
+ if (g_str_equal (interlace_mode, "progressive")) {
+ info->interlace_mode = GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
+ } else {
+ info->interlace_mode = GST_VIDEO_INTERLACE_MODE_MIXED;
+ }
+ if (!gst_structure_get_fraction (structure, "framerate", &info->fps_n,
+ &info->fps_d))
+ goto no_framerate;
+ }
}
if (fourcc == 0)
- return FALSE;
+ goto unhandled_format;
-done:
- *format = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
- *size = outsize;
+ fmt = gst_v4l2_object_get_format_from_fourcc (v4l2object, fourcc);
+ if (fmt == NULL)
+ goto unsupported_format;
+
+ *format = fmt;
return TRUE;
+
+ /* ERRORS */
+no_width:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "no width");
+ return FALSE;
+ }
+no_height:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "no height");
+ return FALSE;
+ }
+no_framerate:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "no framerate");
+ return FALSE;
+ }
+invalid_format:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "invalid format");
+ return FALSE;
+ }
+unhandled_format:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "unhandled format");
+ return FALSE;
+ }
+unsupported_format:
+ {
+ GST_DEBUG_OBJECT (v4l2object, "unsupported format");
+ return FALSE;
+ }
}
@@ -1727,7 +1738,7 @@ return_data:
s = gst_structure_copy (template);
gst_structure_set (s, "width", G_TYPE_INT, (gint) width,
"height", G_TYPE_INT, (gint) height,
- "interlaced", G_TYPE_BOOLEAN, interlaced,
+ "interlace-mode", G_TYPE_STRING, (interlaced ? "mixed" : "progressive"),
"pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1, NULL);
if (G_IS_VALUE (&rates)) {
@@ -1790,7 +1801,7 @@ gst_v4l2_object_probe_caps_for_format (GstV4l2Object * v4l2object,
guint32 w, h;
if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
- return gst_caps_new_simple ("video/mpegts", NULL);
+ return gst_caps_new_empty_simple ("video/mpegts");
memset (&size, 0, sizeof (struct v4l2_frmsizeenum));
size.index = 0;
@@ -1988,9 +1999,10 @@ default_frame_sizes:
else
gst_structure_set (tmp, "height", GST_TYPE_INT_RANGE, min_h, max_h, NULL);
- gst_structure_set (tmp, "interlaced", G_TYPE_BOOLEAN, interlaced, NULL);
- gst_structure_set (tmp, "pixel-aspect-ratio",
- GST_TYPE_FRACTION, 1, 1, NULL);
+ gst_structure_set (tmp, "interlace-mode", G_TYPE_STRING,
+ (interlaced ? "mixed" : "progressive"), NULL);
+ gst_structure_set (tmp, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
+ NULL);
gst_caps_append_structure (ret, tmp);
@@ -2103,16 +2115,102 @@ error:
return FALSE;
}
+static gboolean
+gst_v4l2_object_setup_pool (GstV4l2Object * v4l2object, GstCaps * caps)
+{
+ GstV4l2IOMode mode;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "initializing the capture system");
+
+ GST_V4L2_CHECK_OPEN (v4l2object);
+ GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
+
+ /* find transport */
+ mode = v4l2object->req_mode;
+
+ if (v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
+ if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
+ mode = GST_V4L2_IO_RW;
+ } else if (v4l2object->req_mode == GST_V4L2_IO_RW)
+ goto method_not_supported;
+
+ if (v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
+ if (v4l2object->req_mode == GST_V4L2_IO_AUTO)
+ mode = GST_V4L2_IO_MMAP;
+ } else if (v4l2object->req_mode == GST_V4L2_IO_MMAP)
+ goto method_not_supported;
+
+ /* if still no transport selected, error out */
+ if (mode == GST_V4L2_IO_AUTO)
+ goto no_supported_capture_method;
+
+ GST_INFO_OBJECT (v4l2object->element, "accessing buffers via mode %d", mode);
+ v4l2object->mode = mode;
+
+ /* Map the buffers */
+ GST_LOG_OBJECT (v4l2object->element, "initiating buffer pool");
+
+ if (!(v4l2object->pool = gst_v4l2_buffer_pool_new (v4l2object, caps)))
+ goto buffer_pool_new_failed;
+
+ GST_V4L2_SET_ACTIVE (v4l2object);
+
+ return TRUE;
+
+ /* ERRORS */
+buffer_pool_new_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
+ (_("Could not map buffers from device '%s'"),
+ v4l2object->videodev),
+ ("Failed to create buffer pool: %s", g_strerror (errno)));
+ return FALSE;
+ }
+method_not_supported:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
+ (_("The driver of device '%s' does not support the IO method %d"),
+ v4l2object->videodev, mode), (NULL));
+ return FALSE;
+ }
+no_supported_capture_method:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, READ,
+ (_("The driver of device '%s' does not support any known IO "
+ "method."), v4l2object->videodev), (NULL));
+ return FALSE;
+ }
+}
+
+
+/* Note about fraction simplification
+ * * n1/d1 == n2/d2 is also written as n1 == ( n2 * d1 ) / d2
+ * */
+#define fractions_are_equal(n1,d1,n2,d2) ((n1) == gst_util_uint64_scale_int((n2), (d1), (d2)))
gboolean
-gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
- guint32 width, guint32 height, gboolean interlaced)
+gst_v4l2_object_set_format (GstV4l2Object * v4l2object, GstCaps * caps)
{
gint fd = v4l2object->video_fd;
struct v4l2_format format;
+ struct v4l2_streamparm streamparm;
enum v4l2_field field;
-
- if (interlaced) {
+ guint32 pixelformat;
+ struct v4l2_fmtdesc *fmtdesc;
+ GstVideoInfo info;
+ gint width, height, fps_n, fps_d, stride;
+
+ if (!gst_v4l2_object_get_caps_info (v4l2object, caps, &fmtdesc, &info))
+ goto invalid_caps;
+
+ pixelformat = fmtdesc->pixelformat;
+ width = GST_VIDEO_INFO_WIDTH (&info);
+ height = GST_VIDEO_INFO_HEIGHT (&info);
+ fps_n = GST_VIDEO_INFO_FPS_N (&info);
+ fps_d = GST_VIDEO_INFO_FPS_D (&info);
+ stride = GST_VIDEO_INFO_PLANE_STRIDE (&info, 0);
+
+ if (info.flags & GST_VIDEO_FLAG_INTERLACED) {
GST_DEBUG_OBJECT (v4l2object->element, "interlaced video");
/* ideally we would differentiate between types of interlaced video
* but there is not sufficient information in the caps..
@@ -2123,8 +2221,9 @@ gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
field = V4L2_FIELD_NONE;
}
- GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
- "%" GST_FOURCC_FORMAT, width, height, GST_FOURCC_ARGS (pixelformat));
+ GST_DEBUG_OBJECT (v4l2object->element, "Desired format %dx%d, format "
+ "%" GST_FOURCC_FORMAT " stride: %d", width, height,
+ GST_FOURCC_ARGS (pixelformat), stride);
GST_V4L2_CHECK_OPEN (v4l2object);
GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
@@ -2132,7 +2231,7 @@ gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
/* Only unconditionally accept mpegts for sources */
if ((v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) &&
(pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G')))
- return TRUE;
+ goto done;
memset (&format, 0x00, sizeof (struct v4l2_format));
format.type = v4l2object->type;
@@ -2140,42 +2239,128 @@ gst_v4l2_object_set_format (GstV4l2Object * v4l2object, guint32 pixelformat,
if (v4l2_ioctl (fd, VIDIOC_G_FMT, &format) < 0)
goto get_fmt_failed;
- if (format.type == v4l2object->type &&
- format.fmt.pix.width == width &&
- format.fmt.pix.height == height &&
- format.fmt.pix.pixelformat == pixelformat &&
- format.fmt.pix.field == field) {
- /* Nothing to do. We want to succeed immediately
- * here because setting the same format back
- * can still fail due to EBUSY. By short-circuiting
- * here, we allow pausing and re-playing pipelines
- * with changed caps, as long as the changed caps
- * do not change the webcam's format. Otherwise,
- * any caps change would require us to go to NULL
- * state to close the device and set format.
- */
- return TRUE;
+ GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
+ "%" GST_FOURCC_FORMAT " bytesperline %d, colorspace %d",
+ format.fmt.pix.width, format.fmt.pix.height,
+ GST_FOURCC_ARGS (format.fmt.pix.pixelformat), format.fmt.pix.bytesperline,
+ format.fmt.pix.colorspace);
+
+ if (format.type != v4l2object->type ||
+ format.fmt.pix.width != width ||
+ format.fmt.pix.height != height ||
+ format.fmt.pix.pixelformat != pixelformat ||
+ format.fmt.pix.field != field || format.fmt.pix.bytesperline != stride) {
+ /* something different, set the format */
+ GST_DEBUG_OBJECT (v4l2object->element, "Setting format to %dx%d, format "
+ "%" GST_FOURCC_FORMAT " bytesperline %d", width, height,
+ GST_FOURCC_ARGS (pixelformat), stride);
+
+ format.type = v4l2object->type;
+ format.fmt.pix.width = width;
+ format.fmt.pix.height = height;
+ format.fmt.pix.pixelformat = pixelformat;
+ format.fmt.pix.field = field;
+ /* try to ask our prefered stride */
+ format.fmt.pix.bytesperline = stride;
+
+ if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0)
+ goto set_fmt_failed;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "Got format to %dx%d, format "
+ "%" GST_FOURCC_FORMAT " stride %d", format.fmt.pix.width,
+ format.fmt.pix.height, GST_FOURCC_ARGS (format.fmt.pix.pixelformat),
+ format.fmt.pix.bytesperline);
+
+ if (format.fmt.pix.width != width || format.fmt.pix.height != height)
+ goto invalid_dimensions;
+
+ if (format.fmt.pix.pixelformat != pixelformat)
+ goto invalid_pixelformat;
}
- format.type = v4l2object->type;
- format.fmt.pix.width = width;
- format.fmt.pix.height = height;
- format.fmt.pix.pixelformat = pixelformat;
- format.fmt.pix.field = field;
+ /* figure out the frame layout */
+ v4l2object->bytesperline = format.fmt.pix.bytesperline;
+ v4l2object->sizeimage = format.fmt.pix.sizeimage;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "Got sizeimage %u",
+ v4l2object->sizeimage);
+
+ /* Is there a reason we require the caller to always specify a framerate? */
+ GST_DEBUG_OBJECT (v4l2object->element, "Desired framerate: %u/%u", fps_n,
+ fps_d);
+
+ memset (&streamparm, 0x00, sizeof (struct v4l2_streamparm));
+ streamparm.type = v4l2object->type;
+
+ if (v4l2_ioctl (fd, VIDIOC_G_PARM, &streamparm) < 0)
+ goto get_parm_failed;
+
+ GST_VIDEO_INFO_FPS_N (&info) =
+ streamparm.parm.capture.timeperframe.denominator;
+ GST_VIDEO_INFO_FPS_D (&info) = streamparm.parm.capture.timeperframe.numerator;
+
+ if (v4l2object->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ GST_DEBUG_OBJECT (v4l2object->element, "Got framerate: %u/%u",
+ streamparm.parm.capture.timeperframe.denominator,
+ streamparm.parm.capture.timeperframe.numerator);
+
+ /* We used to skip frame rate setup if the camera was already setup
+ * with the requested frame rate. This breaks some cameras though,
+ * causing them to not output data (several models of Thinkpad cameras
+ * have this problem at least).
+ * So, don't skip. */
+ GST_LOG_OBJECT (v4l2object->element, "Setting framerate to %u/%u", fps_n,
+ fps_d);
+ /* We want to change the frame rate, so check whether we can. Some cheap USB
+ * cameras don't have the capability */
+ if ((streamparm.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
+ GST_DEBUG_OBJECT (v4l2object->element,
+ "Not setting framerate (not supported)");
+ goto done;
+ }
- if (v4l2_ioctl (fd, VIDIOC_S_FMT, &format) < 0) {
- goto set_fmt_failed;
+ /* Note: V4L2 wants the frame interval, we have the frame rate */
+ streamparm.parm.capture.timeperframe.numerator = fps_d;
+ streamparm.parm.capture.timeperframe.denominator = fps_n;
+
+ /* some cheap USB cam's won't accept any change */
+ if (v4l2_ioctl (fd, VIDIOC_S_PARM, &streamparm) < 0)
+ goto set_parm_failed;
+
+ /* get new values */
+ fps_d = streamparm.parm.capture.timeperframe.numerator;
+ fps_n = streamparm.parm.capture.timeperframe.denominator;
+
+ GST_INFO_OBJECT (v4l2object->element, "Set framerate to %u/%u", fps_n,
+ fps_d);
+
+ GST_VIDEO_INFO_FPS_N (&info) = fps_n;
+ GST_VIDEO_INFO_FPS_D (&info) = fps_d;
}
- if (format.fmt.pix.width != width || format.fmt.pix.height != height)
- goto invalid_dimensions;
+done:
+ /* if we have a framerate pre-calculate duration */
+ if (fps_n > 0 && fps_d > 0) {
+ v4l2object->duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
+ } else {
+ v4l2object->duration = GST_CLOCK_TIME_NONE;
+ }
+ v4l2object->info = info;
+ v4l2object->fmtdesc = fmtdesc;
- if (format.fmt.pix.pixelformat != pixelformat)
- goto invalid_pixelformat;
+ /* now configure ther pools */
+ if (!gst_v4l2_object_setup_pool (v4l2object, caps))
+ goto pool_failed;
return TRUE;
/* ERRORS */
+invalid_caps:
+ {
+ GST_DEBUG_OBJECT (v4l2object->element, "can't parse caps %" GST_PTR_FORMAT,
+ caps);
+ return FALSE;
+ }
get_fmt_failed:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
@@ -2222,30 +2407,219 @@ invalid_pixelformat:
GST_FOURCC_ARGS (format.fmt.pix.pixelformat)));
return FALSE;
}
+get_parm_failed:
+ {
+ /* it's possible that this call is not supported */
+ if (errno != EINVAL) {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Could not get parameters on device '%s'"),
+ v4l2object->videodev), GST_ERROR_SYSTEM);
+ }
+ goto done;
+ }
+set_parm_failed:
+ {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Video device did not accept new frame rate setting.")),
+ GST_ERROR_SYSTEM);
+ goto done;
+ }
+pool_failed:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, SETTINGS,
+ (_("Video device could not create buffer pool.")), GST_ERROR_SYSTEM);
+ return FALSE;
+ }
}
gboolean
-gst_v4l2_object_start_streaming (GstV4l2Object * v4l2object)
+gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
{
- if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMON,
- &(v4l2object->type)) < 0) {
- GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ,
- (_("Error starting streaming on device '%s'."), v4l2object->videodev),
- GST_ERROR_SYSTEM);
- return FALSE;
+ GST_LOG_OBJECT (v4l2object->element, "flush poll");
+ gst_poll_set_flushing (v4l2object->poll, TRUE);
+
+ return TRUE;
+}
+
+gboolean
+gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object)
+{
+ GST_LOG_OBJECT (v4l2object->element, "flush stop poll");
+ gst_poll_set_flushing (v4l2object->poll, FALSE);
+
+ return TRUE;
+}
+
+gboolean
+gst_v4l2_object_stop (GstV4l2Object * v4l2object)
+{
+ GST_DEBUG_OBJECT (v4l2object->element, "stopping");
+
+ if (!GST_V4L2_IS_OPEN (v4l2object))
+ goto done;
+ if (!GST_V4L2_IS_ACTIVE (v4l2object))
+ goto done;
+
+ if (v4l2object->pool) {
+ GST_DEBUG_OBJECT (v4l2object->element, "deactivating pool");
+ gst_buffer_pool_set_active (GST_BUFFER_POOL_CAST (v4l2object->pool), FALSE);
+ gst_object_unref (v4l2object->pool);
+ v4l2object->pool = NULL;
}
+
+ GST_V4L2_SET_INACTIVE (v4l2object);
+
+done:
return TRUE;
}
+#if 0
+static GstFlowReturn
+gst_v4l2_object_get_mmap (GstV4l2Object * v4l2object, GstBuffer ** buf)
+{
+ GstFlowReturn res;
+#define NUM_TRIALS 50
+ GstBufferPool *pool;
+ gint32 trials = NUM_TRIALS;
+ GstBuffer *pool_buffer;
+ gboolean need_copy;
+
+ pool = v4l2object->pool;
+ if (!pool)
+ goto no_buffer_pool;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "grab frame");
+
+ for (;;) {
+ if ((res = gst_v4l2_object_poll (v4l2object)) != GST_FLOW_OK)
+ goto poll_error;
+
+ res = gst_buffer_pool_acquire_buffer (pool, &pool_buffer, NULL);
+ if (res != GST_FLOW_OK)
+ goto no_buffer;
+
+ if (v4l2object->size > 0) {
+ gsize size = gst_buffer_get_size (pool_buffer);
+
+ /* if size does not match what we expected, try again */
+ if (size != v4l2object->size) {
+ GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, READ,
+ (_("Got unexpected frame size of %u instead of %u."),
+ size, v4l2object->size), (NULL));
+ gst_buffer_unref (pool_buffer);
+ goto no_buffer;
+ }
+ }
+ /* when we get here all is fine */
+ break;
+
+ no_buffer:
+ GST_WARNING_OBJECT (v4l2object->element, "trials=%d", trials);
+
+ /* if the sync() got interrupted, we can retry */
+ switch (errno) {
+ case EINVAL:
+ case ENOMEM:
+ /* fatal */
+ return GST_FLOW_ERROR;
+
+ case EAGAIN:
+ case EIO:
+ case EINTR:
+ default:
+ /* try again, until too many trials */
+ break;
+ }
+
+ /* check nr. of attempts to capture */
+ if (--trials == -1) {
+ goto too_many_trials;
+ }
+ }
+
+
+ /* if we are handing out the last buffer in the pool, we need to make a
+ * copy and bring the buffer back in the pool. */
+ need_copy = v4l2object->always_copy
+ || !gst_v4l2_buffer_pool_available_buffers (pool);
+
+ if (G_UNLIKELY (need_copy)) {
+ if (!v4l2object->always_copy) {
+ GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2object->element,
+ "running out of buffers, making a copy to reuse current one");
+ }
+ *buf = gst_buffer_copy (pool_buffer);
+ /* this will requeue */
+ gst_buffer_unref (pool_buffer);
+ } else {
+ *buf = pool_buffer;
+ }
+
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+no_buffer_pool:
+ {
+ GST_DEBUG_OBJECT (v4l2object->element, "no buffer pool");
+ return GST_FLOW_FLUSHING;
+ }
+poll_error:
+ {
+ return res;
+ }
+too_many_trials:
+ {
+ GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, FAILED,
+ (_("Failed trying to get video frames from device '%s'."),
+ v4l2object->videodev),
+ (_("Failed after %d tries. device %s. system error: %s"),
+ NUM_TRIALS, v4l2object->videodev, g_strerror (errno)));
+ return GST_FLOW_ERROR;
+ }
+}
+#endif
+
gboolean
-gst_v4l2_object_stop_streaming (GstV4l2Object * v4l2object)
+gst_v4l2_object_copy (GstV4l2Object * v4l2object, GstBuffer * dest,
+ GstBuffer * src)
{
- if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_STREAMOFF,
- &(v4l2object->type)) < 0) {
- GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, OPEN_READ,
- (_("Error stopping streaming on device '%s'."), v4l2object->videodev),
- GST_ERROR_SYSTEM);
- return FALSE;
+ if (v4l2object->info.finfo) {
+ GstVideoFrame src_frame, dest_frame;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "copy video frame");
+
+ /* we have raw video, use videoframe copy to get strides right */
+ if (!gst_video_frame_map (&src_frame, &v4l2object->info, src, GST_MAP_READ))
+ goto invalid_buffer;
+
+ if (!gst_video_frame_map (&dest_frame, &v4l2object->info, dest,
+ GST_MAP_WRITE)) {
+ gst_video_frame_unmap (&src_frame);
+ goto invalid_buffer;
+ }
+
+ gst_video_frame_copy (&dest_frame, &src_frame);
+
+ gst_video_frame_unmap (&src_frame);
+ gst_video_frame_unmap (&dest_frame);
+ } else {
+ GstMapInfo map;
+
+ GST_DEBUG_OBJECT (v4l2object->element, "copy raw bytes");
+ gst_buffer_map (src, &map, GST_MAP_READ);
+ gst_buffer_fill (dest, 0, map.data, map.size);
+ gst_buffer_unmap (src, &map);
}
+ GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2object->element,
+ "slow copy into buffer %p", dest);
+
return TRUE;
+
+ /* ERRORS */
+invalid_buffer:
+ {
+ /* No Window available to put our image into */
+ GST_WARNING_OBJECT (v4l2object->element, "could not map image");
+ return FALSE;
+ }
}
diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h
index a7b590d9b9..1b15627ef6 100644
--- a/sys/v4l2/gstv4l2object.h
+++ b/sys/v4l2/gstv4l2object.h
@@ -49,10 +49,14 @@
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
-#include <gst/controller/gstcontroller.h>
-#include <gst/interfaces/propertyprobe.h>
+#include <gst/video/video.h>
+typedef struct _GstV4l2Object GstV4l2Object;
+typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper;
+typedef struct _GstV4l2Xv GstV4l2Xv;
+
+#include <gstv4l2bufferpool.h>
/* size of v4l2 buffer pool in streaming case */
#define GST_V4L2_MAX_BUFFERS 16
@@ -61,35 +65,66 @@
/* max frame width/height */
#define GST_V4L2_MAX_SIZE (1<<15) /* 2^15 == 32768 */
-
-
G_BEGIN_DECLS
#define GST_V4L2_OBJECT(obj) (GstV4l2Object *)(obj)
-typedef struct _GstV4l2Object GstV4l2Object;
-typedef struct _GstV4l2ObjectClassHelper GstV4l2ObjectClassHelper;
-typedef struct _GstV4l2Xv GstV4l2Xv;
+typedef enum {
+ GST_V4L2_IO_AUTO = 0,
+ GST_V4L2_IO_RW = 1,
+ GST_V4L2_IO_MMAP = 2,
+ GST_V4L2_IO_USERPTR = 3
+} GstV4l2IOMode;
typedef gboolean (*GstV4l2GetInOutFunction) (GstV4l2Object * v4l2object, gint * input);
typedef gboolean (*GstV4l2SetInOutFunction) (GstV4l2Object * v4l2object, gint input);
typedef gboolean (*GstV4l2UpdateFpsFunction) (GstV4l2Object * v4l2object);
+#define GST_V4L2_WIDTH(o) (GST_VIDEO_INFO_WIDTH (&(o)->info))
+#define GST_V4L2_HEIGHT(o) (GST_VIDEO_INFO_HEIGHT (&(o)->info))
+#define GST_V4L2_PIXELFORMAT(o) ((o)->fmtdesc->pixelformat)
+#define GST_V4L2_FPS_N(o) (GST_VIDEO_INFO_FPS_N (&(o)->info))
+#define GST_V4L2_FPS_D(o) (GST_VIDEO_INFO_FPS_D (&(o)->info))
+
+/* simple check whether the device is open */
+#define GST_V4L2_IS_OPEN(o) ((o)->video_fd > 0)
+
+/* check whether the device is 'active' */
+#define GST_V4L2_IS_ACTIVE(o) ((o)->active)
+#define GST_V4L2_SET_ACTIVE(o) ((o)->active = TRUE)
+#define GST_V4L2_SET_INACTIVE(o) ((o)->active = FALSE)
+
struct _GstV4l2Object {
GstElement * element;
+ enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */
+
/* the video device */
char *videodev;
/* the video-device's file descriptor */
gint video_fd;
+ GstV4l2IOMode mode;
GstPoll * poll;
gboolean can_poll_device;
- /* the video buffer (mmap()'ed) */
- guint8 **buffer;
+ gboolean active;
+ gboolean streaming;
- enum v4l2_buf_type type; /* V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_BUF_TYPE_VIDEO_OUTPUT */
+ /* the current format */
+ struct v4l2_fmtdesc *fmtdesc;
+ GstVideoInfo info;
+
+ guint32 bytesperline;
+ guint32 sizeimage;
+ GstClockTime duration;
+
+ /* wanted mode */
+ GstV4l2IOMode req_mode;
+
+ /* optional pool */
+ gboolean always_copy;
+ GstBufferPool *pool;
/* the video device's capabilities */
struct v4l2_capability vcap;
@@ -138,7 +173,8 @@ GType gst_v4l2_object_get_type (void);
PROP_CONTRAST, \
PROP_SATURATION, \
PROP_HUE, \
- PROP_TV_NORM
+ PROP_TV_NORM, \
+ PROP_IO_MODE
/* create/destroy */
GstV4l2Object * gst_v4l2_object_new (GstElement * element,
@@ -159,11 +195,12 @@ gboolean gst_v4l2_object_set_property_helper (GstV4l2Object *v4l2object,
gboolean gst_v4l2_object_get_property_helper (GstV4l2Object *v4l2object,
guint prop_id, GValue * value,
GParamSpec * pspec);
-/* starting/stopping */
-gboolean gst_v4l2_object_start (GstV4l2Object *v4l2object);
-gboolean gst_v4l2_object_stop (GstV4l2Object *v4l2object);
+/* open/close */
+gboolean gst_v4l2_object_open (GstV4l2Object *v4l2object);
+gboolean gst_v4l2_object_close (GstV4l2Object *v4l2object);
/* probing */
+#if 0
const GList* gst_v4l2_probe_get_properties (GstPropertyProbe * probe);
void gst_v4l2_probe_probe_property (GstPropertyProbe * probe, guint prop_id,
@@ -175,25 +212,27 @@ gboolean gst_v4l2_probe_needs_probe (GstPropertyProbe * probe, guint pro
GValueArray* gst_v4l2_probe_get_values (GstPropertyProbe * probe, guint prop_id,
const GParamSpec * pspec,
GList ** klass_devices);
+#endif
GstCaps* gst_v4l2_object_probe_caps_for_format (GstV4l2Object *v4l2object, guint32 pixelformat,
const GstStructure * template);
-gboolean gst_v4l2_object_get_caps_info (GstV4l2Object *v4l2object, GstCaps *caps,
- struct v4l2_fmtdesc **format, gint *w, gint *h,
- gboolean * interlaced, guint *fps_n, guint *fps_d, guint *size);
-
-
GSList* gst_v4l2_object_get_format_list (GstV4l2Object *v4l2object);
GstCaps* gst_v4l2_object_get_all_caps (void);
GstStructure* gst_v4l2_object_v4l2fourcc_to_structure (guint32 fourcc);
-gboolean gst_v4l2_object_set_format (GstV4l2Object *v4l2object, guint32 pixelformat, guint32 width, guint32 height, gboolean interlaced);
+gboolean gst_v4l2_object_set_format (GstV4l2Object *v4l2object, GstCaps * caps);
+
+gboolean gst_v4l2_object_unlock (GstV4l2Object *v4l2object);
+gboolean gst_v4l2_object_unlock_stop (GstV4l2Object *v4l2object);
+
+gboolean gst_v4l2_object_stop (GstV4l2Object *v4l2object);
+
-gboolean gst_v4l2_object_start_streaming (GstV4l2Object *v4l2object);
-gboolean gst_v4l2_object_stop_streaming (GstV4l2Object *v4l2object);
+gboolean gst_v4l2_object_copy (GstV4l2Object * v4l2object,
+ GstBuffer * dest, GstBuffer *src);
#define GST_IMPLEMENT_V4L2_PROBE_METHODS(Type_Class, interface_as_function) \
diff --git a/sys/v4l2/gstv4l2radio.c b/sys/v4l2/gstv4l2radio.c
index 63a2fed17f..bfae360234 100644
--- a/sys/v4l2/gstv4l2radio.c
+++ b/sys/v4l2/gstv4l2radio.c
@@ -251,73 +251,23 @@ gst_v4l2radio_set_unmute (GstV4l2Radio * radio)
return gst_v4l2radio_set_mute_on (radio, FALSE);
}
-GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2RadioClass, gst_v4l2radio);
GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Radio, gst_v4l2radio);
static void gst_v4l2radio_uri_handler_init (gpointer g_iface,
gpointer iface_data);
-static gboolean
-gst_v4l2radio_interface_supported (GstImplementsInterface * iface,
- GType iface_type)
-{
- if (iface_type == GST_TYPE_TUNER)
- return TRUE;
- else
- return FALSE;
-}
-
static void
-gst_v4l2radio_implements_interface_init (GstImplementsInterfaceClass * iface)
-{
- iface->supported = gst_v4l2radio_interface_supported;
-}
-
-static void
-gst_v4l2radio_tuner_interface_reinit (GstTunerClass * iface)
+gst_v4l2radio_tuner_interface_reinit (GstTunerInterface * iface)
{
gst_v4l2radio_tuner_interface_init (iface);
}
-static void
-gst_v4l2radio_interfaces (GType type)
-{
- static const GInterfaceInfo urihandler_info = {
- (GInterfaceInitFunc) gst_v4l2radio_uri_handler_init,
- NULL,
- NULL
- };
-
- static const GInterfaceInfo implements_interface_info = {
- (GInterfaceInitFunc) gst_v4l2radio_implements_interface_init,
- NULL,
- NULL,
- };
-
- static const GInterfaceInfo propertyprobe_info = {
- (GInterfaceInitFunc) gst_v4l2radio_property_probe_interface_init,
- NULL,
- NULL,
- };
-
- static const GInterfaceInfo tuner_interface_info = {
- (GInterfaceInitFunc) gst_v4l2radio_tuner_interface_reinit,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
- g_type_add_interface_static (type,
- GST_TYPE_IMPLEMENTS_INTERFACE, &implements_interface_info);
-
- g_type_add_interface_static (type, GST_TYPE_TUNER, &tuner_interface_info);
-
- g_type_add_interface_static (type,
- GST_TYPE_PROPERTY_PROBE, &propertyprobe_info);
-}
-
-GST_BOILERPLATE_FULL (GstV4l2Radio, gst_v4l2radio, GstElement, GST_TYPE_ELEMENT,
- gst_v4l2radio_interfaces);
+#define gst_v4l2radio_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstV4l2Radio, gst_v4l2radio, GST_TYPE_ELEMENT,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
+ gst_v4l2radio_uri_handler_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_TUNER,
+ gst_v4l2radio_tuner_interface_reinit));
static void gst_v4l2radio_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
@@ -329,24 +279,6 @@ static GstStateChangeReturn gst_v4l2radio_change_state (GstElement * element,
GstStateChange transition);
static void
-gst_v4l2radio_base_init (gpointer gclass)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (gclass);
- GstV4l2RadioClass *gstv4l2radio_class = GST_V4L2RADIO_CLASS (gclass);
-
- GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0,
- "V4l2 radio element");
-
- gstv4l2radio_class->v4l2_class_devices = NULL;
-
- gst_element_class_set_details_simple (gstelement_class,
- "Radio (video4linux2) Tuner",
- "Tuner",
- "Controls a Video4Linux2 radio device",
- "Alexey Chernov <4ernov@gmail.com>");
-}
-
-static void
gst_v4l2radio_class_init (GstV4l2RadioClass * klass)
{
GObjectClass *gobject_class;
@@ -355,6 +287,8 @@ gst_v4l2radio_class_init (GstV4l2RadioClass * klass)
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
+ gobject_class->dispose = gst_v4l2radio_dispose;
+ gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize;
gobject_class->set_property = gst_v4l2radio_set_property;
gobject_class->get_property = gst_v4l2radio_get_property;
@@ -368,16 +302,23 @@ gst_v4l2radio_class_init (GstV4l2RadioClass * klass)
"Station frequency in Hz",
MIN_FREQUENCY, MAX_FREQUENCY, DEFAULT_FREQUENCY, G_PARAM_READWRITE));
- gobject_class->dispose = gst_v4l2radio_dispose;
- gobject_class->finalize = (GObjectFinalizeFunc) gst_v4l2radio_finalize;
-
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_v4l2radio_change_state);
+ gst_element_class_set_details_simple (gstelement_class,
+ "Radio (video4linux2) Tuner",
+ "Tuner",
+ "Controls a Video4Linux2 radio device",
+ "Alexey Chernov <4ernov@gmail.com>");
+
+ klass->v4l2_class_devices = NULL;
+
+ GST_DEBUG_CATEGORY_INIT (v4l2radio_debug, "v4l2radio", 0,
+ "V4l2 radio element");
}
static void
-gst_v4l2radio_init (GstV4l2Radio * filter, GstV4l2RadioClass * gclass)
+gst_v4l2radio_init (GstV4l2Radio * filter)
{
filter->v4l2object = gst_v4l2_object_new (GST_ELEMENT (filter),
V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE,
@@ -473,7 +414,7 @@ gst_v4l2radio_start (GstV4l2Radio * radio)
static gboolean
gst_v4l2radio_stop (GstV4l2Radio * radio)
{
- if (!gst_v4l2_object_stop (radio->v4l2object))
+ if (!gst_v4l2_object_close (radio->v4l2object))
return FALSE;
return TRUE;
@@ -563,19 +504,20 @@ gst_v4l2radio_get_property (GObject * object, guint prop_id,
/* GstURIHandler interface */
static GstURIType
-gst_v4l2radio_uri_get_type (void)
+gst_v4l2radio_uri_get_type (GType type)
{
return GST_URI_SRC;
}
-static gchar **
-gst_v4l2radio_uri_get_protocols (void)
+static const gchar *const *
+gst_v4l2radio_uri_get_protocols (GType type)
{
- static gchar *protocols[] = { (char *) "radio", NULL };
+ static const gchar *protocols[] = { "radio", NULL };
+
return protocols;
}
-static const gchar *
+static gchar *
gst_v4l2radio_uri_get_uri (GstURIHandler * handler)
{
GstV4l2Radio *radio = GST_V4L2RADIO (handler);
@@ -583,19 +525,17 @@ gst_v4l2radio_uri_get_uri (GstURIHandler * handler)
if (radio->v4l2object->videodev != NULL) {
if (gst_v4l2_get_frequency (radio->v4l2object,
0, &(radio->v4l2object->frequency))) {
- gchar uri[20];
- gchar freq[6];
- g_ascii_formatd (freq, 6, "%4.1f", radio->v4l2object->frequency / 1e6);
- g_snprintf (uri, sizeof (uri), "radio://%s", freq);
- return g_intern_string (uri);
+ return g_strdup_printf ("radio://%4.1f",
+ radio->v4l2object->frequency / 1e6);
}
}
- return "radio://";
+ return g_strdup ("radio://");
}
static gboolean
-gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+ GError ** error)
{
GstV4l2Radio *radio = GST_V4L2RADIO (handler);
gdouble dfreq;
@@ -620,6 +560,8 @@ gst_v4l2radio_uri_set_uri (GstURIHandler * handler, const gchar * uri)
return TRUE;
uri_failed:
+ g_set_error_literal (error, GST_URI_ERROR, GST_URI_ERROR_BAD_REFERENCE,
+ "Bad radio URI, could not parse frequency");
return FALSE;
}
diff --git a/sys/v4l2/gstv4l2sink.c b/sys/v4l2/gstv4l2sink.c
index f6aba2455d..a2e2fe5d28 100644
--- a/sys/v4l2/gstv4l2sink.c
+++ b/sys/v4l2/gstv4l2sink.c
@@ -53,11 +53,12 @@
#include <config.h>
#endif
+#include "gst/video/gstvideometa.h"
#include "gstv4l2colorbalance.h"
#include "gstv4l2tuner.h"
#ifdef HAVE_XVIDEO
-#include "gstv4l2xoverlay.h"
+#include "gstv4l2videooverlay.h"
#endif
#include "gstv4l2vidorient.h"
@@ -69,16 +70,12 @@
GST_DEBUG_CATEGORY (v4l2sink_debug);
#define GST_CAT_DEFAULT v4l2sink_debug
-#define PROP_DEF_QUEUE_SIZE 12
-#define PROP_DEF_MIN_QUEUED_BUFS 1
#define DEFAULT_PROP_DEVICE "/dev/video1"
enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
- PROP_QUEUE_SIZE,
- PROP_MIN_QUEUED_BUFS,
PROP_OVERLAY_TOP,
PROP_OVERLAY_LEFT,
PROP_OVERLAY_WIDTH,
@@ -90,53 +87,13 @@ enum
};
-GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SinkClass, gst_v4l2sink);
GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Sink, gst_v4l2sink);
GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Sink, gst_v4l2sink);
#ifdef HAVE_XVIDEO
-GST_IMPLEMENT_V4L2_XOVERLAY_METHODS (GstV4l2Sink, gst_v4l2sink);
+GST_IMPLEMENT_V4L2_VIDEO_OVERLAY_METHODS (GstV4l2Sink, gst_v4l2sink);
#endif
GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Sink, gst_v4l2sink);
-static gboolean
-gst_v4l2sink_iface_supported (GstImplementsInterface * iface, GType iface_type)
-{
- GstV4l2Object *v4l2object = GST_V4L2SINK (iface)->v4l2object;
-
-#ifdef HAVE_XVIDEO
- g_assert (iface_type == GST_TYPE_X_OVERLAY ||
- iface_type == GST_TYPE_NAVIGATION ||
- iface_type == GST_TYPE_COLOR_BALANCE ||
- iface_type == GST_TYPE_VIDEO_ORIENTATION ||
- iface_type == GST_TYPE_TUNER);
-#else
- g_assert (iface_type == GST_TYPE_COLOR_BALANCE ||
- iface_type == GST_TYPE_VIDEO_ORIENTATION ||
- iface_type == GST_TYPE_TUNER);
-#endif
-
- if (v4l2object->video_fd == -1)
- return FALSE;
-
-#ifdef HAVE_XVIDEO
- if (!GST_V4L2_IS_OVERLAY (v4l2object)) {
- if (iface_type == GST_TYPE_X_OVERLAY || iface_type == GST_TYPE_NAVIGATION)
- return FALSE;
- }
-#endif
-
- return TRUE;
-}
-
-static void
-gst_v4l2sink_interface_init (GstImplementsInterfaceClass * klass)
-{
- /*
- * default virtual functions
- */
- klass->supported = gst_v4l2sink_iface_supported;
-}
-
#ifdef HAVE_XVIDEO
static void gst_v4l2sink_navigation_send_event (GstNavigation * navigation,
GstStructure * structure);
@@ -147,66 +104,18 @@ gst_v4l2sink_navigation_init (GstNavigationInterface * iface)
}
#endif
-static void
-gst_v4l2sink_init_interfaces (GType type)
-{
- static const GInterfaceInfo v4l2iface_info = {
- (GInterfaceInitFunc) gst_v4l2sink_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo v4l2_tuner_info = {
- (GInterfaceInitFunc) gst_v4l2sink_tuner_interface_init,
- NULL,
- NULL,
- };
+#define gst_v4l2sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstV4l2Sink, gst_v4l2sink, GST_TYPE_VIDEO_SINK,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_TUNER, gst_v4l2sink_tuner_interface_init);
#ifdef HAVE_XVIDEO
- static const GInterfaceInfo v4l2_xoverlay_info = {
- (GInterfaceInitFunc) gst_v4l2sink_xoverlay_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo v4l2_navigation_info = {
- (GInterfaceInitFunc) gst_v4l2sink_navigation_init,
- NULL,
- NULL,
- };
+ G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
+ gst_v4l2sink_video_overlay_interface_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION, gst_v4l2sink_navigation_init);
#endif
- static const GInterfaceInfo v4l2_colorbalance_info = {
- (GInterfaceInitFunc) gst_v4l2sink_color_balance_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo v4l2_videoorientation_info = {
- (GInterfaceInitFunc) gst_v4l2sink_video_orientation_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo v4l2_propertyprobe_info = {
- (GInterfaceInitFunc) gst_v4l2sink_property_probe_interface_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type,
- GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info);
- g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info);
-#ifdef HAVE_XVIDEO
- g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info);
- g_type_add_interface_static (type,
- GST_TYPE_NAVIGATION, &v4l2_navigation_info);
-#endif
- g_type_add_interface_static (type,
- GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info);
- g_type_add_interface_static (type,
- GST_TYPE_VIDEO_ORIENTATION, &v4l2_videoorientation_info);
- g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
- &v4l2_propertyprobe_info);
-}
-
-
-GST_BOILERPLATE_FULL (GstV4l2Sink, gst_v4l2sink, GstVideoSink,
- GST_TYPE_VIDEO_SINK, gst_v4l2sink_init_interfaces);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+ gst_v4l2sink_color_balance_interface_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_ORIENTATION,
+ gst_v4l2sink_video_orientation_interface_init));
static void gst_v4l2sink_dispose (GObject * object);
@@ -218,42 +127,23 @@ static void gst_v4l2sink_set_property (GObject * object, guint prop_id,
static void gst_v4l2sink_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-
/* GstElement methods: */
static GstStateChangeReturn gst_v4l2sink_change_state (GstElement * element,
GstStateChange transition);
/* GstBaseSink methods: */
-static GstCaps *gst_v4l2sink_get_caps (GstBaseSink * bsink);
+static gboolean gst_v4l2sink_propose_allocation (GstBaseSink * bsink,
+ GstQuery * query);
+static GstCaps *gst_v4l2sink_get_caps (GstBaseSink * bsink, GstCaps * filter);
static gboolean gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
+#if 0
static GstFlowReturn gst_v4l2sink_buffer_alloc (GstBaseSink * bsink,
guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
+#endif
static GstFlowReturn gst_v4l2sink_show_frame (GstBaseSink * bsink,
GstBuffer * buf);
static void
-gst_v4l2sink_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
- GstV4l2SinkClass *gstv4l2sink_class = GST_V4L2SINK_CLASS (g_class);
- GstPadTemplate *pad_template;
-
- gstv4l2sink_class->v4l2_class_devices = NULL;
-
- GST_DEBUG_CATEGORY_INIT (v4l2sink_debug, "v4l2sink", 0, "V4L2 sink element");
-
- gst_element_class_set_details_simple (gstelement_class,
- "Video (video4linux2) Sink", "Sink/Video",
- "Displays frames on a video4linux2 device", "Rob Clark <rob@ti.com>,");
-
- pad_template =
- gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
- gst_v4l2_object_get_all_caps ());
- gst_element_class_add_pad_template (gstelement_class, pad_template);
- gst_object_unref (pad_template);
-}
-
-static void
gst_v4l2sink_class_init (GstV4l2SinkClass * klass)
{
GObjectClass *gobject_class;
@@ -273,17 +163,7 @@ gst_v4l2sink_class_init (GstV4l2SinkClass * klass)
gst_v4l2_object_install_properties_helper (gobject_class,
DEFAULT_PROP_DEVICE);
- g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE,
- g_param_spec_uint ("queue-size", "Queue size",
- "Number of buffers to be enqueud in the driver in streaming mode",
- GST_V4L2_MIN_BUFFERS, GST_V4L2_MAX_BUFFERS, PROP_DEF_QUEUE_SIZE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (gobject_class, PROP_MIN_QUEUED_BUFS,
- g_param_spec_uint ("min-queued-bufs", "Minimum queued bufs",
- "Minimum number of queued bufs; v4l2sink won't dqbuf if the driver "
- "doesn't have more than this number (which normally you shouldn't change)",
- 0, GST_V4L2_MAX_BUFFERS, PROP_DEF_MIN_QUEUED_BUFS,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_property (gobject_class, PROP_OVERLAY_TOP,
g_param_spec_int ("overlay-top", "Overlay top",
"The topmost (y) coordinate of the video overlay; top left corner of screen is 0,0",
@@ -318,14 +198,28 @@ gst_v4l2sink_class_init (GstV4l2SinkClass * klass)
"The height of the video crop; default is equal to negotiated image height",
0, 0xffffffff, 0, G_PARAM_READWRITE));
+ gst_element_class_set_details_simple (element_class,
+ "Video (video4linux2) Sink", "Sink/Video",
+ "Displays frames on a video4linux2 device", "Rob Clark <rob@ti.com>,");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+ gst_v4l2_object_get_all_caps ()));
+
basesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2sink_get_caps);
basesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_v4l2sink_set_caps);
- basesink_class->buffer_alloc = GST_DEBUG_FUNCPTR (gst_v4l2sink_buffer_alloc);
+ basesink_class->propose_allocation =
+ GST_DEBUG_FUNCPTR (gst_v4l2sink_propose_allocation);
basesink_class->render = GST_DEBUG_FUNCPTR (gst_v4l2sink_show_frame);
+
+ klass->v4l2_class_devices = NULL;
+
+ GST_DEBUG_CATEGORY_INIT (v4l2sink_debug, "v4l2sink", 0, "V4L2 sink element");
+
}
static void
-gst_v4l2sink_init (GstV4l2Sink * v4l2sink, GstV4l2SinkClass * klass)
+gst_v4l2sink_init (GstV4l2Sink * v4l2sink)
{
v4l2sink->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2sink),
V4L2_BUF_TYPE_VIDEO_OUTPUT, DEFAULT_PROP_DEVICE,
@@ -338,16 +232,10 @@ gst_v4l2sink_init (GstV4l2Sink * v4l2sink, GstV4l2SinkClass * klass)
*/
g_object_set (v4l2sink, "device", "/dev/video1", NULL);
- /* number of buffers requested */
- v4l2sink->num_buffers = PROP_DEF_QUEUE_SIZE;
- v4l2sink->min_queued_bufs = PROP_DEF_MIN_QUEUED_BUFS;
-
v4l2sink->probed_caps = NULL;
- v4l2sink->current_caps = NULL;
v4l2sink->overlay_fields_set = 0;
v4l2sink->crop_fields_set = 0;
- v4l2sink->state = 0;
}
@@ -360,10 +248,6 @@ gst_v4l2sink_dispose (GObject * object)
gst_caps_unref (v4l2sink->probed_caps);
}
- if (v4l2sink->current_caps) {
- gst_caps_unref (v4l2sink->current_caps);
- }
-
G_OBJECT_CLASS (parent_class)->dispose (object);
}
@@ -378,16 +262,6 @@ gst_v4l2sink_finalize (GstV4l2Sink * v4l2sink)
/*
- * State values
- */
-enum
-{
- STATE_OFF = 0,
- STATE_PENDING_STREAMON,
- STATE_STREAMING
-};
-
-/*
* flags to indicate which overlay/crop properties the user has set (and
* therefore which ones should override the defaults from the driver)
*/
@@ -497,12 +371,6 @@ gst_v4l2sink_set_property (GObject * object,
if (!gst_v4l2_object_set_property_helper (v4l2sink->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
- case PROP_QUEUE_SIZE:
- v4l2sink->num_buffers = g_value_get_uint (value);
- break;
- case PROP_MIN_QUEUED_BUFS:
- v4l2sink->min_queued_bufs = g_value_get_uint (value);
- break;
case PROP_OVERLAY_TOP:
v4l2sink->overlay.top = g_value_get_int (value);
v4l2sink->overlay_fields_set |= RECT_TOP_SET;
@@ -560,12 +428,6 @@ gst_v4l2sink_get_property (GObject * object,
if (!gst_v4l2_object_get_property_helper (v4l2sink->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
- case PROP_QUEUE_SIZE:
- g_value_set_uint (value, v4l2sink->num_buffers);
- break;
- case PROP_MIN_QUEUED_BUFS:
- g_value_set_uint (value, v4l2sink->min_queued_bufs);
- break;
case PROP_OVERLAY_TOP:
g_value_set_int (value, v4l2sink->overlay.top);
break;
@@ -610,7 +472,7 @@ gst_v4l2sink_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
/* open the device */
- if (!gst_v4l2_object_start (v4l2sink->v4l2object))
+ if (!gst_v4l2_object_open (v4l2sink->v4l2object))
return GST_STATE_CHANGE_FAILURE;
break;
default:
@@ -621,21 +483,16 @@ gst_v4l2sink_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_READY:
- if (v4l2sink->state == STATE_STREAMING) {
- if (!gst_v4l2_object_stop_streaming (v4l2sink->v4l2object)) {
- return GST_STATE_CHANGE_FAILURE;
- }
- v4l2sink->state = STATE_PENDING_STREAMON;
- }
+ if (!gst_v4l2_object_stop (v4l2sink->v4l2object))
+ return GST_STATE_CHANGE_FAILURE;
break;
case GST_STATE_CHANGE_READY_TO_NULL:
- if (NULL != v4l2sink->pool)
- gst_v4l2_buffer_pool_destroy (v4l2sink->pool);
- v4l2sink->pool = NULL;
- /* close the device */
+ /* we need to call stop here too */
if (!gst_v4l2_object_stop (v4l2sink->v4l2object))
return GST_STATE_CHANGE_FAILURE;
- v4l2sink->state = STATE_OFF;
+ /* close the device */
+ if (!gst_v4l2_object_close (v4l2sink->v4l2object))
+ return GST_STATE_CHANGE_FAILURE;
break;
default:
break;
@@ -646,7 +503,7 @@ gst_v4l2sink_change_state (GstElement * element, GstStateChange transition)
static GstCaps *
-gst_v4l2sink_get_caps (GstBaseSink * bsink)
+gst_v4l2sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
GstCaps *ret;
@@ -661,40 +518,44 @@ gst_v4l2sink_get_caps (GstBaseSink * bsink)
(v4l2sink)));
}
- if (v4l2sink->probed_caps) {
- LOG_CAPS (v4l2sink, v4l2sink->probed_caps);
- return gst_caps_ref (v4l2sink->probed_caps);
- }
-
- formats = gst_v4l2_object_get_format_list (v4l2sink->v4l2object);
+ if (v4l2sink->probed_caps == NULL) {
+ formats = gst_v4l2_object_get_format_list (v4l2sink->v4l2object);
- ret = gst_caps_new_empty ();
+ ret = gst_caps_new_empty ();
- for (walk = formats; walk; walk = walk->next) {
- struct v4l2_fmtdesc *format;
+ for (walk = formats; walk; walk = walk->next) {
+ struct v4l2_fmtdesc *format;
- GstStructure *template;
+ GstStructure *template;
- format = (struct v4l2_fmtdesc *) walk->data;
+ format = (struct v4l2_fmtdesc *) walk->data;
- template = gst_v4l2_object_v4l2fourcc_to_structure (format->pixelformat);
+ template = gst_v4l2_object_v4l2fourcc_to_structure (format->pixelformat);
- if (template) {
- GstCaps *tmp;
+ if (template) {
+ GstCaps *tmp;
- tmp =
- gst_v4l2_object_probe_caps_for_format (v4l2sink->v4l2object,
- format->pixelformat, template);
- if (tmp)
- gst_caps_append (ret, tmp);
+ tmp =
+ gst_v4l2_object_probe_caps_for_format (v4l2sink->v4l2object,
+ format->pixelformat, template);
+ if (tmp)
+ gst_caps_append (ret, tmp);
- gst_structure_free (template);
- } else {
- GST_DEBUG_OBJECT (v4l2sink, "unknown format %u", format->pixelformat);
+ gst_structure_free (template);
+ } else {
+ GST_DEBUG_OBJECT (v4l2sink, "unknown format %u", format->pixelformat);
+ }
}
+ v4l2sink->probed_caps = ret;
}
- v4l2sink->probed_caps = gst_caps_ref (ret);
+ if (filter) {
+ ret =
+ gst_caps_intersect_full (filter, v4l2sink->probed_caps,
+ GST_CAPS_INTERSECT_FIRST);
+ } else {
+ ret = gst_caps_ref (v4l2sink->probed_caps);
+ }
GST_INFO_OBJECT (v4l2sink, "probed caps: %p", ret);
LOG_CAPS (v4l2sink, ret);
@@ -706,11 +567,7 @@ static gboolean
gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
- gint w = 0, h = 0;
- gboolean interlaced;
- struct v4l2_fmtdesc *format;
- guint fps_n, fps_d;
- guint size;
+ GstV4l2Object *obj = v4l2sink->v4l2object;
LOG_CAPS (v4l2sink, caps);
@@ -719,118 +576,102 @@ gst_v4l2sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
return FALSE;
}
- if (v4l2sink->current_caps) {
- GST_DEBUG_OBJECT (v4l2sink, "already have caps set.. are they equal?");
- LOG_CAPS (v4l2sink, v4l2sink->current_caps);
- if (gst_caps_is_equal (v4l2sink->current_caps, caps)) {
- GST_DEBUG_OBJECT (v4l2sink, "yes they are!");
- return TRUE;
- }
- GST_DEBUG_OBJECT (v4l2sink, "no they aren't!");
- }
+ if (!gst_v4l2_object_stop (obj))
+ goto stop_failed;
- if (v4l2sink->pool) {
- /* TODO: if we've already allocated buffers, we probably need to
- * do something here to free and reallocate....
- *
- * gst_v4l2_object_stop_streaming()
- * gst_v4l2_buffer_pool_destroy()
- *
- */
- GST_DEBUG_OBJECT (v4l2sink, "warning, changing caps not supported yet");
- return FALSE;
- }
+ if (!gst_v4l2_object_set_format (v4l2sink->v4l2object, caps))
+ goto invalid_format;
- /* we want our own v4l2 type of fourcc codes */
- if (!gst_v4l2_object_get_caps_info (v4l2sink->v4l2object, caps,
- &format, &w, &h, &interlaced, &fps_n, &fps_d, &size)) {
- GST_DEBUG_OBJECT (v4l2sink, "can't get capture format from caps %p", caps);
- return FALSE;
- }
+ gst_v4l2sink_sync_overlay_fields (v4l2sink);
+ gst_v4l2sink_sync_crop_fields (v4l2sink);
- if (!format) {
- GST_DEBUG_OBJECT (v4l2sink, "unrecognized caps!!");
- return FALSE;
- }
+#ifdef HAVE_XVIDEO
+ gst_v4l2_video_overlay_prepare_window_handle (v4l2sink->v4l2object, TRUE);
+#endif
- if (!gst_v4l2_object_set_format (v4l2sink->v4l2object, format->pixelformat,
- w, h, interlaced)) {
- /* error already posted */
- return FALSE;
- }
+ GST_INFO_OBJECT (v4l2sink, "outputting buffers via mmap()");
- v4l2sink->video_width = w;
- v4l2sink->video_height = h;
+ v4l2sink->video_width = GST_V4L2_WIDTH (v4l2sink->v4l2object);
+ v4l2sink->video_height = GST_V4L2_HEIGHT (v4l2sink->v4l2object);
/* TODO: videosink width/height should be scaled according to
* pixel-aspect-ratio
*/
- GST_VIDEO_SINK_WIDTH (v4l2sink) = w;
- GST_VIDEO_SINK_HEIGHT (v4l2sink) = h;
-
- v4l2sink->current_caps = gst_caps_ref (caps);
+ GST_VIDEO_SINK_WIDTH (v4l2sink) = v4l2sink->video_width;
+ GST_VIDEO_SINK_HEIGHT (v4l2sink) = v4l2sink->video_height;
return TRUE;
+
+ /* ERRORS */
+stop_failed:
+ {
+ GST_DEBUG_OBJECT (v4l2sink, "failed to stop streaming");
+ return FALSE;
+ }
+invalid_format:
+ {
+ /* error already posted */
+ GST_DEBUG_OBJECT (v4l2sink, "can't set format");
+ return FALSE;
+ }
}
-/* buffer alloc function to implement pad_alloc for upstream element */
-static GstFlowReturn
-gst_v4l2sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
- GstCaps * caps, GstBuffer ** buf)
+static gboolean
+gst_v4l2sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
{
GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
- GstV4l2Buffer *v4l2buf;
-
- if (v4l2sink->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
-
- /* initialize the buffer pool if not initialized yet (first buffer): */
- if (G_UNLIKELY (!v4l2sink->pool)) {
-
- /* set_caps() might not be called yet.. so just to make sure: */
- if (!gst_v4l2sink_set_caps (bsink, caps)) {
- return GST_FLOW_ERROR;
- }
-
- GST_V4L2_CHECK_OPEN (v4l2sink->v4l2object);
+ GstV4l2Object *obj = v4l2sink->v4l2object;
+ GstBufferPool *pool;
+ guint size = 0;
+ GstCaps *caps;
+ gboolean need_pool;
- if (!(v4l2sink->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2sink),
- v4l2sink->v4l2object->video_fd,
- v4l2sink->num_buffers, caps, FALSE,
- V4L2_BUF_TYPE_VIDEO_OUTPUT))) {
- return GST_FLOW_ERROR;
- }
+ gst_query_parse_allocation (query, &caps, &need_pool);
- gst_v4l2sink_sync_overlay_fields (v4l2sink);
- gst_v4l2sink_sync_crop_fields (v4l2sink);
+ if (caps == NULL)
+ goto no_caps;
-#ifdef HAVE_XVIDEO
- gst_v4l2_xoverlay_prepare_xwindow_id (v4l2sink->v4l2object, TRUE);
-#endif
+ if ((pool = obj->pool))
+ gst_object_ref (pool);
- v4l2sink->state = STATE_PENDING_STREAMON;
+ if (pool != NULL) {
+ const GstCaps *pcaps;
+ GstStructure *config;
- GST_INFO_OBJECT (v4l2sink, "outputting buffers via mmap()");
+ /* we had a pool, check caps */
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
- if (v4l2sink->num_buffers != v4l2sink->pool->buffer_count) {
- v4l2sink->num_buffers = v4l2sink->pool->buffer_count;
- g_object_notify (G_OBJECT (v4l2sink), "queue-size");
- }
+ GST_DEBUG_OBJECT (v4l2sink,
+ "we had a pool with caps %" GST_PTR_FORMAT, pcaps);
+ if (!gst_caps_is_equal (caps, pcaps)) {
+ gst_object_unref (pool);
+ goto different_caps;
}
+ }
+ /* we need at least 2 buffers to operate */
+ gst_query_add_allocation_pool (query, pool, size, 2, 0);
- v4l2buf = gst_v4l2_buffer_pool_get (v4l2sink->pool, TRUE);
+ /* we also support various metadata */
+ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE);
+ gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE);
- if (G_LIKELY (v4l2buf)) {
- GST_DEBUG_OBJECT (v4l2sink, "allocated buffer: %p", v4l2buf);
- *buf = GST_BUFFER (v4l2buf);
- return GST_FLOW_OK;
- } else {
- GST_DEBUG_OBJECT (v4l2sink, "failed to allocate buffer");
- return GST_FLOW_ERROR;
- }
+ if (pool)
+ gst_object_unref (pool);
- } else {
- GST_ERROR_OBJECT (v4l2sink, "only supporting streaming mode for now...");
- return GST_FLOW_ERROR;
+ return TRUE;
+
+ /* ERRORS */
+no_caps:
+ {
+ GST_DEBUG_OBJECT (v4l2sink, "no caps specified");
+ return FALSE;
+ }
+different_caps:
+ {
+ /* different caps, we can't use this pool */
+ GST_DEBUG_OBJECT (v4l2sink, "pool has different caps");
+ return FALSE;
}
}
@@ -838,92 +679,26 @@ gst_v4l2sink_buffer_alloc (GstBaseSink * bsink, guint64 offset, guint size,
static GstFlowReturn
gst_v4l2sink_show_frame (GstBaseSink * bsink, GstBuffer * buf)
{
+ GstFlowReturn ret;
GstV4l2Sink *v4l2sink = GST_V4L2SINK (bsink);
- GstBuffer *newbuf = NULL;
+ GstV4l2Object *obj = v4l2sink->v4l2object;
GST_DEBUG_OBJECT (v4l2sink, "render buffer: %p", buf);
- if (!GST_IS_V4L2_BUFFER (buf)) {
- GstFlowReturn ret;
-
- /* special case check for sub-buffers: In certain cases, places like
- * GstBaseTransform, which might check that the buffer is writable
- * before copying metadata, timestamp, and such, will find that the
- * buffer has more than one reference to it. In these cases, they
- * will create a sub-buffer with an offset=0 and length equal to the
- * original buffer size.
- *
- * This could happen in two scenarios: (1) a tee in the pipeline, and
- * (2) because the refcnt is incremented in gst_mini_object_free()
- * before the finalize function is called, and decremented after it
- * returns.. but returning this buffer to the buffer pool in the
- * finalize function, could wake up a thread blocked in _buffer_alloc()
- * which could run and get a buffer w/ refcnt==2 before the thread
- * originally unref'ing the buffer returns from finalize function and
- * decrements the refcnt back to 1!
- */
- if (buf->parent &&
- (GST_BUFFER_DATA (buf) == GST_BUFFER_DATA (buf->parent)) &&
- (GST_BUFFER_SIZE (buf) == GST_BUFFER_SIZE (buf->parent))) {
- GST_DEBUG_OBJECT (v4l2sink, "I have a sub-buffer!");
- return gst_v4l2sink_show_frame (bsink, buf->parent);
- }
-
- GST_DEBUG_OBJECT (v4l2sink, "slow-path.. I got a %s so I need to memcpy",
- g_type_name (G_OBJECT_TYPE (buf)));
-
- ret = gst_v4l2sink_buffer_alloc (bsink,
- GST_BUFFER_OFFSET (buf), GST_BUFFER_SIZE (buf), GST_BUFFER_CAPS (buf),
- &newbuf);
-
- if (GST_FLOW_OK != ret) {
- GST_DEBUG_OBJECT (v4l2sink,
- "dropping frame! Consider increasing 'queue-size' property!");
- return GST_FLOW_OK;
- }
-
- memcpy (GST_BUFFER_DATA (newbuf),
- GST_BUFFER_DATA (buf),
- MIN (GST_BUFFER_SIZE (newbuf), GST_BUFFER_SIZE (buf)));
+ if (G_UNLIKELY (obj->pool == NULL))
+ goto not_negotiated;
- GST_DEBUG_OBJECT (v4l2sink, "render copied buffer: %p", newbuf);
+ ret =
+ gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL_CAST (obj->pool), buf);
- buf = newbuf;
- }
-
- if (!gst_v4l2_buffer_pool_qbuf (v4l2sink->pool, GST_V4L2_BUFFER (buf))) {
- return GST_FLOW_ERROR;
- }
- if (v4l2sink->state == STATE_PENDING_STREAMON) {
- if (!gst_v4l2_object_start_streaming (v4l2sink->v4l2object)) {
- return GST_FLOW_ERROR;
- }
- v4l2sink->state = STATE_STREAMING;
- }
-
- if (!newbuf) {
- gst_buffer_ref (buf);
- }
+ return ret;
- /* if the driver has more than one buffer, ie. more than just the one we
- * just queued, then dequeue one immediately to make it available via
- * _buffer_alloc():
- */
- if (gst_v4l2_buffer_pool_available_buffers (v4l2sink->pool) >
- v4l2sink->min_queued_bufs) {
- GstV4l2Buffer *v4l2buf = gst_v4l2_buffer_pool_dqbuf (v4l2sink->pool);
-
- /* note: if we get a buf, we don't want to use it directly (because
- * someone else could still hold a ref).. but instead we release our
- * reference to it, and if no one else holds a ref it will be returned
- * to the pool of available buffers.. and if not, we keep looping.
- */
- if (v4l2buf) {
- gst_buffer_unref (GST_BUFFER (v4l2buf));
- }
+ /* ERRORS */
+not_negotiated:
+ {
+ GST_ERROR_OBJECT (bsink, "not negotiated");
+ return GST_FLOW_NOT_NEGOTIATED;
}
-
- return GST_FLOW_OK;
}
#ifdef HAVE_XVIDEO
@@ -942,7 +717,7 @@ gst_v4l2sink_navigation_send_event (GstNavigation * navigation,
GstVideoRectangle rect;
gdouble x, y, xscale = 1.0, yscale = 1.0;
- gst_v4l2_xoverlay_get_render_rect (v4l2sink->v4l2object, &rect);
+ gst_v4l2_video_overlay_get_render_rect (v4l2sink->v4l2object, &rect);
/* We calculate scaling using the original video frames geometry to
* include pixel aspect ratio scaling.
diff --git a/sys/v4l2/gstv4l2sink.h b/sys/v4l2/gstv4l2sink.h
index 8fe82221ae..b461e2c922 100644
--- a/sys/v4l2/gstv4l2sink.h
+++ b/sys/v4l2/gstv4l2sink.h
@@ -55,10 +55,6 @@ struct _GstV4l2Sink {
/*< private >*/
GstV4l2Object * v4l2object;
GstCaps *probed_caps; /* all supported caps of underlying v4l2 device */
- GstCaps *current_caps; /* the current negotiated caps */
- GstV4l2BufferPool *pool;
- guint32 num_buffers;
- guint32 min_queued_bufs;
gint video_width, video_height; /* original (unscaled) video w/h */
@@ -73,8 +69,6 @@ struct _GstV4l2Sink {
* setting properties:
*/
guint8 overlay_fields_set, crop_fields_set;
-
- guint8 state;
};
struct _GstV4l2SinkClass {
diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c
index f8ae09ccc1..a27ad3a71c 100644
--- a/sys/v4l2/gstv4l2src.c
+++ b/sys/v4l2/gstv4l2src.c
@@ -48,9 +48,13 @@
#include <string.h>
#include <sys/time.h>
-#include "v4l2src_calls.h"
#include <unistd.h>
+#include "gst/video/gstvideometa.h"
+#include "gst/video/gstvideopool.h"
+
+#include "gstv4l2src.h"
+
#include "gstv4l2colorbalance.h"
#include "gstv4l2tuner.h"
#ifdef HAVE_XVIDEO
@@ -63,7 +67,6 @@
GST_DEBUG_CATEGORY (v4l2src_debug);
#define GST_CAT_DEFAULT v4l2src_debug
-#define PROP_DEF_QUEUE_SIZE 2
#define PROP_DEF_ALWAYS_COPY TRUE
#define PROP_DEF_DECIMATE 1
@@ -73,12 +76,10 @@ enum
{
PROP_0,
V4L2_STD_OBJECT_PROPS,
- PROP_QUEUE_SIZE,
PROP_ALWAYS_COPY,
PROP_DECIMATE
};
-GST_IMPLEMENT_V4L2_PROBE_METHODS (GstV4l2SrcClass, gst_v4l2src);
GST_IMPLEMENT_V4L2_COLOR_BALANCE_METHODS (GstV4l2Src, gst_v4l2src);
GST_IMPLEMENT_V4L2_TUNER_METHODS (GstV4l2Src, gst_v4l2src);
#ifdef HAVE_XVIDEO
@@ -89,104 +90,19 @@ GST_IMPLEMENT_V4L2_VIDORIENT_METHODS (GstV4l2Src, gst_v4l2src);
static void gst_v4l2src_uri_handler_init (gpointer g_iface,
gpointer iface_data);
-static gboolean
-gst_v4l2src_iface_supported (GstImplementsInterface * iface, GType iface_type)
-{
- GstV4l2Object *v4l2object = GST_V4L2SRC (iface)->v4l2object;
-
-#ifdef HAVE_XVIDEO
- if (!(iface_type == GST_TYPE_TUNER ||
- iface_type == GST_TYPE_X_OVERLAY ||
- iface_type == GST_TYPE_COLOR_BALANCE ||
- iface_type == GST_TYPE_VIDEO_ORIENTATION))
- return FALSE;
-#else
- if (!(iface_type == GST_TYPE_TUNER ||
- iface_type == GST_TYPE_COLOR_BALANCE ||
- iface_type == GST_TYPE_VIDEO_ORIENTATION))
- return FALSE;
-#endif
-
- if (v4l2object->video_fd == -1)
- return FALSE;
-
-#ifdef HAVE_XVIDEO
- if (iface_type == GST_TYPE_X_OVERLAY && !GST_V4L2_IS_OVERLAY (v4l2object))
- return FALSE;
-#endif
-
- return TRUE;
-}
-
-static void
-gst_v4l2src_interface_init (GstImplementsInterfaceClass * klass)
-{
- /*
- * default virtual functions
- */
- klass->supported = gst_v4l2src_iface_supported;
-}
-
-static void
-gst_v4l2src_init_interfaces (GType type)
-{
- static const GInterfaceInfo urihandler_info = {
- gst_v4l2src_uri_handler_init,
- NULL,
- NULL
- };
-
- static const GInterfaceInfo v4l2iface_info = {
- (GInterfaceInitFunc) gst_v4l2src_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo v4l2_tuner_info = {
- (GInterfaceInitFunc) gst_v4l2src_tuner_interface_init,
- NULL,
- NULL,
- };
+#define gst_v4l2src_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstV4l2Src, gst_v4l2src, GST_TYPE_PUSH_SRC,
+ G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER, gst_v4l2src_uri_handler_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_TUNER, gst_v4l2src_tuner_interface_init);
#ifdef HAVE_XVIDEO
- /* FIXME: does GstXOverlay for v4l2src make sense in a GStreamer context? */
- static const GInterfaceInfo v4l2_xoverlay_info = {
- (GInterfaceInitFunc) gst_v4l2src_xoverlay_interface_init,
- NULL,
- NULL,
- };
+ /* FIXME: does GstXOverlay for v4l2src make sense in a GStreamer context? */
+ G_IMPLEMENT_INTERFACE (GST_TYPE_X_OVERLAY,
+ gst_v4l2src_xoverlay_interface_init);
#endif
- static const GInterfaceInfo v4l2_colorbalance_info = {
- (GInterfaceInitFunc) gst_v4l2src_color_balance_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo v4l2_videoorientation_info = {
- (GInterfaceInitFunc) gst_v4l2src_video_orientation_interface_init,
- NULL,
- NULL,
- };
- static const GInterfaceInfo v4l2_propertyprobe_info = {
- (GInterfaceInitFunc) gst_v4l2src_property_probe_interface_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
- g_type_add_interface_static (type,
- GST_TYPE_IMPLEMENTS_INTERFACE, &v4l2iface_info);
- g_type_add_interface_static (type, GST_TYPE_TUNER, &v4l2_tuner_info);
-#ifdef HAVE_XVIDEO
- g_type_add_interface_static (type, GST_TYPE_X_OVERLAY, &v4l2_xoverlay_info);
-#endif
- g_type_add_interface_static (type,
- GST_TYPE_COLOR_BALANCE, &v4l2_colorbalance_info);
- g_type_add_interface_static (type,
- GST_TYPE_VIDEO_ORIENTATION, &v4l2_videoorientation_info);
- g_type_add_interface_static (type, GST_TYPE_PROPERTY_PROBE,
- &v4l2_propertyprobe_info);
-}
-
-GST_BOILERPLATE_FULL (GstV4l2Src, gst_v4l2src, GstPushSrc, GST_TYPE_PUSH_SRC,
- gst_v4l2src_init_interfaces);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+ gst_v4l2src_color_balance_interface_init);
+ G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_ORIENTATION,
+ gst_v4l2src_video_orientation_interface_init));
static void gst_v4l2src_dispose (GObject * object);
static void gst_v4l2src_finalize (GstV4l2Src * v4l2src);
@@ -201,10 +117,12 @@ static gboolean gst_v4l2src_unlock (GstBaseSrc * src);
static gboolean gst_v4l2src_unlock_stop (GstBaseSrc * src);
static gboolean gst_v4l2src_stop (GstBaseSrc * src);
static gboolean gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps);
-static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src);
+static GstCaps *gst_v4l2src_get_caps (GstBaseSrc * src, GstCaps * filter);
static gboolean gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query);
-static GstFlowReturn gst_v4l2src_create (GstPushSrc * src, GstBuffer ** out);
-static void gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
+static gboolean gst_v4l2src_decide_allocation (GstBaseSrc * src,
+ GstQuery * query);
+static GstFlowReturn gst_v4l2src_fill (GstPushSrc * src, GstBuffer * out);
+static GstCaps *gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps);
static gboolean gst_v4l2src_negotiate (GstBaseSrc * basesrc);
static void gst_v4l2src_set_property (GObject * object, guint prop_id,
@@ -212,36 +130,6 @@ static void gst_v4l2src_set_property (GObject * object, guint prop_id,
static void gst_v4l2src_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
-/* get_frame io methods */
-static GstFlowReturn
-gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf);
-static GstFlowReturn
-gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf);
-
-static void
-gst_v4l2src_base_init (gpointer g_class)
-{
- GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
- GstV4l2SrcClass *gstv4l2src_class = GST_V4L2SRC_CLASS (g_class);
- GstPadTemplate *pad_template;
-
- gstv4l2src_class->v4l2_class_devices = NULL;
-
- GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element");
-
- gst_element_class_set_details_simple (gstelement_class,
- "Video (video4linux2) Source", "Source/Video",
- "Reads frames from a Video4Linux2 device",
- "Edgard Lima <edgard.lima@indt.org.br>,"
- " Stefan Kost <ensonic@users.sf.net>");
-
- pad_template =
- gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
- gst_v4l2_object_get_all_caps ());
- gst_element_class_add_pad_template (gstelement_class, pad_template);
- gst_object_unref (pad_template);
-}
-
static void
gst_v4l2src_class_init (GstV4l2SrcClass * klass)
{
@@ -264,11 +152,6 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
gst_v4l2_object_install_properties_helper (gobject_class,
DEFAULT_PROP_DEVICE);
- g_object_class_install_property (gobject_class, PROP_QUEUE_SIZE,
- g_param_spec_uint ("queue-size", "Queue size",
- "Number of buffers to be enqueud in the driver in streaming mode",
- GST_V4L2_MIN_BUFFERS, GST_V4L2_MAX_BUFFERS, PROP_DEF_QUEUE_SIZE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_ALWAYS_COPY,
g_param_spec_boolean ("always-copy", "Always Copy",
"If the buffer will or not be used directly from mmap",
@@ -285,6 +168,17 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
"Only use every nth frame", 1, G_MAXINT,
PROP_DEF_DECIMATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ gst_element_class_set_details_simple (element_class,
+ "Video (video4linux2) Source", "Source/Video",
+ "Reads frames from a Video4Linux2 device",
+ "Edgard Lima <edgard.lima@indt.org.br>, "
+ "Stefan Kost <ensonic@users.sf.net>");
+
+ gst_element_class_add_pad_template
+ (element_class,
+ gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
+ gst_v4l2_object_get_all_caps ()));
+
basesrc_class->get_caps = GST_DEBUG_FUNCPTR (gst_v4l2src_get_caps);
basesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_v4l2src_set_caps);
basesrc_class->start = GST_DEBUG_FUNCPTR (gst_v4l2src_start);
@@ -294,34 +188,31 @@ gst_v4l2src_class_init (GstV4l2SrcClass * klass)
basesrc_class->query = GST_DEBUG_FUNCPTR (gst_v4l2src_query);
basesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_v4l2src_fixate);
basesrc_class->negotiate = GST_DEBUG_FUNCPTR (gst_v4l2src_negotiate);
+ basesrc_class->decide_allocation =
+ GST_DEBUG_FUNCPTR (gst_v4l2src_decide_allocation);
+
+ pushsrc_class->fill = GST_DEBUG_FUNCPTR (gst_v4l2src_fill);
+
+ klass->v4l2_class_devices = NULL;
- pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_v4l2src_create);
+ GST_DEBUG_CATEGORY_INIT (v4l2src_debug, "v4l2src", 0, "V4L2 source element");
}
static void
-gst_v4l2src_init (GstV4l2Src * v4l2src, GstV4l2SrcClass * klass)
+gst_v4l2src_init (GstV4l2Src * v4l2src)
{
/* fixme: give an update_fps_function */
v4l2src->v4l2object = gst_v4l2_object_new (GST_ELEMENT (v4l2src),
V4L2_BUF_TYPE_VIDEO_CAPTURE, DEFAULT_PROP_DEVICE,
gst_v4l2_get_input, gst_v4l2_set_input, NULL);
- /* number of buffers requested */
- v4l2src->num_buffers = PROP_DEF_QUEUE_SIZE;
-
- v4l2src->always_copy = PROP_DEF_ALWAYS_COPY;
+ v4l2src->v4l2object->always_copy = PROP_DEF_ALWAYS_COPY;
v4l2src->decimate = PROP_DEF_DECIMATE;
- v4l2src->is_capturing = FALSE;
-
gst_base_src_set_format (GST_BASE_SRC (v4l2src), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (v4l2src), TRUE);
-
- v4l2src->fps_d = 0;
- v4l2src->fps_n = 0;
}
-
static void
gst_v4l2src_dispose (GObject * object)
{
@@ -353,11 +244,8 @@ gst_v4l2src_set_property (GObject * object,
if (!gst_v4l2_object_set_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
- case PROP_QUEUE_SIZE:
- v4l2src->num_buffers = g_value_get_uint (value);
- break;
case PROP_ALWAYS_COPY:
- v4l2src->always_copy = g_value_get_boolean (value);
+ v4l2src->v4l2object->always_copy = g_value_get_boolean (value);
break;
case PROP_DECIMATE:
v4l2src->decimate = g_value_get_int (value);
@@ -369,7 +257,6 @@ gst_v4l2src_set_property (GObject * object,
}
}
-
static void
gst_v4l2src_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
@@ -379,11 +266,8 @@ gst_v4l2src_get_property (GObject * object,
if (!gst_v4l2_object_get_property_helper (v4l2src->v4l2object,
prop_id, value, pspec)) {
switch (prop_id) {
- case PROP_QUEUE_SIZE:
- g_value_set_uint (value, v4l2src->num_buffers);
- break;
case PROP_ALWAYS_COPY:
- g_value_set_boolean (value, v4l2src->always_copy);
+ g_value_set_boolean (value, v4l2src->v4l2object->always_copy);
break;
case PROP_DECIMATE:
g_value_set_int (value, v4l2src->decimate);
@@ -395,9 +279,8 @@ gst_v4l2src_get_property (GObject * object,
}
}
-
/* this function is a bit of a last resort */
-static void
+static GstCaps *
gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
{
GstStructure *structure;
@@ -405,34 +288,25 @@ gst_v4l2src_fixate (GstBaseSrc * basesrc, GstCaps * caps)
GST_DEBUG_OBJECT (basesrc, "fixating caps %" GST_PTR_FORMAT, caps);
- for (i = 0; i < gst_caps_get_size (caps); ++i) {
- const GValue *v;
+ caps = gst_caps_make_writable (caps);
+ for (i = 0; i < gst_caps_get_size (caps); ++i) {
structure = gst_caps_get_structure (caps, i);
- /* FIXME such sizes? we usually fixate to something in the 320x200
- * range... */
- /* We are fixating to greater possble size (limited to GST_V4L2_MAX_SIZE)
+ /* We are fixating to a resonable 320x200 resolution
and the maximum framerate resolution for that size */
- gst_structure_fixate_field_nearest_int (structure, "width",
- GST_V4L2_MAX_SIZE);
- gst_structure_fixate_field_nearest_int (structure, "height",
- GST_V4L2_MAX_SIZE);
+ gst_structure_fixate_field_nearest_int (structure, "width", 320);
+ gst_structure_fixate_field_nearest_int (structure, "height", 200);
gst_structure_fixate_field_nearest_fraction (structure, "framerate",
G_MAXINT, 1);
-
- v = gst_structure_get_value (structure, "format");
- if (v && G_VALUE_TYPE (v) != GST_TYPE_FOURCC) {
- guint32 fourcc;
-
- g_return_if_fail (G_VALUE_TYPE (v) == GST_TYPE_LIST);
-
- fourcc = gst_value_get_fourcc (gst_value_list_get_value (v, 0));
- gst_structure_set (structure, "format", GST_TYPE_FOURCC, fourcc, NULL);
- }
+ gst_structure_fixate_field (structure, "format");
}
GST_DEBUG_OBJECT (basesrc, "fixated caps %" GST_PTR_FORMAT, caps);
+
+ caps = GST_BASE_SRC_CLASS (parent_class)->fixate (basesrc, caps);
+
+ return caps;
}
@@ -445,7 +319,7 @@ gst_v4l2src_negotiate (GstBaseSrc * basesrc)
gboolean result = FALSE;
/* first see what is possible on our source pad */
- thiscaps = gst_pad_get_caps (GST_BASE_SRC_PAD (basesrc));
+ thiscaps = gst_pad_query_caps (GST_BASE_SRC_PAD (basesrc), NULL);
GST_DEBUG_OBJECT (basesrc, "caps of src: %" GST_PTR_FORMAT, thiscaps);
LOG_CAPS (basesrc, thiscaps);
@@ -454,7 +328,7 @@ gst_v4l2src_negotiate (GstBaseSrc * basesrc)
goto no_nego_needed;
/* get the peer caps */
- peercaps = gst_pad_peer_get_caps (GST_BASE_SRC_PAD (basesrc));
+ peercaps = gst_pad_peer_query_caps (GST_BASE_SRC_PAD (basesrc), thiscaps);
GST_DEBUG_OBJECT (basesrc, "caps of peer: %" GST_PTR_FORMAT, peercaps);
LOG_CAPS (basesrc, peercaps);
if (peercaps && !gst_caps_is_any (peercaps)) {
@@ -486,11 +360,8 @@ gst_v4l2src_negotiate (GstBaseSrc * basesrc)
* resolution strictly bigger then the first peer caps */
if (gst_caps_get_size (icaps) > 1) {
GstStructure *s = gst_caps_get_structure (peercaps, 0);
-
int best = 0;
-
int twidth, theight;
-
int width = G_MAXINT, height = G_MAXINT;
if (gst_structure_get_int (s, "width", &twidth)
@@ -501,7 +372,6 @@ gst_v4l2src_negotiate (GstBaseSrc * basesrc)
*/
for (i = gst_caps_get_size (icaps) - 1; i >= 0; i--) {
GstStructure *is = gst_caps_get_structure (icaps, i);
-
int w, h;
if (gst_structure_get_int (is, "width", &w)
@@ -529,12 +399,11 @@ gst_v4l2src_negotiate (GstBaseSrc * basesrc)
if (peercaps)
gst_caps_unref (peercaps);
if (caps) {
- caps = gst_caps_make_writable (caps);
- gst_caps_truncate (caps);
+ caps = gst_caps_truncate (caps);
/* now fixate */
if (!gst_caps_is_empty (caps)) {
- gst_pad_fixate_caps (GST_BASE_SRC_PAD (basesrc), caps);
+ caps = gst_v4l2src_fixate (basesrc, caps);
GST_DEBUG_OBJECT (basesrc, "fixated to: %" GST_PTR_FORMAT, caps);
LOG_CAPS (basesrc, caps);
@@ -544,8 +413,7 @@ gst_v4l2src_negotiate (GstBaseSrc * basesrc)
result = TRUE;
} else if (gst_caps_is_fixed (caps)) {
/* yay, fixed caps, use those then */
- if (gst_pad_set_caps (GST_BASE_SRC_PAD (basesrc), caps))
- result = TRUE;
+ result = gst_base_src_set_caps (basesrc, caps);
}
}
gst_caps_unref (caps);
@@ -562,14 +430,18 @@ no_nego_needed:
}
static GstCaps *
-gst_v4l2src_get_caps (GstBaseSrc * src)
+gst_v4l2src_get_caps (GstBaseSrc * src, GstCaps * filter)
{
- GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+ GstV4l2Src *v4l2src;
+ GstV4l2Object *obj;
GstCaps *ret;
GSList *walk;
GSList *formats;
- if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
+ v4l2src = GST_V4L2SRC (src);
+ obj = v4l2src->v4l2object;
+
+ if (!GST_V4L2_IS_OPEN (obj)) {
/* FIXME: copy? */
return
gst_caps_copy (gst_pad_get_pad_template_caps (GST_BASE_SRC_PAD
@@ -579,13 +451,12 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
if (v4l2src->probed_caps)
return gst_caps_ref (v4l2src->probed_caps);
- formats = gst_v4l2_object_get_format_list (v4l2src->v4l2object);
+ formats = gst_v4l2_object_get_format_list (obj);
ret = gst_caps_new_empty ();
for (walk = formats; walk; walk = walk->next) {
struct v4l2_fmtdesc *format;
-
GstStructure *template;
format = (struct v4l2_fmtdesc *) walk->data;
@@ -596,7 +467,7 @@ gst_v4l2src_get_caps (GstBaseSrc * src)
GstCaps *tmp;
tmp =
- gst_v4l2_object_probe_caps_for_format (v4l2src->v4l2object,
+ gst_v4l2_object_probe_caps_for_format (obj,
format->pixelformat, template);
if (tmp)
gst_caps_append (ret, tmp);
@@ -618,57 +489,108 @@ static gboolean
gst_v4l2src_set_caps (GstBaseSrc * src, GstCaps * caps)
{
GstV4l2Src *v4l2src;
- gint w = 0, h = 0;
- gboolean interlaced;
- struct v4l2_fmtdesc *format;
- guint fps_n, fps_d;
- guint size;
+ GstV4l2Object *obj;
v4l2src = GST_V4L2SRC (src);
-
- /* if we're not open, punt -- we'll get setcaps'd later via negotiate */
- if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object))
- return FALSE;
+ obj = v4l2src->v4l2object;
/* make sure we stop capturing and dealloc buffers */
- if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
- /* both will throw an element-error on failure */
- if (!gst_v4l2src_capture_stop (v4l2src))
- return FALSE;
- if (!gst_v4l2src_capture_deinit (v4l2src))
- return FALSE;
- }
-
- /* we want our own v4l2 type of fourcc codes */
- if (!gst_v4l2_object_get_caps_info (v4l2src->v4l2object, caps, &format, &w,
- &h, &interlaced, &fps_n, &fps_d, &size)) {
- GST_INFO_OBJECT (v4l2src,
- "can't get capture format from caps %" GST_PTR_FORMAT, caps);
+ if (!gst_v4l2_object_stop (obj))
return FALSE;
- }
- GST_DEBUG_OBJECT (v4l2src, "trying to set_capture %dx%d at %d/%d fps, "
- "format %s", w, h, fps_n, fps_d, format->description);
-
- if (!gst_v4l2src_set_capture (v4l2src, format->pixelformat, w, h,
- interlaced, fps_n, fps_d))
+ if (!gst_v4l2_object_set_format (obj, caps))
/* error already posted */
return FALSE;
- if (!gst_v4l2src_capture_init (v4l2src, caps))
- return FALSE;
+ return TRUE;
+}
+
+static gboolean
+gst_v4l2src_decide_allocation (GstBaseSrc * bsrc, GstQuery * query)
+{
+ GstV4l2Src *src;
+ GstV4l2Object *obj;
+ GstBufferPool *pool;
+ guint size, min, max;
+ gboolean update;
- if (v4l2src->use_mmap) {
- v4l2src->get_frame = gst_v4l2src_get_mmap;
+ src = GST_V4L2SRC (bsrc);
+ obj = src->v4l2object;
+
+ if (gst_query_get_n_allocation_pools (query) > 0) {
+ gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+ update = TRUE;
} else {
- v4l2src->get_frame = gst_v4l2src_get_read;
+ pool = NULL;
+ min = max = 0;
+ size = 0;
+ update = FALSE;
}
- if (!gst_v4l2src_capture_start (v4l2src))
- return FALSE;
+ GST_DEBUG_OBJECT (src, "allocation: size:%u min:%u max:%u pool:%"
+ GST_PTR_FORMAT, size, min, max, pool);
- /* now store the expected output size */
- v4l2src->frame_byte_size = size;
+ if (min != 0) {
+ /* if there is a min-buffers suggestion, use it. We add 1 because we need 1
+ * buffer extra to capture while the other two buffers are downstream */
+ min += 1;
+ } else {
+ min = 2;
+ }
+
+ /* select a pool */
+ switch (obj->mode) {
+ case GST_V4L2_IO_RW:
+ if (pool == NULL) {
+ /* no downstream pool, use our own then */
+ GST_DEBUG_OBJECT (src,
+ "read/write mode: no downstream pool, using our own");
+ pool = GST_BUFFER_POOL_CAST (obj->pool);
+ size = obj->sizeimage;
+ } else {
+ /* in READ/WRITE mode, prefer a downstream pool because our own pool
+ * doesn't help much, we have to write to it as well */
+ GST_DEBUG_OBJECT (src, "read/write mode: using downstream pool");
+ /* use the bigest size, when we use our own pool we can't really do any
+ * other size than what the hardware gives us but for downstream pools
+ * we can try */
+ size = MAX (size, obj->sizeimage);
+ }
+ break;
+ case GST_V4L2_IO_MMAP:
+ case GST_V4L2_IO_USERPTR:
+ /* in streaming mode, prefer our own pool */
+ pool = GST_BUFFER_POOL_CAST (obj->pool);
+ size = obj->sizeimage;
+ GST_DEBUG_OBJECT (src,
+ "streaming mode: using our own pool %" GST_PTR_FORMAT, pool);
+ break;
+ case GST_V4L2_IO_AUTO:
+ default:
+ GST_WARNING_OBJECT (src, "unhandled mode");
+ break;
+ }
+
+ if (pool) {
+ GstStructure *config;
+ const GstCaps *caps;
+
+ config = gst_buffer_pool_get_config (pool);
+ gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL);
+ gst_buffer_pool_config_set_params (config, caps, size, min, max);
+
+ /* if downstream supports video metadata, add this to the pool config */
+ if (gst_query_has_allocation_meta (query, GST_VIDEO_META_API_TYPE))
+ gst_buffer_pool_config_add_option (config,
+ GST_BUFFER_POOL_OPTION_VIDEO_META);
+
+ gst_buffer_pool_set_config (pool, config);
+ }
+
+ if (update)
+ gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
+ else
+ gst_query_add_allocation_pool (query, pool, size, min, max);
return TRUE;
}
@@ -677,35 +599,40 @@ static gboolean
gst_v4l2src_query (GstBaseSrc * bsrc, GstQuery * query)
{
GstV4l2Src *src;
-
+ GstV4l2Object *obj;
gboolean res = FALSE;
src = GST_V4L2SRC (bsrc);
+ obj = src->v4l2object;
switch (GST_QUERY_TYPE (query)) {
case GST_QUERY_LATENCY:{
GstClockTime min_latency, max_latency;
+ guint32 fps_n, fps_d;
/* device must be open */
- if (!GST_V4L2_IS_OPEN (src->v4l2object)) {
+ if (!GST_V4L2_IS_OPEN (obj)) {
GST_WARNING_OBJECT (src,
"Can't give latency since device isn't open !");
goto done;
}
+ fps_n = GST_V4L2_FPS_N (obj);
+ fps_d = GST_V4L2_FPS_D (obj);
+
/* we must have a framerate */
- if (src->fps_n <= 0 || src->fps_d <= 0) {
+ if (fps_n <= 0 || fps_d <= 0) {
GST_WARNING_OBJECT (src,
"Can't give latency since framerate isn't fixated !");
goto done;
}
/* min latency is the time to capture one frame */
- min_latency =
- gst_util_uint64_scale_int (GST_SECOND, src->fps_d, src->fps_n);
+ min_latency = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
/* max latency is total duration of the frame buffer */
- max_latency = src->num_buffers * min_latency;
+ max_latency =
+ GST_V4L2_BUFFER_POOL_CAST (obj->pool)->max_buffers * min_latency;
GST_DEBUG_OBJECT (bsrc,
"report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
@@ -741,7 +668,7 @@ gst_v4l2src_start (GstBaseSrc * src)
/* activate settings for first frame */
v4l2src->ctrl_time = 0;
- gst_object_sync_values (G_OBJECT (src), v4l2src->ctrl_time);
+ gst_object_sync_values (GST_OBJECT (src), v4l2src->ctrl_time);
return TRUE;
}
@@ -750,41 +677,26 @@ static gboolean
gst_v4l2src_unlock (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
-
- GST_LOG_OBJECT (src, "Flushing");
- gst_poll_set_flushing (v4l2src->v4l2object->poll, TRUE);
-
- return TRUE;
+ return gst_v4l2_object_unlock (v4l2src->v4l2object);
}
static gboolean
gst_v4l2src_unlock_stop (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
-
- GST_LOG_OBJECT (src, "No longer flushing");
- gst_poll_set_flushing (v4l2src->v4l2object->poll, FALSE);
-
- return TRUE;
+ return gst_v4l2_object_unlock_stop (v4l2src->v4l2object);
}
static gboolean
gst_v4l2src_stop (GstBaseSrc * src)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+ GstV4l2Object *obj = v4l2src->v4l2object;
- if (GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)
- && !gst_v4l2src_capture_stop (v4l2src))
- return FALSE;
-
- if (v4l2src->v4l2object->buffer != NULL) {
- if (!gst_v4l2src_capture_deinit (v4l2src))
+ if (GST_V4L2_IS_ACTIVE (obj)) {
+ if (!gst_v4l2_object_stop (obj))
return FALSE;
}
-
- v4l2src->fps_d = 0;
- v4l2src->fps_n = 0;
-
return TRUE;
}
@@ -793,11 +705,12 @@ gst_v4l2src_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
GstV4l2Src *v4l2src = GST_V4L2SRC (element);
+ GstV4l2Object *obj = v4l2src->v4l2object;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
/* open the device */
- if (!gst_v4l2_object_start (v4l2src->v4l2object))
+ if (!gst_v4l2_object_open (obj))
return GST_STATE_CHANGE_FAILURE;
break;
default:
@@ -809,7 +722,7 @@ gst_v4l2src_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_READY_TO_NULL:
/* close the device */
- if (!gst_v4l2_object_stop (v4l2src->v4l2object))
+ if (!gst_v4l2_object_close (obj))
return GST_STATE_CHANGE_FAILURE;
if (v4l2src->probed_caps) {
@@ -825,228 +738,123 @@ gst_v4l2src_change_state (GstElement * element, GstStateChange transition)
}
static GstFlowReturn
-gst_v4l2src_get_read (GstV4l2Src * v4l2src, GstBuffer ** buf)
+gst_v4l2src_fill (GstPushSrc * src, GstBuffer * buf)
{
- gint amount;
- gint ret;
-
- gint buffersize;
-
- buffersize = v4l2src->frame_byte_size;
- /* In case the size per frame is unknown assume it's a streaming format (e.g.
- * mpegts) and grab a reasonable default size instead */
- if (buffersize == 0)
- buffersize = GST_BASE_SRC (v4l2src)->blocksize;
-
- *buf = gst_buffer_new_and_alloc (buffersize);
-
- do {
- ret = gst_poll_wait (v4l2src->v4l2object->poll, GST_CLOCK_TIME_NONE);
- if (G_UNLIKELY (ret < 0)) {
- if (errno == EBUSY)
- goto stopped;
- if (errno == ENXIO) {
- GST_DEBUG_OBJECT (v4l2src,
- "v4l2 device doesn't support polling. Disabling");
- v4l2src->v4l2object->can_poll_device = FALSE;
- } else {
- if (errno != EAGAIN && errno != EINTR)
- goto select_error;
- }
- }
- amount =
- v4l2_read (v4l2src->v4l2object->video_fd, GST_BUFFER_DATA (*buf),
- buffersize);
- if (amount == buffersize) {
- break;
- } else if (amount == -1) {
- if (errno == EAGAIN || errno == EINTR) {
- continue;
- } else
- goto read_error;
- } else {
- /* short reads can happen if a signal interrupts the read */
- continue;
- }
- } while (TRUE);
-
- /* we set the buffer metadata in gst_v4l2src_create() */
-
- return GST_FLOW_OK;
+ GstV4l2Src *v4l2src = GST_V4L2SRC (src);
+ GstV4l2Object *obj = v4l2src->v4l2object;
+ GstFlowReturn ret;
+ GstClock *clock;
+ GstClockTime timestamp, duration;
- /* ERRORS */
-select_error:
- {
- GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ, (NULL),
- ("select error %d: %s (%d)", ret, g_strerror (errno), errno));
- return GST_FLOW_ERROR;
- }
-stopped:
- {
- GST_DEBUG ("stop called");
- return GST_FLOW_WRONG_STATE;
- }
-read_error:
- {
- GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
- (_("Error reading %d bytes from device '%s'."),
- buffersize, v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
+#if 0
+ int i;
+ /* decimate, just capture and throw away frames */
+ for (i = 0; i < v4l2src->decimate - 1; i++) {
+ ret = gst_v4l2_buffer_pool_process (obj, buf);
+ if (ret != GST_FLOW_OK) {
+ return ret;
+ }
gst_buffer_unref (*buf);
- return GST_FLOW_ERROR;
}
-}
+#endif
-static GstFlowReturn
-gst_v4l2src_get_mmap (GstV4l2Src * v4l2src, GstBuffer ** buf)
-{
- GstBuffer *temp;
- GstFlowReturn ret;
- guint size;
- guint count = 0;
+ ret =
+ gst_v4l2_buffer_pool_process (GST_V4L2_BUFFER_POOL_CAST (obj->pool), buf);
-again:
- ret = gst_v4l2src_grab_frame (v4l2src, &temp);
if (G_UNLIKELY (ret != GST_FLOW_OK))
- goto done;
-
- if (v4l2src->frame_byte_size > 0) {
- size = GST_BUFFER_SIZE (temp);
-
- /* if size does not match what we expected, try again */
- if (size != v4l2src->frame_byte_size) {
- GST_ELEMENT_WARNING (v4l2src, RESOURCE, READ,
- (_("Got unexpected frame size of %u instead of %u."),
- size, v4l2src->frame_byte_size), (NULL));
- gst_buffer_unref (temp);
- if (count++ > 50)
- goto size_error;
+ goto error;
- goto again;
- }
+ /* set buffer metadata */
+ GST_BUFFER_OFFSET (buf) = v4l2src->offset++;
+ GST_BUFFER_OFFSET_END (buf) = v4l2src->offset;
+
+ /* timestamps, LOCK to get clock and base time. */
+ /* FIXME: element clock and base_time is rarely changing */
+ GST_OBJECT_LOCK (v4l2src);
+ if ((clock = GST_ELEMENT_CLOCK (v4l2src))) {
+ /* we have a clock, get base time and ref clock */
+ timestamp = GST_ELEMENT (v4l2src)->base_time;
+ gst_object_ref (clock);
+ } else {
+ /* no clock, can't set timestamps */
+ timestamp = GST_CLOCK_TIME_NONE;
}
+ GST_OBJECT_UNLOCK (v4l2src);
- *buf = temp;
-done:
- return ret;
-
- /* ERRORS */
-size_error:
- {
- GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
- (_("Error reading %d bytes on device '%s'."),
- v4l2src->frame_byte_size, v4l2src->v4l2object->videodev), (NULL));
- return GST_FLOW_ERROR;
- }
-}
+ duration = obj->duration;
-static GstFlowReturn
-gst_v4l2src_create (GstPushSrc * src, GstBuffer ** buf)
-{
- GstV4l2Src *v4l2src = GST_V4L2SRC (src);
- int i;
- GstFlowReturn ret;
+ if (G_LIKELY (clock)) {
+ /* the time now is the time of the clock minus the base time */
+ timestamp = gst_clock_get_time (clock) - timestamp;
+ gst_object_unref (clock);
- for (i = 0; i < v4l2src->decimate - 1; i++) {
- ret = v4l2src->get_frame (v4l2src, buf);
- if (ret != GST_FLOW_OK) {
- return ret;
+ /* if we have a framerate adjust timestamp for frame latency */
+ if (GST_CLOCK_TIME_IS_VALID (duration)) {
+ if (timestamp > duration)
+ timestamp -= duration;
+ else
+ timestamp = 0;
}
- gst_buffer_unref (*buf);
}
- ret = v4l2src->get_frame (v4l2src, buf);
+ /* activate settings for next frame */
+ if (GST_CLOCK_TIME_IS_VALID (duration)) {
+ v4l2src->ctrl_time += duration;
+ } else {
+ /* this is not very good (as it should be the next timestamp),
+ * still good enough for linear fades (as long as it is not -1)
+ */
+ v4l2src->ctrl_time = timestamp;
+ }
+ gst_object_sync_values (GST_OBJECT (src), v4l2src->ctrl_time);
+ GST_INFO_OBJECT (src, "sync to %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (v4l2src->ctrl_time));
- /* set buffer metadata */
- if (G_LIKELY (ret == GST_FLOW_OK && *buf)) {
- GstClock *clock;
- GstClockTime timestamp;
-
- GST_BUFFER_OFFSET (*buf) = v4l2src->offset++;
- GST_BUFFER_OFFSET_END (*buf) = v4l2src->offset;
-
- /* timestamps, LOCK to get clock and base time. */
- /* FIXME: element clock and base_time is rarely changing */
- GST_OBJECT_LOCK (v4l2src);
- if ((clock = GST_ELEMENT_CLOCK (v4l2src))) {
- /* we have a clock, get base time and ref clock */
- timestamp = GST_ELEMENT (v4l2src)->base_time;
- gst_object_ref (clock);
- } else {
- /* no clock, can't set timestamps */
- timestamp = GST_CLOCK_TIME_NONE;
- }
- GST_OBJECT_UNLOCK (v4l2src);
-
- if (G_LIKELY (clock)) {
- /* the time now is the time of the clock minus the base time */
- timestamp = gst_clock_get_time (clock) - timestamp;
- gst_object_unref (clock);
-
- /* if we have a framerate adjust timestamp for frame latency */
- if (GST_CLOCK_TIME_IS_VALID (v4l2src->duration)) {
- if (timestamp > v4l2src->duration)
- timestamp -= v4l2src->duration;
- else
- timestamp = 0;
- }
- }
+ /* FIXME: use the timestamp from the buffer itself! */
+ GST_BUFFER_TIMESTAMP (buf) = timestamp;
+ GST_BUFFER_DURATION (buf) = duration;
- /* activate settings for next frame */
- if (GST_CLOCK_TIME_IS_VALID (v4l2src->duration)) {
- v4l2src->ctrl_time += v4l2src->duration;
- } else {
- /* this is not very good (as it should be the next timestamp),
- * still good enough for linear fades (as long as it is not -1)
- */
- v4l2src->ctrl_time = timestamp;
- }
- gst_object_sync_values (G_OBJECT (src), v4l2src->ctrl_time);
- GST_INFO_OBJECT (src, "sync to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (v4l2src->ctrl_time));
+ return ret;
- /* FIXME: use the timestamp from the buffer itself! */
- GST_BUFFER_TIMESTAMP (*buf) = timestamp;
- GST_BUFFER_DURATION (*buf) = v4l2src->duration;
+ /* ERROR */
+error:
+ {
+ GST_ERROR_OBJECT (src, "error processing buffer");
+ return ret;
}
- return ret;
}
/* GstURIHandler interface */
static GstURIType
-gst_v4l2src_uri_get_type (void)
+gst_v4l2src_uri_get_type (GType type)
{
return GST_URI_SRC;
}
-static gchar **
-gst_v4l2src_uri_get_protocols (void)
+static const gchar *const *
+gst_v4l2src_uri_get_protocols (GType type)
{
- static gchar *protocols[] = { (char *) "v4l2", NULL };
+ static const gchar *protocols[] = { "v4l2", NULL };
return protocols;
}
-static const gchar *
+static gchar *
gst_v4l2src_uri_get_uri (GstURIHandler * handler)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (handler);
if (v4l2src->v4l2object->videodev != NULL) {
- gchar uri[256];
-
- /* need to return a const string, but also don't want to leak the generated
- * string, so just intern it - there's a limited number of video devices
- * after all */
- g_snprintf (uri, sizeof (uri), "v4l2://%s", v4l2src->v4l2object->videodev);
- return g_intern_string (uri);
+ return g_strdup_printf ("v4l2://%s", v4l2src->v4l2object->videodev);
}
- return "v4l2://";
+ return g_strdup ("v4l2://");
}
static gboolean
-gst_v4l2src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
+gst_v4l2src_uri_set_uri (GstURIHandler * handler, const gchar * uri,
+ GError ** error)
{
GstV4l2Src *v4l2src = GST_V4L2SRC (handler);
const gchar *device = DEFAULT_PROP_DEVICE;
diff --git a/sys/v4l2/gstv4l2src.h b/sys/v4l2/gstv4l2src.h
index 0dd794a711..8ebaa57692 100644
--- a/sys/v4l2/gstv4l2src.h
+++ b/sys/v4l2/gstv4l2src.h
@@ -45,8 +45,6 @@ G_BEGIN_DECLS
typedef struct _GstV4l2Src GstV4l2Src;
typedef struct _GstV4l2SrcClass GstV4l2SrcClass;
-typedef GstFlowReturn (*GstV4l2SrcGetFunc)(GstV4l2Src * v4l2src, GstBuffer ** buf);
-
/**
* GstV4l2Src:
*
@@ -62,30 +60,11 @@ struct _GstV4l2Src
/* pads */
GstCaps *probed_caps;
- /* buffer handling */
- GstV4l2BufferPool *pool;
-
- guint32 num_buffers;
- gboolean use_mmap;
- guint32 frame_byte_size;
-
- /* if the buffer will be or not used from directly mmap */
- gboolean always_copy;
-
int decimate;
- /* True if we want to stop */
- gboolean quit;
- gboolean is_capturing;
-
guint64 offset;
- gint fps_d, fps_n; /* framerate if device is open */
- GstClockTime duration; /* duration of one frame */
-
GstClockTime ctrl_time;
-
- GstV4l2SrcGetFunc get_frame;
};
struct _GstV4l2SrcClass
diff --git a/sys/v4l2/gstv4l2tuner.c b/sys/v4l2/gstv4l2tuner.c
index a805396cac..c885dc6740 100644
--- a/sys/v4l2/gstv4l2tuner.c
+++ b/sys/v4l2/gstv4l2tuner.c
@@ -30,7 +30,6 @@
#include "gstv4l2tuner.h"
#include "gstv4l2object.h"
#include "v4l2_calls.h"
-#include "v4l2src_calls.h"
static void gst_v4l2_tuner_channel_class_init (GstV4l2TunerChannelClass *
klass);
diff --git a/sys/v4l2/gstv4l2tuner.h b/sys/v4l2/gstv4l2tuner.h
index 699ca87e10..75d4559e04 100644
--- a/sys/v4l2/gstv4l2tuner.h
+++ b/sys/v4l2/gstv4l2tuner.h
@@ -179,20 +179,20 @@ interface_as_function ## _tuner_signal_strength (GstTuner * mixer,
} \
\
static void \
-interface_as_function ## _tuner_interface_init (GstTunerClass * klass) \
+interface_as_function ## _tuner_interface_init (GstTunerInterface * iface) \
{ \
/* default virtual functions */ \
- klass->list_channels = interface_as_function ## _tuner_list_channels; \
- klass->set_channel = interface_as_function ## _tuner_set_channel; \
- klass->get_channel = interface_as_function ## _tuner_get_channel; \
+ iface->list_channels = interface_as_function ## _tuner_list_channels; \
+ iface->set_channel = interface_as_function ## _tuner_set_channel; \
+ iface->get_channel = interface_as_function ## _tuner_get_channel; \
\
- klass->list_norms = interface_as_function ## _tuner_list_norms; \
- klass->set_norm = interface_as_function ## _tuner_set_norm_and_notify; \
- klass->get_norm = interface_as_function ## _tuner_get_norm; \
+ iface->list_norms = interface_as_function ## _tuner_list_norms; \
+ iface->set_norm = interface_as_function ## _tuner_set_norm_and_notify; \
+ iface->get_norm = interface_as_function ## _tuner_get_norm; \
\
- klass->set_frequency = interface_as_function ## _tuner_set_frequency_and_notify; \
- klass->get_frequency = interface_as_function ## _tuner_get_frequency; \
- klass->signal_strength = interface_as_function ## _tuner_signal_strength; \
+ iface->set_frequency = interface_as_function ## _tuner_set_frequency_and_notify; \
+ iface->get_frequency = interface_as_function ## _tuner_get_frequency; \
+ iface->signal_strength = interface_as_function ## _tuner_signal_strength; \
} \
#endif /* __GST_V4L2_TUNER_H__ */
diff --git a/sys/v4l2/gstv4l2xoverlay.c b/sys/v4l2/gstv4l2videooverlay.c
index f1c4d5196d..ae9a317918 100644
--- a/sys/v4l2/gstv4l2xoverlay.c
+++ b/sys/v4l2/gstv4l2videooverlay.c
@@ -1,9 +1,8 @@
/* GStreamer
- *
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
- * gstv4l2xoverlay.c: X-based overlay interface implementation for V4L2
+ * gstv4l2video_overlay.c: X-based overlay interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -37,7 +36,7 @@
#include <gst/interfaces/navigation.h>
-#include "gstv4l2xoverlay.h"
+#include "gstv4l2videooverlay.h"
#include "gstv4l2object.h"
#include "v4l2_calls.h"
@@ -48,21 +47,21 @@ struct _GstV4l2Xv
{
Display *dpy;
gint port, idle_id, event_id;
- GMutex *mutex; /* to serialize calls to X11 */
+ GMutex mutex; /* to serialize calls to X11 */
};
GST_DEBUG_CATEGORY_STATIC (v4l2xv_debug);
#define GST_CAT_DEFAULT v4l2xv_debug
void
-gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass)
+gst_v4l2_video_overlay_interface_init (GstVideoOverlayInterface * iface)
{
GST_DEBUG_CATEGORY_INIT (v4l2xv_debug, "v4l2xv", 0,
- "V4L2 XOverlay interface debugging");
+ "V4L2 GstVideoOverlay interface debugging");
}
static void
-gst_v4l2_xoverlay_open (GstV4l2Object * v4l2object)
+gst_v4l2_video_overlay_open (GstV4l2Object * v4l2object)
{
struct stat s;
GstV4l2Xv *v4l2xv;
@@ -134,18 +133,19 @@ gst_v4l2_xoverlay_open (GstV4l2Object * v4l2object)
v4l2xv = g_new0 (GstV4l2Xv, 1);
v4l2xv->dpy = dpy;
v4l2xv->port = id;
- v4l2xv->mutex = g_mutex_new ();
+ g_mutex_init (&v4l2xv->mutex);
v4l2xv->idle_id = 0;
v4l2xv->event_id = 0;
v4l2object->xv = v4l2xv;
if (v4l2object->xwindow_id) {
- gst_v4l2_xoverlay_set_window_handle (v4l2object, v4l2object->xwindow_id);
+ gst_v4l2_video_overlay_set_window_handle (v4l2object,
+ v4l2object->xwindow_id);
}
}
static void
-gst_v4l2_xoverlay_close (GstV4l2Object * v4l2object)
+gst_v4l2_video_overlay_close (GstV4l2Object * v4l2object)
{
GstV4l2Xv *v4l2xv = v4l2object->xv;
@@ -153,11 +153,11 @@ gst_v4l2_xoverlay_close (GstV4l2Object * v4l2object)
return;
if (v4l2object->xwindow_id) {
- gst_v4l2_xoverlay_set_window_handle (v4l2object, 0);
+ gst_v4l2_video_overlay_set_window_handle (v4l2object, 0);
}
XCloseDisplay (v4l2xv->dpy);
- g_mutex_free (v4l2xv->mutex);
+ g_mutex_clear (&v4l2xv->mutex);
if (v4l2xv->idle_id)
g_source_remove (v4l2xv->idle_id);
if (v4l2xv->event_id)
@@ -167,17 +167,17 @@ gst_v4l2_xoverlay_close (GstV4l2Object * v4l2object)
}
void
-gst_v4l2_xoverlay_start (GstV4l2Object * v4l2object)
+gst_v4l2_video_overlay_start (GstV4l2Object * v4l2object)
{
if (v4l2object->xwindow_id) {
- gst_v4l2_xoverlay_open (v4l2object);
+ gst_v4l2_video_overlay_open (v4l2object);
}
}
void
-gst_v4l2_xoverlay_stop (GstV4l2Object * v4l2object)
+gst_v4l2_video_overlay_stop (GstV4l2Object * v4l2object)
{
- gst_v4l2_xoverlay_close (v4l2object);
+ gst_v4l2_video_overlay_close (v4l2object);
}
/* should be called with mutex held */
@@ -200,15 +200,15 @@ get_render_rect (GstV4l2Object * v4l2object, GstVideoRectangle * rect)
}
gboolean
-gst_v4l2_xoverlay_get_render_rect (GstV4l2Object * v4l2object,
+gst_v4l2_video_overlay_get_render_rect (GstV4l2Object * v4l2object,
GstVideoRectangle * rect)
{
GstV4l2Xv *v4l2xv = v4l2object->xv;
gboolean ret = FALSE;
if (v4l2xv) {
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
ret = get_render_rect (v4l2object, rect);
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
}
return ret;
}
@@ -238,12 +238,12 @@ idle_refresh (gpointer data)
GST_LOG_OBJECT (v4l2object->element, "idle refresh");
if (v4l2xv) {
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
update_geometry (v4l2object);
v4l2xv->idle_id = 0;
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
}
/* once */
@@ -262,7 +262,7 @@ event_refresh (gpointer data)
if (v4l2xv) {
XEvent e;
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
/* If the element supports navigation, collect the relavent input
* events and push them upstream as navigation events
@@ -289,10 +289,10 @@ event_refresh (gpointer data)
if (pointer_moved) {
GST_DEBUG_OBJECT (v4l2object->element,
"pointer moved over window at %d,%d", pointer_x, pointer_y);
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
gst_navigation_send_mouse_event (GST_NAVIGATION (v4l2object->element),
"mouse-move", 0, e.xbutton.x, e.xbutton.y);
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
}
/* We get all events on our window to throw them upstream
@@ -303,7 +303,7 @@ event_refresh (gpointer data)
KeySym keysym;
const char *key_str = NULL;
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
switch (e.type) {
case ButtonPress:
@@ -324,14 +324,14 @@ event_refresh (gpointer data)
break;
case KeyPress:
case KeyRelease:
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
keysym = XkbKeycodeToKeysym (v4l2xv->dpy, e.xkey.keycode, 0, 0);
if (keysym != NoSymbol) {
key_str = XKeysymToString (keysym);
} else {
key_str = "unknown";
}
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
GST_DEBUG_OBJECT (v4l2object->element,
"key %d pressed over window at %d,%d (%s)",
e.xkey.keycode, e.xkey.x, e.xkey.y, key_str);
@@ -343,7 +343,7 @@ event_refresh (gpointer data)
"unhandled X event (%d)", e.type);
}
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
}
}
@@ -358,7 +358,7 @@ event_refresh (gpointer data)
break;
}
}
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
}
/* repeat */
@@ -366,7 +366,8 @@ event_refresh (gpointer data)
}
void
-gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object, guintptr id)
+gst_v4l2_video_overlay_set_window_handle (GstV4l2Object * v4l2object,
+ guintptr id)
{
GstV4l2Xv *v4l2xv;
XID xwindow_id = id;
@@ -376,12 +377,12 @@ gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object, guintptr id)
(gulong) xwindow_id);
if (!v4l2object->xv && GST_V4L2_IS_OPEN (v4l2object))
- gst_v4l2_xoverlay_open (v4l2object);
+ gst_v4l2_video_overlay_open (v4l2object);
v4l2xv = v4l2object->xv;
if (v4l2xv)
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
if (change) {
if (v4l2object->xwindow_id && v4l2xv) {
@@ -398,7 +399,7 @@ gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object, guintptr id)
if (!v4l2xv || xwindow_id == 0) {
if (v4l2xv)
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
return;
}
@@ -416,11 +417,11 @@ gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object, guintptr id)
if (v4l2xv->idle_id)
g_source_remove (v4l2xv->idle_id);
v4l2xv->idle_id = g_idle_add (idle_refresh, v4l2object);
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
}
/**
- * gst_v4l2_xoverlay_prepare_xwindow_id:
+ * gst_v4l2_video_overlay_prepare_window_handle:
* @v4l2object: the v4l2object
* @required: %TRUE if display is required (ie. TRUE for v4l2sink, but
* FALSE for any other element with optional overlay capabilities)
@@ -428,13 +429,16 @@ gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object, guintptr id)
* Helper function to create a windo if none is set from the application.
*/
void
-gst_v4l2_xoverlay_prepare_xwindow_id (GstV4l2Object * v4l2object,
+gst_v4l2_video_overlay_prepare_window_handle (GstV4l2Object * v4l2object,
gboolean required)
{
+ GstVideoOverlay *overlay;
+
if (!GST_V4L2_IS_OVERLAY (v4l2object))
return;
- gst_x_overlay_prepare_xwindow_id (GST_X_OVERLAY (v4l2object->element));
+ overlay = GST_VIDEO_OVERLAY (v4l2object->element);
+ gst_video_overlay_prepare_window_handle (overlay);
if (required && !v4l2object->xwindow_id) {
GstV4l2Xv *v4l2xv;
@@ -443,18 +447,18 @@ gst_v4l2_xoverlay_prepare_xwindow_id (GstV4l2Object * v4l2object,
long event_mask;
if (!v4l2object->xv && GST_V4L2_IS_OPEN (v4l2object))
- gst_v4l2_xoverlay_open (v4l2object);
+ gst_v4l2_video_overlay_open (v4l2object);
v4l2xv = v4l2object->xv;
- /* if xoverlay is not supported, just bail */
+ /* if video_overlay is not supported, just bail */
if (!v4l2xv)
return;
- /* xoverlay is supported, but we don't have a window.. so create one */
+ /* video_overlay is supported, but we don't have a window.. so create one */
GST_DEBUG_OBJECT (v4l2object->element, "creating window");
- g_mutex_lock (v4l2xv->mutex);
+ g_mutex_lock (&v4l2xv->mutex);
width = XDisplayWidth (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy));
height = XDisplayHeight (v4l2xv->dpy, DefaultScreen (v4l2xv->dpy));
@@ -479,10 +483,10 @@ gst_v4l2_xoverlay_prepare_xwindow_id (GstV4l2Object * v4l2object,
XSync (v4l2xv->dpy, FALSE);
- g_mutex_unlock (v4l2xv->mutex);
+ g_mutex_unlock (&v4l2xv->mutex);
GST_DEBUG_OBJECT (v4l2object->element, "got window");
- gst_v4l2_xoverlay_set_window_handle (v4l2object, win);
+ gst_v4l2_video_overlay_set_window_handle (v4l2object, win);
}
}
diff --git a/sys/v4l2/gstv4l2xoverlay.h b/sys/v4l2/gstv4l2videooverlay.h
index 1a09306836..7c044e71d8 100644
--- a/sys/v4l2/gstv4l2xoverlay.h
+++ b/sys/v4l2/gstv4l2videooverlay.h
@@ -1,9 +1,8 @@
/* GStreamer
- *
* Copyright (C) 2003 Ronald Bultje <rbultje@ronald.bitfreak.net>
* 2006 Edgard Lima <edgard.lima@indt.org.br>
*
- * gstv4l2xoverlay.h: tv mixer interface implementation for V4L2
+ * gstv4l2videooverlay.h: tv mixer interface implementation for V4L2
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,50 +20,50 @@
* Boston, MA 02111-1307, USA.
*/
-#ifndef __GST_V4L2_X_OVERLAY_H__
-#define __GST_V4L2_X_OVERLAY_H__
+#ifndef __GST_V4L2_VIDEO_OVERLAY_H__
+#define __GST_V4L2_VIDEO_OVERLAY_H__
#include <X11/X.h>
#include <gst/gst.h>
-#include <gst/interfaces/xoverlay.h>
#include <gst/interfaces/navigation.h>
#include <gst/video/gstvideosink.h> /* for GstVideoRectange */
+#include <gst/video/videooverlay.h>
#include "gstv4l2object.h"
G_BEGIN_DECLS
-void gst_v4l2_xoverlay_start (GstV4l2Object *v4l2object);
-void gst_v4l2_xoverlay_stop (GstV4l2Object *v4l2object);
-gboolean gst_v4l2_xoverlay_get_render_rect (GstV4l2Object *v4l2object,
+void gst_v4l2_video_overlay_start (GstV4l2Object *v4l2object);
+void gst_v4l2_video_overlay_stop (GstV4l2Object *v4l2object);
+gboolean gst_v4l2_video_overlay_get_render_rect (GstV4l2Object *v4l2object,
GstVideoRectangle *rect);
-void gst_v4l2_xoverlay_interface_init (GstXOverlayClass * klass);
-void gst_v4l2_xoverlay_set_window_handle (GstV4l2Object * v4l2object,
+void gst_v4l2_video_overlay_interface_init (GstVideoOverlayInterface * iface);
+void gst_v4l2_video_overlay_set_window_handle (GstV4l2Object * v4l2object,
guintptr id);
-void gst_v4l2_xoverlay_prepare_xwindow_id (GstV4l2Object * v4l2object,
+void gst_v4l2_video_overlay_prepare_window_handle (GstV4l2Object * v4l2object,
gboolean required);
-#define GST_IMPLEMENT_V4L2_XOVERLAY_METHODS(Type, interface_as_function) \
+#define GST_IMPLEMENT_V4L2_VIDEO_OVERLAY_METHODS(Type, interface_as_function) \
\
static void \
-interface_as_function ## _xoverlay_set_window_handle (GstXOverlay * xoverlay, \
- guintptr id) \
+interface_as_function ## _video_overlay_set_window_handle (GstVideoOverlay * overlay, \
+ guintptr id) \
{ \
- Type *this = (Type*) xoverlay; \
- gst_v4l2_xoverlay_set_window_handle (this->v4l2object, id); \
+ Type *this = (Type*) overlay; \
+ gst_v4l2_video_overlay_set_window_handle (this->v4l2object, id); \
} \
\
static void \
-interface_as_function ## _xoverlay_interface_init (GstXOverlayClass * klass) \
+interface_as_function ## _video_overlay_interface_init (GstVideoOverlayInterface * iface) \
{ \
/* default virtual functions */ \
- klass->set_window_handle = interface_as_function ## _xoverlay_set_window_handle; \
+ iface->set_window_handle = interface_as_function ## _video_overlay_set_window_handle; \
\
- gst_v4l2_xoverlay_interface_init(klass); \
+ gst_v4l2_video_overlay_interface_init (iface); \
} \
-#endif /* __GST_V4L2_X_OVERLAY_H__ */
+#endif /* __GST_V4L2_VIDEO_OVERLAY_H__ */
diff --git a/sys/v4l2/gstv4l2vidorient.c b/sys/v4l2/gstv4l2vidorient.c
index 1fa47e794f..4dc0da73f2 100644
--- a/sys/v4l2/gstv4l2vidorient.c
+++ b/sys/v4l2/gstv4l2vidorient.c
@@ -29,7 +29,6 @@
#include "gstv4l2vidorient.h"
#include "gstv4l2object.h"
#include "v4l2_calls.h"
-#include "v4l2src_calls.h"
GST_DEBUG_CATEGORY_STATIC (v4l2vo_debug);
#define GST_CAT_DEFAULT v4l2vo_debug
@@ -43,7 +42,7 @@ GST_DEBUG_CATEGORY_STATIC (v4l2vo_debug);
#endif
void
-gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * klass)
+gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * iface)
{
GST_DEBUG_CATEGORY_INIT (v4l2vo_debug, "v4l2vo", 0,
"V4L2 VideoOrientation interface debugging");
diff --git a/sys/v4l2/gstv4l2vidorient.h b/sys/v4l2/gstv4l2vidorient.h
index 39682e2f1a..bf3736f9ba 100644
--- a/sys/v4l2/gstv4l2vidorient.h
+++ b/sys/v4l2/gstv4l2vidorient.h
@@ -24,13 +24,13 @@
#define __GST_V4L2_VIDORIENT_H__
#include <gst/gst.h>
-#include <gst/interfaces/videoorientation.h>
+#include <gst/video/videoorientation.h>
#include "gstv4l2object.h"
G_BEGIN_DECLS
-void gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * klass);
+void gst_v4l2_video_orientation_interface_init (GstVideoOrientationInterface * iface);
gboolean gst_v4l2_video_orientation_get_hflip (GstV4l2Object *v4l2object, gboolean *flip);
gboolean gst_v4l2_video_orientation_get_vflip (GstV4l2Object *v4l2object, gboolean *flip);
@@ -101,17 +101,17 @@ gboolean gst_v4l2_video_orientation_set_vcenter (GstV4l2Object *v4l2object, gint
} \
\
static void \
- interface_as_function ## _video_orientation_interface_init (GstVideoOrientationInterface * klass) \
+ interface_as_function ## _video_orientation_interface_init (GstVideoOrientationInterface * iface) \
{ \
/* default virtual functions */ \
- klass->get_hflip = interface_as_function ## _video_orientation_get_hflip; \
- klass->get_vflip = interface_as_function ## _video_orientation_get_vflip; \
- klass->get_hcenter = interface_as_function ## _video_orientation_get_hcenter; \
- klass->get_vcenter = interface_as_function ## _video_orientation_get_vcenter; \
- klass->set_hflip = interface_as_function ## _video_orientation_set_hflip; \
- klass->set_vflip = interface_as_function ## _video_orientation_set_vflip; \
- klass->set_hcenter = interface_as_function ## _video_orientation_set_hcenter; \
- klass->set_vcenter = interface_as_function ## _video_orientation_set_vcenter; \
+ iface->get_hflip = interface_as_function ## _video_orientation_get_hflip; \
+ iface->get_vflip = interface_as_function ## _video_orientation_get_vflip; \
+ iface->get_hcenter = interface_as_function ## _video_orientation_get_hcenter; \
+ iface->get_vcenter = interface_as_function ## _video_orientation_get_vcenter; \
+ iface->set_hflip = interface_as_function ## _video_orientation_set_hflip; \
+ iface->set_vflip = interface_as_function ## _video_orientation_set_vflip; \
+ iface->set_hcenter = interface_as_function ## _video_orientation_set_hcenter; \
+ iface->set_vcenter = interface_as_function ## _video_orientation_set_vcenter; \
}
#endif /* __GST_V4L2_VIDORIENT_H__ */
diff --git a/sys/v4l2/v4l2_calls.c b/sys/v4l2/v4l2_calls.c
index 309bfb668e..62c03ee051 100644
--- a/sys/v4l2/v4l2_calls.c
+++ b/sys/v4l2/v4l2_calls.c
@@ -46,10 +46,7 @@
#include "gstv4l2colorbalance.h"
#include "gstv4l2src.h"
-
-#ifdef HAVE_EXPERIMENTAL
#include "gstv4l2sink.h"
-#endif
#include "gst/gst-i18n-plugin.h"
@@ -465,11 +462,9 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE))
goto not_capture;
-#ifdef HAVE_EXPERIMENTAL
if (GST_IS_V4L2SINK (v4l2object->element) &&
!(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OUTPUT))
goto not_output;
-#endif
/* create enumerations, posts errors. */
if (!gst_v4l2_fill_lists (v4l2object))
@@ -515,7 +510,6 @@ not_capture:
("Capabilities: 0x%x", v4l2object->vcap.capabilities));
goto error;
}
-#ifdef HAVE_EXPERIMENTAL
not_output:
{
GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
@@ -524,7 +518,6 @@ not_output:
("Capabilities: 0x%x", v4l2object->vcap.capabilities));
goto error;
}
-#endif
error:
{
if (GST_V4L2_IS_OPEN (v4l2object)) {
diff --git a/sys/v4l2/v4l2_calls.h b/sys/v4l2/v4l2_calls.h
index d2e2c723e5..36cf0f3a94 100644
--- a/sys/v4l2/v4l2_calls.h
+++ b/sys/v4l2/v4l2_calls.h
@@ -40,14 +40,6 @@
# define v4l2_munmap munmap
#endif
-/* simple check whether the device is open */
-#define GST_V4L2_IS_OPEN(v4l2object) \
- (v4l2object->video_fd > 0)
-
-/* check whether the device is 'active' */
-#define GST_V4L2_IS_ACTIVE(v4l2object) \
- (v4l2object->buffer != NULL)
-
#define GST_V4L2_IS_OVERLAY(v4l2object) \
(v4l2object->vcap.capabilities & V4L2_CAP_VIDEO_OVERLAY)
diff --git a/sys/v4l2/v4l2src_calls.c b/sys/v4l2/v4l2src_calls.c
deleted file mode 100644
index bfa5589601..0000000000
--- a/sys/v4l2/v4l2src_calls.c
+++ /dev/null
@@ -1,434 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
- * 2006 Edgard Lima <edgard.lima@indt.org.br>
- *
- * v4l2src.c - system calls
- *
- * 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 details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <string.h>
-#include <errno.h>
-#include "v4l2src_calls.h"
-#include <sys/time.h>
-#include <unistd.h>
-#ifdef __sun
-/* Needed on older Solaris Nevada builds (72 at least) */
-#include <stropts.h>
-#include <sys/ioccom.h>
-#endif
-
-#include "gstv4l2tuner.h"
-#include "gstv4l2bufferpool.h"
-
-#include "gst/gst-i18n-plugin.h"
-
-#define GST_CAT_DEFAULT v4l2src_debug
-GST_DEBUG_CATEGORY_EXTERN (GST_CAT_PERFORMANCE);
-
-/* lalala... */
-#define GST_V4L2_SET_ACTIVE(element) (element)->buffer = GINT_TO_POINTER (-1)
-#define GST_V4L2_SET_INACTIVE(element) (element)->buffer = NULL
-
-/* On some systems MAP_FAILED seems to be missing */
-#ifndef MAP_FAILED
-#define MAP_FAILED ((caddr_t) -1)
-#endif
-
-
-/* Local functions */
-
-static gboolean
-gst_v4l2src_buffer_pool_activate (GstV4l2BufferPool * pool,
- GstV4l2Src * v4l2src)
-{
- GstV4l2Buffer *buf;
-
- while ((buf = gst_v4l2_buffer_pool_get (pool, FALSE)) != NULL)
- if (!gst_v4l2_buffer_pool_qbuf (pool, buf))
- goto queue_failed;
-
- return TRUE;
-
- /* ERRORS */
-queue_failed:
- {
- GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
- (_("Could not enqueue buffers in device '%s'."),
- v4l2src->v4l2object->videodev),
- ("enqueing buffer %d/%d failed: %s",
- buf->vbuffer.index, v4l2src->num_buffers, g_strerror (errno)));
- return FALSE;
- }
-}
-
-/******************************************************
- * gst_v4l2src_grab_frame ():
- * grab a frame for capturing
- * return value: GST_FLOW_OK, GST_FLOW_WRONG_STATE or GST_FLOW_ERROR
- ******************************************************/
-GstFlowReturn
-gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer ** buf)
-{
-#define NUM_TRIALS 50
- GstV4l2Object *v4l2object;
- GstV4l2BufferPool *pool;
- gint32 trials = NUM_TRIALS;
- GstBuffer *pool_buffer;
- gboolean need_copy;
- gint ret;
-
- v4l2object = v4l2src->v4l2object;
- pool = v4l2src->pool;
- if (!pool)
- goto no_buffer_pool;
-
- GST_DEBUG_OBJECT (v4l2src, "grab frame");
-
- for (;;) {
- if (v4l2object->can_poll_device) {
- ret = gst_poll_wait (v4l2object->poll, GST_CLOCK_TIME_NONE);
- if (G_UNLIKELY (ret < 0)) {
- if (errno == EBUSY)
- goto stopped;
- if (errno == ENXIO) {
- GST_DEBUG_OBJECT (v4l2src,
- "v4l2 device doesn't support polling. Disabling");
- v4l2object->can_poll_device = FALSE;
- } else {
- if (errno != EAGAIN && errno != EINTR)
- goto select_error;
- }
- }
- }
-
- pool_buffer = GST_BUFFER (gst_v4l2_buffer_pool_dqbuf (pool));
- if (pool_buffer)
- break;
-
- GST_WARNING_OBJECT (pool->v4l2elem, "trials=%d", trials);
-
- /* if the sync() got interrupted, we can retry */
- switch (errno) {
- case EINVAL:
- case ENOMEM:
- /* fatal */
- return GST_FLOW_ERROR;
-
- case EAGAIN:
- case EIO:
- case EINTR:
- default:
- /* try again, until too many trials */
- break;
- }
-
- /* check nr. of attempts to capture */
- if (--trials == -1) {
- goto too_many_trials;
- }
- }
-
- /* if we are handing out the last buffer in the pool, we need to make a
- * copy and bring the buffer back in the pool. */
- need_copy = v4l2src->always_copy
- || !gst_v4l2_buffer_pool_available_buffers (pool);
-
- if (G_UNLIKELY (need_copy)) {
- if (!v4l2src->always_copy) {
- GST_CAT_LOG_OBJECT (GST_CAT_PERFORMANCE, v4l2src,
- "running out of buffers, making a copy to reuse current one");
- }
- *buf = gst_buffer_copy (pool_buffer);
- GST_BUFFER_FLAG_UNSET (*buf, GST_BUFFER_FLAG_READONLY);
- /* this will requeue */
- gst_buffer_unref (pool_buffer);
- } else {
- *buf = pool_buffer;
- }
- /* we set the buffer metadata in gst_v4l2src_create() */
-
- return GST_FLOW_OK;
-
- /* ERRORS */
-no_buffer_pool:
- {
- GST_DEBUG ("no buffer pool");
- return GST_FLOW_WRONG_STATE;
- }
-select_error:
- {
- GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, READ, (NULL),
- ("select error %d: %s (%d)", ret, g_strerror (errno), errno));
- return GST_FLOW_ERROR;
- }
-stopped:
- {
- GST_DEBUG ("stop called");
- return GST_FLOW_WRONG_STATE;
- }
-too_many_trials:
- {
- GST_ELEMENT_ERROR (pool->v4l2elem, RESOURCE, FAILED,
- (_("Failed trying to get video frames from device '%s'."),
- v4l2object->videodev),
- (_("Failed after %d tries. device %s. system error: %s"),
- NUM_TRIALS, v4l2object->videodev, g_strerror (errno)));
- return GST_FLOW_ERROR;
- }
-}
-
-/******************************************************
- * gst_v4l2src_set_capture():
- * set capture parameters
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-gboolean
-gst_v4l2src_set_capture (GstV4l2Src * v4l2src, guint32 pixelformat,
- guint32 width, guint32 height, gboolean interlaced,
- guint fps_n, guint fps_d)
-{
- gint fd = v4l2src->v4l2object->video_fd;
- struct v4l2_streamparm stream;
-
- if (pixelformat == GST_MAKE_FOURCC ('M', 'P', 'E', 'G'))
- return TRUE;
-
- if (!gst_v4l2_object_set_format (v4l2src->v4l2object, pixelformat, width,
- height, interlaced)) {
- /* error already reported */
- return FALSE;
- }
-
- /* Is there a reason we require the caller to always specify a framerate? */
- GST_DEBUG_OBJECT (v4l2src, "Desired framerate: %u/%u", fps_n, fps_d);
-
- memset (&stream, 0x00, sizeof (struct v4l2_streamparm));
- stream.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (v4l2_ioctl (fd, VIDIOC_G_PARM, &stream) < 0) {
- GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
- (_("Could not get parameters on device '%s'"),
- v4l2src->v4l2object->videodev), GST_ERROR_SYSTEM);
- goto done;
- }
-
- /* We used to skip frame rate setup if the camera was already setup
- with the requested frame rate. This breaks some cameras though,
- causing them to not output data (several models of Thinkpad cameras
- have this problem at least).
- So, don't skip. */
-
- /* We want to change the frame rate, so check whether we can. Some cheap USB
- * cameras don't have the capability */
- if ((stream.parm.capture.capability & V4L2_CAP_TIMEPERFRAME) == 0) {
- GST_DEBUG_OBJECT (v4l2src, "Not setting framerate (not supported)");
- goto done;
- }
-
- GST_LOG_OBJECT (v4l2src, "Setting framerate to %u/%u", fps_n, fps_d);
-
- /* Note: V4L2 wants the frame interval, we have the frame rate */
- stream.parm.capture.timeperframe.numerator = fps_d;
- stream.parm.capture.timeperframe.denominator = fps_n;
-
- /* some cheap USB cam's won't accept any change */
- if (v4l2_ioctl (fd, VIDIOC_S_PARM, &stream) < 0) {
- GST_ELEMENT_WARNING (v4l2src, RESOURCE, SETTINGS,
- (_("Video input device did not accept new frame rate setting.")),
- GST_ERROR_SYSTEM);
- goto done;
- }
-
- v4l2src->fps_n = fps_n;
- v4l2src->fps_d = fps_d;
-
- /* if we have a framerate pre-calculate duration */
- if (fps_n > 0 && fps_d > 0) {
- v4l2src->duration = gst_util_uint64_scale_int (GST_SECOND, fps_d, fps_n);
- } else {
- v4l2src->duration = GST_CLOCK_TIME_NONE;
- }
-
- GST_INFO_OBJECT (v4l2src,
- "Set framerate to %u/%u and duration to %" GST_TIME_FORMAT, fps_n, fps_d,
- GST_TIME_ARGS (v4l2src->duration));
-done:
-
- return TRUE;
-}
-
-/******************************************************
- * gst_v4l2src_capture_init():
- * initialize the capture system
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-gboolean
-gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps * caps)
-{
- GST_DEBUG_OBJECT (v4l2src, "initializing the capture system");
-
- GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
- GST_V4L2_CHECK_NOT_ACTIVE (v4l2src->v4l2object);
-
- if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_STREAMING) {
-
- /* Map the buffers */
- GST_LOG_OBJECT (v4l2src, "initiating buffer pool");
-
- if (!(v4l2src->pool = gst_v4l2_buffer_pool_new (GST_ELEMENT (v4l2src),
- v4l2src->v4l2object->video_fd,
- v4l2src->num_buffers, caps, TRUE, V4L2_BUF_TYPE_VIDEO_CAPTURE)))
- goto buffer_pool_new_failed;
-
- GST_INFO_OBJECT (v4l2src, "capturing buffers via mmap()");
- v4l2src->use_mmap = TRUE;
-
- if (v4l2src->num_buffers != v4l2src->pool->buffer_count) {
- v4l2src->num_buffers = v4l2src->pool->buffer_count;
- g_object_notify (G_OBJECT (v4l2src), "queue-size");
- }
-
- } else if (v4l2src->v4l2object->vcap.capabilities & V4L2_CAP_READWRITE) {
- GST_INFO_OBJECT (v4l2src, "capturing buffers via read()");
- v4l2src->use_mmap = FALSE;
- v4l2src->pool = NULL;
- } else {
- goto no_supported_capture_method;
- }
-
- GST_V4L2_SET_ACTIVE (v4l2src->v4l2object);
-
- return TRUE;
-
- /* ERRORS */
-buffer_pool_new_failed:
- {
- GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
- (_("Could not map buffers from device '%s'"),
- v4l2src->v4l2object->videodev),
- ("Failed to create buffer pool: %s", g_strerror (errno)));
- return FALSE;
- }
-no_supported_capture_method:
- {
- GST_ELEMENT_ERROR (v4l2src, RESOURCE, READ,
- (_("The driver of device '%s' does not support any known capture "
- "method."), v4l2src->v4l2object->videodev), (NULL));
- return FALSE;
- }
-}
-
-
-/******************************************************
- * gst_v4l2src_capture_start():
- * start streaming capture
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-gboolean
-gst_v4l2src_capture_start (GstV4l2Src * v4l2src)
-{
- GST_DEBUG_OBJECT (v4l2src, "starting the capturing");
- //GST_V4L2_CHECK_OPEN (v4l2src->v4l2object);
- GST_V4L2_CHECK_ACTIVE (v4l2src->v4l2object);
-
- v4l2src->quit = FALSE;
-
- if (v4l2src->use_mmap) {
- if (!gst_v4l2src_buffer_pool_activate (v4l2src->pool, v4l2src)) {
- return FALSE;
- }
-
- if (!gst_v4l2_object_start_streaming (v4l2src->v4l2object)) {
- return FALSE;
- }
- }
-
- v4l2src->is_capturing = TRUE;
-
- return TRUE;
-}
-
-/******************************************************
- * gst_v4l2src_capture_stop():
- * stop streaming capture
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-gboolean
-gst_v4l2src_capture_stop (GstV4l2Src * v4l2src)
-{
- GST_DEBUG_OBJECT (v4l2src, "stopping capturing");
-
- if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
- goto done;
- }
- if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
- goto done;
- }
-
- if (v4l2src->use_mmap) {
- /* we actually need to sync on all queued buffers but not
- * on the non-queued ones */
- if (!gst_v4l2_object_stop_streaming (v4l2src->v4l2object)) {
- return FALSE;
- }
- }
-
-done:
-
- /* make an optional pending wait stop */
- v4l2src->quit = TRUE;
- v4l2src->is_capturing = FALSE;
-
- return TRUE;
-}
-
-/******************************************************
- * gst_v4l2src_capture_deinit():
- * deinitialize the capture system
- * return value: TRUE on success, FALSE on error
- ******************************************************/
-gboolean
-gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src)
-{
- GST_DEBUG_OBJECT (v4l2src, "deinitting capture system");
-
- if (!GST_V4L2_IS_OPEN (v4l2src->v4l2object)) {
- return TRUE;
- }
- if (!GST_V4L2_IS_ACTIVE (v4l2src->v4l2object)) {
- return TRUE;
- }
-
- if (v4l2src->pool) {
- gst_v4l2_buffer_pool_destroy (v4l2src->pool);
- v4l2src->pool = NULL;
- }
-
- GST_V4L2_SET_INACTIVE (v4l2src->v4l2object);
-
- return TRUE;
-}
diff --git a/sys/v4l2/v4l2src_calls.h b/sys/v4l2/v4l2src_calls.h
deleted file mode 100644
index 709191870e..0000000000
--- a/sys/v4l2/v4l2src_calls.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* GStreamer
- *
- * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
- * 2006 Edgard Lima <edgard.lima@indt.org.br>
- *
- * v4l2src.h - system calls
- *
- * 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 details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-#ifndef __V4L2SRC_CALLS_H__
-#define __V4L2SRC_CALLS_H__
-
-#include "gstv4l2src.h"
-#include "v4l2_calls.h"
-
-gboolean gst_v4l2src_get_capture (GstV4l2Src * v4l2src);
-gboolean gst_v4l2src_set_capture (GstV4l2Src * v4l2src,
- guint32 pixelformat,
- guint32 width, guint32 height,
- gboolean interlaced,
- guint32 fps_n, guint32 fps_d);
-
-gboolean gst_v4l2src_capture_init (GstV4l2Src * v4l2src, GstCaps *caps);
-gboolean gst_v4l2src_capture_start (GstV4l2Src * v4l2src);
-
-GstFlowReturn gst_v4l2src_grab_frame (GstV4l2Src * v4l2src, GstBuffer **buf);
-
-gboolean gst_v4l2src_capture_stop (GstV4l2Src * v4l2src);
-gboolean gst_v4l2src_capture_deinit (GstV4l2Src * v4l2src);
-
-
-#endif /* __V4L2SRC_CALLS_H__ */
diff --git a/sys/waveform/gstwaveformsink.c b/sys/waveform/gstwaveformsink.c
index 3ff72a91e7..2c10c61761 100644
--- a/sys/waveform/gstwaveformsink.c
+++ b/sys/waveform/gstwaveformsink.c
@@ -54,17 +54,18 @@ static void gst_waveform_sink_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_waveform_sink_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-static GstCaps *gst_waveform_sink_getcaps (GstBaseSink * bsink);
+static GstCaps *gst_waveform_sink_getcaps (GstBaseSink * bsink,
+ GstCaps * filter);
/************************************************************************/
/* GstAudioSink functions */
/************************************************************************/
static gboolean gst_waveform_sink_prepare (GstAudioSink * asink,
- GstRingBufferSpec * spec);
+ GstAudioRingBufferSpec * spec);
static gboolean gst_waveform_sink_unprepare (GstAudioSink * asink);
static gboolean gst_waveform_sink_open (GstAudioSink * asink);
static gboolean gst_waveform_sink_close (GstAudioSink * asink);
-static guint gst_waveform_sink_write (GstAudioSink * asink, gpointer data,
+static gint gst_waveform_sink_write (GstAudioSink * asink, gpointer data,
guint length);
static guint gst_waveform_sink_delay (GstAudioSink * asink);
static void gst_waveform_sink_reset (GstAudioSink * asink);
@@ -73,42 +74,23 @@ static void gst_waveform_sink_reset (GstAudioSink * asink);
/* Utils */
/************************************************************************/
GstCaps *gst_waveform_sink_create_caps (gint rate, gint channels,
- gint bits_per_sample);
+ const gchar * format);
WAVEHDR *bufferpool_get_buffer (GstWaveFormSink * wfsink, gpointer data,
guint length);
void CALLBACK waveOutProc (HWAVEOUT hwo, UINT uMsg, DWORD_PTR dwInstance,
DWORD_PTR dwParam1, DWORD_PTR dwParam2);
static GstStaticPadTemplate waveformsink_sink_factory =
- GST_STATIC_PAD_TEMPLATE ("sink",
+GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("audio/x-raw-int, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 16, "
- "depth = (int) 16, "
- "rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]; "
- "audio/x-raw-int, "
- "signed = (boolean) { TRUE, FALSE }, "
- "width = (int) 8, "
- "depth = (int) 8, "
+ GST_STATIC_CAPS ("audio/x-raw, "
+ "format = (string) { " GST_AUDIO_NE (S16) ", S8 }, "
+ "layout = (string) interleaved, "
"rate = (int) [ 1, MAX ], " "channels = (int) [ 1, 2 ]"));
-GST_BOILERPLATE (GstWaveFormSink, gst_waveform_sink, GstAudioSink,
- GST_TYPE_AUDIO_SINK);
-
-static void
-gst_waveform_sink_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (element_class, "WaveForm Audio Sink",
- "Sink/Audio",
- "Output to a sound card via WaveForm API",
- "Sebastien Moutte <sebastien@moutte.net>");
- gst_element_class_add_static_pad_template (element_class,
- &waveformsink_sink_factory);
-}
+#define gst_waveform_sink_parent_class parent_class
+G_DEFINE_TYPE (GstWaveFormSink, gst_waveform_sink, GST_TYPE_AUDIO_SINK);
static void
gst_waveform_sink_class_init (GstWaveFormSinkClass * klass)
@@ -116,14 +98,14 @@ gst_waveform_sink_class_init (GstWaveFormSinkClass * klass)
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSinkClass *gstbasesink_class;
- GstBaseAudioSinkClass *gstbaseaudiosink_class;
GstAudioSinkClass *gstaudiosink_class;
+ GstElementClass *element_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesink_class = (GstBaseSinkClass *) klass;
- gstbaseaudiosink_class = (GstBaseAudioSinkClass *) klass;
gstaudiosink_class = (GstAudioSinkClass *) klass;
+ element_class = GST_ELEMENT_CLASS (klass);
parent_class = g_type_class_peek_parent (klass);
@@ -144,6 +126,14 @@ gst_waveform_sink_class_init (GstWaveFormSinkClass * klass)
GST_DEBUG_CATEGORY_INIT (waveformsink_debug, "waveformsink", 0,
"Waveform sink");
+
+ gst_element_class_set_details_simple (element_class, "WaveForm Audio Sink",
+ "Sink/Audio",
+ "Output to a sound card via WaveForm API",
+ "Sebastien Moutte <sebastien@moutte.net>");
+
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&waveformsink_sink_factory));
}
static void
@@ -173,8 +163,7 @@ gst_waveform_sink_get_property (GObject * object, guint prop_id,
}
static void
-gst_waveform_sink_init (GstWaveFormSink * wfsink,
- GstWaveFormSinkClass * g_class)
+gst_waveform_sink_init (GstWaveFormSink * wfsink)
{
/* initialize members */
wfsink->hwaveout = NULL;
@@ -205,7 +194,7 @@ gst_waveform_sink_finalise (GObject * object)
}
static GstCaps *
-gst_waveform_sink_getcaps (GstBaseSink * bsink)
+gst_waveform_sink_getcaps (GstBaseSink * bsink, GstCaps * filter)
{
GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (bsink);
MMRESULT mmresult;
@@ -232,97 +221,97 @@ gst_waveform_sink_getcaps (GstBaseSink * bsink)
/* create a caps for all wave formats supported by the device
starting by the best quality format */
if (wocaps.dwFormats & WAVE_FORMAT_96S16) {
- caps_temp = gst_waveform_sink_create_caps (96000, 2, 16);
+ caps_temp = gst_waveform_sink_create_caps (96000, 2, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_96S08) {
- caps_temp = gst_waveform_sink_create_caps (96000, 2, 8);
+ caps_temp = gst_waveform_sink_create_caps (96000, 2, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_96M16) {
- caps_temp = gst_waveform_sink_create_caps (96000, 1, 16);
+ caps_temp = gst_waveform_sink_create_caps (96000, 1, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_96M08) {
- caps_temp = gst_waveform_sink_create_caps (96000, 1, 8);
+ caps_temp = gst_waveform_sink_create_caps (96000, 1, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_4S16) {
- caps_temp = gst_waveform_sink_create_caps (44100, 2, 16);
+ caps_temp = gst_waveform_sink_create_caps (44100, 2, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_4S08) {
- caps_temp = gst_waveform_sink_create_caps (44100, 2, 8);
+ caps_temp = gst_waveform_sink_create_caps (44100, 2, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_4M16) {
- caps_temp = gst_waveform_sink_create_caps (44100, 1, 16);
+ caps_temp = gst_waveform_sink_create_caps (44100, 1, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_4M08) {
- caps_temp = gst_waveform_sink_create_caps (44100, 1, 8);
+ caps_temp = gst_waveform_sink_create_caps (44100, 1, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_2S16) {
- caps_temp = gst_waveform_sink_create_caps (22050, 2, 16);
+ caps_temp = gst_waveform_sink_create_caps (22050, 2, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_2S08) {
- caps_temp = gst_waveform_sink_create_caps (22050, 2, 8);
+ caps_temp = gst_waveform_sink_create_caps (22050, 2, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_2M16) {
- caps_temp = gst_waveform_sink_create_caps (22050, 1, 16);
+ caps_temp = gst_waveform_sink_create_caps (22050, 1, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_2M08) {
- caps_temp = gst_waveform_sink_create_caps (22050, 1, 8);
+ caps_temp = gst_waveform_sink_create_caps (22050, 1, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_1S16) {
- caps_temp = gst_waveform_sink_create_caps (11025, 2, 16);
+ caps_temp = gst_waveform_sink_create_caps (11025, 2, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_1S08) {
- caps_temp = gst_waveform_sink_create_caps (11025, 2, 8);
+ caps_temp = gst_waveform_sink_create_caps (11025, 2, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_1M16) {
- caps_temp = gst_waveform_sink_create_caps (11025, 1, 16);
+ caps_temp = gst_waveform_sink_create_caps (11025, 1, GST_AUDIO_NE (S16));
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
}
if (wocaps.dwFormats & WAVE_FORMAT_1M08) {
- caps_temp = gst_waveform_sink_create_caps (11025, 1, 8);
+ caps_temp = gst_waveform_sink_create_caps (11025, 1, "S8");
if (caps_temp) {
gst_caps_append (caps, caps_temp);
}
@@ -352,7 +341,7 @@ gst_waveform_sink_open (GstAudioSink * asink)
}
static gboolean
-gst_waveform_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
+gst_waveform_sink_prepare (GstAudioSink * asink, GstAudioRingBufferSpec * spec)
{
GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
WAVEFORMATEX wfx;
@@ -363,14 +352,14 @@ gst_waveform_sink_prepare (GstAudioSink * asink, GstRingBufferSpec * spec)
memset (&wfx, 0, sizeof (wfx));
wfx.cbSize = 0;
wfx.wFormatTag = WAVE_FORMAT_PCM;
- wfx.nChannels = spec->channels;
- wfx.nSamplesPerSec = spec->rate;
- wfx.wBitsPerSample = (spec->bytes_per_sample * 8) / wfx.nChannels;
- wfx.nBlockAlign = spec->bytes_per_sample;
+ wfx.nChannels = spec->info.channels;
+ wfx.nSamplesPerSec = spec->info.rate;
+ wfx.wBitsPerSample = (spec->info.bpf * 8) / wfx.nChannels;
+ wfx.nBlockAlign = spec->info.bpf;
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
/* save bytes per sample to use it in delay */
- wfsink->bytes_per_sample = spec->bytes_per_sample;
+ wfsink->bytes_per_sample = spec->info.bpf;
/* open the default audio device with the given caps */
mmresult = waveOutOpen (&wfsink->hwaveout, WAVE_MAPPER,
@@ -449,7 +438,7 @@ gst_waveform_sink_close (GstAudioSink * asink)
return TRUE;
}
-static guint
+static gint
gst_waveform_sink_write (GstAudioSink * asink, gpointer data, guint length)
{
GstWaveFormSink *wfsink = GST_WAVEFORM_SINK (asink);
@@ -554,15 +543,13 @@ gst_waveform_sink_reset (GstAudioSink * asink)
}
GstCaps *
-gst_waveform_sink_create_caps (gint rate, gint channels, gint bits_per_sample)
+gst_waveform_sink_create_caps (gint rate, gint channels, const gchar * format)
{
GstCaps *caps = NULL;
- caps = gst_caps_new_simple ("audio/x-raw-int",
- "width", G_TYPE_INT, bits_per_sample,
- "depth", G_TYPE_INT, bits_per_sample,
- "endianness", G_TYPE_INT, G_BYTE_ORDER,
- "signed", G_TYPE_BOOLEAN, TRUE,
+ caps = gst_caps_new_simple ("audio/x-raw",
+ "format", G_TYPE_STRING, format,
+ "layout", G_TYPE_STRING, "interleaved",
"channels", G_TYPE_INT, channels, "rate", G_TYPE_INT, rate, NULL);
return caps;
}
diff --git a/sys/ximage/Makefile.am b/sys/ximage/Makefile.am
index db3ab228df..553226e30a 100644
--- a/sys/ximage/Makefile.am
+++ b/sys/ximage/Makefile.am
@@ -7,7 +7,7 @@ libgstximagesrc_la_CFLAGS = \
$(GST_CFLAGS) \
$(X_CFLAGS) $(XFIXES_CFLAGS) $(XDAMAGE_CFLAGS)
libgstximagesrc_la_LIBADD = \
- $(GST_PLUGINS_BASE_LIBS) \
+ $(GST_PLUGINS_BASE_LIBS) -lgstvideo-$(GST_MAJORMINOR) \
$(GST_BASE_LIBS) \
$(X_LIBS) $(XSHM_LIBS) $(XFIXES_LIBS) $(XDAMAGE_LIBS)
libgstximagesrc_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
diff --git a/sys/ximage/gstximagesrc.c b/sys/ximage/gstximagesrc.c
index 974031295d..0ec9688b4a 100644
--- a/sys/ximage/gstximagesrc.c
+++ b/sys/ximage/gstximagesrc.c
@@ -30,7 +30,7 @@
* <refsect2>
* <title>Example pipelines</title>
* |[
- * gst-launch ximagesrc ! video/x-raw-rgb,framerate=5/1 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=desktop.ogg
+ * gst-launch ximagesrc ! video/x-raw,framerate=5/1 ! ffmpegcolorspace ! theoraenc ! oggmux ! filesink location=desktop.ogg
* ]| Encodes your X display to an Ogg theora video at 5 frames per second.
* </refsect2>
*/
@@ -48,6 +48,7 @@
#include <gst/gst.h>
#include <gst/gst-i18n-plugin.h>
+#include <gst/video/video.h>
#include "gst/glib-compat-private.h"
@@ -56,7 +57,7 @@ GST_DEBUG_CATEGORY_STATIC (gst_debug_ximage_src);
static GstStaticPadTemplate t =
GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
- GST_STATIC_CAPS ("video/x-raw-rgb, "
+ GST_STATIC_CAPS ("video/x-raw, "
"framerate = (fraction) [ 0, MAX ], "
"width = (int) [ 1, MAX ], " "height = (int) [ 1, MAX ], "
"pixel-aspect-ratio = (fraction) [ 0, MAX ]"));
@@ -77,35 +78,35 @@ enum
PROP_XNAME,
};
-GST_BOILERPLATE (GstXImageSrc, gst_ximage_src, GstPushSrc, GST_TYPE_PUSH_SRC);
+#define gst_ximage_src_parent_class parent_class
+G_DEFINE_TYPE (GstXImageSrc, gst_ximage_src, GST_TYPE_PUSH_SRC);
-static void gst_ximage_src_fixate (GstPad * pad, GstCaps * caps);
+static GstCaps *gst_ximage_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
static void gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc);
/* Called when a buffer is returned from the pipeline */
static void
-gst_ximage_src_return_buf (GstXImageSrc * ximagesrc,
- GstXImageSrcBuffer * ximage)
+gst_ximage_src_return_buf (GstXImageSrc * ximagesrc, GstBuffer * ximage)
{
+ GstMetaXImage *meta = GST_META_XIMAGE_GET (ximage);
+
/* If our geometry changed we can't reuse that image. */
- if ((ximage->width != ximagesrc->width) ||
- (ximage->height != ximagesrc->height)) {
+ if ((meta->width != ximagesrc->width) || (meta->height != ximagesrc->height)) {
GST_DEBUG_OBJECT (ximagesrc,
"destroy image %p as its size changed %dx%d vs current %dx%d",
- ximage, ximage->width, ximage->height,
- ximagesrc->width, ximagesrc->height);
- g_mutex_lock (ximagesrc->x_lock);
+ ximage, meta->width, meta->height, ximagesrc->width, ximagesrc->height);
+ g_mutex_lock (&ximagesrc->x_lock);
gst_ximageutil_ximage_destroy (ximagesrc->xcontext, ximage);
- g_mutex_unlock (ximagesrc->x_lock);
+ g_mutex_unlock (&ximagesrc->x_lock);
} else {
/* In that case we can reuse the image and add it to our image pool. */
GST_LOG_OBJECT (ximagesrc, "recycling image %p in pool", ximage);
/* need to increment the refcount again to recycle */
- gst_buffer_ref (GST_BUFFER (ximage));
- g_mutex_lock (ximagesrc->pool_lock);
+ gst_buffer_ref (ximage);
+ g_mutex_lock (&ximagesrc->pool_lock);
GST_BUFFER_FLAGS (GST_BUFFER (ximage)) = 0; /* clear out any flags from the previous use */
ximagesrc->buffer_pool = g_slist_prepend (ximagesrc->buffer_pool, ximage);
- g_mutex_unlock (ximagesrc->pool_lock);
+ g_mutex_unlock (&ximagesrc->pool_lock);
}
}
@@ -146,10 +147,10 @@ gst_ximage_src_open_display (GstXImageSrc * s, const gchar * name)
if (s->xcontext != NULL)
return TRUE;
- g_mutex_lock (s->x_lock);
+ g_mutex_lock (&s->x_lock);
s->xcontext = ximageutil_xcontext_get (GST_ELEMENT (s), name);
if (s->xcontext == NULL) {
- g_mutex_unlock (s->x_lock);
+ g_mutex_unlock (&s->x_lock);
GST_ELEMENT_ERROR (s, RESOURCE, OPEN_READ,
("Could not open X display for reading"),
("NULL returned from getting xcontext"));
@@ -259,7 +260,7 @@ use_root_window:
#endif
#endif
- g_mutex_unlock (s->x_lock);
+ g_mutex_unlock (&s->x_lock);
if (s->xcontext == NULL)
return FALSE;
@@ -301,7 +302,7 @@ gst_ximage_src_stop (GstBaseSrc * basesrc)
#endif
if (src->xcontext) {
- g_mutex_lock (src->x_lock);
+ g_mutex_lock (&src->x_lock);
#ifdef HAVE_XDAMAGE
if (src->damage_copy_gc != None) {
@@ -320,7 +321,7 @@ gst_ximage_src_stop (GstBaseSrc * basesrc)
ximageutil_xcontext_clear (src->xcontext);
src->xcontext = NULL;
- g_mutex_unlock (src->x_lock);
+ g_mutex_unlock (&src->x_lock);
}
return TRUE;
@@ -433,35 +434,47 @@ composite_pixel (GstXContext * xcontext, guchar * dest, guchar * src)
}
#endif
+#ifdef HAVE_XDAMAGE
+static void
+copy_buffer (GstBuffer * dest, GstBuffer * src)
+{
+ GstMapInfo map;
+
+ gst_buffer_map (src, &map, GST_MAP_READ);
+ gst_buffer_fill (dest, 0, map.data, map.size);
+ gst_buffer_unmap (src, &map);
+}
+#endif
+
/* Retrieve an XImageSrcBuffer, preferably from our
* pool of existing images and populate it from the window */
-static GstXImageSrcBuffer *
+static GstBuffer *
gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
{
- GstXImageSrcBuffer *ximage = NULL;
+ GstBuffer *ximage = NULL;
+ GstMetaXImage *meta;
- g_mutex_lock (ximagesrc->pool_lock);
+ g_mutex_lock (&ximagesrc->pool_lock);
while (ximagesrc->buffer_pool != NULL) {
ximage = ximagesrc->buffer_pool->data;
- if ((ximage->width != ximagesrc->width) ||
- (ximage->height != ximagesrc->height)) {
+ meta = GST_META_XIMAGE_GET (ximage);
+
+ if ((meta->width != ximagesrc->width) ||
+ (meta->height != ximagesrc->height)) {
gst_ximage_buffer_free (ximage);
}
ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
ximagesrc->buffer_pool);
}
- g_mutex_unlock (ximagesrc->pool_lock);
+ g_mutex_unlock (&ximagesrc->pool_lock);
if (ximage == NULL) {
- GstXContext *xcontext;
- GstCaps *caps = NULL;
-
GST_DEBUG_OBJECT (ximagesrc, "creating image (%dx%d)",
ximagesrc->width, ximagesrc->height);
- g_mutex_lock (ximagesrc->x_lock);
+ g_mutex_lock (&ximagesrc->x_lock);
ximage = gst_ximageutil_ximage_new (ximagesrc->xcontext,
GST_ELEMENT (ximagesrc), ximagesrc->width, ximagesrc->height,
(BufferReturnFunc) (gst_ximage_src_return_buf));
@@ -469,34 +482,17 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
GST_ELEMENT_ERROR (ximagesrc, RESOURCE, WRITE, (NULL),
("could not create a %dx%d ximage", ximagesrc->width,
ximagesrc->height));
- g_mutex_unlock (ximagesrc->x_lock);
+ g_mutex_unlock (&ximagesrc->x_lock);
return NULL;
}
- xcontext = ximagesrc->xcontext;
-
-
- caps = gst_caps_new_simple ("video/x-raw-rgb",
- "bpp", G_TYPE_INT, xcontext->bpp,
- "depth", G_TYPE_INT, xcontext->depth,
- "endianness", G_TYPE_INT, xcontext->endianness,
- "red_mask", G_TYPE_INT, xcontext->r_mask_output,
- "green_mask", G_TYPE_INT, xcontext->g_mask_output,
- "blue_mask", G_TYPE_INT, xcontext->b_mask_output,
- "width", G_TYPE_INT, ximagesrc->width,
- "height", G_TYPE_INT, ximagesrc->height,
- "framerate", GST_TYPE_FRACTION, ximagesrc->fps_n, ximagesrc->fps_d,
- "pixel-aspect-ratio", GST_TYPE_FRACTION,
- gst_value_get_fraction_numerator (xcontext->par),
- gst_value_get_fraction_denominator (xcontext->par), NULL);
-
- gst_buffer_set_caps (GST_BUFFER (ximage), caps);
- g_mutex_unlock (ximagesrc->x_lock);
-
- gst_caps_unref (caps);
+ g_mutex_unlock (&ximagesrc->x_lock);
}
g_return_val_if_fail (GST_IS_XIMAGE_SRC (ximagesrc), NULL);
+
+ meta = GST_META_XIMAGE_GET (ximage);
+
#ifdef HAVE_XDAMAGE
if (ximagesrc->have_xdamage && ximagesrc->use_damage &&
ximagesrc->last_ximage != NULL) {
@@ -526,11 +522,9 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
if (!have_frame) {
GST_LOG_OBJECT (ximagesrc,
- "Copying from last frame ximage->size: %d",
- GST_BUFFER_SIZE (GST_BUFFER (ximage)));
- memcpy (GST_BUFFER_DATA (GST_BUFFER (ximage)),
- GST_BUFFER_DATA (GST_BUFFER (ximagesrc->last_ximage)),
- GST_BUFFER_SIZE (GST_BUFFER (ximage)));
+ "Copying from last frame ximage->size: %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (ximage));
+ copy_buffer (ximage, ximagesrc->last_ximage);
have_frame = TRUE;
}
for (i = 0; i < nrects; i++) {
@@ -569,7 +563,7 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
startx, starty, width, height);
XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
startx, starty, width, height, AllPlanes, ZPixmap,
- ximage->ximage, startx - ximagesrc->startx,
+ meta->ximage, startx - ximagesrc->startx,
starty - ximagesrc->starty);
}
} else {
@@ -581,7 +575,7 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
rects[i].x, rects[i].y,
rects[i].width, rects[i].height,
- AllPlanes, ZPixmap, ximage->ximage, rects[i].x, rects[i].y);
+ AllPlanes, ZPixmap, meta->ximage, rects[i].x, rects[i].y);
}
}
free (rects);
@@ -590,11 +584,9 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
} while (XPending (ximagesrc->xcontext->disp));
if (!have_frame) {
GST_LOG_OBJECT (ximagesrc,
- "Copying from last frame ximage->size: %d",
- GST_BUFFER_SIZE (GST_BUFFER (ximage)));
- memcpy (GST_BUFFER_DATA (GST_BUFFER (ximage)),
- GST_BUFFER_DATA (GST_BUFFER (ximagesrc->last_ximage)),
- GST_BUFFER_SIZE (GST_BUFFER (ximage)));
+ "Copying from last frame ximage->size: %" G_GSIZE_FORMAT,
+ gst_buffer_get_size (ximage));
+ copy_buffer (ximage, ximagesrc->last_ximage);
}
#ifdef HAVE_XFIXES
/* re-get area where last mouse pointer was but only if in our clipping
@@ -643,14 +635,14 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y);
XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
startx, starty, iwidth, iheight, AllPlanes, ZPixmap,
- ximage->ximage, startx - ximagesrc->startx,
+ meta->ximage, startx - ximagesrc->startx,
starty - ximagesrc->starty);
}
} else {
GST_DEBUG_OBJECT (ximagesrc, "Removing cursor from %d,%d", x, y);
XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
- x, y, width, height, AllPlanes, ZPixmap, ximage->ximage, x, y);
+ x, y, width, height, AllPlanes, ZPixmap, meta->ximage, x, y);
}
}
#endif
@@ -663,7 +655,7 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
if (ximagesrc->xcontext->use_xshm) {
GST_DEBUG_OBJECT (ximagesrc, "Retrieving screen using XShm");
XShmGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
- ximage->ximage, ximagesrc->startx, ximagesrc->starty, AllPlanes);
+ meta->ximage, ximagesrc->startx, ximagesrc->starty, AllPlanes);
} else
#endif /* HAVE_XSHM */
@@ -672,9 +664,9 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
if (ximagesrc->remote) {
XGetSubImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
ximagesrc->startx, ximagesrc->starty, ximagesrc->width,
- ximagesrc->height, AllPlanes, ZPixmap, ximage->ximage, 0, 0);
+ ximagesrc->height, AllPlanes, ZPixmap, meta->ximage, 0, 0);
} else {
- ximage->ximage =
+ meta->ximage =
XGetImage (ximagesrc->xcontext->disp, ximagesrc->xwindow,
ximagesrc->startx, ximagesrc->starty, ximagesrc->width,
ximagesrc->height, AllPlanes, ZPixmap);
@@ -754,7 +746,7 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
(guint8 *) & (ximagesrc->cursor_image->pixels[((j -
cy) * ximagesrc->cursor_image->width + (i - cx))]);
dest =
- (guint8 *) & (ximage->ximage->data[((j -
+ (guint8 *) & (meta->ximage->data[((j -
ximagesrc->starty) * ximagesrc->width + (i -
ximagesrc->startx)) * (ximagesrc->xcontext->bpp /
8)]);
@@ -770,9 +762,9 @@ gst_ximage_src_ximage_get (GstXImageSrc * ximagesrc)
#ifdef HAVE_XDAMAGE
if (ximagesrc->have_xdamage && ximagesrc->use_damage) {
/* need to ref ximage to put in last_ximage */
- gst_buffer_ref (GST_BUFFER (ximage));
+ gst_buffer_ref (ximage);
if (ximagesrc->last_ximage) {
- gst_buffer_unref (GST_BUFFER (ximagesrc->last_ximage));
+ gst_buffer_unref (ximagesrc->last_ximage);
}
ximagesrc->last_ximage = ximage;
GST_LOG_OBJECT (ximagesrc, "reffing current buffer for last_ximage");
@@ -785,7 +777,7 @@ static GstFlowReturn
gst_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf)
{
GstXImageSrc *s = GST_XIMAGE_SRC (bs);
- GstXImageSrcBuffer *image;
+ GstBuffer *image;
GstClockTime base_time;
GstClockTime next_capture_ts;
GstClockTime dur;
@@ -847,7 +839,7 @@ gst_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf)
if (ret == GST_CLOCK_UNSCHEDULED) {
/* Got woken up by the unlock function */
GST_OBJECT_UNLOCK (s);
- return GST_FLOW_WRONG_STATE;
+ return GST_FLOW_FLUSHING;
}
/* Duration is a complete 1/fps frame duration */
dur = gst_util_uint64_scale_int (GST_SECOND, s->fps_d, s->fps_n);
@@ -869,7 +861,7 @@ gst_ximage_src_create (GstPushSrc * bs, GstBuffer ** buf)
if (!image)
return GST_FLOW_ERROR;
- *buf = GST_BUFFER (image);
+ *buf = image;
GST_BUFFER_TIMESTAMP (*buf) = next_capture_ts;
GST_BUFFER_DURATION (*buf) = dur;
@@ -985,30 +977,16 @@ gst_ximage_src_get_property (GObject * object, guint prop_id, GValue * value,
static void
gst_ximage_src_clear_bufpool (GstXImageSrc * ximagesrc)
{
- g_mutex_lock (ximagesrc->pool_lock);
+ g_mutex_lock (&ximagesrc->pool_lock);
while (ximagesrc->buffer_pool != NULL) {
- GstXImageSrcBuffer *ximage = ximagesrc->buffer_pool->data;
+ GstBuffer *ximage = ximagesrc->buffer_pool->data;
gst_ximage_buffer_free (ximage);
ximagesrc->buffer_pool = g_slist_delete_link (ximagesrc->buffer_pool,
ximagesrc->buffer_pool);
}
- g_mutex_unlock (ximagesrc->pool_lock);
-}
-
-static void
-gst_ximage_src_base_init (gpointer g_class)
-{
- GstElementClass *ec = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_set_details_simple (ec, "Ximage video source",
- "Source/Video",
- "Creates a screenshot video stream",
- "Lutz Mueller <lutz@users.sourceforge.net>, "
- "Jan Schmidt <thaytan@mad.scientist.com>, "
- "Zaheer Merali <zaheerabbas at merali dot org>");
- gst_element_class_add_static_pad_template (ec, &t);
+ g_mutex_unlock (&ximagesrc->pool_lock);
}
static void
@@ -1029,18 +1007,19 @@ gst_ximage_src_finalize (GObject * object)
ximageutil_xcontext_clear (src->xcontext);
g_free (src->xname);
- g_mutex_free (src->pool_lock);
- g_mutex_free (src->x_lock);
+ g_mutex_clear (&src->pool_lock);
+ g_mutex_clear (&src->x_lock);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static GstCaps *
-gst_ximage_src_get_caps (GstBaseSrc * bs)
+gst_ximage_src_get_caps (GstBaseSrc * bs, GstCaps * filter)
{
GstXImageSrc *s = GST_XIMAGE_SRC (bs);
GstXContext *xcontext;
gint width, height;
+ GstVideoFormat format;
if ((!s->xcontext) && (!gst_ximage_src_open_display (s, s->display_name)))
return
@@ -1094,13 +1073,14 @@ gst_ximage_src_get_caps (GstBaseSrc * bs)
s->endy = height - 1;
}
GST_DEBUG ("width = %d, height=%d", width, height);
- return gst_caps_new_simple ("video/x-raw-rgb",
- "bpp", G_TYPE_INT, xcontext->bpp,
- "depth", G_TYPE_INT, xcontext->depth,
- "endianness", G_TYPE_INT, xcontext->endianness,
- "red_mask", G_TYPE_INT, xcontext->r_mask_output,
- "green_mask", G_TYPE_INT, xcontext->g_mask_output,
- "blue_mask", G_TYPE_INT, xcontext->b_mask_output,
+
+ format =
+ gst_video_format_from_masks (xcontext->depth, xcontext->bpp,
+ xcontext->endianness, xcontext->r_mask_output, xcontext->g_mask_output,
+ xcontext->b_mask_output, 0);
+
+ return gst_caps_new_simple ("video/x-raw",
+ "format", G_TYPE_STRING, gst_video_format_to_string (format),
"width", G_TYPE_INT, width,
"height", G_TYPE_INT, height,
"framerate", GST_TYPE_FRACTION_RANGE, 1, G_MAXINT, G_MAXINT, 1,
@@ -1134,23 +1114,29 @@ gst_ximage_src_set_caps (GstBaseSrc * bs, GstCaps * caps)
return TRUE;
}
-static void
-gst_ximage_src_fixate (GstPad * pad, GstCaps * caps)
+static GstCaps *
+gst_ximage_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
{
gint i;
GstStructure *structure;
+ caps = gst_caps_make_writable (caps);
+
for (i = 0; i < gst_caps_get_size (caps); ++i) {
structure = gst_caps_get_structure (caps, i);
gst_structure_fixate_field_nearest_fraction (structure, "framerate", 25, 1);
}
+ caps = GST_BASE_SRC_CLASS (parent_class)->fixate (bsrc, caps);
+
+ return caps;
}
static void
gst_ximage_src_class_init (GstXImageSrcClass * klass)
{
GObjectClass *gc = G_OBJECT_CLASS (klass);
+ GstElementClass *ec = GST_ELEMENT_CLASS (klass);
GstBaseSrcClass *bc = GST_BASE_SRC_CLASS (klass);
GstPushSrcClass *push_class = GST_PUSH_SRC_CLASS (klass);
@@ -1241,7 +1227,6 @@ gst_ximage_src_class_init (GstXImageSrcClass * klass)
g_param_spec_boolean ("remote", "Remote dispay",
"Whether the display is remote", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
/**
* GstXImageSrc:xid
*
@@ -1253,7 +1238,6 @@ gst_ximage_src_class_init (GstXImageSrcClass * klass)
g_param_spec_uint64 ("xid", "Window XID",
"Window XID to capture from", 0, G_MAXUINT64, 0,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
/**
* GstXImageSrc:xname
*
@@ -1266,26 +1250,31 @@ gst_ximage_src_class_init (GstXImageSrcClass * klass)
"Window name to capture from", NULL,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- parent_class = g_type_class_peek_parent (klass);
+ gst_element_class_set_details_simple (ec, "Ximage video source",
+ "Source/Video",
+ "Creates a screenshot video stream",
+ "Lutz Mueller <lutz@users.sourceforge.net>, "
+ "Jan Schmidt <thaytan@mad.scientist.com>, "
+ "Zaheer Merali <zaheerabbas at merali dot org>");
+ gst_element_class_add_pad_template (ec, gst_static_pad_template_get (&t));
- push_class->create = gst_ximage_src_create;
+ bc->fixate = gst_ximage_src_fixate;
bc->get_caps = gst_ximage_src_get_caps;
bc->set_caps = gst_ximage_src_set_caps;
bc->start = gst_ximage_src_start;
bc->stop = gst_ximage_src_stop;
bc->unlock = gst_ximage_src_unlock;
+ push_class->create = gst_ximage_src_create;
}
static void
-gst_ximage_src_init (GstXImageSrc * ximagesrc, GstXImageSrcClass * klass)
+gst_ximage_src_init (GstXImageSrc * ximagesrc)
{
gst_base_src_set_format (GST_BASE_SRC (ximagesrc), GST_FORMAT_TIME);
gst_base_src_set_live (GST_BASE_SRC (ximagesrc), TRUE);
- gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (ximagesrc),
- gst_ximage_src_fixate);
- ximagesrc->pool_lock = g_mutex_new ();
- ximagesrc->x_lock = g_mutex_new ();
+ g_mutex_init (&ximagesrc->pool_lock);
+ g_mutex_init (&ximagesrc->x_lock);
ximagesrc->show_pointer = TRUE;
ximagesrc->use_damage = TRUE;
ximagesrc->startx = 0;
diff --git a/sys/ximage/gstximagesrc.h b/sys/ximage/gstximagesrc.h
index e58513c1ec..7f5275a85a 100644
--- a/sys/ximage/gstximagesrc.h
+++ b/sys/ximage/gstximagesrc.h
@@ -69,10 +69,10 @@ struct _GstXImageSrc
gint64 last_frame_no;
/* Protect X Windows calls */
- GMutex *x_lock;
+ GMutex x_lock;
/* Gathered pool of emitted buffers */
- GMutex *pool_lock;
+ GMutex pool_lock;
GSList *buffer_pool;
/* XFixes and XDamage support */
@@ -99,7 +99,7 @@ struct _GstXImageSrc
int damage_event_base;
XserverRegion damage_region;
GC damage_copy_gc;
- GstXImageSrcBuffer *last_ximage;
+ GstBuffer *last_ximage;
#endif
};
diff --git a/sys/ximage/ximageutil.c b/sys/ximage/ximageutil.c
index 2fac09a231..907aa3aefd 100644
--- a/sys/ximage/ximageutil.c
+++ b/sys/ximage/ximageutil.c
@@ -23,6 +23,33 @@
#include "ximageutil.h"
+GType
+gst_meta_ximage_api_get_type (void)
+{
+ static volatile GType type;
+ static const gchar *tags[] = { "memory", NULL };
+
+ if (g_once_init_enter (&type)) {
+ GType _type = gst_meta_api_type_register ("GstMetaXImageSrcAPI", tags);
+ g_once_init_leave (&type, _type);
+ }
+ return type;
+}
+
+const GstMetaInfo *
+gst_meta_ximage_get_info (void)
+{
+ static const GstMetaInfo *meta_ximage_info = NULL;
+
+ if (meta_ximage_info == NULL) {
+ meta_ximage_info =
+ gst_meta_register (gst_meta_ximage_api_get_type (), "GstMetaXImageSrc",
+ sizeof (GstMetaXImage), (GstMetaInitFunction) NULL,
+ (GstMetaFreeFunction) NULL, (GstMetaTransformFunction) NULL);
+ }
+ return meta_ximage_info;
+}
+
#ifdef HAVE_XSHM
static gboolean error_caught = FALSE;
@@ -296,108 +323,70 @@ ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext)
gst_value_get_fraction_denominator (xcontext->par));
}
-static GstBufferClass *ximagesrc_buffer_parent_class = NULL;
-
static void
-gst_ximagesrc_buffer_finalize (GstXImageSrcBuffer * ximage)
+gst_ximagesrc_buffer_dispose (GstBuffer * ximage)
{
GstElement *parent;
+ GstMetaXImage *meta;
g_return_if_fail (ximage != NULL);
- parent = ximage->parent;
+ meta = GST_META_XIMAGE_GET (ximage);
+
+ parent = meta->parent;
if (parent == NULL) {
g_warning ("XImageSrcBuffer->ximagesrc == NULL");
goto beach;
}
- if (ximage->return_func)
- ximage->return_func (parent, ximage);
+ if (meta->return_func)
+ meta->return_func (parent, ximage);
beach:
-
- GST_MINI_OBJECT_CLASS (ximagesrc_buffer_parent_class)->finalize
- (GST_MINI_OBJECT (ximage));
-
return;
}
void
-gst_ximage_buffer_free (GstXImageSrcBuffer * ximage)
+gst_ximage_buffer_free (GstBuffer * ximage)
{
- /* make sure it is not recycled */
- ximage->width = -1;
- ximage->height = -1;
- gst_buffer_unref (GST_BUFFER (ximage));
-}
+ GstMetaXImage *meta;
-static void
-gst_ximagesrc_buffer_init (GstXImageSrcBuffer * ximage_buffer, gpointer g_class)
-{
-#ifdef HAVE_XSHM
- ximage_buffer->SHMInfo.shmaddr = ((void *) -1);
- ximage_buffer->SHMInfo.shmid = -1;
-#endif
-}
-
-static void
-gst_ximagesrc_buffer_class_init (gpointer g_class, gpointer class_data)
-{
- GstMiniObjectClass *mini_object_class = GST_MINI_OBJECT_CLASS (g_class);
-
- ximagesrc_buffer_parent_class = g_type_class_peek_parent (g_class);
+ meta = GST_META_XIMAGE_GET (ximage);
- mini_object_class->finalize = (GstMiniObjectFinalizeFunction)
- gst_ximagesrc_buffer_finalize;
-}
-
-static GType
-gst_ximagesrc_buffer_get_type (void)
-{
- static GType _gst_ximagesrc_buffer_type;
-
- if (G_UNLIKELY (_gst_ximagesrc_buffer_type == 0)) {
- static const GTypeInfo ximagesrc_buffer_info = {
- sizeof (GstBufferClass),
- NULL,
- NULL,
- gst_ximagesrc_buffer_class_init,
- NULL,
- NULL,
- sizeof (GstXImageSrcBuffer),
- 0,
- (GInstanceInitFunc) gst_ximagesrc_buffer_init,
- NULL
- };
- _gst_ximagesrc_buffer_type = g_type_register_static (GST_TYPE_BUFFER,
- "GstXImageSrcBuffer", &ximagesrc_buffer_info, 0);
- }
- return _gst_ximagesrc_buffer_type;
+ /* make sure it is not recycled */
+ meta->width = -1;
+ meta->height = -1;
+ gst_buffer_unref (ximage);
}
/* This function handles GstXImageSrcBuffer creation depending on XShm availability */
-GstXImageSrcBuffer *
+GstBuffer *
gst_ximageutil_ximage_new (GstXContext * xcontext,
GstElement * parent, int width, int height, BufferReturnFunc return_func)
{
- GstXImageSrcBuffer *ximage = NULL;
+ GstBuffer *ximage = NULL;
+ GstMetaXImage *meta;
gboolean succeeded = FALSE;
- ximage =
- (GstXImageSrcBuffer *) gst_mini_object_new (GST_TYPE_XIMAGESRC_BUFFER);
+ ximage = gst_buffer_new ();
+ GST_MINI_OBJECT_CAST (ximage)->dispose =
+ (GstMiniObjectDisposeFunction) gst_ximagesrc_buffer_dispose;
- ximage->width = width;
- ximage->height = height;
+ meta = GST_META_XIMAGE_ADD (ximage);
+ meta->width = width;
+ meta->height = height;
#ifdef HAVE_XSHM
+ meta->SHMInfo.shmaddr = ((void *) -1);
+ meta->SHMInfo.shmid = -1;
+
if (xcontext->use_xshm) {
- ximage->ximage = XShmCreateImage (xcontext->disp,
+ meta->ximage = XShmCreateImage (xcontext->disp,
xcontext->visual, xcontext->depth,
- ZPixmap, NULL, &ximage->SHMInfo, ximage->width, ximage->height);
- if (!ximage->ximage) {
+ ZPixmap, NULL, &meta->SHMInfo, meta->width, meta->height);
+ if (!meta->ximage) {
GST_WARNING_OBJECT (parent,
- "could not XShmCreateImage a %dx%d image",
- ximage->width, ximage->height);
+ "could not XShmCreateImage a %dx%d image", meta->width, meta->height);
/* Retry without XShm */
xcontext->use_xshm = FALSE;
@@ -405,24 +394,23 @@ gst_ximageutil_ximage_new (GstXContext * xcontext,
}
/* we have to use the returned bytes_per_line for our shm size */
- ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
- ximage->SHMInfo.shmid = shmget (IPC_PRIVATE, ximage->size,
- IPC_CREAT | 0777);
- if (ximage->SHMInfo.shmid == -1)
+ meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
+ meta->SHMInfo.shmid = shmget (IPC_PRIVATE, meta->size, IPC_CREAT | 0777);
+ if (meta->SHMInfo.shmid == -1)
goto beach;
- ximage->SHMInfo.shmaddr = shmat (ximage->SHMInfo.shmid, 0, 0);
- if (ximage->SHMInfo.shmaddr == ((void *) -1))
+ meta->SHMInfo.shmaddr = shmat (meta->SHMInfo.shmid, 0, 0);
+ if (meta->SHMInfo.shmaddr == ((void *) -1))
goto beach;
/* Delete the SHM segment. It will actually go away automatically
* when we detach now */
- shmctl (ximage->SHMInfo.shmid, IPC_RMID, 0);
+ shmctl (meta->SHMInfo.shmid, IPC_RMID, 0);
- ximage->ximage->data = ximage->SHMInfo.shmaddr;
- ximage->SHMInfo.readOnly = FALSE;
+ meta->ximage->data = meta->SHMInfo.shmaddr;
+ meta->SHMInfo.readOnly = FALSE;
- if (XShmAttach (xcontext->disp, &ximage->SHMInfo) == 0)
+ if (XShmAttach (xcontext->disp, &meta->SHMInfo) == 0)
goto beach;
XSync (xcontext->disp, FALSE);
@@ -430,27 +418,28 @@ gst_ximageutil_ximage_new (GstXContext * xcontext,
no_xshm:
#endif /* HAVE_XSHM */
{
- ximage->ximage = XCreateImage (xcontext->disp,
+ meta->ximage = XCreateImage (xcontext->disp,
xcontext->visual,
xcontext->depth,
- ZPixmap, 0, NULL, ximage->width, ximage->height, xcontext->bpp, 0);
- if (!ximage->ximage)
+ ZPixmap, 0, NULL, meta->width, meta->height, xcontext->bpp, 0);
+ if (!meta->ximage)
goto beach;
/* we have to use the returned bytes_per_line for our image size */
- ximage->size = ximage->ximage->bytes_per_line * ximage->ximage->height;
- ximage->ximage->data = g_malloc (ximage->size);
+ meta->size = meta->ximage->bytes_per_line * meta->ximage->height;
+ meta->ximage->data = g_malloc (meta->size);
XSync (xcontext->disp, FALSE);
}
succeeded = TRUE;
- GST_BUFFER_DATA (ximage) = (guchar *) ximage->ximage->data;
- GST_BUFFER_SIZE (ximage) = ximage->size;
+ gst_buffer_take_memory (ximage, -1,
+ gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, meta->ximage->data,
+ meta->size, 0, meta->size, NULL, NULL));
/* Keep a ref to our src */
- ximage->parent = gst_object_ref (parent);
- ximage->return_func = return_func;
+ meta->parent = gst_object_ref (parent);
+ meta->return_func = return_func;
beach:
if (!succeeded) {
gst_ximage_buffer_free (ximage);
@@ -462,9 +451,12 @@ beach:
/* This function destroys a GstXImageBuffer handling XShm availability */
void
-gst_ximageutil_ximage_destroy (GstXContext * xcontext,
- GstXImageSrcBuffer * ximage)
+gst_ximageutil_ximage_destroy (GstXContext * xcontext, GstBuffer * ximage)
{
+ GstMetaXImage *meta;
+
+ meta = GST_META_XIMAGE_GET (ximage);
+
/* We might have some buffers destroyed after changing state to NULL */
if (!xcontext)
goto beach;
@@ -473,28 +465,28 @@ gst_ximageutil_ximage_destroy (GstXContext * xcontext,
#ifdef HAVE_XSHM
if (xcontext->use_xshm) {
- if (ximage->SHMInfo.shmaddr != ((void *) -1)) {
- XShmDetach (xcontext->disp, &ximage->SHMInfo);
+ if (meta->SHMInfo.shmaddr != ((void *) -1)) {
+ XShmDetach (xcontext->disp, &meta->SHMInfo);
XSync (xcontext->disp, 0);
- shmdt (ximage->SHMInfo.shmaddr);
+ shmdt (meta->SHMInfo.shmaddr);
}
- if (ximage->ximage)
- XDestroyImage (ximage->ximage);
+ if (meta->ximage)
+ XDestroyImage (meta->ximage);
} else
#endif /* HAVE_XSHM */
{
- if (ximage->ximage) {
- XDestroyImage (ximage->ximage);
+ if (meta->ximage) {
+ XDestroyImage (meta->ximage);
}
}
XSync (xcontext->disp, FALSE);
beach:
- if (ximage->parent) {
+ if (meta->parent) {
/* Release the ref to our parent */
- gst_object_unref (ximage->parent);
- ximage->parent = NULL;
+ gst_object_unref (meta->parent);
+ meta->parent = NULL;
}
return;
diff --git a/sys/ximage/ximageutil.h b/sys/ximage/ximageutil.h
index 517fc8e06a..aa03e7a857 100644
--- a/sys/ximage/ximageutil.h
+++ b/sys/ximage/ximageutil.h
@@ -43,7 +43,7 @@ G_BEGIN_DECLS
typedef struct _GstXContext GstXContext;
typedef struct _GstXWindow GstXWindow;
typedef struct _GstXImage GstXImage;
-typedef struct _GstXImageSrcBuffer GstXImageSrcBuffer;
+typedef struct _GstMetaXImage GstMetaXImage;
/* Global X Context stuff */
/**
@@ -130,20 +130,20 @@ void ximageutil_calculate_pixel_aspect_ratio (GstXContext * xcontext);
/* custom ximagesrc buffer, copied from ximagesink */
/* BufferReturnFunc is called when a buffer is finalised */
-typedef void (*BufferReturnFunc) (GstElement *parent, GstXImageSrcBuffer *buf);
+typedef void (*BufferReturnFunc) (GstElement *parent, GstBuffer *buf);
/**
- * GstXImageSrcBuffer:
+ * GstMetaXImage:
* @parent: a reference to the element we belong to
* @ximage: the XImage of this buffer
* @width: the width in pixels of XImage @ximage
* @height: the height in pixels of XImage @ximage
* @size: the size in bytes of XImage @ximage
*
- * Subclass of #GstBuffer containing additional information about an XImage.
+ * Extra data attached to buffers containing additional information about an XImage.
*/
-struct _GstXImageSrcBuffer {
- GstBuffer buffer;
+struct _GstMetaXImage {
+ GstMeta meta;
/* Reference to the ximagesrc we belong to */
GstElement *parent;
@@ -156,26 +156,23 @@ struct _GstXImageSrcBuffer {
gint width, height;
size_t size;
-
+
BufferReturnFunc return_func;
};
+GType gst_meta_ximage_api_get_type (void);
+const GstMetaInfo * gst_meta_ximage_get_info (void);
+#define GST_META_XIMAGE_GET(buf) ((GstMetaXImage *)gst_buffer_get_meta(buf,gst_meta_ximage_api_get_type()))
+#define GST_META_XIMAGE_ADD(buf) ((GstMetaXImage *)gst_buffer_add_meta(buf,gst_meta_ximage_get_info(),NULL))
-GstXImageSrcBuffer *gst_ximageutil_ximage_new (GstXContext *xcontext,
+GstBuffer *gst_ximageutil_ximage_new (GstXContext *xcontext,
GstElement *parent, int width, int height, BufferReturnFunc return_func);
void gst_ximageutil_ximage_destroy (GstXContext *xcontext,
- GstXImageSrcBuffer * ximage);
+ GstBuffer * ximage);
/* Call to manually release a buffer */
-void gst_ximage_buffer_free (GstXImageSrcBuffer *ximage);
-
-#define GST_TYPE_XIMAGESRC_BUFFER (gst_ximagesrc_buffer_get_type())
-#define GST_IS_XIMAGESRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_XIMAGESRC_BUFFER))
-#define GST_IS_XIMAGESRC_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_XIMAGESRC_BUFFER))
-#define GST_XIMAGESRC_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBuffer))
-#define GST_XIMAGESRC_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBufferClass))
-#define GST_XIMAGESRC_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_XIMAGESRC_BUFFER, GstXImageSrcBufferClass))
+void gst_ximage_buffer_free (GstBuffer *ximage);
G_END_DECLS