This patch fixes some issues caused by design issues in video4linux, adds some nicety to video4linux2 plugins and doe...

Original commit message from CVS:
This patch fixes some issues caused by design issues in video4linux, adds
some nicety to video4linux2 plugins and does some more evil stuff:
* video4linux doesn't tell us which formats are supported by a card, so
the only way to know this is by simply trying it out. This patch adds that.
* v4lmjpegsink didnt have a bufferpool yet - is integrated now.
* all copy() bufferpool functions have been removed since they're not needed.
* v4lmjpegsink doesnt have a free() function, because hen playing the frames,
all this is already handled. When the frame is not played, nothing has to
be done. In total, the function is not needed.
* adds a get_caps() function to v4l2src
* some minor crap
This commit is contained in:
Ronald S. Bultje 2002-09-20 09:28:46 +00:00
parent d9d0a69dec
commit 20538dadc9
7 changed files with 205 additions and 76 deletions

View file

@ -1,24 +1,14 @@
TODO list (short term):
=======================
* as soon as we've trashed Gtk-1.2, change 'gint palette'
to 'guint16 palette' in gstv4lsrc.[ch]
* v4lsrc: actually try the format out on capsnego
* all plugins: on try_set_caps(), loop try_set_caps() per caps
instead of using a multi-caps so we know the end-format
* all three: fix interlacing (not handled at all...)
* add overlay handling in v4lelement
* libgstrec
* avidemux: add events (seek)
* avimux: fps calculations (or make that a set/get_property()?)
* v4lsrc/v4lmjpegsrc/v4l2src: fix interlacing (not handled at all...)
TODO list (long term):
======================
* v4lmpegsrc (*hint* MPEG card needed *hint*)
* v4l2element && v4l2src
* v4l2sink
* BSD-videosrc (meteorsrc?)
* color correction (brightness, hue, etc.)
* gamma correction
* dxr3sink
Useful Documentation:
=====================

View file

@ -71,6 +71,12 @@ static void gst_v4lmjpegsink_get_property (GObject
static GstElementStateReturn gst_v4lmjpegsink_change_state (GstElement *element);
static void gst_v4lmjpegsink_set_clock (GstElement *element, GstClock *clock);
/* bufferpool functions */
static GstBuffer* gst_v4lmjpegsink_buffer_new (GstBufferPool *pool,
guint64 offset,
guint size,
gpointer user_data);
static GstCaps *capslist = NULL;
static GstPadTemplate *sink_template;
@ -174,6 +180,14 @@ gst_v4lmjpegsink_init (GstV4lMjpegSink *v4lmjpegsink)
v4lmjpegsink->bufsize = 256;
GST_FLAG_SET(v4lmjpegsink, GST_ELEMENT_THREAD_SUGGESTED);
v4lmjpegsink->bufferpool = gst_buffer_pool_new(
NULL,
NULL,
gst_v4lmjpegsink_buffer_new,
NULL,
NULL,
v4lmjpegsink);
}
@ -259,20 +273,28 @@ gst_v4lmjpegsink_chain (GstPad *pad,
gst_element_clock_wait(GST_ELEMENT(v4lmjpegsink), v4lmjpegsink->clock, GST_BUFFER_TIMESTAMP(buf), NULL);
}
/* check size */
if (GST_BUFFER_SIZE(buf) > v4lmjpegsink->breq.size)
if (GST_BUFFER_POOL(buf) == v4lmjpegsink->bufferpool)
{
gst_element_error(GST_ELEMENT(v4lmjpegsink),
"Buffer too big (%d KB), max. buffersize is %d KB",
GST_BUFFER_SIZE(buf)/1024, v4lmjpegsink->breq.size/1024);
return;
num = GPOINTER_TO_INT(GST_BUFFER_POOL_PRIVATE(buf));
gst_v4lmjpegsink_play_frame(v4lmjpegsink, num);
}
else
{
/* check size */
if (GST_BUFFER_SIZE(buf) > v4lmjpegsink->breq.size)
{
gst_element_error(GST_ELEMENT(v4lmjpegsink),
"Buffer too big (%d KB), max. buffersize is %d KB",
GST_BUFFER_SIZE(buf)/1024, v4lmjpegsink->breq.size/1024);
return;
}
/* put JPEG data to the device */
gst_v4lmjpegsink_wait_frame(v4lmjpegsink, &num);
memcpy(gst_v4lmjpegsink_get_buffer(v4lmjpegsink, num),
GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
gst_v4lmjpegsink_play_frame(v4lmjpegsink, num);
/* put JPEG data to the device */
gst_v4lmjpegsink_wait_frame(v4lmjpegsink, &num);
memcpy(gst_v4lmjpegsink_get_buffer(v4lmjpegsink, num),
GST_BUFFER_DATA(buf), GST_BUFFER_SIZE(buf));
gst_v4lmjpegsink_play_frame(v4lmjpegsink, num);
}
g_signal_emit(G_OBJECT(v4lmjpegsink),gst_v4lmjpegsink_signals[SIGNAL_FRAME_DISPLAYED],0);
@ -280,6 +302,43 @@ gst_v4lmjpegsink_chain (GstPad *pad,
}
static GstBuffer *
gst_v4lmjpegsink_buffer_new (GstBufferPool *pool,
guint64 offset,
guint size,
gpointer user_data)
{
GstV4lMjpegSink *v4lmjpegsink = GST_V4LMJPEGSINK(user_data);
GstBuffer *buffer = NULL;
guint8 *data;
gint num;
if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsink)))
return NULL;
if (v4lmjpegsink->breq.size < size) {
GST_DEBUG(GST_CAT_PLUGIN_INFO, "Requested buffer size is too large (%d > %ld)",
size, v4lmjpegsink->breq.size);
return NULL;
}
if (!gst_v4lmjpegsink_wait_frame(v4lmjpegsink, &num))
return NULL;
data = gst_v4lmjpegsink_get_buffer(v4lmjpegsink, num);
if (!data)
return NULL;
buffer = gst_buffer_new();
GST_BUFFER_DATA(buffer) = data;
GST_BUFFER_MAXSIZE(buffer) = v4lmjpegsink->breq.size;
GST_BUFFER_SIZE(buffer) = size;
GST_BUFFER_POOL(buffer) = pool;
GST_BUFFER_POOL_PRIVATE(buffer) = GINT_TO_POINTER(num);
/* with this flag set, we don't need our own buffer_free() function */
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
return buffer;
}
static void
gst_v4lmjpegsink_set_property (GObject *object,
guint prop_id,

View file

@ -68,6 +68,9 @@ struct _GstV4lMjpegSink {
pthread_cond_t *cond_queued_frames;
gint current_frame;
/* something to get our buffers from */
GstBufferPool *bufferpool;
/* width/height/norm of the jpeg stream */
gint width;
gint height;

View file

@ -86,9 +86,6 @@ static GstBuffer* gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
guint64 location,
guint size,
gpointer user_data);
static GstBuffer* gst_v4lmjpegsrc_buffer_copy (GstBufferPool *pool,
const GstBuffer *srcbuf,
gpointer user_data);
static void gst_v4lmjpegsrc_buffer_free (GstBufferPool *pool,
GstBuffer *buf,
gpointer user_data);
@ -195,7 +192,7 @@ gst_v4lmjpegsrc_init (GstV4lMjpegSrc *v4lmjpegsrc)
NULL,
NULL,
gst_v4lmjpegsrc_buffer_new,
gst_v4lmjpegsrc_buffer_copy,
NULL,
gst_v4lmjpegsrc_buffer_free,
v4lmjpegsrc);
@ -553,28 +550,18 @@ gst_v4lmjpegsrc_buffer_new (GstBufferPool *pool,
gpointer user_data)
{
GstBuffer *buffer;
GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC(user_data);
if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lmjpegsrc)))
return NULL;
buffer = gst_buffer_new();
if (!buffer) return NULL;
if (!buffer)
return NULL;
/* TODO: add interlacing info to buffer as metadata */
return buffer;
}
static GstBuffer*
gst_v4lmjpegsrc_buffer_copy (GstBufferPool *pool, const GstBuffer *srcbuf, gpointer user_data)
{
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);
GST_BUFFER_MAXSIZE(buffer) = v4lmjpegsrc->breq.size;
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
return buffer;
}
@ -586,15 +573,22 @@ gst_v4lmjpegsrc_buffer_free (GstBufferPool *pool, GstBuffer *buf, gpointer user_
GstV4lMjpegSrc *v4lmjpegsrc = GST_V4LMJPEGSRC (user_data);
int n;
if (gst_element_get_state(GST_ELEMENT(v4lmjpegsrc)) != GST_STATE_PLAYING)
return; /* we've already cleaned up ourselves */
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;
break;
}
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Couldn't find the buffer");
if (n == v4lmjpegsrc->breq.count)
gst_element_error(GST_ELEMENT(v4lmjpegsrc),
"Couldn't find the buffer");
/* free the buffer struct et all */
gst_buffer_default_free(buf);
}

