New video4linux plugins, can also handle hardware JPEG devices. First check-in, probably has lots of bugs which will ...

Original commit message from CVS:
New video4linux plugins, can also handle hardware JPEG devices. First check-in, probably has lots of bugs which will be fixed when we find them
This commit is contained in:
Ronald S. Bultje 2001-12-23 15:31:15 +00:00
parent 940291a6d6
commit ab228b7235
16 changed files with 3376 additions and 414 deletions

View file

@ -1,12 +1,40 @@
plugindir = $(libdir)/gst
filterdir = $(libdir)/gst
plugin_LTLIBRARIES = libv4lsrc.la
filter_LTLIBRARIES = libv4lelement.la libv4lsrc.la \
libv4lmjpegsrc.la
#libv4lmjpegsink.la
libv4lsrc_la_SOURCES = \
gstv4lsrc.c \
grab-v4l.c
libv4lelement_la_SOURCES = \
gstv4lelement.c \
v4l_calls.c
libv4lelement_la_CFLAGS = \
$(GST_CFLAGS)
## FIXME : do we need -O2 ? libv4lsrc_la_CFLAGS = -O2 $(GST_CFLAGS)
libv4lsrc_la_CFLAGS = $(GST_CFLAGS)
libv4lsrc_la_SOURCES = \
gstv4lsrc.c \
v4lsrc_calls.c
libv4lsrc_la_LIBADD = \
libv4lelement.la
libv4lsrc_la_CFLAGS = \
$(GST_CFLAGS)
noinst_HEADERS = gstv4lsrc.h grab.h
libv4lmjpegsrc_la_SOURCES = \
gstv4lmjpegsrc.c \
v4lmjpegsrc_calls.c
libv4lmjpegsrc_la_LIBADD = \
libv4lelement.la
libv4lmjpegsrc_la_CFLAGS = \
$(GST_CFLAGS)
#libv4lmjpegsink_la_SOURCED = \
# gstv4lmjpegsink.c \
# v4lmjpegsikn_calls.c
#libv4lmjpegsink_la_LIBADD = \
# libv4lelement.la
#libv4lmjpegsink_la_CFLAGS = \
# $(GST_CFLAGS)
noinst_HEADERS = gstv4lelement.h v4l_calls.h \
gstv4lsrc.h v4lsrc_calls.h \
gstv4lmjpegsrc.h v4lmjpegsrc_calls.h
#gstv4lmjpegsink.h v4lmjpegsink_calls.h

22
sys/v4l/README Normal file
View file

@ -0,0 +1,22 @@
General idea:
/ gstv4lsrc.[ch]
/ v4lsrc_calls.[ch]
/
gstv4lelement.[ch] ------------- gstv4lmjpegsrc.[ch]
v4l_calls.[ch] ------------- v4lmjpegsrc_calls.[ch]
\
\ gstv4lmjpegsink.[ch]
\ v4lmjpegsink_calls.[ch]
I.e., all the files on thei right are child classes of
the v4lelement 'parent' on the left.mjpegsink is still
todo.
Generic idea:
* v4lelement handles generic v4l stuff (picture settings,
audio, norm/input setting, open()/close())
* v4lsrc, v4lmjpegsrc handle the capture specific
functions. Maybe we'd need a v4lmpegsrc too
* v4lmjpegsink handles mjpeg hardware playback of video

5
sys/v4l/TODO Normal file
View file

@ -0,0 +1,5 @@
* v4lmjpegsrc: integrate input/norm autodetection
* v4lmjpegsink: build
* v4lsrc: threaded sync()
* v4lsrc: threaded wait-for-sync()-until-queue()
* BSD-src: build (based on Bt848/Bt878/Meteor API)

479
sys/v4l/gstv4lelement.c Normal file
View file

