mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 09:40:37 +00:00
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:
parent
d9d0a69dec
commit
20538dadc9
7 changed files with 205 additions and 76 deletions
14
sys/v4l/TODO
14
sys/v4l/TODO
|
@ -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:
|
||||
=====================
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue