[vlc-devel] [PATCH] add V4L2 video_output module
Francois Cartegnie
fcvlcdev at free.fr
Sun Jan 15 23:08:02 CET 2012
---
configure.ac | 5 +
modules/video_output/Modules.am | 3 +
modules/video_output/v4l2_output.c | 650 ++++++++++++++++++++++++++++++++++++
3 files changed, 658 insertions(+), 0 deletions(-)
create mode 100644 modules/video_output/v4l2_output.c
diff --git a/configure.ac b/configure.ac
index e6b30ed..0583033 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1840,6 +1840,8 @@ AC_ARG_ENABLE(libv4l2, [AS_HELP_STRING([--disable-libv4l2],
[disable userspace V4L2 library (default auto)])])
AC_ARG_ENABLE(pvr, [AS_HELP_STRING([--enable-pvr],
[support PVR V4L2 cards (default disabled)])])
+AC_ARG_ENABLE(v4l2_output, [AS_HELP_STRING([--enable-v4l2out],
+ [support V4L2 output (default auto)])])
have_v4l2="no"
AC_CHECK_HEADERS([linux/videodev2.h sys/videoio.h], [
have_v4l2="yes"
@@ -1855,6 +1857,9 @@ AS_IF([test "$have_v4l2" = "yes"], [
AS_IF([test "${enable_pvr}" = "yes"], [
VLC_ADD_PLUGIN([pvr])
])
+ AS_IF([test "${enable_v4l2out}" != "no"], [
+ VLC_ADD_PLUGIN([v4l2_output])
+ ])
])
AM_CONDITIONAL(HAVE_V4L2, [test "${have_v4l2}" != "no"])
diff --git a/modules/video_output/Modules.am b/modules/video_output/Modules.am
index 1c26b92..f40481b 100644
--- a/modules/video_output/Modules.am
+++ b/modules/video_output/Modules.am
@@ -14,6 +14,9 @@ SOURCES_yuv = yuv.c
SOURCES_vout_macosx = macosx.m opengl.h opengl.c
SOURCES_vout_ios = ios.m opengl.h opengl.c
SOURCES_android_surface = androidsurface.c
+SOURCES_v4l2_output = v4l2_output.c \
+ ../access/v4l2/v4l2_common.c \
+ ../access/v4l2/v4l2_common.h
### OpenGL ###
# TODO: merge all three source files (?)
diff --git a/modules/video_output/v4l2_output.c b/modules/video_output/v4l2_output.c
new file mode 100644
index 0000000..8b18d64
--- /dev/null
+++ b/modules/video_output/v4l2_output.c
@@ -0,0 +1,650 @@
+/*****************************************************************************
+ * v4l2_output.c : V4L2 output module for vlc
+ *****************************************************************************
+ * Copyright (C) 2012 the VideoLAN team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdarg.h>
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include <vlc_common.h>
+#include <vlc_plugin.h>
+#include <vlc_vout_display.h>
+#include <vlc_picture_pool.h>
+
+#include "../access/v4l2/v4l2.h"
+#include "../access/v4l2/v4l2_common.h"
+
+#define V4L2_DEVICE_TEXT N_("Device")
+#define V4L2_DEVICE_LONGTEXT N_("V4L2 output device")
+#define V4L2_PROFILE_TEXT N_("Loopback application profile")
+#define V4L2_PROFILE_LONGTEXT N_("Profile (chroma + size) for special apps using v4l2loopback")
+#define V4L2_CHROMA_TEXT N_("Chroma used")
+#define V4L2_CHROMA_LONGTEXT N_("Force use of a specific chroma for output. Default is I420.")
+
+#define CFG_PREFIX "v4l2_output_"
+
+struct vout_display_sys_t {
+ picture_pool_t *pool;
+ int fd;
+ int i_imagesize;
+ bool b_streaming;
+ struct buffer_t *buffers;
+ int (* poollock)(picture_t *);
+ int i_buffers;
+};
+
+struct picture_sys_t {
+ vout_display_sys_t *p_vdsys;
+ int i_target_buffer;
+ bool b_buffer_ready;
+};
+
+static int Open (vlc_object_t *);
+static void Close(vlc_object_t *);
+
+static picture_pool_t *Pool (vout_display_t *, unsigned);
+static int MMAPPoolLock(picture_t *);
+static void PictureDisplayRW(vout_display_t *, picture_t *, subpicture_t *);
+static void PictureDisplayMMAP(vout_display_t *, picture_t *, subpicture_t *);
+static int Control(vout_display_t *, int, va_list);
+
+static const char * const psz_profiles_texts[] = { N_("None"), N_("Skype"), N_("Flash Plugin") };
+static const char * const psz_profiles_values[] = { NULL, "skype", "flashplugin" };
+
+/*
+ * Module descriptor
+ */
+vlc_module_begin ()
+ set_shortname (N_("V4L2 Output"))
+ set_description (N_("V4L2 Output"))
+ set_category (CAT_VIDEO)
+ set_subcategory (SUBCAT_VIDEO_VOUT)
+ set_capability ("vout display", 0)
+ set_callbacks (Open, Close)
+ add_string(CFG_PREFIX "dev", "/dev/video0", V4L2_DEVICE_TEXT, V4L2_DEVICE_LONGTEXT, false)
+ add_string(CFG_PREFIX "profile", NULL, V4L2_PROFILE_TEXT, V4L2_PROFILE_LONGTEXT, true)
+ change_string_list( psz_profiles_values, psz_profiles_texts, 0 )
+ add_string(CFG_PREFIX "chroma", NULL, V4L2_CHROMA_TEXT, V4L2_CHROMA_LONGTEXT, true)
+vlc_module_end ()
+
+/* applications profiles for v4l2loopback output */
+static struct {
+ const char const * psz_name;
+ const int i_width;
+ const int i_height;
+ const int i_chroma;
+} const app_profiles[] = {
+ /* apps requested profiles */
+ { "skype", 640, 480, V4L2_PIX_FMT_YUV420 },
+ { "flashplugin", 0, 0, V4L2_PIX_FMT_RGB32 },
+ { NULL, 0, 0, 0 }
+};
+
+/* same/from v4l2 access IsPixelFormatSupported() */
+static bool is_fallback_v4l2_chroma( uint32_t i_pixelformat )
+{
+ static const uint32_t const p_chroma_fallbacks[] =
+ {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_YUV422P,
+ V4L2_PIX_FMT_YUYV,
+ V4L2_PIX_FMT_UYVY,
+ V4L2_PIX_FMT_BGR24,
+ V4L2_PIX_FMT_BGR32
+ // minus mjpeg/jpeg
+ };
+
+ size_t n = ARRAY_SIZE( p_chroma_fallbacks );
+ for( size_t j = 0; j < n; j++ )
+ if( i_pixelformat == p_chroma_fallbacks[ j ] )
+ return true;
+ return false;
+}
+/* ! from v4l2 access */
+
+static bool toggle_stream( vout_display_t *vd, int i_request )
+{
+ struct v4l2_requestbuffers reqbuf;
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ reqbuf.memory = V4L2_MEMORY_MMAP;
+ reqbuf.count = vd->sys->i_buffers;
+ return ioctl( vd->sys->fd, i_request, & reqbuf.type );
+}
+
+static void free_buffers( vout_display_sys_t *sys )
+{
+ for( int i=0; i<sys->i_buffers; i++ )
+ munmap( sys->buffers[ i ].start, sys->buffers[ i ].length );
+ free( sys->buffers );
+}
+
+static bool copy_frames( picture_t *picture, struct buffer_t *buffer, unsigned int *offset )
+{
+ *offset = 0;
+ for (int i = 0; i < picture->i_planes; i++)
+ {
+ const plane_t *plane = &picture->p[i];
+ for( int y = 0; y < plane->i_visible_lines; y++)
+ {
+ if ( unlikely( *offset + plane->i_visible_pitch > buffer->length ) )
+ return false;
+ else
+ memcpy( ((char *)buffer->start) + *offset,
+ &plane->p_pixels[y*plane->i_pitch],
+ plane->i_visible_pitch );
+ *offset += plane->i_visible_pitch;
+ }
+ }
+ return true;
+}
+
+static bool apply_profile( char *psz_profile, video_format_t *fmt )
+{
+ if ( !psz_profile )
+ return false;
+
+ for (int i=0; app_profiles[i].psz_name != NULL ; i++)
+ {
+ if ( strcmp( app_profiles[i].psz_name, psz_profile ) == 0 )
+ {
+ vlc_fourcc_t i_fourcc;
+ int i_foo;
+ if ( app_profiles[i].i_chroma &&
+ get_fourcc_by_v4l2pixelformat( &i_fourcc,
+ &i_foo,
+ &i_foo,
+ &i_foo,
+ app_profiles[i].i_chroma ) )
+ {
+ fmt->i_chroma = i_fourcc;
+ }
+ else
+ {
+ return false;
+ }
+ if ( app_profiles[i].i_width )
+ {
+ fmt->i_width = fmt->i_visible_width = app_profiles[i].i_width;
+ fmt->i_height = fmt->i_visible_height = app_profiles[i].i_height;
+ }
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/* mostly from v4l2 access. should be merged */
+static inline bool probe_device_v4l2_chromas( vlc_object_t *p_obj, int i_fd,
+ uint32_t type, struct v4l2_fmtdesc **p_codecs,
+ uint32_t *ncodec )
+{
+ /* Probe for available chromas */
+ struct v4l2_fmtdesc *codecs, codec = {
+ .index = 0,
+ .type = type,
+ };
+
+ while( ioctl( i_fd, VIDIOC_ENUM_FMT, &codec ) >= 0 )
+ {
+ codec.index = ++*ncodec;
+ }
+
+ *p_codecs = malloc( *ncodec * sizeof( struct v4l2_fmtdesc ) );
+ if( unlikely(*p_codecs == NULL) )
+ *ncodec = 0;
+ codecs = *p_codecs;
+
+ for( uint32_t i = 0; i < *ncodec; i++ )
+ {
+ codecs[i].index = i;
+ codecs[i].type = type;
+
+ if( ioctl( i_fd, VIDIOC_ENUM_FMT, &codecs[i] ) < 0 )
+ {
+ msg_Err( p_obj, "cannot get codec description: %m" );
+ return false;
+ }
+
+ /* only print if vlc supports the format */
+ char fourcc_v4l2[4];
+ vlc_fourcc_to_char( codecs[i].pixelformat, fourcc_v4l2 );
+
+ vlc_fourcc_t i_fourcc;
+ int i_foo;
+
+ if( get_fourcc_by_v4l2pixelformat( &i_fourcc,
+ &i_foo,
+ &i_foo,
+ &i_foo,
+ codecs[i].pixelformat ) )
+ {
+ char fourcc[4];
+ vlc_fourcc_to_char( i_fourcc, fourcc );
+ msg_Dbg( p_obj, "device supports chroma %4.4s [%s, %4.4s]",
+ fourcc, codecs[i].description, fourcc_v4l2 );
+ /* can store in driver reserved fields as we won't ioctl again */
+ codecs[i].reserved[0] = true; /* supported */
+ codecs[i].reserved[1] = is_fallback_v4l2_chroma( codecs[i].pixelformat );
+ }
+ else
+ {
+ msg_Dbg( p_obj, "device codec %4.4s (%s) not supported",
+ fourcc_v4l2, codecs[i].description );
+ codecs[i].reserved[0] = false;
+ }
+ }
+ return true;
+}
+
+static int Open (vlc_object_t *obj)
+{
+ vout_display_t *vd = (vout_display_t *)obj;
+ struct v4l2_capability vid_caps;
+ struct v4l2_format v;
+ char *psz_video_device = var_InheritString(vd, CFG_PREFIX "dev");
+ char *psz_profile = var_InheritString(vd, CFG_PREFIX "profile");
+ char *psz_reqchroma = var_InheritString( vd, CFG_PREFIX "chroma" );
+ uint32_t i_requested_v4l2_chroma = 0;
+ bool b_streamable;
+ struct v4l2_fmtdesc *codecs = NULL;
+ uint32_t ncodecs = 0;
+
+ vd->sys = calloc( 1, sizeof(vout_display_sys_t) );
+ if ( !vd->sys ) goto earlyerror;
+
+ vd->sys->fd = open( psz_video_device, O_RDWR|O_NONBLOCK|O_CLOEXEC );
+ if (vd->sys->fd < 0)
+ {
+ msg_Err( obj, "cannot open v4l2 output device (%s): %m", psz_video_device );
+ free(vd->sys);
+ goto earlyerror;
+ }
+
+ if ( ioctl(vd->sys->fd, VIDIOC_QUERYCAP, &vid_caps) < 0 )
+ {
+ msg_Err( obj, "cannot query v4l2 output device (%s): %m", psz_video_device );
+ goto error;
+ }
+
+ if ( !strncmp( (char*)vid_caps.driver, "v4l2 loopback", 16 )
+ && ( vid_caps.version < 0x00000500 ) )
+ {
+ /* some apps won't work on v4l2oopback < 0.5 (skype) */
+ msg_Warn( obj, "Please update your V4L2 loopback driver" );
+ }
+
+ if ( ( vid_caps.capabilities & V4L2_CAP_VIDEO_OUTPUT ) == 0 )
+ {
+ msg_Err( obj, "device (%s) is not an output device", psz_video_device );
+ goto error;
+ }
+
+ if ( ( vid_caps.capabilities & (V4L2_CAP_READWRITE|V4L2_CAP_STREAMING) ) == 0 )
+ {
+ msg_Err( obj, "no supported I/O method" );
+ goto error;
+ }
+
+ b_streamable = vid_caps.capabilities & V4L2_CAP_STREAMING;
+// b_streamble = false; // uncomment to force RW method
+
+ v.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ if ( ioctl(vd->sys->fd, VIDIOC_G_FMT, &v) < 0 )
+ {
+ msg_Err( obj, "cannot control v4l2 format: %m" );
+ goto error;
+ }
+
+ vd->pool = Pool;
+ vd->prepare = NULL;
+ vd->control = Control;
+ vd->manage = NULL;
+ vout_display_SendEventFullscreen(vd, false);
+
+ if ( apply_profile( psz_profile, & vd->fmt ) ) /* sets vd->fmt.i_chroma */
+ msg_Info( obj, "using profile %s", psz_profile );
+
+ if( psz_reqchroma != NULL ) /* can override profile */
+ vd->fmt.i_chroma = vlc_fourcc_GetCodecFromString( VIDEO_ES, psz_reqchroma );
+
+ /* try to match selection from above or by default module's one first */
+ if ( ! get_v4l2pixelformat_by_fourcc( & i_requested_v4l2_chroma, vd->fmt.i_chroma ) )
+ msg_Warn( obj, "can't match requested chroma");
+
+ v.fmt.pix.width = vd->fmt.i_visible_width;
+ v.fmt.pix.height = vd->fmt.i_visible_height;
+ v.fmt.pix.pixelformat = 0;
+
+ if ( probe_device_v4l2_chromas( obj, vd->sys->fd, V4L2_CAP_VIDEO_OUTPUT,
+ &codecs, &ncodecs ) )
+ {
+ for( uint32_t i = 0; i < ncodecs; i++ )
+ {
+ if ( codecs[i].reserved[0] == true ) /* supported */
+ {
+ if ( i_requested_v4l2_chroma > 0 )
+ {
+ if ( i_requested_v4l2_chroma == codecs[i].pixelformat )
+ {
+ v.fmt.pix.pixelformat = i_requested_v4l2_chroma;
+ msg_Dbg( obj, "using chroma %s", codecs[i].description );
+ break;
+ }
+ }
+ else
+ {
+ /* pick first available fallback */
+ if ( codecs[i].reserved[1] == true ) /* is_fallback */
+ {
+ v.fmt.pix.pixelformat = codecs[i].pixelformat;
+ msg_Dbg( obj, "using fallback chroma %s", codecs[i].description );
+ break;
+ }
+ }
+ }
+ }
+ free( codecs );
+ }
+ else
+ {
+ msg_Err( obj, "probing device for chromas failed" );
+ }
+
+ if ( v.fmt.pix.pixelformat == 0 )
+ {
+ msg_Warn( obj, "No valid V4L2 chroma found" );
+ goto error;
+ }
+ else
+ {
+ int foo;
+ /* ensure to have it configured on display's side */
+ get_fourcc_by_v4l2pixelformat( & vd->fmt.i_chroma, &foo, &foo, &foo,
+ v.fmt.pix.pixelformat );
+ }
+
+ video_format_FixRgb(&vd->fmt);
+ v.fmt.pix.field = V4L2_FIELD_NONE;
+
+ if ( ioctl(vd->sys->fd, VIDIOC_S_FMT, &v) < 0 )
+ {
+ msg_Err( obj, "cannot control dst format: %m" );
+ goto error;
+ }
+
+ /* image size has been computed by driver */
+ vd->sys->i_imagesize = v.fmt.pix.sizeimage;
+
+ struct v4l2_requestbuffers reqbuf;
+ memset (&reqbuf, 0, sizeof (reqbuf));
+ reqbuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ reqbuf.memory = V4L2_MEMORY_MMAP;
+ reqbuf.count = 8;
+
+ if ( !b_streamable || ( ioctl(vd->sys->fd, VIDIOC_REQBUFS, &reqbuf) < 0 ) )
+ {
+ if ( !b_streamable || errno == EINVAL )
+ {
+ msg_Dbg( obj, "Video capturing or mmap-streaming is not supported" );
+ vd->display = PictureDisplayRW;
+ vd->sys->buffers = calloc( 1, sizeof( struct buffer_t ) );
+ if ( !vd->sys->buffers )
+ {
+ msg_Err( obj, "can't allocate buffer");
+ goto error;
+ }
+ vd->sys->i_buffers = 1;
+ vd->sys->buffers[0].length = v.fmt.pix.sizeimage;
+ vd->sys->buffers[0].start = calloc( v.fmt.pix.sizeimage, sizeof(uint32_t) );
+ if ( !vd->sys->buffers[0].start ) goto error;
+ }
+ else
+ {
+ msg_Err( obj, "ioctl error with reqbufs: %m");
+ goto error;
+ }
+ }
+ else
+ {
+
+ if ( reqbuf.count < 2 ) /* should at least have an in and out queue */
+ {
+ msg_Err( obj, "Not enough buffer memory");
+ free( vd->sys );
+ return VLC_EGENERIC;
+ }
+
+ vd->display = PictureDisplayMMAP;
+ vd->sys->poollock = MMAPPoolLock;
+
+ vd->sys->buffers = calloc( reqbuf.count, sizeof( struct buffer_t ) );
+ if ( !vd->sys->buffers )
+ {
+ msg_Err( obj, "can't allocate mmap buffers");
+ goto error;
+ }
+
+ for( unsigned int i=0; i<reqbuf.count; i++ )
+ {
+ struct v4l2_buffer buf;
+ buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ buf.memory = V4L2_MEMORY_MMAP;
+ buf.index = i;
+
+ if ( ioctl (vd->sys->fd, VIDIOC_QUERYBUF, & buf ) < 0 )
+ {
+ msg_Err( obj, "Error in VIDIOC_QUERYBUF: %m");
+ goto error;
+ }
+
+ vd->sys->buffers[ i ].start = mmap( NULL, buf.length,
+ PROT_READ | PROT_WRITE,
+ MAP_SHARED,
+ vd->sys->fd, buf.m.offset );
+ if ( vd->sys->buffers[ i ].start == MAP_FAILED )
+ {
+ msg_Err( obj, "Can't mmap buffer");
+ goto error;
+ }
+ vd->sys->buffers[ i ].length = buf.length;
+ vd->sys->i_buffers++;
+ }
+
+ }
+
+ return VLC_SUCCESS;
+
+error:
+ close( vd->sys->fd );
+ free_buffers( vd->sys );
+ free( vd->sys );
+earlyerror:
+ free( psz_video_device );
+ free( psz_profile );
+ free( psz_reqchroma );
+ return VLC_EGENERIC;
+}
+
+static void Close (vlc_object_t *obj)
+{
+ vout_display_t *vd = (vout_display_t *)obj;
+
+ if ( vd->sys->b_streaming )
+ toggle_stream( vd, VIDIOC_STREAMOFF );
+
+ if (vd->sys->pool)
+ picture_pool_Delete(vd->sys->pool);
+
+ close( vd->sys->fd );
+ if ( vd->display == PictureDisplayRW )
+ free( vd->sys->buffers[ 0 ].start ); /* free local buffer */
+ free_buffers( vd->sys );
+ free( vd->sys );
+}
+
+static picture_pool_t *Pool(vout_display_t *vd, unsigned count)
+{
+ vout_display_sys_t *sys = vd->sys;
+
+ if ( sys->pool ) return sys->pool;
+
+ /* Allocate pictures */
+ picture_t **pp_picture = calloc( count, sizeof( picture_t * ) );
+ if ( !pp_picture )
+ return NULL;
+
+ unsigned i_allocated_count = 0;
+ for (i_allocated_count = 0; i_allocated_count < count; i_allocated_count++)
+ {
+ pp_picture[ i_allocated_count ] = picture_NewFromFormat( &vd->fmt );
+ if ( !pp_picture[ i_allocated_count ] )
+ break;
+ pp_picture[ i_allocated_count ]->p_sys = calloc( 1, sizeof( picture_sys_t ) );
+ if ( !pp_picture[ i_allocated_count ]->p_sys )
+ {
+ free( pp_picture[ i_allocated_count ] );
+ break;
+ }
+ pp_picture[ i_allocated_count ]->p_sys->p_vdsys = sys;
+ }
+
+ /* Configure pool */
+ picture_pool_configuration_t cfg;
+ memset( &cfg, 0, sizeof( cfg ) );
+ cfg.picture_count = i_allocated_count;
+ cfg.picture = pp_picture;
+ cfg.lock = sys->poollock;
+
+ sys->pool = picture_pool_NewExtended( &cfg );
+ if ( !sys->pool ) goto error;
+
+ return sys->pool;
+
+error:
+ for ( unsigned i = 0; i < i_allocated_count; i++ )
+ picture_Delete( pp_picture[ i ] );
+ return NULL;
+
+}
+
+static void PictureDisplayRW(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
+{
+ assert( vd->sys->i_buffers );
+ vout_display_sys_t *sys = vd->sys;
+ struct buffer_t *buffer = &vd->sys->buffers[0];
+ unsigned int i_offset;
+
+ /* we need to merge into memory to make only 1 write */
+ copy_frames( picture, buffer, &i_offset );
+ if ( i_offset != write( sys->fd, buffer->start, i_offset ) )
+ msg_Warn( vd, "can't fully write to device");
+
+ picture_Release(picture);
+ VLC_UNUSED(subpicture);
+}
+
+static void PictureDisplayMMAP(vout_display_t *vd, picture_t *picture, subpicture_t *subpicture)
+{
+ vout_display_sys_t *sys = vd->sys;
+ struct v4l2_buffer freebuf;
+ if ( ! picture->p_sys->b_buffer_ready )
+ {
+ msg_Warn( vd, "device buffer not ready after VIDIOC_DQBUF: %m");
+ }
+ else
+ {
+ freebuf.index = picture->p_sys->i_target_buffer;
+ struct buffer_t *buffer = &vd->sys->buffers[ freebuf.index ];
+ unsigned int i_offset = 0;
+
+ copy_frames( picture, buffer, &i_offset );
+
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+ freebuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ freebuf.memory = V4L2_MEMORY_MMAP;
+ freebuf.timestamp = tv;
+ freebuf.flags = 0;
+ freebuf.reserved = 0;
+ freebuf.field = V4L2_FIELD_NONE;
+ freebuf.bytesused = i_offset;
+ if ( ioctl( sys->fd, VIDIOC_QBUF, &freebuf ) < 0 )
+ msg_Err( vd, "VIDIOC_QBUF: %m");
+ /* we should test for V4L2_BUF_FLAG_QUEUED flag here */
+ /* but this won't work with the v4l2loopback driver which changes */
+ /* flag immediately to DONE and returns it in the ioctl */
+
+ if ( !sys->b_streaming )
+ {
+ if ( toggle_stream( vd, VIDIOC_STREAMON ) < 0 )
+ msg_Warn( vd, "can't VIDIOC_STREAMON");
+ else
+ sys->b_streaming = true;
+ }
+
+ }
+
+ picture_Release(picture);
+ VLC_UNUSED(subpicture);
+}
+
+static int MMAPPoolLock( picture_t *p_picture )
+{
+ vout_display_sys_t *p_sys = p_picture->p_sys->p_vdsys;
+
+ struct v4l2_buffer freebuf;
+
+ freebuf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ freebuf.memory = V4L2_MEMORY_MMAP;
+ freebuf.flags = 0;
+
+ /* Query the driver for a free buffer */
+ if ( ioctl( p_sys->fd, VIDIOC_DQBUF, &freebuf ) < 0 )
+ {
+ p_picture->p_sys->b_buffer_ready = false;
+ return VLC_EGENERIC; /* error will be triggered later */
+ }
+
+ p_picture->p_sys->b_buffer_ready = true;
+ p_picture->p_sys->i_target_buffer = freebuf.index;
+
+ return VLC_SUCCESS;
+}
+
+static int Control(vout_display_t *vd, int query, va_list args)
+{
+ VLC_UNUSED(vd);
+ VLC_UNUSED(args);
+ switch (query)
+ {
+ default:
+ return VLC_EGENERIC;
+ }
+}
--
1.7.6
More information about the vlc-devel
mailing list