@ -0,0 +1,479 @@
/* G-Streamer generic V4L element - generic V4L calls handling
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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.
*/
#include "v4l_calls.h"
#if 0
static GstElementDetails gst_v4lelement_details = {
"Generic video4linux Element",
"None/Video",
"Generic plugin for handling common video4linux calls",
VERSION,
"Ronald Bultje <rbultje@ronald.bitfreak.net>",
"(C) 2001",
};
#endif
/* V4lElement signals and args */
enum {
/* FILL ME */
LAST_SIGNAL
};
enum {
ARG_0,
ARG_CHANNEL,
ARG_NORM,
ARG_HAS_TUNER,
ARG_FREQUENCY,
ARG_HAS_AUDIO,
ARG_MUTE,
ARG_MODE,
ARG_VOLUME,
ARG_HUE,
ARG_BRIGHTNESS,
ARG_CONTRAST,
ARG_SATURATION,
ARG_DEVICE
};
static void gst_v4lelement_class_init (GstV4lElementClass *klass);
static void gst_v4lelement_init (GstV4lElement *v4lelement);
static void gst_v4lelement_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gst_v4lelement_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static GstElementStateReturn gst_v4lelement_change_state (GstElement *element);
static gboolean plugin_init (GModule *module,
GstPlugin *plugin);
static GstElementClass *parent_class = NULL;
//static guint gst_v4lelement_signals[LAST_SIGNAL] = { 0 };
GType
gst_v4lelement_get_type (void)
{
static GType v4lelement_type = 0;
if (!v4lelement_type) {
static const GTypeInfo v4lelement_info = {
sizeof(GstV4lElementClass),
NULL,
NULL,
(GClassInitFunc)gst_v4lelement_class_init,
NULL,
NULL,
sizeof(GstV4lElement),
0,
(GInstanceInitFunc)gst_v4lelement_init,
NULL
};
v4lelement_type = g_type_register_static(GST_TYPE_ELEMENT, "GstV4lElement", &v4lelement_info, 0);
}
return v4lelement_type;
}
static void
gst_v4lelement_class_init (GstV4lElementClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CHANNEL,
g_param_spec_int("channel","channel","channel",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM,
g_param_spec_int("norm","norm","norm",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_TUNER,
g_param_spec_boolean("has_tuner","has_tuner","has_tuner",0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FREQUENCY,
g_param_spec_ulong("frequency","frequency","frequency",0,G_MAXULONG,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HAS_AUDIO,
g_param_spec_boolean("has_audio","has_audio","has_audio",0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
g_param_spec_boolean("mute","mute","mute",0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
g_param_spec_int("volume","volume","volume",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MODE,
g_param_spec_int("mode","mode","mode",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HUE,
g_param_spec_int("hue","hue","hue",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BRIGHTNESS,
g_param_spec_int("brightness","brightness","brightness",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CONTRAST,
g_param_spec_int("contrast","contrast","contrast",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_SATURATION,
g_param_spec_int("saturation","saturation","saturation",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
g_param_spec_string("device","device","device", NULL, G_PARAM_READWRITE));
gobject_class->set_property = gst_v4lelement_set_property;
gobject_class->get_property = gst_v4lelement_get_property;
gstelement_class->change_state = gst_v4lelement_change_state;
}
static void
gst_v4lelement_init (GstV4lElement *v4lelement)
{
/* some default values */
v4lelement->video_fd = -1;
v4lelement->buffer = NULL;
v4lelement->videodev = NULL;
v4lelement->norm = -1;
v4lelement->channel = 0; /* the first channel */
v4lelement->frequency = 0;
v4lelement->mute = -1;
v4lelement->volume = -1;
v4lelement->mode = -1;
v4lelement->brightness = -1;
v4lelement->hue = -1;
v4lelement->contrast = -1;
v4lelement->saturation = -1;
}
static void
gst_v4lelement_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GstV4lElement *v4lelement;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail(GST_IS_V4LELEMENT(object));
v4lelement = GST_V4LELEMENT(object);
switch (prop_id)
{
case ARG_CHANNEL:
v4lelement->channel = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
{
if (v4lelement->norm >= 0)
if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
return;
}
break;
case ARG_NORM:
v4lelement->norm = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
{
if (v4lelement->norm >= 0)
if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
return;
}
break;
case ARG_FREQUENCY:
v4lelement->frequency = g_value_get_ulong(value);
if (GST_V4L_IS_ACTIVE(v4lelement) && !GST_V4L_IS_ACTIVE(v4lelement))
{
if (!gst_v4l_set_frequency(v4lelement, v4lelement->frequency))
return;
}
break;
case ARG_MUTE:
v4lelement->mute = g_value_get_boolean(value)?1:0;
if (GST_V4L_IS_OPEN(v4lelement))
{
if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_MUTE, v4lelement->mute))
return;
}
break;
case ARG_MODE:
v4lelement->mode = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement))
{
if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_MODE, v4lelement->mute))
return;
}
break;
case ARG_VOLUME:
v4lelement->volume = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement))
{
if (!gst_v4l_set_audio(v4lelement, V4L_AUDIO_VOLUME, v4lelement->volume))
return;
}
break;
case ARG_HUE:
v4lelement->hue = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement))
{
if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_HUE, v4lelement->hue))
return;
}
break;
case ARG_BRIGHTNESS:
v4lelement->brightness = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement))
{
if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_BRIGHTNESS, v4lelement->brightness))
return;
}
break;
case ARG_CONTRAST:
v4lelement->contrast = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement))
{
if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_CONTRAST, v4lelement->contrast))
return;
}
break;
case ARG_SATURATION:
v4lelement->saturation = g_value_get_int(value);
if (GST_V4L_IS_OPEN(v4lelement))
{
if (!gst_v4l_set_picture(v4lelement, V4L_PICTURE_SATURATION, v4lelement->saturation))
return;
}
break;
case ARG_DEVICE:
if (GST_V4L_IS_OPEN(v4lelement))
break; /* only set when *not* open */
if (v4lelement->videodev)
g_free(v4lelement->videodev);
v4lelement->videodev = g_strdup(g_value_get_string(value));
break;
default:
//G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
gst_v4lelement_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GstV4lElement *v4lelement;
gint temp_i = 0;
gulong temp_ul = 0;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail(GST_IS_V4LELEMENT(object));
v4lelement = GST_V4LELEMENT(object);
switch (prop_id)
{
case ARG_CHANNEL:
if (GST_V4L_IS_OPEN(v4lelement))
gst_v4l_get_chan_norm(v4lelement, &temp_i, NULL);
g_value_set_int(value, temp_i);
break;
case ARG_NORM:
if (GST_V4L_IS_OPEN(v4lelement))
gst_v4l_get_chan_norm(v4lelement, NULL, &temp_i);
g_value_set_int(value, temp_i);
break;
case ARG_HAS_TUNER:
g_value_set_boolean(value, FALSE);
if (GST_V4L_IS_OPEN(v4lelement))
if (gst_v4l_has_tuner(v4lelement))
g_value_set_boolean(value, TRUE);
break;
case ARG_FREQUENCY:
if (GST_V4L_IS_OPEN(v4lelement))
gst_v4l_get_frequency(v4lelement, &temp_ul);
g_value_set_ulong(value, temp_ul);
break;
case ARG_HAS_AUDIO:
g_value_set_boolean(value, FALSE);
if (GST_V4L_IS_OPEN(v4lelement))
if (gst_v4l_has_audio(v4lelement))
g_value_set_boolean(value, TRUE);
break;
case ARG_MUTE:
if (GST_V4L_IS_OPEN(v4lelement))
if (gst_v4l_has_tuner(v4lelement))
gst_v4l_get_audio(v4lelement, V4L_AUDIO_MUTE, &temp_i);
g_value_set_int(value, temp_i?TRUE:FALSE);
break;
case ARG_MODE:
if (GST_V4L_IS_OPEN(v4lelement))
if (gst_v4l_has_tuner(v4lelement))
gst_v4l_get_audio(v4lelement, V4L_AUDIO_MODE, &temp_i);
g_value_set_int(value, temp_i);
break;
case ARG_VOLUME:
if (GST_V4L_IS_OPEN(v4lelement))
if (gst_v4l_has_tuner(v4lelement))
gst_v4l_get_audio(v4lelement, V4L_AUDIO_VOLUME, &temp_i);
g_value_set_int(value, temp_i);
break;
case ARG_HUE:
if (GST_V4L_IS_OPEN(v4lelement))
gst_v4l_get_picture(v4lelement, V4L_PICTURE_HUE, &temp_i);
g_value_set_int(value, temp_i);
break;
case ARG_BRIGHTNESS:
if (GST_V4L_IS_OPEN(v4lelement))
gst_v4l_get_picture(v4lelement, V4L_PICTURE_BRIGHTNESS, &temp_i);
g_value_set_int(value, temp_i);
break;
case ARG_CONTRAST:
if (GST_V4L_IS_OPEN(v4lelement))
gst_v4l_get_picture(v4lelement, V4L_PICTURE_CONTRAST, &temp_i);
g_value_set_int(value, temp_i);
break;
case ARG_SATURATION:
if (GST_V4L_IS_OPEN(v4lelement))
gst_v4l_get_picture(v4lelement, V4L_PICTURE_SATURATION, &temp_i);
g_value_set_int(value, temp_i);
break;
case ARG_DEVICE:
g_value_set_string(value, v4lelement->videodev?v4lelement->videodev:"/dev/video");
break;
default:
//G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static GstElementStateReturn
gst_v4lelement_change_state (GstElement *element)
{
GstV4lElement *v4lelement;
g_return_val_if_fail(GST_IS_V4LELEMENT(element), FALSE);
v4lelement = GST_V4LELEMENT(element);
/* if going down into NULL state, close the device if it's open
* if going to READY, open the device (and set some options)
*/
switch (GST_STATE_PENDING(element))
{
case GST_STATE_NULL:
if (GST_V4L_IS_OPEN(v4lelement))
if (!gst_v4l_close(v4lelement))
return GST_STATE_FAILURE;
break;
case GST_STATE_READY:
if (!GST_V4L_IS_OPEN(v4lelement))
{
int n, temp;
if (!gst_v4l_open(v4lelement))
return GST_STATE_FAILURE;
/* now, sync options */
if (v4lelement->norm >= VIDEO_MODE_PAL &&
v4lelement->norm < VIDEO_MODE_AUTO &&
v4lelement->channel >= 0)
{
if (!gst_v4l_set_chan_norm(v4lelement, v4lelement->channel, v4lelement->norm))
return GST_STATE_FAILURE;
}
if (v4lelement->frequency > 0 && gst_v4l_has_tuner(v4lelement))
{
if (!gst_v4l_set_frequency(v4lelement, v4lelement->frequency))
return GST_STATE_FAILURE;
}
for (n=V4L_AUDIO_VOLUME;n<=V4L_AUDIO_MODE;n++)
{
switch (n)
{
case V4L_AUDIO_MUTE: temp = v4lelement->mute; break;
case V4L_AUDIO_VOLUME: temp = v4lelement->volume; break;
case V4L_AUDIO_MODE: temp = v4lelement->mode; break;
}
if (temp >= 0 && gst_v4l_has_audio(v4lelement))
{
if (!gst_v4l_set_audio(v4lelement, n, temp))
return GST_STATE_FAILURE;
}
}
for (n=V4L_PICTURE_HUE;n<=V4L_PICTURE_SATURATION;n++)
{
switch (n)
{
case V4L_PICTURE_HUE: temp = v4lelement->hue; break;
case V4L_PICTURE_BRIGHTNESS: temp = v4lelement->brightness; break;
case V4L_PICTURE_SATURATION: temp = v4lelement->saturation; break;
case V4L_PICTURE_CONTRAST: temp = v4lelement->contrast; break;
}
if (temp >= 0)
{
if (!gst_v4l_set_picture(v4lelement, n, temp))
return GST_STATE_FAILURE;
}
}
}
break;
default:
break;
}
if (GST_ELEMENT_CLASS(parent_class)->change_state)
return GST_ELEMENT_CLASS(parent_class)->change_state(element);
return GST_STATE_SUCCESS;
}
static gboolean
plugin_init (GModule *module,
GstPlugin *plugin)
{
#if 0
GstElementFactory *factory;
/* create an elementfactory for the v4lelement */
factory = gst_elementfactory_new("v4lelement",GST_TYPE_V4LELEMENT,
&gst_v4lelement_details);
g_return_val_if_fail(factory != NULL, FALSE);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
#endif
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"v4lelement",
plugin_init
};

84
sys/v4l/gstv4lelement.h Normal file
View file

@ -0,0 +1,84 @@
/* G-Streamer generic V4L element - generic V4L calls handling
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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 __GST_V4LELEMENT_H__
#define __GST_V4LELEMENT_H__
#include <config.h>
#include <gst/gst.h>
#include <sys/types.h>
#include <linux/videodev.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GST_TYPE_V4LELEMENT \
(gst_v4lelement_get_type())
#define GST_V4LELEMENT(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LELEMENT,GstV4lElement))
#define GST_V4LELEMENT_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LELEMENT,GstV4lElementClass))
#define GST_IS_V4LELEMENT(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LELEMENT))
#define GST_IS_V4LELEMENT_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LELEMENT))
typedef struct _GstV4lElement GstV4lElement;
typedef struct _GstV4lElementClass GstV4lElementClass;
struct _GstV4lElement {
GstElement element;
/* the video device */
char *videodev;
/* the video-device's file descriptor */
gint video_fd;
/* the video buffer (mmap()'ed) */
guint8 *buffer;
/* the video-device's capabilities */
struct video_capability vcap;
/* caching values */
gint channel;
gint norm;
gulong frequency;
gint mute;
gint volume;
gint mode;
gint brightness;
gint hue;
gint contrast;
gint saturation;
};
struct _GstV4lElementClass {
GstElementClass parent_class;
};
GType gst_v4lelement_get_type(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_V4LELEMENT_H__ */

488
sys/v4l/gstv4lmjpegsrc.c Normal file
View file

@ -0,0 +1,488 @@
/* G-Streamer hardware MJPEG video source plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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.
*/
#include <string.h>
#include "v4lmjpegsrc_calls.h"
static GstElementDetails gst_v4lmjpegsrc_details = {
"Video (video4linux/MJPEG) Source",
"Source/Video",
"Reads MJPEG-encoded frames from a zoran MJPEG/video4linux device",
VERSION,
"Ronald Bultje <rbultje@ronald.bitfreak.net>",
"(C) 2001",
};
/* V4lMjpegSrc signals and args */
enum {
/* FILL ME */
LAST_SIGNAL
};
/* arguments */
enum {
ARG_0,
ARG_X_OFFSET,
ARG_Y_OFFSET,
ARG_F_WIDTH,
ARG_F_HEIGHT,
ARG_H_DECIMATION,
ARG_V_DECIMATION,
ARG_WIDTH,
ARG_HEIGHT,
ARG_QUALITY,
ARG_NUMBUFS,
ARG_BUFSIZE
};
/* init functions */
static void gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass);
static void gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc);
/* pad/buffer functions */
static GstPadNegotiateReturn gst_v4lmjpegsrc_negotiate (GstPad *pad,
GstCaps **caps,
gpointer *user_data);
static GstCaps* gst_v4lmjpegsrc_create_caps (GstV4lMjpegSrc *v4lmjpegsrc);
static GstBuffer* gst_v4lmjpegsrc_get (GstPad *pad);
/* get/set params */
static void gst_v4lmjpegsrc_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gst_v4lmjpegsrc_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
/* state handling */
static GstElementStateReturn gst_v4lmjpegsrc_change_state (GstElement *element);
/* bufferpool functions */
static GstBuffer* gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
gint64 location,
gint size,
gpointer user_data);
static GstBuffer* gst_v4lmjpegsrc_buffer_copy (GstBuffer *srcbuf);
static void gst_v4lmjpegsrc_buffer_free (GstBuffer *buf);
static GstElementClass *parent_class = NULL;
//static guint gst_v4lmjpegsrc_signals[LAST_SIGNAL] = { 0 };
GType
gst_v4lmjpegsrc_get_type (void)
{
static GType v4lmjpegsrc_type = 0;
if (!v4lmjpegsrc_type) {
static const GTypeInfo v4lmjpegsrc_info = {
sizeof(GstV4lMjpegSrcClass),
NULL,
NULL,
(GClassInitFunc)gst_v4lmjpegsrc_class_init,
NULL,
NULL,
sizeof(GstV4lMjpegSrc),
0,
(GInstanceInitFunc)gst_v4lmjpegsrc_init,
NULL
};
v4lmjpegsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lMjpegSrc", &v4lmjpegsrc_info, 0);
}
return v4lmjpegsrc_type;
}
static void
gst_v4lmjpegsrc_class_init (GstV4lMjpegSrcClass *klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_X_OFFSET,
g_param_spec_int("x_offset","x_offset","x_offset",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_Y_OFFSET,
g_param_spec_int("y_offset","y_offset","y_offset",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_WIDTH,
g_param_spec_int("frame_width","frame_width","frame_width",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_F_HEIGHT,
g_param_spec_int("frame_height","frame_height","frame_height",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_H_DECIMATION,
g_param_spec_int("h_decimation","h_decimation","h_decimation",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_V_DECIMATION,
g_param_spec_int("v_decimation","v_decimation","v_decimation",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
g_param_spec_int("width","width","width",G_MININT,G_MAXINT,0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT,
g_param_spec_int("height","height","height",G_MININT,G_MAXINT,0,G_PARAM_READABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_QUALITY,
g_param_spec_int("quality","quality","quality",G_MININT,G_MAXINT,0,G_PARAM_WRITABLE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NUMBUFS,
g_param_spec_int("num_buffers","num_buffers","num_buffers",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BUFSIZE,
g_param_spec_int("buffer_size","buffer_size","buffer_size",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
gobject_class->set_property = gst_v4lmjpegsrc_set_property;
gobject_class->get_property = gst_v4lmjpegsrc_get_property;
gstelement_class->change_state = gst_v4lmjpegsrc_change_state;
}
static void
gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
{
v4lmjpegsrc->srcpad = gst_pad_new("src", GST_PAD_SRC);
gst_element_add_pad(GST_ELEMENT(v4lmjpegsrc), v4lmjpegsrc->srcpad);
gst_pad_set_get_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_get);
gst_pad_set_negotiate_function (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_negotiate);
v4lmjpegsrc->bufferpool = gst_buffer_pool_new();
gst_buffer_pool_set_buffer_new_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_new);
gst_buffer_pool_set_buffer_copy_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_copy);
gst_buffer_pool_set_buffer_free_function(v4lmjpegsrc->bufferpool, gst_v4lmjpegsrc_buffer_free);
gst_buffer_pool_set_user_data(v4lmjpegsrc->bufferpool, v4lmjpegsrc);
v4lmjpegsrc->frame_width = 0;
v4lmjpegsrc->frame_height = 0;
v4lmjpegsrc->x_offset = -1;
v4lmjpegsrc->y_offset = -1;
v4lmjpegsrc->horizontal_decimation = 4;
v4lmjpegsrc->vertical_decimation = 4;
v4lmjpegsrc->end_width = 0;
v4lmjpegsrc->end_height = 0;
v4lmjpegsrc->quality = 50;
v4lmjpegsrc->numbufs = 64;
v4lmjpegsrc->bufsize = 256 * 1024;
v4lmjpegsrc->init = TRUE;
}
static GstPadNegotiateReturn
gst_v4lmjpegsrc_negotiate (GstPad *pad,
GstCaps **caps,
gpointer *user_data)
{
GstV4lMjpegSrc *v4lmjpegsrc;
v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
if (!*caps) {
return GST_PAD_NEGOTIATE_FAIL;
}
else {
return GST_PAD_NEGOTIATE_AGREE;
}
return GST_PAD_NEGOTIATE_FAIL;
}
static GstCaps*
gst_v4lmjpegsrc_create_caps (GstV4lMjpegSrc *v4lmjpegsrc)
{
GstCaps *caps;
caps = GST_CAPS_NEW (
"v4lmjpegsrc_caps",
"video/jpeg",
"width", GST_PROPS_INT(v4lmjpegsrc->end_width),
"height", GST_PROPS_INT(v4lmjpegsrc->end_height)
);
return caps;
}
static GstBuffer*
gst_v4lmjpegsrc_get (GstPad *pad)
{
GstV4lMjpegSrc *v4lmjpegsrc;
GstBuffer *buf;
gint num;
g_return_val_if_fail (pad != NULL, NULL);
v4lmjpegsrc = GST_V4LMJPEGSRC (gst_pad_get_parent (pad));
if (v4lmjpegsrc->init) {
gst_pad_set_caps (v4lmjpegsrc->srcpad, gst_v4lmjpegsrc_create_caps (v4lmjpegsrc));
v4lmjpegsrc->init = FALSE;
}
else {
if (!gst_pad_get_caps (v4lmjpegsrc->srcpad) &&
!gst_pad_renegotiate (v4lmjpegsrc->srcpad)) {
return NULL;
}
}
buf = gst_buffer_new_from_pool(v4lmjpegsrc->bufferpool, 0, 0);
if (!buf)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Failed to create a new GstBuffer");
return NULL;
}
/* grab a frame from the device */
if (!gst_v4lmjpegsrc_grab_frame(v4lmjpegsrc, &num, &(GST_BUFFER_SIZE(buf))))
return NULL;
GST_BUFFER_DATA(buf) = gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, num);
buf->timestamp = v4lmjpegsrc->bsync.timestamp.tv_sec * 1000000000 +
v4lmjpegsrc->bsync.timestamp.tv_usec * 1000;
return buf;
}
static void
gst_v4lmjpegsrc_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GstV4lMjpegSrc *v4lmjpegsrc;
g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
v4lmjpegsrc = GST_V4LMJPEGSRC(object);
switch (prop_id) {
case ARG_X_OFFSET:
v4lmjpegsrc->x_offset = g_value_get_int(value);
break;
case ARG_Y_OFFSET:
v4lmjpegsrc->y_offset = g_value_get_int(value);
break;
case ARG_F_WIDTH:
v4lmjpegsrc->frame_width = g_value_get_int(value);
break;
case ARG_F_HEIGHT:
v4lmjpegsrc->frame_height = g_value_get_int(value);
break;
case ARG_H_DECIMATION:
v4lmjpegsrc->horizontal_decimation = g_value_get_int(value);
break;
case ARG_V_DECIMATION:
v4lmjpegsrc->vertical_decimation = g_value_get_int(value);
break;
case ARG_QUALITY:
v4lmjpegsrc->quality = g_value_get_int(value);
break;
case ARG_NUMBUFS:
v4lmjpegsrc->numbufs = g_value_get_int(value);
break;
case ARG_BUFSIZE:
v4lmjpegsrc->bufsize = g_value_get_int(value);
break;
default:
parent_class->set_property(object, prop_id, value, pspec);
break;
}
}
static void
gst_v4lmjpegsrc_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GstV4lMjpegSrc *v4lmjpegsrc;
g_return_if_fail(GST_IS_V4LMJPEGSRC(object));
v4lmjpegsrc = GST_V4LMJPEGSRC(object);
switch (prop_id) {
case ARG_WIDTH:
g_value_set_int(value, v4lmjpegsrc->end_width);
break;
case ARG_HEIGHT:
g_value_set_int(value, v4lmjpegsrc->end_height);
break;
case ARG_NUMBUFS:
g_value_set_int(value, v4lmjpegsrc->breq.count);
break;
case ARG_BUFSIZE:
g_value_set_int(value, v4lmjpegsrc->breq.size);
break;
default:
parent_class->get_property(object, prop_id, value, pspec);
break;
}
}
static GstElementStateReturn
gst_v4lmjpegsrc_change_state (GstElement *element)
{
GstV4lMjpegSrc *v4lmjpegsrc;
g_return_val_if_fail(GST_IS_V4LMJPEGSRC(element), FALSE);
v4lmjpegsrc = GST_V4LMJPEGSRC(element);
switch (GST_STATE_PENDING(element)) {
case GST_STATE_READY:
if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc))) {
/* stop capturing, unmap all buffers */
if (!gst_v4lmjpegsrc_capture_deinit(v4lmjpegsrc))
return GST_STATE_FAILURE;
}
break;
case GST_STATE_PAUSED:
if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc))) {
/* set buffer info */
if (!gst_v4lmjpegsrc_set_buffer(v4lmjpegsrc, v4lmjpegsrc->numbufs, v4lmjpegsrc->bufsize))
return GST_STATE_FAILURE;
/* set capture parameters and mmap the buffers */
if (!v4lmjpegsrc->frame_width && !v4lmjpegsrc->frame_height &&
v4lmjpegsrc->x_offset < 0 && v4lmjpegsrc->y_offset < 0 &&
v4lmjpegsrc->horizontal_decimation == v4lmjpegsrc->vertical_decimation)
{
if (!gst_v4lmjpegsrc_set_capture(v4lmjpegsrc,
v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->quality))
return GST_STATE_FAILURE;
}
else
{
if (!gst_v4lmjpegsrc_set_capture_m(v4lmjpegsrc,
v4lmjpegsrc->x_offset, v4lmjpegsrc->y_offset,
v4lmjpegsrc->frame_width, v4lmjpegsrc->frame_height,
v4lmjpegsrc->horizontal_decimation, v4lmjpegsrc->vertical_decimation,
v4lmjpegsrc->quality))
return GST_STATE_FAILURE;
}
v4lmjpegsrc->init = TRUE;
if (!gst_v4lmjpegsrc_capture_init(v4lmjpegsrc))
return GST_STATE_FAILURE;
}
else {
/* de-queue all queued buffers */
if (!gst_v4lmjpegsrc_capture_stop(v4lmjpegsrc))
return GST_STATE_FAILURE;
}
break;
case GST_STATE_PLAYING:
/* queue all buffer, start streaming capture */
if (!gst_v4lmjpegsrc_capture_start(v4lmjpegsrc))
return GST_STATE_FAILURE;
break;
}
if (GST_ELEMENT_CLASS(parent_class)->change_state)
return GST_ELEMENT_CLASS(parent_class)->change_state(element);
return GST_STATE_SUCCESS;
}
static GstBuffer*
gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
gint64 location,
gint size,
gpointer user_data)
{
GstBuffer *buffer;
buffer = gst_buffer_new();
if (!buffer) return NULL;
buffer->pool_private = user_data;
/* TODO: add interlacing info to buffer as metadata */
return buffer;
}
static GstBuffer*
gst_v4lmjpegsrc_buffer_copy (GstBuffer *srcbuf)
{
GstBuffer *buffer;
buffer = gst_buffer_new();
if (!buffer) return NULL;
GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
if (!GST_BUFFER_DATA(buffer)) return NULL;
GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
return buffer;
}
static void
gst_v4lmjpegsrc_buffer_free (GstBuffer *buf)
{
GstV4lMjpegSrc *v4lmjpegsrc = buf->pool_private;
int n;
for (n=0;n<v4lmjpegsrc->breq.count;n++)
if (GST_BUFFER_DATA(buf) == gst_v4lmjpegsrc_get_buffer(v4lmjpegsrc, n))
{
gst_v4lmjpegsrc_requeue_frame(v4lmjpegsrc, n);
return;
}
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Couldn't find the buffer");
}
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
{
GstElementFactory *factory;
/* create an elementfactory for the v4lmjpegsrcparse element */
factory = gst_elementfactory_new("v4lmjpegsrc",GST_TYPE_V4LMJPEGSRC,
&gst_v4lmjpegsrc_details);
g_return_val_if_fail(factory != NULL, FALSE);
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"v4lmjpegsrc",
plugin_init
};

86
sys/v4l/gstv4lmjpegsrc.h Normal file
View file

@ -0,0 +1,86 @@
/* G-Streamer hardware MJPEG video source plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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 __GST_V4LMJPEGSRC_H__
#define __GST_V4LMJPEGSRC_H__
#include <gstv4lelement.h>
#include <sys/time.h>
#include <videodev_mjpeg.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GST_TYPE_V4LMJPEGSRC \
(gst_v4lmjpegsrc_get_type())
#define GST_V4LMJPEGSRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrc))
#define GST_V4LMJPEGSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LMJPEGSRC,GstV4lMjpegSrcClass))
#define GST_IS_V4LMJPEGSRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LMJPEGSRC))
#define GST_IS_V4LMJPEGSRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LMJPEGSRC))
typedef struct _GstV4lMjpegSrc GstV4lMjpegSrc;
typedef struct _GstV4lMjpegSrcClass GstV4lMjpegSrcClass;
struct _GstV4lMjpegSrc {
GstV4lElement v4lelement;
/* pads */
GstPad *srcpad;
/* the bufferpool */
GstBufferPool *bufferpool;
/* buffer/capture info */
struct mjpeg_sync bsync;
struct mjpeg_requestbuffers breq;
/* caching values */
gint x_offset;
gint y_offset;
gint frame_width;
gint frame_height;
gint horizontal_decimation;
gint vertical_decimation;
gint end_width;
gint end_height;
gint quality;
gint numbufs;
gint bufsize;
gboolean init;
};
struct _GstV4lMjpegSrcClass {
GstV4lElementClass parent_class;
};
GType gst_v4lmjpegsrc_get_type(void);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __GST_V4LMJPEGSRC_H__ */

View file

@ -1,5 +1,5 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
/* G-Streamer BT8x8/V4L frame grabber plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -17,25 +17,18 @@
* Boston, MA 02111-1307, USA.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <sys/time.h>
#include "v4lsrc_calls.h"
//#define DEBUG_ENABLED
#include <gstv4lsrc.h>
#include <linux/videodev.h>
static GstElementDetails gst_v4lsrc_details = {
"Video (v4l) Source",
"Video (video4linux/raw) Source",
"Source/Video",
"Read from a Video for Linux capture device",
"Reads raw frames from a video4linux (BT8x8) device",
VERSION,
"Wim Taymans <wim.taymans@tvd.be>",
"(C) 2000",
"Ronald Bultje <rbultje@ronald.bitfreak.net>",
"(C) 2001",
};
/* V4lSrc signals and args */
@ -44,43 +37,51 @@ enum {
LAST_SIGNAL
};
/* arguments */
enum {
ARG_0,
ARG_WIDTH,
ARG_HEIGHT,
ARG_FORMAT,
ARG_TUNE,
ARG_TUNED,
ARG_INPUT,
ARG_NORM,
ARG_VOLUME,
ARG_MUTE,
ARG_AUDIO_MODE,
ARG_COLOR,
ARG_BRIGHT,
ARG_HUE,
ARG_CONTRAST,
ARG_DEVICE,
ARG_PALETTE
};
static void gst_v4lsrc_class_init (GstV4lSrcClass *klass);
static void gst_v4lsrc_init (GstV4lSrc *v4lsrc);
/* init functions */
static void gst_v4lsrc_class_init (GstV4lSrcClass *klass);
static void gst_v4lsrc_init (GstV4lSrc *v4lsrc);
static void gst_v4lsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
static void gst_v4lsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
/* pad/buffer functions */
static GstPadNegotiateReturn gst_v4lsrc_negotiate (GstPad *pad,
GstCaps **caps,
gpointer *user_data);
static GstCaps* gst_v4lsrc_create_caps (GstV4lSrc *v4lsrc);
static GstBuffer* gst_v4lsrc_get (GstPad *pad);
static GstElementStateReturn gst_v4lsrc_change_state (GstElement *element);
static void gst_v4lsrc_close_v4l (GstV4lSrc *src);
static gboolean gst_v4lsrc_open_v4l (GstV4lSrc *src);
/* get/set params */
static void gst_v4lsrc_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void gst_v4lsrc_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
static GstBuffer* gst_v4lsrc_get (GstPad *pad);
static GstPadNegotiateReturn gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data);
/* state handling */
static GstElementStateReturn gst_v4lsrc_change_state (GstElement *element);
static gboolean gst_v4lsrc_sync_parms (GstV4lSrc *v4lsrc);
/* bufferpool functions */
static GstBuffer* gst_v4lsrc_buffer_new (GstBufferPool *pool,
gint64 location,
gint size,
gpointer user_data);
static GstBuffer* gst_v4lsrc_buffer_copy (GstBuffer *srcbuf);
static void gst_v4lsrc_buffer_free (GstBuffer *buf);
static GstElementClass *parent_class = NULL;\
//static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 };
static GstElementClass *parent_class = NULL;
////static guint gst_v4lsrc_signals[LAST_SIGNAL] = { 0 };
GType
gst_v4lsrc_get_type (void)
@ -89,7 +90,8 @@ gst_v4lsrc_get_type (void)
if (!v4lsrc_type) {
static const GTypeInfo v4lsrc_info = {
sizeof(GstV4lSrcClass), NULL,
sizeof(GstV4lSrcClass),
NULL,
NULL,
(GClassInitFunc)gst_v4lsrc_class_init,
NULL,
@ -99,11 +101,12 @@ gst_v4lsrc_get_type (void)
(GInstanceInitFunc)gst_v4lsrc_init,
NULL
};
v4lsrc_type = g_type_register_static(GST_TYPE_ELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
v4lsrc_type = g_type_register_static(GST_TYPE_V4LELEMENT, "GstV4lSrc", &v4lsrc_info, 0);
}
return v4lsrc_type;
}
static void
gst_v4lsrc_class_init (GstV4lSrcClass *klass)
{
@ -113,54 +116,14 @@ gst_v4lsrc_class_init (GstV4lSrcClass *klass)
gobject_class = (GObjectClass*)klass;
gstelement_class = (GstElementClass*)klass;
parent_class = g_type_class_ref(GST_TYPE_ELEMENT);
parent_class = g_type_class_ref(GST_TYPE_V4LELEMENT);
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_WIDTH,
g_param_spec_int("width","width","width",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_param_spec_int("width","width","width",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HEIGHT,
g_param_spec_int("height","height","height",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_FORMAT,
g_param_spec_int("format","format","format",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TUNE,
g_param_spec_ulong("tune","tune","tune",
0,G_MAXULONG,0,G_PARAM_WRITABLE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_TUNED,
g_param_spec_boolean("tuned","tuned","tuned",
TRUE,G_PARAM_READABLE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_INPUT,
g_param_spec_int("input","input","input",
G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_NORM,
g_param_spec_int("norm","norm","norm",
G_MININT,G_MAXINT,0,G_PARAM_WRITABLE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_VOLUME,
g_param_spec_int("volume","volume","volume",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_MUTE,
g_param_spec_boolean("mute","mute","mute",
TRUE,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_AUDIO_MODE,
g_param_spec_int("mode","mode","mode",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_COLOR,
g_param_spec_int("color","color","color",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_BRIGHT,
g_param_spec_int("bright","bright","bright",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_HUE,
g_param_spec_int("hue","hue","hue",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_CONTRAST,
g_param_spec_int("contrast","contrast","contrast",
G_MININT,G_MAXINT,0,G_PARAM_READWRITE)); // CHECKME
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_DEVICE,
g_param_spec_string("device","device","device",
NULL, G_PARAM_READWRITE)); // CHECKME
g_param_spec_int("height","height","height",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
g_object_class_install_property(G_OBJECT_CLASS(klass), ARG_PALETTE,
g_param_spec_int("palette","palette","palette",G_MININT,G_MAXINT,0,G_PARAM_READWRITE));
gobject_class->set_property = gst_v4lsrc_set_property;
gobject_class->get_property = gst_v4lsrc_get_property;
@ -168,33 +131,38 @@ gst_v4lsrc_class_init (GstV4lSrcClass *klass)
gstelement_class->change_state = gst_v4lsrc_change_state;
}
static void
gst_v4lsrc_init (GstV4lSrc *v4lsrc)
{
v4lsrc->srcpad = gst_pad_new("src",GST_PAD_SRC);
gst_element_add_pad(GST_ELEMENT(v4lsrc),v4lsrc->srcpad);
v4lsrc->srcpad = gst_pad_new("src", GST_PAD_SRC);
gst_element_add_pad(GST_ELEMENT(v4lsrc), v4lsrc->srcpad);
gst_pad_set_get_function (v4lsrc->srcpad,gst_v4lsrc_get);
gst_pad_set_negotiate_function (v4lsrc->srcpad,gst_v4lsrc_negotiate);
gst_pad_set_get_function (v4lsrc->srcpad, gst_v4lsrc_get);
gst_pad_set_negotiate_function (v4lsrc->srcpad, gst_v4lsrc_negotiate);
v4lsrc->bufferpool = gst_buffer_pool_new();
gst_buffer_pool_set_buffer_new_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_new);
gst_buffer_pool_set_buffer_copy_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_copy);
gst_buffer_pool_set_buffer_free_function(v4lsrc->bufferpool, gst_v4lsrc_buffer_free);
gst_buffer_pool_set_user_data(v4lsrc->bufferpool, v4lsrc);
v4lsrc->palette = VIDEO_PALETTE_YUV420P;
v4lsrc->width = 160;
v4lsrc->height = 120;
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
/* if the destination cannot say what it wants, we give this */
v4lsrc->width = 100;
v4lsrc->height = 100;
v4lsrc->format = 0;
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 3;
// make a grbber
v4lsrc->grabber = grab_init();
v4lsrc->device = NULL;
v4lsrc->init = TRUE;
}
static GstPadNegotiateReturn
gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data)
gst_v4lsrc_negotiate (GstPad *pad,
GstCaps **caps,
gpointer *user_data)
{
GstV4lSrc *v4lsrc;
GST_DEBUG (0, "v4lsrc: negotiate %p\n", user_data);
v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
if (!*caps) {
@ -204,175 +172,181 @@ gst_v4lsrc_negotiate (GstPad *pad, GstCaps **caps, gpointer *user_data)
gint width, height;
gulong format;
GST_DEBUG (0, "%08lx\n", gst_caps_get_fourcc_int (*caps, "format"));
width = gst_caps_get_int (*caps, "width");
height = gst_caps_get_int (*caps, "height");
format = gst_caps_get_fourcc_int (*caps, "format");
g_print ("v4lsrc: got format %08lx\n", format);
format = gst_caps_get_fourcc_int (*caps, "format");
switch (format) {
case GST_MAKE_FOURCC ('R','G','B',' '):
{
gint depth, endianness, bpp;
gint depth;
depth = gst_caps_get_int (*caps, "depth");
bpp = gst_caps_get_int (*caps, "bpp");
endianness = gst_caps_get_int (*caps, "endianness");
GST_DEBUG (0, "%d\n", depth);
g_print ("v4lsrc: got depth %d, bpp %d, endianness %d\n", depth, bpp, endianness);
switch (depth) {
switch (depth) {
case 15:
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
VIDEO_RGB15_LE:
VIDEO_RGB15_BE);
v4lsrc->palette = VIDEO_PALETTE_RGB555;
v4lsrc->buffer_size = width * height * 2;
break;
case 16:
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
VIDEO_RGB16_LE:
VIDEO_RGB16_BE);
v4lsrc->palette = VIDEO_PALETTE_RGB565;
v4lsrc->buffer_size = width * height * 2;
break;
case 24:
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
VIDEO_BGR24:
VIDEO_RGB24);
v4lsrc->palette = VIDEO_PALETTE_RGB24;
v4lsrc->buffer_size = width * height * 3;
break;
case 32:
v4lsrc->format = (endianness == G_LITTLE_ENDIAN ?
VIDEO_BGR32:
VIDEO_RGB32);
v4lsrc->palette = VIDEO_PALETTE_RGB32;
v4lsrc->buffer_size = width * height * 4;
break;
default:
*caps = NULL;
return GST_PAD_NEGOTIATE_TRY;
}
break;
}
break;
}
case GST_MAKE_FOURCC ('I','4','2','0'):
v4lsrc->format = VIDEO_YUV420P;
v4lsrc->buffer_size = width * height +
width * height / 2;
break;
v4lsrc->palette = VIDEO_PALETTE_YUV420P;
v4lsrc->buffer_size = width * height * 1.5;
break;
case GST_MAKE_FOURCC ('U','Y','V','Y'):
if (G_BYTE_ORDER == G_BIG_ENDIAN) {
v4lsrc->format = VIDEO_YUV422;
v4lsrc->buffer_size = width * height * 2;
break;
}
else {
*caps = NULL;
return GST_PAD_NEGOTIATE_TRY;
}
v4lsrc->palette = VIDEO_PALETTE_UYVY; //YUV422?;
v4lsrc->buffer_size = width * height * 2;
break;
case GST_MAKE_FOURCC ('Y','U','Y','2'):
if (G_BYTE_ORDER == G_LITTLE_ENDIAN) {
v4lsrc->format = VIDEO_YUV422;
v4lsrc->buffer_size = width * height * 2;
break;
}
else {
*caps = NULL;
return GST_PAD_NEGOTIATE_TRY;
}
v4lsrc->palette = VIDEO_PALETTE_YUYV; //YUV422?;
v4lsrc->buffer_size = width * height * 2;
break;
/* TODO: add YUV4:2:2 planar and YUV4:2:0 packed, maybe also YUV4:1:1? */
default:
*caps = NULL;
return GST_PAD_NEGOTIATE_TRY;
}
/* if we get here, it's okay */
v4lsrc->width = width;
v4lsrc->height = height;
if (gst_v4lsrc_sync_parms (v4lsrc)) {
return GST_PAD_NEGOTIATE_AGREE;
}
else {
*caps = NULL;
return GST_PAD_NEGOTIATE_TRY;
}
return GST_PAD_NEGOTIATE_AGREE;
}
return GST_PAD_NEGOTIATE_FAIL;
}
static GstCaps*
gst_v4lsrc_create_caps (GstV4lSrc *src)
gst_v4lsrc_create_caps (GstV4lSrc *v4lsrc)
{
GstCaps *caps;
GstCaps *caps = NULL;
gulong fourcc = 0;
gint width, height;
width = src->width;
height = src->height;
switch (v4lsrc->palette) {
case VIDEO_PALETTE_RGB555:
case VIDEO_PALETTE_RGB565:
case VIDEO_PALETTE_RGB24:
case VIDEO_PALETTE_RGB32:
{
int depth=0, bpp=0;
switch (src->format) {
case VIDEO_RGB08:
case VIDEO_GRAY:
case VIDEO_LUT2:
case VIDEO_LUT4:
caps = NULL;
break;
case VIDEO_RGB15_LE:
case VIDEO_RGB16_LE:
case VIDEO_RGB15_BE:
case VIDEO_RGB16_BE:
case VIDEO_BGR24:
case VIDEO_BGR32:
case VIDEO_RGB24:
case VIDEO_RGB32:
caps = NULL;
break;
case VIDEO_YUV422:
case VIDEO_YUV422P:
case VIDEO_YUV420P: {
fourcc = GST_STR_FOURCC ("RGB ");
if (src->format == VIDEO_YUV422) {
fourcc = GST_STR_FOURCC ("YUY2");
src->buffer_size = width * height * 2;
switch (v4lsrc->palette) {
case VIDEO_PALETTE_RGB555:
depth = 15;
bpp = 2;
break;
case VIDEO_PALETTE_RGB565:
depth = 16;
bpp = 2;
break;
case VIDEO_PALETTE_RGB24:
depth = 24;
bpp = 3;
break;
case VIDEO_PALETTE_RGB32:
depth = 32;
bpp = 4;
break;
}
else if (src->format == VIDEO_YUV422P) {
fourcc = GST_STR_FOURCC ("YV12");
src->buffer_size = width * height * 2;
}
else if (src->format == VIDEO_YUV420P) {
fourcc = GST_STR_FOURCC ("I420");
src->buffer_size = width * height +
width * height / 2;
}
caps = GST_CAPS_NEW (
"v4lsrc_caps",
"video/raw",
"format", GST_PROPS_FOURCC (fourcc),
"width", GST_PROPS_INT (src->width),
"height", GST_PROPS_INT (src->height)
);
"v4lsrc_caps",
"video/raw",
"format", GST_PROPS_FOURCC (fourcc),
"width", GST_PROPS_INT (v4lsrc->width),
"height", GST_PROPS_INT (v4lsrc->height),
"bpp", GST_PROPS_INT (bpp),
"depth", GST_PROPS_INT (depth)
);
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * bpp;
break;
}
default:
caps = NULL;
case VIDEO_PALETTE_YUV422:
case VIDEO_PALETTE_YUV420P:
{
switch (v4lsrc->palette) {
case VIDEO_PALETTE_YUV422:
fourcc = (G_BYTE_ORDER == G_BIG_ENDIAN) ?
GST_STR_FOURCC("UYVY") : GST_STR_FOURCC("YUY2");
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
break;
case VIDEO_PALETTE_YUYV:
fourcc = GST_STR_FOURCC("YUY2");
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
break;
case VIDEO_PALETTE_UYVY:
fourcc = GST_STR_FOURCC("UYVY");
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 2;
break;
case VIDEO_PALETTE_YUV420P:
fourcc = GST_STR_FOURCC("I420");
v4lsrc->buffer_size = v4lsrc->width * v4lsrc->height * 1.5;
break;
}
caps = GST_CAPS_NEW (
"v4lsrc_caps",
"video/raw",
"format", GST_PROPS_FOURCC (fourcc),
"width", GST_PROPS_INT (v4lsrc->width),
"height", GST_PROPS_INT (v4lsrc->height)
);
break;
}
default:
return NULL;
}
return caps;
}
static GstBuffer*
gst_v4lsrc_get (GstPad *pad)
{
GstV4lSrc *v4lsrc;
GstBuffer *buf = NULL;
guint8 *grab_buf;
GstBuffer *buf;
gint num;
struct timeval timestamp;
g_return_val_if_fail (pad != NULL, NULL);
v4lsrc = GST_V4LSRC (gst_pad_get_parent (pad));
if (v4lsrc->format && v4lsrc->init) {
if (v4lsrc->init) {
gst_pad_set_caps (v4lsrc->srcpad, gst_v4lsrc_create_caps (v4lsrc));
v4lsrc->init = FALSE;
}
@ -383,172 +357,125 @@ gst_v4lsrc_get (GstPad *pad)
}
}
buf = gst_buffer_new();
GST_BUFFER_DATA(buf) = g_malloc(v4lsrc->buffer_size);
buf = gst_buffer_new_from_pool(v4lsrc->bufferpool, 0, 0);
if (!buf)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Failed to create a new GstBuffer");
return NULL;
}
/* grab a frame from the device */
if (!gst_v4lsrc_grab_frame(v4lsrc, &num))
return NULL;
gettimeofday(&timestamp, 0); /* TODO: threaded sync() */
GST_BUFFER_DATA(buf) = gst_v4lsrc_get_buffer(v4lsrc, num);
GST_BUFFER_SIZE(buf) = v4lsrc->buffer_size;
GST_DEBUG (0,"v4lsrc: making new buffer %p\n", GST_BUFFER_DATA(buf));
GST_DEBUG (0,"v4lsrc: request buffer\n");
// request a buffer from the grabber
grab_buf = v4lsrc->grabber->grab_capture(v4lsrc->grabber, 0);
//meta_pull->overlay_info->did_overlay = FALSE;
g_assert(buf != NULL);
GST_DEBUG (0,"v4lsrc: sending %d bytes in %p\n", GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
// copy the buffer
memcpy(GST_BUFFER_DATA(buf), grab_buf, GST_BUFFER_SIZE(buf));
GST_DEBUG (0,"v4lsrc: sent %d bytes in %p\n", GST_BUFFER_SIZE(buf), GST_BUFFER_DATA(buf));
buf->timestamp = timestamp.tv_sec * 1000000000 + timestamp.tv_usec * 1000;
return buf;
}
static void
gst_v4lsrc_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
{
GstV4lSrc *src;
int ret = 0;
/* it's not null if we got it, but it might not be ours */
static void
gst_v4lsrc_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GstV4lSrc *v4lsrc;
g_return_if_fail(GST_IS_V4LSRC(object));
src = GST_V4LSRC(object);
v4lsrc = GST_V4LSRC(object);
switch (prop_id) {
case ARG_WIDTH:
src->width = g_value_get_int (value);
gst_v4lsrc_sync_parms(src);
v4lsrc->width = g_value_get_int(value);
break;
case ARG_HEIGHT:
src->height = g_value_get_int (value);
gst_v4lsrc_sync_parms(src);
v4lsrc->height = g_value_get_int(value);
break;
case ARG_FORMAT:
src->format = g_value_get_int (value);
break;
case ARG_TUNE:
src->tune = g_value_get_ulong (value);
ret = src->grabber->grab_tune(src->grabber, src->tune);
break;
case ARG_INPUT:
src->input = g_value_get_int (value);
ret = src->grabber->grab_input(src->grabber, src->input, -1);
break;
case ARG_NORM:
src->norm = g_value_get_int (value);
ret = src->grabber->grab_input(src->grabber, -1, src->norm);
break;
case ARG_VOLUME:
src->volume = g_value_get_int (value);
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_VOLUME, src->volume);
break;
case ARG_MUTE:
src->mute = g_value_get_boolean (value);
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_MUTE, src->mute);
break;
case ARG_AUDIO_MODE:
src->audio_mode = g_value_get_int (value);
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_MODE, src->audio_mode);
break;
case ARG_COLOR:
src->color = g_value_get_int (value);
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_COLOR, src->color);
break;
case ARG_BRIGHT:
src->bright = g_value_get_int (value);
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_BRIGHT, src->bright);
break;
case ARG_HUE:
src->hue = g_value_get_int (value);
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_HUE, src->hue);
break;
case ARG_CONTRAST:
src->contrast = g_value_get_int (value);
ret = src->grabber->grab_setattr(src->grabber, GRAB_ATTR_CONTRAST, src->contrast);
break;
case ARG_DEVICE:
if (src->device)
g_free (src->device);
src->device = g_strdup (g_value_get_string (value));
case ARG_PALETTE:
v4lsrc->palette = g_value_get_int(value);
break;
default:
ret = -1;
parent_class->set_property(object, prop_id, value, pspec);
break;
}
if (ret == -1) {
fprintf(stderr, "v4lsrc: error setting property\n");
}
}
static void
gst_v4lsrc_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
gst_v4lsrc_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GstV4lSrc *src;
GstV4lSrc *v4lsrc;
/* it's not null if we got it, but it might not be ours */
g_return_if_fail(GST_IS_V4LSRC(object));
src = GST_V4LSRC(object);
g_print ("get arg\n");
v4lsrc = GST_V4LSRC(object);
switch (prop_id) {
case ARG_WIDTH:
g_value_set_int (value, src->width);
g_value_set_int(value, v4lsrc->mmap.width);
break;
case ARG_HEIGHT:
g_value_set_int (value, src->height);
g_value_set_int(value, v4lsrc->mmap.height);
break;
case ARG_TUNED:
g_value_set_boolean (value, src->grabber->grab_tuned(src->grabber));
break;
case ARG_VOLUME:
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_VOLUME));
break;
case ARG_MUTE:
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_MUTE));
break;
case ARG_AUDIO_MODE:
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_MODE));
break;
case ARG_COLOR:
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_COLOR));
break;
case ARG_BRIGHT:
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_BRIGHT));
break;
case ARG_HUE:
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_HUE));
break;
case ARG_CONTRAST:
g_value_set_int (value, src->grabber->grab_getattr(src->grabber, GRAB_ATTR_CONTRAST));
break;
case ARG_DEVICE:
g_value_set_string (value, src->device);
case ARG_PALETTE:
g_value_set_int(value, v4lsrc->mmap.format);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
parent_class->get_property(object, prop_id, value, pspec);
break;
}
}
static GstElementStateReturn
gst_v4lsrc_change_state (GstElement *element)
{
GstV4lSrc *v4lsrc;
g_return_val_if_fail(GST_IS_V4LSRC(element), FALSE);
v4lsrc = GST_V4LSRC(element);
/* if going down into NULL state, close the file if it's open */
if (GST_STATE_PENDING(element) == GST_STATE_NULL) {
if (GST_FLAG_IS_SET(element,GST_V4LSRC_OPEN))
gst_v4lsrc_close_v4l(GST_V4LSRC(element));
/* otherwise (READY or higher) we need to open the sound card */
} else {
gst_info ("v4lsrc: opening\n");
if (!GST_FLAG_IS_SET(element,GST_V4LSRC_OPEN)) {
if (!gst_v4lsrc_open_v4l(GST_V4LSRC(element))) {
gst_info ("v4lsrc: open failed\n");
return GST_STATE_FAILURE;
switch (GST_STATE_PENDING(element)) {
case GST_STATE_READY:
if (GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc))) {
/* stop capturing, unmap all buffers */
if (!gst_v4lsrc_capture_deinit(v4lsrc))
return GST_STATE_FAILURE;
}
}
break;
case GST_STATE_PAUSED:
if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc))) {
/* set capture parameters and mmap the buffers */
if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, v4lsrc->palette))
return GST_STATE_FAILURE;
v4lsrc->init = TRUE;
if (!gst_v4lsrc_capture_init(v4lsrc))
return GST_STATE_FAILURE;
}
else {
/* de-queue all queued buffers */
if (!gst_v4lsrc_capture_stop(v4lsrc))
return GST_STATE_FAILURE;
}
break;
case GST_STATE_PLAYING:
/* queue all buffer, start streaming capture */
if (!gst_v4lsrc_capture_start(v4lsrc))
return GST_STATE_FAILURE;
break;
}
if (GST_ELEMENT_CLASS(parent_class)->change_state)
@ -557,61 +484,67 @@ gst_v4lsrc_change_state (GstElement *element)
return GST_STATE_SUCCESS;
}
static gboolean
gst_v4lsrc_sync_parms (GstV4lSrc *src)
static GstBuffer*
gst_v4lsrc_buffer_new (GstBufferPool *pool,
gint64 location,
gint size,
gpointer user_data)
{
gint linelength;
gboolean success;
GstBuffer *buffer;
g_return_val_if_fail(src != NULL, FALSE);
g_return_val_if_fail(GST_IS_V4LSRC(src), FALSE);
buffer = gst_buffer_new();
if (!buffer) return NULL;
buffer->pool_private = user_data;
GST_DEBUG (0,"v4lsrc: resync %d %d %d\n", src->width, src->height, src->format);
/* TODO: add interlacing info to buffer as metadata (height>288 or 240 = topfieldfirst, else noninterlaced) */
if (!src->grabber->opened)
return FALSE;
if (src->grabber->grab_setparams(src->grabber, src->format, &src->width, &src->height, &linelength) != 0) {
fprintf(stderr, "v4lsrc: error setting params\n");
success = FALSE;
}
else {
GST_DEBUG (0,"v4lsrc: resynced to %d %d %d\n", src->width, src->height, src->buffer_size);
success = TRUE;
}
return success;
return buffer;
}
static gboolean
gst_v4lsrc_open_v4l (GstV4lSrc *src)
{
g_return_val_if_fail(src->grabber != NULL, FALSE);
g_return_val_if_fail(!src->grabber->opened, FALSE);
if (src->grabber->grab_open(src->grabber, src->device) != -1) {
gst_v4lsrc_sync_parms(src);
GST_FLAG_SET(src, GST_V4LSRC_OPEN);
return TRUE;
}
return FALSE;
static GstBuffer*
gst_v4lsrc_buffer_copy (GstBuffer *srcbuf)
{
GstBuffer *buffer;
buffer = gst_buffer_new();
if (!buffer) return NULL;
GST_BUFFER_DATA(buffer) = g_malloc(GST_BUFFER_SIZE(srcbuf));
if (!GST_BUFFER_DATA(buffer)) return NULL;
GST_BUFFER_SIZE(buffer) = GST_BUFFER_SIZE(srcbuf);
memcpy(GST_BUFFER_DATA(buffer), GST_BUFFER_DATA(srcbuf), GST_BUFFER_SIZE(srcbuf));
GST_BUFFER_TIMESTAMP(buffer) = GST_BUFFER_TIMESTAMP(srcbuf);
return buffer;
}
static void
gst_v4lsrc_close_v4l (GstV4lSrc *src)
gst_v4lsrc_buffer_free (GstBuffer *buf)
{
g_return_if_fail(src->grabber != NULL);
g_return_if_fail(src->grabber->opened);
GstV4lSrc *v4lsrc = buf->pool_private;
int n;
src->grabber->grab_close(src->grabber);
GST_FLAG_UNSET(src, GST_V4LSRC_OPEN);
for (n=0;n<v4lsrc->mbuf.frames;n++)
if (GST_BUFFER_DATA(buf) == gst_v4lsrc_get_buffer(v4lsrc, n))
{
gst_v4lsrc_requeue_frame(v4lsrc, n);
return;
}
gst_element_error(GST_ELEMENT(v4lsrc),
"Couldn't find the buffer");
}
static gboolean
plugin_init (GModule *module, GstPlugin *plugin)
plugin_init (GModule *module,
GstPlugin *plugin)
{
GstElementFactory *factory;
/* create an elementfactory for the v4lsrcparse element */
/* create an elementfactory for the v4lsrc */
factory = gst_elementfactory_new("v4lsrc",GST_TYPE_V4LSRC,
&gst_v4lsrc_details);
g_return_val_if_fail(factory != NULL, FALSE);
@ -620,10 +553,10 @@ plugin_init (GModule *module, GstPlugin *plugin)
return TRUE;
}
GstPluginDesc plugin_desc = {
GST_VERSION_MAJOR,
GST_VERSION_MINOR,
"v4lsrc",
plugin_init
};

View file

@ -1,5 +1,5 @@
/* Gnome-Streamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
/* G-Streamer BT8x8/V4L frame grabber plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -17,23 +17,15 @@
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_V4LSRC_H__
#define __GST_V4LSRC_H__
#include <config.h>
#include <gst/gst.h>
#include <linux/videodev.h>
#include "grab.h"
#include <gstv4lelement.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#define GST_TYPE_V4LSRC \
(gst_v4lsrc_get_type())
#define GST_V4LSRC(obj) \
@ -45,46 +37,36 @@ extern "C" {
#define GST_IS_V4LSRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LSRC))
// NOTE: per-element flags start with 16 for now
typedef enum {
GST_V4LSRC_OPEN = GST_ELEMENT_FLAG_LAST,
GST_V4LSRC_FLAG_LAST = GST_ELEMENT_FLAG_LAST+2,
} GstV4lSrcFlags;
typedef struct _GstV4lSrc GstV4lSrc;
typedef struct _GstV4lSrcClass GstV4lSrcClass;
struct _GstV4lSrc {
GstElement element;
GstV4lElement v4lelement;
/* pads */
GstPad *srcpad;
/* video device */
struct GRABBER *grabber;
/* bufferpool for the buffers we're gonna use */
GstBufferPool *bufferpool;
/* whether we need to reset the GstPad */
gboolean init;
/* capture/buffer info */
struct video_mmap mmap;
struct video_mbuf mbuf;
gint sync_frame;
gboolean *frame_queued;
guint buffer_size;
/* caching values */
gint width;
gint height;
guint16 format;
guint32 buffer_size;
gulong tune;
gboolean tuned;
gint input;
gint norm;
gint volume;
gboolean mute;
gint audio_mode;
gint color;
gint bright;
gint hue;
gint contrast;
gchar *device;
gint palette;
};
struct _GstV4lSrcClass {
GstElementClass parent_class;
GstV4lElementClass parent_class;
};
GType gst_v4lsrc_get_type(void);
@ -93,5 +75,4 @@ GType gst_v4lsrc_get_type(void);
}
#endif /* __cplusplus */
#endif /* __GST_V4LSRC_H__ */

