sys/v4l/: Add new v4ljpegsrc for handling the ov51x hacky "I'll give you jpeg inside rgb frames" driver.

Original commit message from CVS:
* sys/v4l/gstv4l.c: (plugin_init):
* sys/v4l/gstv4ljpegsrc.c: (gst_v4ljpegsrc_get_type),
(gst_v4ljpegsrc_base_init), (gst_v4ljpegsrc_class_init),
(gst_v4ljpegsrc_init), (gst_v4ljpegsrc_src_link),
(gst_v4ljpegsrc_getcaps), (gst_v4ljpegsrc_get):
* sys/v4l/gstv4ljpegsrc.h:
* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_open), (gst_v4lsrc_src_link):
* sys/v4l/v4l_calls.h:
* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_palette_name),
(gst_v4lsrc_get_fps):
* sys/v4l/v4lsrc_calls.h:
Add new v4ljpegsrc for handling the ov51x hacky "I'll give
you jpeg inside rgb frames" driver.
Don't error in the v4lsrc link function, just return
REFUSED.
This commit is contained in:
Jan Schmidt 2005-02-03 18:23:17 +00:00
parent 4aa442fcb4
commit 91d410ea19
9 changed files with 437 additions and 56 deletions

View file

@ -1,3 +1,20 @@
2005-02-04 Jan Schmidt <thaytan@mad.scientist.com>
* sys/v4l/gstv4l.c: (plugin_init):
* sys/v4l/gstv4ljpegsrc.c: (gst_v4ljpegsrc_get_type),
(gst_v4ljpegsrc_base_init), (gst_v4ljpegsrc_class_init),
(gst_v4ljpegsrc_init), (gst_v4ljpegsrc_src_link),
(gst_v4ljpegsrc_getcaps), (gst_v4ljpegsrc_get):
* sys/v4l/gstv4ljpegsrc.h:
* sys/v4l/gstv4lsrc.c: (gst_v4lsrc_open), (gst_v4lsrc_src_link):
* sys/v4l/v4l_calls.h:
* sys/v4l/v4lsrc_calls.c: (gst_v4lsrc_palette_name),
(gst_v4lsrc_get_fps):
* sys/v4l/v4lsrc_calls.h:
Add new v4ljpegsrc for handling the ov51x hacky "I'll give
you jpeg inside rgb frames" driver.
Don't error in the v4lsrc link function, just return
REFUSED.
2005-02-03 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* sys/qcam/gstqcamsrc.c: (gst_qcamsrc_change_state),

View file

@ -11,6 +11,7 @@ endif
libgstvideo4linux_la_SOURCES = \
gstv4lelement.c v4l_calls.c \
gstv4lsrc.c v4lsrc_calls.c \
gstv4ljpegsrc.c \
gstv4lmjpegsrc.c v4lmjpegsrc_calls.c \
gstv4lmjpegsink.c v4lmjpegsink_calls.c \
gstv4l.c \
@ -26,6 +27,7 @@ libgstvideo4linux_la_LDFLAGS = \
noinst_HEADERS = gstv4lelement.h v4l_calls.h \
gstv4lsrc.h v4lsrc_calls.h \
gstv4ljpegsrc.h \
gstv4lmjpegsrc.h v4lmjpegsrc_calls.h \
gstv4lmjpegsink.h v4lmjpegsink_calls.h \
videodev_mjpeg.h \

View file

@ -30,6 +30,7 @@
#include "gstv4lelement.h"
#include "gstv4lsrc.h"
#include "gstv4ljpegsrc.h"
#include "gstv4lmjpegsrc.h"
#include "gstv4lmjpegsink.h"
@ -44,6 +45,8 @@ plugin_init (GstPlugin * plugin)
GST_RANK_NONE, GST_TYPE_V4LELEMENT) ||
!gst_element_register (plugin, "v4lsrc",
GST_RANK_NONE, GST_TYPE_V4LSRC) ||
!gst_element_register (plugin, "v4ljpegsrc",
GST_RANK_NONE, GST_TYPE_V4LJPEGSRC) ||
!gst_element_register (plugin, "v4lmjpegsrc",
GST_RANK_NONE, GST_TYPE_V4LMJPEGSRC) ||
!gst_element_register (plugin, "v4lmjpegsink",

295
sys/v4l/gstv4ljpegsrc.c Normal file
View file

@ -0,0 +1,295 @@
/* GStreamer
*
* gstv4ljpegsrc.c: V4L source element for JPEG cameras
*
* Copyright (C) 2004-2005 Jan Schmidt <thaytan@mad.scientist.com>
*
* 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,
e Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <string.h>
#include <sys/time.h>
#include "gstv4ljpegsrc.h"
#include "v4lsrc_calls.h"
/* elementfactory information */
static GstElementDetails gst_v4ljpegsrc_details =
GST_ELEMENT_DETAILS ("Video (video4linux/raw) Jpeg Source",
"Source/Video",
"Reads jpeg frames from a video4linux (eg ov519) device",
"Jan Schmidt <thaytan@mad.scientist.com>");
GST_DEBUG_CATEGORY (v4ljpegsrc_debug);
#define GST_CAT_DEFAULT v4ljpegsrc_debug
/* init functions */
static void gst_v4ljpegsrc_base_init (gpointer g_class);
static void gst_v4ljpegsrc_class_init (GstV4lJpegSrcClass * klass);
static void gst_v4ljpegsrc_init (GstV4lJpegSrc * v4ljpegsrc);
/* buffer functions */
static GstPadLinkReturn gst_v4ljpegsrc_src_link (GstPad * pad,
const GstCaps * caps);
static GstCaps *gst_v4ljpegsrc_getcaps (GstPad * pad);
static GstData *gst_v4ljpegsrc_get (GstPad * pad);
static GstElementClass *parent_class = NULL;
GType
gst_v4ljpegsrc_get_type (void)
{
static GType v4ljpegsrc_type = 0;
if (!v4ljpegsrc_type) {
static const GTypeInfo v4ljpegsrc_info = {
sizeof (GstV4lJpegSrcClass),
gst_v4ljpegsrc_base_init,
NULL,
(GClassInitFunc) gst_v4ljpegsrc_class_init,
NULL,
NULL,
sizeof (GstV4lJpegSrc),
0,
(GInstanceInitFunc) gst_v4ljpegsrc_init,
NULL
};
v4ljpegsrc_type =
g_type_register_static (GST_TYPE_V4LSRC, "GstV4lJpegSrc",
&v4ljpegsrc_info, 0);
GST_DEBUG_CATEGORY_INIT (v4ljpegsrc_debug, "v4ljpegsrc", 0,
"V4L JPEG source element");
}
return v4ljpegsrc_type;
}
static void
gst_v4ljpegsrc_base_init (gpointer g_class)
{
GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
gst_element_class_set_details (gstelement_class, &gst_v4ljpegsrc_details);
}
static void
gst_v4ljpegsrc_class_init (GstV4lJpegSrcClass * klass)
{
parent_class = g_type_class_ref (GST_TYPE_V4LSRC);
}
static void
gst_v4ljpegsrc_init (GstV4lJpegSrc * v4ljpegsrc)
{
GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc);
GstPad *pad = v4lsrc->srcpad;
/*
* Stash away and then replace the getcaps and get functions on the src pad
*/
v4ljpegsrc->getfn = GST_RPAD_GETFUNC (pad);
v4ljpegsrc->getcapsfn = GST_RPAD_GETCAPSFUNC (pad);
gst_pad_set_get_function (v4lsrc->srcpad, gst_v4ljpegsrc_get);
gst_pad_set_getcaps_function (v4lsrc->srcpad, gst_v4ljpegsrc_getcaps);
gst_pad_set_link_function (v4lsrc->srcpad, gst_v4ljpegsrc_src_link);
}
static GstPadLinkReturn
gst_v4ljpegsrc_src_link (GstPad * pad, const GstCaps * vscapslist)
{
GstV4lJpegSrc *v4ljpegsrc;
GstV4lSrc *v4lsrc;
gint w, h, palette = -1;
gdouble fps;
GstStructure *structure;
gboolean was_capturing;
struct video_window *vwin;
v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
v4lsrc = GST_V4LSRC (v4ljpegsrc);
vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
was_capturing = v4lsrc->is_capturing;
/* in case the buffers are active (which means that we already
* did capsnego before and didn't clean up), clean up anyways */
if (GST_V4L_IS_ACTIVE (GST_V4LELEMENT (v4lsrc))) {
if (was_capturing) {
if (!gst_v4lsrc_capture_stop (v4lsrc))
return GST_PAD_LINK_REFUSED;
}
if (!gst_v4lsrc_capture_deinit (v4lsrc))
return GST_PAD_LINK_REFUSED;
} else if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
return GST_PAD_LINK_DELAYED;
}
structure = gst_caps_get_structure (vscapslist, 0);
gst_structure_get_int (structure, "width", &w);
gst_structure_get_int (structure, "height", &h);
gst_structure_get_double (structure, "framerate", &fps);
GST_DEBUG_OBJECT (v4ljpegsrc, "linking with %dx%d at %f fps", w, h, fps);
/* set framerate if it's not already correct */
if (fps != gst_v4lsrc_get_fps (v4lsrc)) {
int fps_index = fps / 15.0 * 16;
GST_DEBUG_OBJECT (v4ljpegsrc, "Trying to set fps index %d", fps_index);
/* set bits 16 to 21 to 0 */
vwin->flags &= (0x3F00 - 1);
/* set bits 16 to 21 to the index */
vwin->flags |= fps_index << 16;
if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
return GST_PAD_LINK_DELAYED;
}
}
/*
* Try to set the camera to capture RGB24
*/
palette = VIDEO_PALETTE_RGB24;
v4lsrc->buffer_size = w * h * 3;
GST_DEBUG_OBJECT (v4ljpegsrc, "trying to set_capture %dx%d, palette %d",
w, h, palette);
/* this only fills in v4lsrc->mmap values */
if (!gst_v4lsrc_set_capture (v4lsrc, w, h, palette)) {
GST_WARNING_OBJECT (v4ljpegsrc, "could not set_capture %dx%d, palette %d",
w, h, palette);
return GST_PAD_LINK_REFUSED;
}
/* first try the negotiated settings using try_capture */
if (!gst_v4lsrc_try_capture (v4lsrc, w, h, palette)) {
GST_DEBUG_OBJECT (v4ljpegsrc, "failed trying palette %d for %dx%d", palette,
w, h);
return GST_PAD_LINK_REFUSED;
}
if (!gst_v4lsrc_capture_init (v4lsrc))
return GST_PAD_LINK_REFUSED;
if (was_capturing || GST_STATE (v4lsrc) == GST_STATE_PLAYING) {
if (!gst_v4lsrc_capture_start (v4lsrc))
return GST_PAD_LINK_REFUSED;
}
return GST_PAD_LINK_OK;
}
static GstCaps *
gst_v4ljpegsrc_getcaps (GstPad * pad)
{
GstCaps *list;
GstV4lJpegSrc *v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
GstV4lSrc *v4lsrc = GST_V4LSRC (v4ljpegsrc);
struct video_capability *vcap = &GST_V4LELEMENT (v4lsrc)->vcap;
gfloat fps = 0.0;
if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc))) {
return gst_caps_new_any ();
}
if (!v4lsrc->autoprobe) {
/* FIXME: query current caps and return those, with _any appended */
return gst_caps_new_any ();
}
list = gst_caps_new_simple ("image/jpeg", NULL);
GST_DEBUG_OBJECT (v4ljpegsrc,
"Device reports w: %d-%d, h: %d-%d, fps: %f",
vcap->minwidth, vcap->maxwidth, vcap->minheight, vcap->maxheight, fps);
if (vcap->minwidth < vcap->maxwidth) {
gst_caps_set_simple (list, "width", GST_TYPE_INT_RANGE, vcap->minwidth,
vcap->maxwidth, NULL);
} else {
gst_caps_set_simple (list, "width", G_TYPE_INT, vcap->minwidth, NULL);
}
if (vcap->minheight < vcap->maxheight) {
gst_caps_set_simple (list, "height", GST_TYPE_INT_RANGE, vcap->minheight,
vcap->maxheight, NULL);
} else {
gst_caps_set_simple (list, "height", G_TYPE_INT, vcap->minheight, NULL);
}
if (v4lsrc->fps_list) {
GstStructure *structure = gst_caps_get_structure (list, 0);
gst_structure_set_value (structure, "framerate", v4lsrc->fps_list);
}
GST_DEBUG_OBJECT (v4ljpegsrc, "caps: %" GST_PTR_FORMAT, list);
return list;
}
static GstData *
gst_v4ljpegsrc_get (GstPad * pad)
{
GstV4lJpegSrc *v4ljpegsrc;
GstV4lSrc *v4lsrc;
GstData *data;
GstBuffer *buf;
GstBuffer *outbuf;
int jpeg_size;
g_return_val_if_fail (pad != NULL, NULL);
v4ljpegsrc = GST_V4LJPEGSRC (gst_pad_get_parent (pad));
v4lsrc = GST_V4LSRC (v4ljpegsrc);
/* Fetch from the v4lsrc class get fn. */
data = v4ljpegsrc->getfn (pad);
/* If not a buffer, return it unchanged */
if (!data || (!GST_IS_BUFFER (data)))
return data;
buf = GST_BUFFER (data);
/* Confirm that the buffer contains jpeg data */
/*
* Create a new subbuffer from the jpeg data
* The first 2 bytes in the buffer are the size of the jpeg data
*/
if (GST_BUFFER_SIZE (buf) > 2) {
jpeg_size = (int) (GST_READ_UINT16_LE (GST_BUFFER_DATA (buf))) * 8;
} else
jpeg_size = 0;
/* Check that the size is sensible */
if ((jpeg_size <= 0) || (jpeg_size > GST_BUFFER_SIZE (buf) - 2)) {
GST_ELEMENT_ERROR (v4ljpegsrc, STREAM, FORMAT, (NULL),
("Invalid non-jpeg frame from camera"));
return NULL;
}
GST_DEBUG_OBJECT (v4ljpegsrc, "Creating JPEG subbuffer of size %d",
jpeg_size);
outbuf = gst_buffer_create_sub (buf, 2, jpeg_size);
/* Copy timestamps onto the subbuffer */
gst_buffer_stamp (outbuf, buf);
/* Release the main buffer */
gst_buffer_unref (buf);
return GST_DATA (outbuf);
}

57
sys/v4l/gstv4ljpegsrc.h Normal file
View file

@ -0,0 +1,57 @@
/* GStreamer
*
* gstv4ljpegsrc.h: V4L video source element for JPEG cameras
*
* Copyright (C) 2001-2005 Jan Schmidt <thaytan@mad.scientist.com>
*
* 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_V4LJPEGSRC_H__
#define __GST_V4LJPEGSRC_H__
#include <gstv4lsrc.h>
G_BEGIN_DECLS
#define GST_TYPE_V4LJPEGSRC \
(gst_v4ljpegsrc_get_type())
#define GST_V4LJPEGSRC(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_V4LJPEGSRC,GstV4lJpegSrc))
#define GST_V4LJPEGSRC_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_V4LJPEGSRC,GstV4lJpegSrcClass))
#define GST_IS_V4LJPEGSRC(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_V4LJPEGSRC))
#define GST_IS_V4LJPEGSRC_CLASS(obj) \
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_V4LJPEGSRC))
typedef struct _GstV4lJpegSrc GstV4lJpegSrc;
typedef struct _GstV4lJpegSrcClass GstV4lJpegSrcClass;
struct _GstV4lJpegSrc
{
GstV4lSrc v4lsrc;
GstPadGetFunction getfn;
GstPadGetCapsFunction getcapsfn;
};
struct _GstV4lJpegSrcClass
{
GstV4lSrcClass parent_class;
};
GType gst_v4ljpegsrc_get_type (void);
G_END_DECLS
#endif /* __GST_V4LJPEGSRC_H__ */

View file

@ -29,11 +29,6 @@
#include "v4lsrc_calls.h"
#include <sys/ioctl.h>
/* FIXME: small cheat */
gboolean gst_v4l_set_window_properties (GstV4lElement * v4lelement);
gboolean gst_v4l_get_capabilities (GstV4lElement * v4lelement);
extern const char *v4l_palette_name[];
/* elementfactory information */
static GstElementDetails gst_v4lsrc_details =
GST_ELEMENT_DETAILS ("Video (video4linux/raw) Source",
@ -320,7 +315,7 @@ gst_v4lsrc_open (GstElement * element, const gchar * device)
if (!gst_v4lsrc_try_capture (v4lsrc, width, height, palette[i]))
continue;
GST_DEBUG_OBJECT (v4lsrc, "Added palette %d (%s) to supported list",
palette[i], v4l_palette_name[palette[i]]);
palette[i], gst_v4lsrc_palette_name (palette[i]));
v4lsrc->colourspaces = g_list_append (v4lsrc->colourspaces,
GINT_TO_POINTER (palette[i]));
}
@ -400,54 +395,6 @@ gst_v4lsrc_get_fps_list (GstV4lSrc * v4lsrc)
return NULL;
}
static gfloat
gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc)
{
gint norm;
gint fps_index;
gfloat fps;
struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
/* check if we have vwin window properties giving a framerate,
* as is done for webcams
* See http://www.smcc.demon.nl/webcam/api.html
* which is used for the Philips and qce-ga drivers */
fps_index = (vwin->flags >> 16) & 0x3F; /* 6 bit index for framerate */
/* webcams have a non-zero fps_index */
if (fps_index != 0) {
gfloat current_fps;
/* index of 16 corresponds to 15 fps */
current_fps = fps_index * 15.0 / 16;
GST_LOG_OBJECT (v4lsrc, "device reports fps of %.4f", current_fps);
return current_fps;
}
if (!(v4lsrc->syncmode == GST_V4LSRC_SYNC_MODE_FIXED_FPS) &&
v4lsrc->clock != NULL && v4lsrc->handled > 0) {
/* try to get time from clock master and calculate fps */
GstClockTime time =
gst_clock_get_time (v4lsrc->clock) - v4lsrc->substract_time;
return v4lsrc->handled * GST_SECOND / time;
}
/* if that failed ... */
if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc)))
return 0.;
if (!gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lsrc), NULL, &norm))
return 0.;
if (norm == VIDEO_MODE_NTSC)
fps = 30000 / 1001;
else
fps = 25.;
return fps;
}
static gboolean
gst_v4lsrc_src_convert (GstPad * pad,
GstFormat src_format,
@ -659,8 +606,7 @@ gst_v4lsrc_src_link (GstPad * pad, const GstCaps * vscapslist)
/* set bits 16 to 21 to the index */
vwin->flags |= fps_index << 16;
if (!gst_v4l_set_window_properties (GST_V4LELEMENT (v4lsrc))) {
GST_ELEMENT_ERROR (v4lsrc, RESOURCE, SETTINGS, (NULL),
("Could not set framerate of %f fps", fps));
return GST_PAD_LINK_REFUSED;
}
}

View file

@ -144,6 +144,10 @@ gboolean gst_v4l_set_audio (GstV4lElement *v4lelement,
GstV4lAudioType type,
gint value);
/* functions that v4lsrc needs */
gboolean gst_v4l_set_window_properties (GstV4lElement * v4lelement);
gboolean gst_v4l_get_capabilities (GstV4lElement * v4lelement);
#ifdef __cplusplus
}
#endif /* __cplusplus */

View file

@ -511,3 +511,57 @@ gst_v4lsrc_try_capture (GstV4lSrc * v4lsrc, gint width, gint height,
/* if we got here, it worked! woohoo, the format is supported! */
return TRUE;
}
const char *
gst_v4lsrc_palette_name (int i)
{
return v4l_palette_name[i];
}
gfloat
gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc)
{
gint norm;
gint fps_index;
gfloat fps;
struct video_window *vwin = &GST_V4LELEMENT (v4lsrc)->vwin;
/* check if we have vwin window properties giving a framerate,
* as is done for webcams
* See http://www.smcc.demon.nl/webcam/api.html
* which is used for the Philips and qce-ga drivers */
fps_index = (vwin->flags >> 16) & 0x3F; /* 6 bit index for framerate */
/* webcams have a non-zero fps_index */
if (fps_index != 0) {
gfloat current_fps;
/* index of 16 corresponds to 15 fps */
current_fps = fps_index * 15.0 / 16;
GST_LOG_OBJECT (v4lsrc, "device reports fps of %.4f", current_fps);
return current_fps;
}
if (!(v4lsrc->syncmode == GST_V4LSRC_SYNC_MODE_FIXED_FPS) &&
v4lsrc->clock != NULL && v4lsrc->handled > 0) {
/* try to get time from clock master and calculate fps */
GstClockTime time =
gst_clock_get_time (v4lsrc->clock) - v4lsrc->substract_time;
return v4lsrc->handled * GST_SECOND / time;
}
/* if that failed ... */
if (!GST_V4L_IS_OPEN (GST_V4LELEMENT (v4lsrc)))
return 0.;
if (!gst_v4l_get_chan_norm (GST_V4LELEMENT (v4lsrc), NULL, &norm))
return 0.;
if (norm == VIDEO_MODE_NTSC)
fps = 30000 / 1001;
else
fps = 25.;
return fps;
}

View file

@ -40,10 +40,13 @@ 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);
gfloat gst_v4lsrc_get_fps (GstV4lSrc * v4lsrc);
/* "the ugliest hack ever, now available at your local mirror" */
gboolean gst_v4lsrc_try_capture (GstV4lSrc *v4lsrc, gint width, gint height, gint palette);
/* For debug purposes, share the palette names */
const char *gst_v4lsrc_palette_name (int i);
#ifdef __cplusplus
}