mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-04 05:22:30 +00:00
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:
parent
940291a6d6
commit
ab228b7235
16 changed files with 3376 additions and 414 deletions
|
@ -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
22
sys/v4l/README
Normal 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
5
sys/v4l/TODO
Normal 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
479
sys/v4l/gstv4lelement.c
Normal 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
84
sys/v4l/gstv4lelement.h
Normal 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
488
sys/v4l/gstv4lmjpegsrc.c
Normal 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
86
sys/v4l/gstv4lmjpegsrc.h
Normal 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__ */
|
|
@ -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(×tamp, 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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
573
sys/v4l/v4l_calls.c
Normal 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
123
sys/v4l/v4l_calls.h
Normal 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
595
sys/v4l/v4lmjpegsrc_calls.c
Normal 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;
|
||||
}
|
63
sys/v4l/v4lmjpegsrc_calls.h
Normal file
63
sys/v4l/v4lmjpegsrc_calls.h
Normal 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
338
sys/v4l/v4lsrc_calls.c
Normal 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
46
sys/v4l/v4lsrc_calls.h
Normal 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
118
sys/v4l/videodev_mjpeg.h
Normal 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)
|
Loading…
Reference in a new issue