573
sys/v4l/v4l_calls.c Normal file
View file

@ -0,0 +1,573 @@
/* G-Streamer generic V4L element - generic V4L calls handling
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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.
*/
//#define DEBUG
#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 "v4l_calls.h"
char *picture_name[] = { "Hue", "Brightness", "Contrast", "Saturation" };
char *audio_name[] = { "Volume", "Mute", "Mode" };
char *norm_name[] = { "PAL", "NTSC", "SECAM", "Autodetect" };
/******************************************************
* gst_v4l_get_capabilities():
* get the device's capturing capabilities
* return value: TRUE on success, FALSE on error
******************************************************/
static gboolean
gst_v4l_get_capabilities (GstV4lElement *v4lelement)
{
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_get_capabilities()\n");
#endif
GST_V4L_CHECK_OPEN(v4lelement);
if (ioctl(v4lelement->video_fd, VIDIOCGCAP, &(v4lelement->vcap)) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting \'%s\' capabilities: %s",
v4lelement->videodev, sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4l_open():
* open the video device (v4lelement->videodev)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_open (GstV4lElement *v4lelement)
{
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_open()\n");
#endif
GST_V4L_CHECK_NOT_OPEN(v4lelement);
GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
/* be sure we have a device */
if (!v4lelement->videodev)
v4lelement->videodev = g_strdup("/dev/video");
/* open the device */
v4lelement->video_fd = open(v4lelement->videodev, O_RDONLY);
if (!GST_V4L_IS_OPEN(v4lelement))
{
gst_element_error(GST_ELEMENT(v4lelement),
"Failed to open device (\'%s\'): %s",
v4lelement->videodev, sys_errlist[errno]);
return FALSE;
}
/* get capabilities */
if (!gst_v4l_get_capabilities(v4lelement))
{
close(v4lelement->video_fd);
v4lelement->video_fd = -1;
return FALSE;
}
gst_element_info(GST_ELEMENT(v4lelement),
"Opened device \'%s\' (\'%s\') successfully",
v4lelement->vcap.name, v4lelement->videodev);
return TRUE;
}
/******************************************************
* gst_v4l_close():
* close the video device (v4lelement->video_fd)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_close (GstV4lElement *v4lelement)
{
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_close()\n");
#endif
GST_V4L_CHECK_OPEN(v4lelement);
GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
close(v4lelement->video_fd);
v4lelement->video_fd = -1;
return TRUE;
}
/******************************************************
* gst_v4l_get_num_chans()
* return value: the numver of video input channels
******************************************************/
gint
gst_v4l_get_num_chans (GstV4lElement *v4lelement)
{
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_get_num_chans()\n");
#endif
GST_V4L_CHECK_OPEN(v4lelement);
return v4lelement->vcap.channels;
}
/******************************************************
* gst_v4l_get_chan_norm():
* get the currently active video-channel and it's
* norm (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO})
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_get_chan_norm (GstV4lElement *v4lelement,
gint *channel,
gint *norm)
{
struct video_channel vchan;
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_get_chan_norm()\n");
#endif
GST_V4L_CHECK_OPEN(v4lelement);
if (ioctl(v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting the channel/norm settings: %s",
sys_errlist[errno]);
return FALSE;
}
if (channel)
*channel = vchan.channel;
if (norm)
*norm = vchan.norm;
return TRUE;
}
/******************************************************
* gst_v4l_set_chan_norm():
* set a new active channel and it's norm
* (VIDEO_MODE_{PAL|NTSC|SECAM|AUTO})
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_set_chan_norm (GstV4lElement *v4lelement,
gint channel,
gint norm)
{
struct video_channel vchan;
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_set_chan_norm(), channel = %d, norm = %d (%s)\n",
channel, norm, norm_name[norm]);
#endif
GST_V4L_CHECK_OPEN(v4lelement);
GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
// if (ioctl(v4lelement->video_fd, VIDIOCGCHAN, &vchan) < 0)
// {
// gst_error("V4lElement - Error getting the channel/norm settings: %s",
// sys_errlist[errno]);
// return FALSE;
// }
vchan.channel = channel;
vchan.norm = norm;
if (ioctl(v4lelement->video_fd, VIDIOCSCHAN, &vchan) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting the channel/norm settings: %s",
sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4l_has_tuner():
* return value: TRUE if it has a tuner, else FALSE
******************************************************/
gboolean
gst_v4l_has_tuner (GstV4lElement *v4lelement)
{
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_has_tuner()\n");
#endif
GST_V4L_CHECK_OPEN(v4lelement);
return (v4lelement->vcap.type & VID_TYPE_TUNER);
}
/******************************************************
* gst_v4l_get_frequency():
* get the current frequency
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_get_frequency (GstV4lElement *v4lelement,
gulong *frequency)
{
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_get_frequency()\n");
#endif
GST_V4L_CHECK_OPEN(v4lelement);
if (!gst_v4l_has_tuner(v4lelement))
return FALSE;
if (ioctl(v4lelement->video_fd, VIDIOCGFREQ, frequency) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting tuner frequency: %s",
sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4l_set_frequency():
* set frequency
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_set_frequency (GstV4lElement *v4lelement,
gulong frequency)
{
#ifdef DEBUG
fprintf(stderr, "gst_v4l_set_frequency(), frequency = %ul\n",
frequency);
#endif
GST_V4L_CHECK_OPEN(v4lelement);
GST_V4L_CHECK_NOT_ACTIVE(v4lelement);
if (!gst_v4l_has_tuner(v4lelement))
return FALSE;
if (ioctl(v4lelement->video_fd, VIDIOCSFREQ, &frequency) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting tuner frequency: %s",
sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4l_get_picture():
* get a picture value
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_get_picture (GstV4lElement *v4lelement,
GstV4lPictureType type,
gint *value)
{
struct video_picture vpic;
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_get_picture(), type = %d (%s)\n",
type, picture_name[type]);
#endif
GST_V4L_CHECK_OPEN(v4lelement);
if (ioctl(v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting picture parameters: %s",
sys_errlist[errno]);
return FALSE;
}
switch (type)
{
case V4L_PICTURE_HUE:
*value = vpic.hue;
break;
case V4L_PICTURE_BRIGHTNESS:
*value = vpic.brightness;
break;
case V4L_PICTURE_CONTRAST:
*value = vpic.contrast;
break;
case V4L_PICTURE_SATURATION:
*value = vpic.colour;
break;
default:
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting picture parameters: unknown type %d",
type);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4l_set_picture():
* set a picture value
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_set_picture (GstV4lElement *v4lelement,
GstV4lPictureType type,
gint value)
{
struct video_picture vpic;
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_set_picture(), type = %d (%s), value = %d\n",
type, picture_name[type], value);
#endif
GST_V4L_CHECK_OPEN(v4lelement);
if (ioctl(v4lelement->video_fd, VIDIOCGPICT, &vpic) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting picture parameters: %s",
sys_errlist[errno]);
return FALSE;
}
switch (type)
{
case V4L_PICTURE_HUE:
vpic.hue = value;
break;
case V4L_PICTURE_BRIGHTNESS:
vpic.brightness = value;
break;
case V4L_PICTURE_CONTRAST:
vpic.contrast = value;
break;
case V4L_PICTURE_SATURATION:
vpic.colour = value;
break;
default:
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting picture parameters: unknown type %d",
type);
return FALSE;
}
if (ioctl(v4lelement->video_fd, VIDIOCSPICT, &vpic) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting picture parameters: %s",
sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4l_has_audio():
* return value: TRUE if it can do audio, else FALSE
******************************************************/
gboolean
gst_v4l_has_audio (GstV4lElement *v4lelement)
{
#ifdef DEBUG
fprintf(stderr, "V4L: gst_v4l_has_audio()\n");
#endif
GST_V4L_CHECK_OPEN(v4lelement);
return (v4lelement->vcap.audios > 0);
}
/******************************************************
* gst_v4l_get_audio():
* get some audio value
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_get_audio (GstV4lElement *v4lelement,
GstV4lAudioType type,
gint *value)
{
struct video_audio vau;
#ifdef DEBUG
fprintf(stderr, "V4L: v4l_gst_get_audio(), type = %d (%s)\n",
type, audio_name[type]);
#endif
GST_V4L_CHECK_OPEN(v4lelement);
if (!gst_v4l_has_audio(v4lelement))
return FALSE;
if (ioctl(v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting audio parameters: %s",
sys_errlist[errno]);
return FALSE;
}
switch (type)
{
case V4L_AUDIO_MUTE:
*value = (vau.flags & VIDEO_AUDIO_MUTE);
break;
case V4L_AUDIO_VOLUME:
*value = vau.volume;
break;
case V4L_AUDIO_MODE:
*value = vau.mode;
break;
default:
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting audio parameters: unknown type %d",
type);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4l_set_audio():
* set some audio value
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4l_set_audio (GstV4lElement *v4lelement,
GstV4lAudioType type,
gint value)
{
struct video_audio vau;
#ifdef DEBUG
fprintf(stderr, "V4L: v4l_gst_set_audio(), type = %d (%s), value = %d\n",
type, audio_name[type], value);
#endif
GST_V4L_CHECK_OPEN(v4lelement);
if (!gst_v4l_has_audio(v4lelement))
return FALSE;
if (ioctl(v4lelement->video_fd, VIDIOCGAUDIO, &vau) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error getting audio parameters: %s",
sys_errlist[errno]);
return FALSE;
}
switch (type)
{
case V4L_AUDIO_MUTE:
if (!(vau.flags & VIDEO_AUDIO_MUTABLE))
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting audio mute: (un)setting mute is not supported");
return FALSE;
}
if (value)
vau.flags |= VIDEO_AUDIO_MUTE;
else
vau.flags &= ~VIDEO_AUDIO_MUTE;
break;
case V4L_AUDIO_VOLUME:
if (!(vau.flags & VIDEO_AUDIO_VOLUME))
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting audio volume: setting volume is not supported");
return FALSE;
}
vau.volume = value;
break;
case V4L_AUDIO_MODE:
vau.mode = value;
break;
default:
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting audio parameters: unknown type %d",
type);
return FALSE;
}
if (ioctl(v4lelement->video_fd, VIDIOCSAUDIO, &vau) < 0)
{
gst_element_error(GST_ELEMENT(v4lelement),
"Error setting audio parameters: %s",
sys_errlist[errno]);
return FALSE;
}
return TRUE;
}

123
sys/v4l/v4l_calls.h Normal file
View file

@ -0,0 +1,123 @@
/* G-Streamer generic V4L element - generic V4L calls handling
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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 __V4L_CALLS_H__
#define __V4L_CALLS_H__
#include "gstv4lelement.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* simple check whether the device is open */
#define GST_V4L_IS_OPEN(v4lelement) \
(v4lelement->video_fd > 0)
/* check whether the device is 'active' */
#define GST_V4L_IS_ACTIVE(v4lelement) \
(v4lelement->buffer != NULL)
/* checks whether the current v4lelement has already been open()'ed or not */
#define GST_V4L_CHECK_OPEN(v4lelement) \
if (v4lelement->video_fd <= 0) \
{ \
gst_element_error(GST_ELEMENT(v4lelement), \
"Device is not open"); \
return FALSE; \
}
/* checks whether the current v4lelement is close()'ed or whether it is still open */
#define GST_V4L_CHECK_NOT_OPEN(v4lelement) \
if (v4lelement->video_fd != -1) \
{ \
gst_element_error(GST_ELEMENT(v4lelement), \
"Device is open"); \
return FALSE; \
}
/* checks whether we're in capture mode or not */
#define GST_V4L_CHECK_ACTIVE(v4lelement) \
if (v4lelement->buffer == NULL) \
{ \
gst_element_error(GST_ELEMENT(v4lelement), \
"Device is not in streaming mode"); \
return FALSE; \
}
/* checks whether we're out of capture mode or not */
#define GST_V4L_CHECK_NOT_ACTIVE(v4lelement) \
if (v4lelement->buffer != NULL) \
{ \
gst_element_error(GST_ELEMENT(v4lelement), \
"Device is in streaming mode"); \
return FALSE; \
}
typedef enum {
V4L_PICTURE_HUE,
V4L_PICTURE_BRIGHTNESS,
V4L_PICTURE_CONTRAST,
V4L_PICTURE_SATURATION,
} GstV4lPictureType;
extern char *picture_name[];
typedef enum {
V4L_AUDIO_VOLUME,
V4L_AUDIO_MUTE,
V4L_AUDIO_MODE, /* stereo, mono, ... (see videodev.h) */
} GstV4lAudioType;
extern char *audio_name[];
extern char *norm_name[];
/* open/close the device */
gboolean gst_v4l_open (GstV4lElement *v4lelement);
gboolean gst_v4l_close (GstV4lElement *v4lelement);
/* norm control (norm = VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) */
gint gst_v4l_get_num_chans (GstV4lElement *v4lelement);
gboolean gst_v4l_get_chan_norm (GstV4lElement *v4lelement, gint *channel, gint *norm);
gboolean gst_v4l_set_chan_norm (GstV4lElement *v4lelement, gint channel, gint norm);
/* frequency control */
gboolean gst_v4l_has_tuner (GstV4lElement *v4lelement);
gboolean gst_v4l_get_frequency (GstV4lElement *v4lelement, gulong *frequency);
gboolean gst_v4l_set_frequency (GstV4lElement *v4lelement, gulong frequency);
/* picture control */
gboolean gst_v4l_get_picture (GstV4lElement *v4lelement, GstV4lPictureType type, gint *value);
gboolean gst_v4l_set_picture (GstV4lElement *v4lelement, GstV4lPictureType type, gint value);
/* audio control */
gboolean gst_v4l_has_audio (GstV4lElement *v4lelement);
gboolean gst_v4l_get_audio (GstV4lElement *v4lelement, GstV4lAudioType type, gint *value);
gboolean gst_v4l_set_audio (GstV4lElement *v4lelement, GstV4lAudioType type, gint value);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __V4L_CALLS_H__ */

595
sys/v4l/v4lmjpegsrc_calls.c Normal file
View file

@ -0,0 +1,595 @@
/* G-Streamer hardware MJPEG video source plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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.
*/
//#define DEBUG
#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 "v4lmjpegsrc_calls.h"
/* On some systems MAP_FAILED seems to be missing */
#ifndef MAP_FAILED
#define MAP_FAILED ( (caddr_t) -1 )
#endif
char *input_name[] = { "Composite", "S-Video", "TV-Tuner", "Autodetect" };
/******************************************************
* gst_v4lmjpegsrc_queue_frame():
* queue a frame for capturing
* return value: TRUE on success, FALSE on error
******************************************************/
static gboolean
gst_v4lmjpegsrc_queue_frame (GstV4lMjpegSrc *v4lmjpegsrc,
gint num)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_queue_frame(), num = %d\n",
num);
#endif
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_QBUF_CAPT, &num) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error queueing a buffer (%d): %s",
num, sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_sync_next_frame():
* sync on the next frame for capturing
* return value: TRUE on success, FALSE on error
******************************************************/
static gboolean
gst_v4lmjpegsrc_sync_next_frame (GstV4lMjpegSrc *v4lmjpegsrc,
gint *num)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_sync_frame(), num = %d\n",
num);
#endif
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_SYNC, &(v4lmjpegsrc->bsync)) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error syncing on a buffer (%ld): %s",
v4lmjpegsrc->bsync.frame, sys_errlist[errno]);
return FALSE;
}
*num = v4lmjpegsrc->bsync.frame;
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_set_input_norm():
* set input/norm (includes autodetection), norm is
* VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_set_input_norm (GstV4lMjpegSrc *v4lmjpegsrc,
GstV4lMjpegInputType input,
gint norm)
{
struct mjpeg_status bstat;
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_input_norm(), input = %d (%s), norm = %d (%s)\n",
input, input_name[input], norm, norm_name[norm]);
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
if (input == V4L_MJPEG_INPUT_AUTO)
{
int n;
for (n=V4L_MJPEG_INPUT_COMPOSITE;n<V4L_MJPEG_INPUT_AUTO;n++)
{
gst_element_info(GST_ELEMENT(v4lmjpegsrc),
"Trying %s as input...",
input_name[n]);
bstat.input = n;
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_STATUS, &bstat) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error getting device status: %s",
sys_errlist[errno]);
return FALSE;
}
if (bstat.signal)
{
input = bstat.input;
if (norm == VIDEO_MODE_AUTO)
norm = bstat.norm;
gst_element_info(GST_ELEMENT(v4lmjpegsrc),
"Signal found: on input %s, norm %s",
input_name[bstat.input], norm_name[bstat.norm]);
break;
}
}
}
else if (norm == VIDEO_MODE_AUTO && input)
{
bstat.input = input;
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_STATUS, &bstat) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error getting device status: %s",
sys_errlist[errno]);
return FALSE;
}
if (bstat.signal)
{
norm = bstat.norm;
gst_element_info(GST_ELEMENT(v4lmjpegsrc),
"Norm %s detected on input %s",
norm_name[bstat.norm], input_name[input]);
}
else
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"No signal found on input %s",
input_name[input]);
return FALSE;
}
}
return gst_v4l_set_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), input, norm);
}
/******************************************************
* gst_v4lmjpegsrc_set_buffer():
* set buffer parameters (size/count)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_set_buffer (GstV4lMjpegSrc *v4lmjpegsrc,
gint numbufs,
gint bufsize)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_buffer(), numbufs = %d, bufsize = %d\n",
numbufs, bufsize);
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
v4lmjpegsrc->breq.size = bufsize;
v4lmjpegsrc->breq.count = numbufs;
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_set_capture():
* set capture parameters (simple)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_set_capture (GstV4lMjpegSrc *v4lmjpegsrc,
gint decimation,
gint quality)
{
int norm, input, mw;
struct mjpeg_params bparm;
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_capture(), decimation = %d, quality = %d\n",
decimation, quality);
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
gst_v4l_get_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), &input, &norm);
/* Query params for capture */
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS, &bparm) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error getting video parameters: %s",
sys_errlist[errno]);
return FALSE;
}
bparm.decimation = decimation;
bparm.quality = quality;
bparm.norm = norm;
bparm.input = input;
bparm.APP_len = 0; /* no JPEG markers - TODO: this is definately not right for decimation==1 */
mw = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth;
if (mw != 768 && mw != 640)
{
if (decimation == 1)
mw = 720;
else
mw = 704;
}
v4lmjpegsrc->end_width = mw / decimation;
v4lmjpegsrc->end_height = (norm==VIDEO_MODE_NTSC?480:576) / decimation;
/* TODO: interlacing */
/* Set params for capture */
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS, &bparm) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error setting video parameters: %s",
sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_set_capture_m():
* set capture parameters (advanced)
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean gst_v4lmjpegsrc_set_capture_m (GstV4lMjpegSrc *v4lmjpegsrc,
gint x_offset,
gint y_offset,
gint width,
gint height,
gint h_decimation,
gint v_decimation,
gint quality)
{
gint norm, input;
gint maxwidth;
struct mjpeg_params bparm;
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_set_capture_m(), x_offset = %d, y_offset = %d, "
"width = %d, height = %d, h_decimation = %d, v_decimation = %d, quality = %d\n",
x_offset, y_offset, width, height, h_decimation, v_decimation, quality);
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
gst_v4l_get_chan_norm(GST_V4LELEMENT(v4lmjpegsrc), &input, &norm);
if (GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth != 768 &&
GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth != 640)
maxwidth = 720;
else
maxwidth = GST_V4LELEMENT(v4lmjpegsrc)->vcap.maxwidth;
/* Query params for capture */
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_G_PARAMS, &bparm) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error getting video parameters: %s",
sys_errlist[errno]);
return FALSE;
}
bparm.decimation = 0;
bparm.quality = quality;
bparm.norm = norm;
bparm.input = input;
bparm.APP_len = 0; /* no JPEG markers - TODO: this is definately not right for decimation==1 */
if (width <= 0)
{
if (x_offset < 0) x_offset = 0;
width = (maxwidth==720&&h_decimation!=1)?704:maxwidth - 2*x_offset;
}
else
{
if (x_offset < 0)
x_offset = (maxwidth - width)/2;
}
if (height <= 0)
{
if (y_offset < 0) y_offset = 0;
height = (norm==VIDEO_MODE_NTSC)?480:576 - 2*y_offset;
}
else
{
if (y_offset < 0)
y_offset = ((norm==VIDEO_MODE_NTSC)?480:576 - height)/2;
}
if (width + x_offset > maxwidth)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Image width+offset (%d) bigger than maximum (%d)",
width + x_offset, maxwidth);
return FALSE;
}
if ((width%(bparm.HorDcm*16))!=0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Image width (%d) not multiple of %d (required for JPEG)",
width, bparm.HorDcm*16);
return FALSE;
}
if (height + y_offset > (norm==VIDEO_MODE_NTSC ? 480 : 576))
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Image height+offset (%d) bigger than maximum (%d)",
height + y_offset, (norm==VIDEO_MODE_NTSC ? 480 : 576));
return FALSE;
}
/* RJ: Image height must only be a multiple of 8, but geom_height
* is double the field height
*/
if ((height%(bparm.VerDcm*16))!=0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Image height (%d) not multiple of %d (required for JPEG)",
height, bparm.VerDcm*16);
return FALSE;
}
bparm.img_x = x_offset;
bparm.img_width = width;
bparm.img_y = y_offset;
bparm.img_height = height;
bparm.HorDcm = h_decimation;
bparm.VerDcm = (v_decimation==4) ? 2 : 1;
bparm.TmpDcm = (v_decimation==1) ? 1 : 2;
bparm.field_per_buff = (v_decimation==1) ? 2 : 1;
v4lmjpegsrc->end_width = width / h_decimation;
v4lmjpegsrc->end_width = height / v_decimation;
/* TODO: interlacing */
/* Set params for capture */
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_S_PARAMS, &bparm) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error setting video parameters: %s",
sys_errlist[errno]);
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_capture_init():
* initialize the capture system
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_capture_init (GstV4lMjpegSrc *v4lmjpegsrc)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_init()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
/* Request buffers */
if (ioctl(GST_V4LELEMENT(v4lmjpegsrc)->video_fd, MJPIOC_REQBUFS, &(v4lmjpegsrc->breq)) < 0)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error requesting video buffers: %s",
sys_errlist[errno]);
return FALSE;
}
gst_element_info(GST_ELEMENT(v4lmjpegsrc),
"Got %ld buffers of size %ld KB",
v4lmjpegsrc->breq.count, v4lmjpegsrc->breq.size/1024);
/* Map the buffers */
GST_V4LELEMENT(v4lmjpegsrc)->buffer = mmap(0, v4lmjpegsrc->breq.count * v4lmjpegsrc->breq.size,
PROT_READ, MAP_SHARED, GST_V4LELEMENT(v4lmjpegsrc)->video_fd, 0);
if (GST_V4LELEMENT(v4lmjpegsrc)->buffer == MAP_FAILED)
{
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Error mapping video buffers: %s",
sys_errlist[errno]);
GST_V4LELEMENT(v4lmjpegsrc)->buffer = NULL;
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_capture_start():
* start streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_capture_start (GstV4lMjpegSrc *v4lmjpegsrc)
{
int n;
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_start()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
/* queue'ing the buffers starts streaming capture */
for (n=0;n<v4lmjpegsrc->breq.count;n++)
if (!gst_v4lmjpegsrc_queue_frame(v4lmjpegsrc, n))
return FALSE;
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_grab_frame():
* grab one frame during streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_grab_frame (GstV4lMjpegSrc *v4lmjpegsrc,
gint *num,
gint *size)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_grab_frame()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
/* syncing on the buffer grabs it */
if (!gst_v4lmjpegsrc_sync_next_frame(v4lmjpegsrc, num))
return FALSE;
*size = v4lmjpegsrc->bsync.length;
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_get_buffer():
* get the memory address of a single buffer
* return value: TRUE on success, FALSE on error
******************************************************/
guint8 *
gst_v4lmjpegsrc_get_buffer (GstV4lMjpegSrc *v4lmjpegsrc,
gint num)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_get_buffer(), num = %d\n",
num);
#endif
if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
return NULL;
return GST_V4LELEMENT(v4lmjpegsrc)->buffer+(v4lmjpegsrc->breq.size*num);
}
/******************************************************
* gst_v4lmjpegsrc_requeue_frame():
* requeue a frame for capturing
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_requeue_frame (GstV4lMjpegSrc *v4lmjpegsrc,
gint num)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_requeue_frame(), num = %d\n",
num);
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
if (!gst_v4lmjpegsrc_queue_frame(v4lmjpegsrc, num))
return FALSE;
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_capture_stop():
* stop streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_capture_stop (GstV4lMjpegSrc *v4lmjpegsrc)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_stop()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
/* unqueue the buffers */
if (!gst_v4lmjpegsrc_queue_frame(v4lmjpegsrc, -1))
return FALSE;
return TRUE;
}
/******************************************************
* gst_v4lmjpegsrc_capture_deinit():
* deinitialize the capture system
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc *v4lmjpegsrc)
{
#ifdef DEBUG
fprintf(stderr, "V4LMJPEGSRC: gst_v4lmjpegsrc_capture_deinit()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lmjpegsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc));
/* unmap the buffer */
munmap(GST_V4LELEMENT(v4lmjpegsrc)->buffer, v4lmjpegsrc->breq.size * v4lmjpegsrc->breq.count);
GST_V4LELEMENT(v4lmjpegsrc)->buffer = NULL;
return TRUE;
}