View file

@ -82,9 +82,6 @@ static GstBuffer* gst_v4lsrc_buffer_new (GstBufferPool *pool,
guint64 offset,
guint size,
gpointer user_data);
static GstBuffer* gst_v4lsrc_buffer_copy (GstBufferPool *pool,
const GstBuffer *srcbuf,
gpointer user_data);
static void gst_v4lsrc_buffer_free (GstBufferPool *pool,
GstBuffer *buf,
gpointer user_data);
@ -172,7 +169,7 @@ gst_v4lsrc_init (GstV4lSrc *v4lsrc)
NULL,
NULL,
gst_v4lsrc_buffer_new,
gst_v4lsrc_buffer_copy,
NULL,
gst_v4lsrc_buffer_free,
v4lsrc);
@ -388,9 +385,8 @@ gst_v4lsrc_srcconnect (GstPad *pad,
/* if this caps was useful, try it out */
try_caps:
/* TODO: try the current 'palette' out on the video device */
if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, palette))
/* try the current 'palette' out on the video device */
if (!gst_v4lsrc_try_palette(v4lsrc, palette))
continue;
/* try to connect the pad/caps with the actual width/height */
@ -428,6 +424,9 @@ gst_v4lsrc_srcconnect (GstPad *pad,
else if (ret_val == GST_PAD_CONNECT_DELAYED)
return GST_PAD_CONNECT_DELAYED;
if (!gst_v4lsrc_set_capture(v4lsrc, v4lsrc->width, v4lsrc->height, palette))
return GST_PAD_CONNECT_REFUSED;
if (!gst_v4lsrc_capture_init(v4lsrc))
return GST_PAD_CONNECT_REFUSED;
@ -616,27 +615,19 @@ gst_v4lsrc_buffer_new (GstBufferPool *pool,
gpointer user_data)
{
GstBuffer *buffer;
GstV4lSrc *v4lsrc = GST_V4LSRC(user_data);
if (!GST_V4L_IS_ACTIVE(GST_V4LELEMENT(v4lsrc)))
return NULL;
buffer = gst_buffer_new();
if (!buffer) return NULL;
/* TODO: add interlacing info to buffer as metadata (height>288 or 240 = topfieldfirst, else noninterlaced) */
if (!buffer)
return NULL;
return buffer;
}
static GstBuffer*
gst_v4lsrc_buffer_copy (GstBufferPool *pool, const GstBuffer *srcbuf, gpointer user_data)
{
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);
/* TODO: add interlacing info to buffer as metadata
* (height>288 or 240 = topfieldfirst, else noninterlaced) */
GST_BUFFER_MAXSIZE(buffer) = v4lsrc->mbuf.size / v4lsrc->mbuf.frames;
GST_BUFFER_FLAG_SET(buffer, GST_BUFFER_DONTFREE);
return buffer;
}
@ -648,15 +639,22 @@ gst_v4lsrc_buffer_free (GstBufferPool *pool, GstBuffer *buf, gpointer user_data)
GstV4lSrc *v4lsrc = GST_V4LSRC (user_data);
int n;
if (gst_element_get_state(GST_ELEMENT(v4lsrc)) != GST_STATE_PLAYING)
return; /* we've already cleaned up ourselves */
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;
break;
}
gst_element_error(GST_ELEMENT(v4lsrc),
"Couldn\'t find the buffer");
if (n == v4lsrc->mbuf.frames)
gst_element_error(GST_ELEMENT(v4lsrc),
"Couldn\'t find the buffer");
/* free struct */
gst_buffer_default_free(buf);
}

View file

@ -493,3 +493,85 @@ gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc)
return TRUE;
}
/******************************************************
* gst_v4lsrc_try_palette():
* try out a palette on the device
* This has to be done before initializing the
* actual capture system, to make sure we don't
* mess up anything. So we need to mini-mmap()
* a buffer here, queue and sync on one buffer,
* and unmap it.
* This is ugly, yes, I know - but it's a major
* design flaw of v4l1 that you don't know in
* advance which formats will be supported...
* This is better than "just assuming that it'll
* work"...
* return value: TRUE on success, FALSE on error
******************************************************/
gboolean
gst_v4lsrc_try_palette (GstV4lSrc *v4lsrc,
gint palette)
{
/* so, we need a buffer and some more stuff */
int frame = 0;
guint8 *buffer;
struct video_mbuf vmbuf;
struct video_mmap vmmap;
DEBUG("gonna try out palette format %d (%s)",
palette, palette_name[palette]);
GST_V4L_CHECK_OPEN(GST_V4LELEMENT(v4lsrc));
GST_V4L_CHECK_NOT_ACTIVE(GST_V4LELEMENT(v4lsrc));
/* let's start by requesting a buffer and mmap()'ing it */
if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCGMBUF, &vmbuf) < 0)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error getting buffer information: %s",
sys_errlist[errno]);
return FALSE;
}
/* Map the buffers */
buffer = mmap(0, vmbuf.size, PROT_READ|PROT_WRITE,
MAP_SHARED, GST_V4LELEMENT(v4lsrc)->video_fd, 0);
if (buffer == MAP_FAILED)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error mapping our try-out buffer: %s",
sys_errlist[errno]);
return FALSE;
}
/* now that we have a buffer, let's try out our format */
vmmap.width = GST_V4LELEMENT(v4lsrc)->vcap.minwidth;
vmmap.height = GST_V4LELEMENT(v4lsrc)->vcap.minheight;
vmmap.format = palette;
vmmap.frame = frame;
if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCMCAPTURE, &vmmap) < 0)
{
if (errno != EINVAL) /* our format failed! */
gst_element_error(GST_ELEMENT(v4lsrc),
"Error queueing our try-out buffer: %s",
sys_errlist[errno]);
munmap(buffer, vmbuf.size);
return FALSE;
}
if (ioctl(GST_V4LELEMENT(v4lsrc)->video_fd, VIDIOCSYNC, &frame) < 0)
{
gst_element_error(GST_ELEMENT(v4lsrc),
"Error syncing on a buffer (%d): %s",
frame, sys_errlist[errno]);
munmap(buffer, vmbuf.size);
return FALSE;
}
munmap(buffer, vmbuf.size);
/* if we got here, it worked! woohoo, the format is supported! */
return TRUE;
}

View file

@ -41,6 +41,9 @@ gboolean gst_v4lsrc_requeue_frame (GstV4lSrc *v4lsrc, gint num);
gboolean gst_v4lsrc_capture_stop (GstV4lSrc *v4lsrc);
gboolean gst_v4lsrc_capture_deinit (GstV4lSrc *v4lsrc);
/* "the ugliest hack ever, now available at your local mirror" */
gboolean gst_v4lsrc_try_palette (GstV4lSrc *v4lsrc, gint palette);
#ifdef __cplusplus
}