View file

@ -0,0 +1,63 @@
/* G-Streamer hardware MJPEG video source plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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 __V4L_MJPEG_SRC_CALLS_H__
#define __V4L_MJPEG_SRC_CALLS_H__
#include "gstv4lmjpegsrc.h"
#include "v4l_calls.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef enum {
V4L_MJPEG_INPUT_COMPOSITE = 0,
V4L_MJPEG_INPUT_SVIDEO = 1,
V4L_MJPEG_INPUT_TVTUNER = 2,
V4L_MJPEG_INPUT_AUTO = 3,
} GstV4lMjpegInputType;
extern char *input_name[];
/* set input/norm (includes autodetection, norm = VIDEO_MODE_{PAL|NTSC|SECAM|AUTO}) */
gboolean gst_v4lmjpegsrc_set_input_norm (GstV4lMjpegSrc *v4lmjpegsrc, GstV4lMjpegInputType input, gint norm);
/* frame grabbing/capture */
gboolean gst_v4lmjpegsrc_set_buffer (GstV4lMjpegSrc *v4lmjpegsrc, gint numbufs, gint bufsize);
gboolean gst_v4lmjpegsrc_set_capture (GstV4lMjpegSrc *v4lmjpegsrc, gint decimation, gint quality);
gboolean gst_v4lmjpegsrc_set_capture_m (GstV4lMjpegSrc *v4lmjpegsrc,
gint x_offset, gint y_offset, gint width, gint height,
gint h_decimation, gint v_decimation, gint quality);
gboolean gst_v4lmjpegsrc_capture_init (GstV4lMjpegSrc *v4lmjpegsrc);
gboolean gst_v4lmjpegsrc_capture_start (GstV4lMjpegSrc *v4lmjpegsrc);
gboolean gst_v4lmjpegsrc_grab_frame (GstV4lMjpegSrc *v4lmjpegsrc, gint *num, gint *size);
guint8 * gst_v4lmjpegsrc_get_buffer (GstV4lMjpegSrc *v4lmjpegsrc, gint num);
gboolean gst_v4lmjpegsrc_requeue_frame (GstV4lMjpegSrc *v4lmjpegsrc, gint num);
gboolean gst_v4lmjpegsrc_capture_stop (GstV4lMjpegSrc *v4lmjpegsrc);
gboolean gst_v4lmjpegsrc_capture_deinit (GstV4lMjpegSrc *v4lmjpegsrc);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __V4L_MJPEG_SRC_CALLS_H__ */

338
sys/v4l/v4lsrc_calls.c Normal file
View file

@ -0,0 +1,338 @@
/* G-Streamer BT8x8/V4L frame grabber plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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.
*/
//#define DEBUG
#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 "v4lsrc_calls.h"
/* On some systems MAP_FAILED seems to be missing */
#ifndef MAP_FAILED
#define MAP_FAILED ( (caddr_t) -1 )
#endif
/******************************************************
* gst_v4lsrc_queue_frame():
* queue a frame for capturing
* return value: TRUE on success, FALSE on error
******************************************************/
static gboolean
gst_v4lsrc_queue_frame (GstV4lSrc *v4lsrc,
gint num)
{
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_queue_frame(), num = %d\n",
num);
#endif
v4lsrc->mmap.frame = num;
if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCMCAPTURE, &(v4lsrc->mmap)) < 0)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error queueing a buffer (%d): %s",
num, sys_errlist[errno]);
return FALSE;
}
v4lsrc->frame_queued[num] = TRUE;
return TRUE;
}
/******************************************************
* gst_v4lsrc_sync_frame():
* sync on a frame for capturing
* return value: TRUE on success, FALSE on error
******************************************************/
static gboolean
gst_v4lsrc_sync_next_frame (GstV4lSrc *v4lsrc,
gint *num)
{
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_sync_frame(), num = %d\n",
num);
#endif
*num = (v4lsrc->sync_frame + 1)%v4lsrc->mbuf.frames;
if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCSYNC, num) < 0)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error syncing on a buffer (%d): %s",
*num, sys_errlist[errno]);
return FALSE;
}
v4lsrc->frame_queued[*num] = FALSE;
return TRUE;
}
/******************************************************
* gst_v4lsrc_set_capture():
* set capture parameters, palette = VIDEO_PALETTE_*
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_set_capture (GstV4lSrc *v4lsrc,
gint width,
gint height,
gint palette)
{
#ifdef DBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_set_capture(), width = %d, height = %d, palette = %d\n",
width, height, palette);
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lsrc));
v4lsrc->mmap.width = width;
v4lsrc->mmap.height = height;
v4lsrc->mmap.format = palette;
return TRUE;
}
/******************************************************
* gst_v4lsrc_capture_init():
* initialize the capture system
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_capture_init (GstV4lSrc *v4lsrc)
{
int n;
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_init()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lsrc));
/* request buffer info */
if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCGMBUF, &(v4lsrc->mbuf)) < 0)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error getting buffer information: %s",
sys_errlist[errno]);
return FALSE;
}
gst_element_info(GST_ELEMENT(v4lsrc),
"Got %d buffers of size %d KB",
v4lsrc->mbuf.frames, v4lsrc->mbuf.size/(v4lsrc->mbuf.frames*1024));
/* keep trakc of queued buffers */
v4lsrc->frame_queued = (gint *) malloc(sizeof(gint) * v4lsrc->mbuf.frames);
if (!v4lsrc->frame_queued)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error creating buffer tracker: %s",
sys_errlist[errno]);
return FALSE;
}
for (n=0;n<v4lsrc->mbuf.frames;n++)
v4lsrc->frame_queued[n] = FALSE;
/* Map the buffers */
GST_V4LELEMENT(v4lsrc)->buffer = mmap(0, v4lsrc->mbuf.size,
PROT_READ, MAP_SHARED, GST_V4LELEMENT(v4lsrc)->video_fd, 0);
if (GST_V4LELEMENT(v4lsrc)->buffer == MAP_FAILED)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error mapping video buffers: %s",
sys_errlist[errno]);
GST_V4LELEMENT(v4lsrc)->buffer = NULL;
return FALSE;
}
return TRUE;
}
/******************************************************
* gst_v4lsrc_capture_start():
* start streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_capture_start (GstV4lSrc *v4lsrc)
{
int n;
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_start()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
/* queue all buffers, this starts streaming capture */
for (n=0;n<v4lsrc->mbuf.frames;n++)
if (!gst_v4lsrc_queue_frame(v4lsrc, n))
return FALSE;
v4lsrc->sync_frame = -1;
return TRUE;
}
/******************************************************
* gst_v4lsrc_grab_frame():
* capture one frame during streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_grab_frame (GstV4lSrc *v4lsrc, gint *num)
{
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_grab_frame()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
/* syncing on the buffer grabs it */
if (!gst_v4lsrc_sync_next_frame(v4lsrc, num))
return FALSE;
return TRUE;
}
/******************************************************
* gst_v4lsrc_get_buffer():
* get the address of the just-capture buffer
* return value: TRUE on success, FALSE on error
******************************************************/
guint8 *
gst_v4lsrc_get_buffer (GstV4lSrc *v4lsrc, gint num)
{
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_get_buffer(), num = %d\n",
num);
#endif
if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc)))
return NULL;
return GST_V4LELEMENT(v4lsrc)->buffer+v4lsrc->mbuf.offsets[num];
}
/******************************************************
* gst_v4lsrc_requeue_frame():
* re-queue a frame after we're done with the buffer
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_requeue_frame (GstV4lSrc *v4lsrc, gint num)
{
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_requeue_buffer(), num = %d\n",
num);
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
/* and let's queue the buffer */
if (!gst_v4lsrc_queue_frame(v4lsrc, num))
return FALSE;
return TRUE;
}
/******************************************************
* gst_v4lsrc_capture_stop():
* stop streaming capture
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_capture_stop (GstV4lSrc *v4lsrc)
{
int n, num;
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_stop()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
/* we actually need to sync on all queued buffers but not on the non-queued ones */
for (n=0;n<v4lsrc->mbuf.frames;n++)
while (v4lsrc->frame_queued[n])
if (!gst_v4lsrc_sync_next_frame(v4lsrc, &num))
return FALSE;
return TRUE;
}
/******************************************************
* gst_v4lsrc_capture_deinit():
* deinitialize the capture system
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc)
{
#ifdef DEBUG
fprintf(stderr, "V4LSRC: gst_v4lsrc_capture_deinit()\n");
#endif
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_ACTIVE(GST_V4LELEMENT(v4lsrc));
/* free buffer tracker */
free(v4lsrc->frame_queued);
/* unmap the buffer */
munmap(GST_V4LELEMENT(v4lsrc)->buffer, v4lsrc->mbuf.size);
GST_V4LELEMENT(v4lsrc)->buffer = NULL;
return TRUE;
}

46
sys/v4l/v4lsrc_calls.h Normal file
View file

@ -0,0 +1,46 @@
/* G-Streamer BT8x8/V4L frame grabber plugin
* Copyright (C) 2001 Ronald Bultje <rbultje@ronald.bitfreak.net>
*
* 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 __V4L_SRC_CALLS_H__
#define __V4L_SRC_CALLS_H__
#include "gstv4lsrc.h"
#include "v4l_calls.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* frame grabbing/capture (palette = VIDEO_PALETTE_* - see videodev.h) */
gboolean gst_v4lsrc_set_capture (GstV4lSrc *v4lsrc, gint width, gint height, gint palette);
gboolean gst_v4lsrc_capture_init (GstV4lSrc *v4lsrc);
gboolean gst_v4lsrc_capture_start (GstV4lSrc *v4lsrc);
gboolean gst_v4lsrc_grab_frame (GstV4lSrc *v4lsrc, gint *num);
guint8 * gst_v4lsrc_get_buffer (GstV4lSrc *v4lsrc, gint num);
gboolean gst_v4lsrc_requeue_frame (GstV4lSrc *v4lsrc, gint num);
gboolean gst_v4lsrc_capture_stop (GstV4lSrc *v4lsrc);
gboolean gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __V4L_SRC_CALLS_H__ */

118
sys/v4l/videodev_mjpeg.h Normal file
View file

@ -0,0 +1,118 @@
/* These are the MJPEG API extensions for the Video4Linux API,
first introduced by the Iomega Buz driver by Rainer Johanni
<rainer@johanni.de>
*/
/* This is identical with the mgavideo internal params struct,
please tell me if you change this struct here ! <gz@lysator.liu.se) */
struct mjpeg_params
{
/* The following parameters can only be queried */
int major_version; /* Major version number of driver */
int minor_version; /* Minor version number of driver */
/* Main control parameters */
int input; /* Input channel: 0 = Composite, 1 = S-VHS */
int norm; /* Norm: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
int decimation; /* decimation of captured video,
enlargement of video played back.
Valid values are 1, 2, 4 or 0.
0 is a special value where the user
has full control over video scaling */
/* The following parameters only have to be set if decimation==0,
for other values of decimation they provide the data how the image is captured */
int HorDcm; /* Horizontal decimation: 1, 2 or 4 */
int VerDcm; /* Vertical decimation: 1 or 2 */
int TmpDcm; /* Temporal decimation: 1 or 2,
if TmpDcm==2 in capture every second frame is dropped,
in playback every frame is played twice */
int field_per_buff; /* Number of fields per buffer: 1 or 2 */
int img_x; /* start of image in x direction */
int img_y; /* start of image in y direction */
int img_width; /* image width BEFORE decimation,
must be a multiple of HorDcm*16 */
int img_height; /* image height BEFORE decimation,
must be a multiple of VerDcm*8 */
/* --- End of parameters for decimation==0 only --- */
/* JPEG control parameters */
int quality; /* Measure for quality of compressed images.
Scales linearly with the size of the compressed images.
Must be beetween 0 and 100, 100 is a compression
ratio of 1:4 */
int odd_even; /* Which field should come first ???
This is more aptly named "top_first",
i.e. (odd_even==1) --> top-field-first */
int APPn; /* Number of APP segment to be written, must be 0..15 */
int APP_len; /* Length of data in JPEG APPn segment */
char APP_data[60]; /* Data in the JPEG APPn segment. */
int COM_len; /* Length of data in JPEG COM segment */
char COM_data[60]; /* Data in JPEG COM segment */
unsigned long jpeg_markers; /* Which markers should go into the JPEG output.
Unless you exactly know what you do, leave them untouched.
Inluding less markers will make the resulting code
smaller, but there will be fewer aplications
which can read it.
The presence of the APP and COM marker is
influenced by APP0_len and COM_len ONLY! */
#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
#define JPEG_MARKER_COM (1<<6) /* Comment segment */
#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */
int VFIFO_FB; /* Flag for enabling Video Fifo Feedback.
If this flag is turned on and JPEG decompressing
is going to the screen, the decompress process
is stopped every time the Video Fifo is full.
This enables a smooth decompress to the screen
but the video output signal will get scrambled */
/* Misc */
char reserved[312]; /* Makes 512 bytes for this structure */
};
struct mjpeg_requestbuffers
{
unsigned long count; /* Number of buffers for MJPEG grabbing */
unsigned long size; /* Size PER BUFFER in bytes */
};
struct mjpeg_sync
{
unsigned long frame; /* Frame (0 - n) for double buffer */
unsigned long length; /* number of code bytes in buffer (capture only) */
unsigned long seq; /* frame sequence number */
struct timeval timestamp; /* timestamp */
};
struct mjpeg_status
{
int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */
int signal; /* Returned: 1 if valid video signal detected */
int norm; /* Returned: VIDEO_MODE_PAL or VIDEO_MODE_NTSC */
int color; /* Returned: 1 if color signal detected */
};
/*
Private IOCTL to set up for displaying MJPEG
*/
#define MJPIOC_G_PARAMS _IOR ('v', BASE_VIDIOCPRIVATE+0, struct mjpeg_params)
#define MJPIOC_S_PARAMS _IOWR('v', BASE_VIDIOCPRIVATE+1, struct mjpeg_params)
#define MJPIOC_REQBUFS _IOWR('v', BASE_VIDIOCPRIVATE+2, struct mjpeg_requestbuffers)
#define MJPIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOCPRIVATE+3, int)
#define MJPIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOCPRIVATE+4, int)
#define MJPIOC_SYNC _IOR ('v', BASE_VIDIOCPRIVATE+5, struct mjpeg_sync)
#define MJPIOC_G_STATUS _IOWR('v', BASE_VIDIOCPRIVATE+6, struct mjpeg_status)