[vlc-devel] [PATCH v2] Add support for reading EIA-608 closed captions via V4L2 VBI devices

Devin Heitmueller dheitmueller at kernellabs.com
Mon Oct 29 03:34:09 CET 2012


** Resend including missing vbi.c file

This patch provides initial support for sending EIA-608
 closed captions provided via the /dev/vbi interface to the
 VLC CC decoder.  It makes use of the ZVBI library, which is
 what does the VBI slicing.

Validated with the Hauppauge HVR-950q.

This patch is a modified version of a patch series I sent on Oct 21, 2012,
which takes into account the feedback received from the VLC developers.
---
 modules/access/Modules.am    |    5 +-
 modules/access/v4l2/access.c |    3 +-
 modules/access/v4l2/demux.c  |  229 +++++++++++++++++++++++++++++++-----------
 modules/access/v4l2/v4l2.c   |    8 ++
 modules/access/v4l2/v4l2.h   |   14 ++-
 modules/access/v4l2/vbi.c    |  131 ++++++++++++++++++++++++
 modules/access/v4l2/video.c  |   21 ++--
 7 files changed, 341 insertions(+), 70 deletions(-)
 create mode 100644 modules/access/v4l2/vbi.c

diff --git a/modules/access/Modules.am b/modules/access/Modules.am
index 5665477..9dc2a80 100644
--- a/modules/access/Modules.am
+++ b/modules/access/Modules.am
@@ -132,14 +132,15 @@ libv4l2_plugin_la_SOURCES = \
 	v4l2/videodev2.h \
 	v4l2/v4l2.c \
 	v4l2/video.c \
+	v4l2/vbi.c \
 	v4l2/demux.c \
 	v4l2/access.c \
 	v4l2/radio.c \
 	v4l2/controls.c \
 	v4l2/lib.c \
 	v4l2/v4l2.h
-libv4l2_plugin_la_CFLAGS = $(AM_CFLAGS)
-libv4l2_plugin_la_LIBADD = $(AM_LIBADD) $(LIBDL) $(LIBM)
+libv4l2_plugin_la_CFLAGS = $(AM_CFLAGS) $(ZVBI_CFLAGS)
+libv4l2_plugin_la_LIBADD = $(AM_LIBADD) $(LIBDL) $(LIBM) $(ZVBI_LIBS)
 if HAVE_V4L2
 libvlc_LTLIBRARIES += libv4l2_plugin.la
 endif
diff --git a/modules/access/v4l2/access.c b/modules/access/v4l2/access.c
index df5add0..d4676f5 100644
--- a/modules/access/v4l2/access.c
+++ b/modules/access/v4l2/access.c
@@ -103,7 +103,8 @@ int InitVideo (access_t *access, int fd, uint32_t caps)
         return -1;
     }
 
-    if (SetupInput (VLC_OBJECT(access), fd))
+    v4l2_std_id std;
+    if (SetupInput (VLC_OBJECT(access), fd, &std))
         return -1;
 
     /* NOTE: The V4L access_demux expects a VLC FOURCC as "chroma". It is used to set the
diff --git a/modules/access/v4l2/demux.c b/modules/access/v4l2/demux.c
index 15b540f..12c8690 100644
--- a/modules/access/v4l2/demux.c
+++ b/modules/access/v4l2/demux.c
@@ -58,22 +58,33 @@ struct demux_sys_t
     es_out_id_t *es;
     vlc_v4l2_ctrl_t *controls;
     mtime_t start;
+
+#ifdef ZVBI_COMPILED
+    vbi_capture *vbi_cap;
+    es_out_id_t *p_es_subt[VBI_NUM_CC_STREAMS];
+#endif
 };
 
 static void *UserPtrThread (void *);
 static void *MmapThread (void *);
 static void *ReadThread (void *);
 static int DemuxControl( demux_t *, int, va_list );
-static int InitVideo (demux_t *, int fd, uint32_t caps);
+static int InitVideo (demux_t *, int fd, uint32_t caps, v4l2_std_id *std,
+                      void *(**entry) (void *));
+#ifdef ZVBI_COMPILED
+static int InitVBI (demux_t *);
+#endif
 
 int DemuxOpen( vlc_object_t *obj )
 {
     demux_t *demux = (demux_t *)obj;
-
+    void *(*entry) (void *);
+    
     demux_sys_t *sys = malloc (sizeof (*sys));
     if (unlikely(sys == NULL))
         return VLC_ENOMEM;
     demux->p_sys = sys;
+    sys->vbi_cap = NULL;
 
     ParseMRL( obj, demux->psz_location );
 
@@ -88,12 +99,32 @@ int DemuxOpen( vlc_object_t *obj )
         goto error;
     sys->fd = fd;
 
-    if (InitVideo (demux, fd, caps))
+    v4l2_std_id std;
+    if (InitVideo (demux, fd, caps, &std, &entry))
     {
         v4l2_close (fd);
         goto error;
     }
 
+#ifdef ZVBI_COMPILED
+    char *vbi_path = var_InheritString (obj, CFG_PREFIX"vbidev");
+    if (vbi_path != NULL && (std & V4L2_STD_NTSC_M))
+    {    
+        sys->vbi_cap = OpenVBIDev (obj, vbi_path);
+        if (sys->vbi_cap)
+            InitVBI(demux);
+        free(vbi_path);
+    }
+#endif
+
+    /* Now that everything is setup, start the reading thread */
+    if (vlc_clone (&sys->thread, entry, demux, VLC_THREAD_PRIORITY_INPUT))
+    {
+        if (sys->bufv != NULL)
+            StopMmap (sys->fd, sys->bufv, sys->bufc);
+        goto error;
+    }
+    
     sys->controls = ControlsInit (VLC_OBJECT(demux), fd);
     sys->start = mdate ();
     demux->pf_demux = NULL;
@@ -261,7 +292,8 @@ static void GetAR (int fd, unsigned *restrict num, unsigned *restrict den)
     *den = cropcap.pixelaspect.denominator;
 }
 
-static int InitVideo (demux_t *demux, int fd, uint32_t caps)
+static int InitVideo (demux_t *demux, int fd, uint32_t caps, v4l2_std_id *std,
+                      void *(**entry) (void *))
 {
     demux_sys_t *sys = demux->p_sys;
 
@@ -271,7 +303,7 @@ static int InitVideo (demux_t *demux, int fd, uint32_t caps)
         return -1;
     }
 
-    if (SetupInput (VLC_OBJECT(demux), fd))
+    if (SetupInput (VLC_OBJECT(demux), fd, std))
         return -1;
 
     /* Picture format negotiation */
@@ -399,7 +431,6 @@ static int InitVideo (demux_t *demux, int fd, uint32_t caps)
     sys->es = es_out_Add (demux->out, &es_fmt);
 
     /* Init I/O method */
-    void *(*entry) (void *);
     if (caps & V4L2_CAP_STREAMING)
     {
         if (StartUserPtr (VLC_OBJECT(demux), fd) == 0)
@@ -411,7 +442,7 @@ static int InitVideo (demux_t *demux, int fd, uint32_t caps)
 
             sys->blocksize = (fmt.fmt.pix.sizeimage + pagemask) & ~pagemask;
             sys->bufv = NULL;
-            entry = UserPtrThread;
+            *entry = UserPtrThread;
             msg_Dbg (demux, "streaming with %"PRIu32"-bytes user buffers",
                      sys->blocksize);
         }
@@ -421,7 +452,7 @@ static int InitVideo (demux_t *demux, int fd, uint32_t caps)
             sys->bufv = StartMmap (VLC_OBJECT(demux), fd, &sys->bufc);
             if (sys->bufv == NULL)
                 return -1;
-            entry = MmapThread;
+            *entry = MmapThread;
             msg_Dbg (demux, "streaming with %"PRIu32" memory-mapped buffers",
                      sys->bufc);
         }
@@ -430,7 +461,7 @@ static int InitVideo (demux_t *demux, int fd, uint32_t caps)
     {
         sys->blocksize = fmt.fmt.pix.sizeimage;
         sys->bufv = NULL;
-        entry = ReadThread;
+        *entry = ReadThread;
         msg_Dbg (demux, "reading %"PRIu32" bytes at a time", sys->blocksize);
     }
     else
@@ -439,14 +470,33 @@ static int InitVideo (demux_t *demux, int fd, uint32_t caps)
         return -1;
     }
 
-    if (vlc_clone (&sys->thread, entry, demux, VLC_THREAD_PRIORITY_INPUT))
+    return 0;
+}
+
+#ifdef ZVBI_COMPILED
+static int InitVBI (demux_t *demux)
+{
+    demux_sys_t *sys = demux->p_sys;
+
+    for (int i = 0; i < VBI_NUM_CC_STREAMS; i++)
     {
-        if (sys->bufv != NULL)
-            StopMmap (sys->fd, sys->bufv, sys->bufc);
-        return -1;
+        es_format_t fmt;
+
+        es_format_Init( &fmt, SPU_ES, VLC_FOURCC('c','c',0x31 + i,' ') );
+        if (asprintf(&fmt.psz_description, "CC%d", i + 1) >= 0)
+        {
+            msg_Dbg( demux, "new spu es %4.4s", (char*)&fmt.i_codec );
+            sys->p_es_subt[i] = es_out_Add( demux->out, &fmt );
+        }
     }
+    
+    /* Do a single read and throw away the results so that ZVBI calls
+       the STREAMON ioctl() */
+    GrabVBI(demux, sys->vbi_cap, sys->p_es_subt, VBI_NUM_CC_STREAMS);
+
     return 0;
 }
+#endif
 
 void DemuxClose( vlc_object_t *obj )
 {
@@ -459,6 +509,15 @@ void DemuxClose( vlc_object_t *obj )
         StopMmap (sys->fd, sys->bufv, sys->bufc);
     ControlsDeinit( obj, sys->controls );
     v4l2_close (sys->fd);
+
+#ifdef ZVBI_COMPILED
+    if( sys->vbi_cap )
+    {
+        close(vbi_capture_fd(sys->vbi_cap));
+        vbi_capture_delete( sys->vbi_cap );
+    }
+#endif
+
     free( sys );
 }
 
@@ -503,11 +562,22 @@ static void *UserPtrThread (void *data)
     demux_t *demux = data;
     demux_sys_t *sys = demux->p_sys;
     int fd = sys->fd;
-    struct pollfd ufd[1];
-
+    struct pollfd ufd[2];
+    nfds_t numfds = 1;
+    
     ufd[0].fd = fd;
     ufd[0].events = POLLIN;
 
+#ifdef ZVBI_COMPILED
+    if ( sys->vbi_cap )
+    {
+        ufd[1].fd = vbi_capture_fd(sys->vbi_cap);
+        ufd[1].events = POLLIN;
+        ufd[1].revents = 0;
+        numfds++;
+    }
+#endif
+    
     int canc = vlc_savecancel ();
     for (;;)
     {
@@ -522,25 +592,32 @@ static void *UserPtrThread (void *data)
         /* Wait for data */
         vlc_restorecancel (canc);
         block_cleanup_push (block);
-        while (poll (ufd, 1, -1) == -1)
+        while (poll (ufd, numfds, -1) == -1)
            if (errno != EINTR)
                msg_Err (demux, "poll error: %m");
         vlc_cleanup_pop ();
         canc = vlc_savecancel ();
 
-        if (v4l2_ioctl (fd, VIDIOC_DQBUF, &buf) < 0)
+        if( ufd[0].revents & POLLIN )
         {
-            msg_Err (demux, "cannot dequeue buffer: %m");
-            block_Release (block);
-            continue;
+            if (v4l2_ioctl (fd, VIDIOC_DQBUF, &buf) < 0)
+            {
+                msg_Err (demux, "cannot dequeue buffer: %m");
+                block_Release (block);
+                continue;
+            }
+
+            assert (block->p_buffer == (void *)buf.m.userptr);
+            block->i_buffer = buf.length;
+            block->i_pts = block->i_dts = mdate ();
+            block->i_flags |= sys->block_flags;
+            es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
+            es_out_Send (demux->out, sys->es, block);
         }
-
-        assert (block->p_buffer == (void *)buf.m.userptr);
-        block->i_buffer = buf.length;
-        block->i_pts = block->i_dts = mdate ();
-        block->i_flags |= sys->block_flags;
-        es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
-        es_out_Send (demux->out, sys->es, block);
+#ifdef ZVBI_COMPILED
+        if( sys->vbi_cap && (ufd[1].revents & POLLIN) )
+            GrabVBI(demux, sys->vbi_cap, sys->p_es_subt, VBI_NUM_CC_STREAMS);
+#endif
     }
     vlc_restorecancel (canc); /* <- hmm, this is purely cosmetic */
     return NULL;
@@ -551,31 +628,49 @@ static void *MmapThread (void *data)
     demux_t *demux = data;
     demux_sys_t *sys = demux->p_sys;
     int fd = sys->fd;
-    struct pollfd ufd[1];
+    struct pollfd ufd[2];
+    nfds_t numfds = 1;
 
     ufd[0].fd = fd;
     ufd[0].events = POLLIN;
 
+#ifdef ZVBI_COMPILED
+    if ( sys->vbi_cap )
+    {
+        ufd[1].fd = vbi_capture_fd(sys->vbi_cap);
+        ufd[1].events = POLLIN;
+        ufd[1].revents = 0;
+        numfds++;
+    }
+#endif
+
     for (;;)
     {
         /* Wait for data */
-        if (poll (ufd, 1, -1) == -1)
+        if (poll (ufd, numfds, -1) == -1)
         {
            if (errno != EINTR)
                msg_Err (demux, "poll error: %m");
            continue;
         }
 
-        int canc = vlc_savecancel ();
-        block_t *block = GrabVideo (VLC_OBJECT(demux), fd, sys->bufv);
-        if (block != NULL)
+        if( ufd[0].revents & POLLIN )
         {
-            block->i_pts = block->i_dts = mdate ();
-            block->i_flags |= sys->block_flags;
-            es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
-            es_out_Send (demux->out, sys->es, block);
+            int canc = vlc_savecancel ();
+            block_t *block = GrabVideo (VLC_OBJECT(demux), fd, sys->bufv);
+            if (block != NULL)
+            {
+                block->i_pts = block->i_dts = mdate ();
+                block->i_flags |= sys->block_flags;
+                es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
+                es_out_Send (demux->out, sys->es, block);
+            }
+            vlc_restorecancel (canc);
         }
-        vlc_restorecancel (canc);
+#ifdef ZVBI_COMPILED
+        if( sys->vbi_cap && (ufd[1].revents & POLLIN) )
+            GrabVBI(demux, sys->vbi_cap, sys->p_es_subt, VBI_NUM_CC_STREAMS);
+#endif
     }
 
     assert (0);
@@ -586,42 +681,60 @@ static void *ReadThread (void *data)
     demux_t *demux = data;
     demux_sys_t *sys = demux->p_sys;
     int fd = sys->fd;
-    struct pollfd ufd[1];
-
+    struct pollfd ufd[2];
+    nfds_t numfds = 1;
+    
     ufd[0].fd = fd;
     ufd[0].events = POLLIN;
 
+#ifdef ZVBI_COMPILED
+    if ( sys->vbi_cap )
+    {
+        ufd[1].fd = vbi_capture_fd(sys->vbi_cap);
+        ufd[1].events = POLLIN;
+        ufd[1].revents = 0;
+        numfds++;
+    }
+#endif
+
     for (;;)
     {
         /* Wait for data */
-        if (poll (ufd, 1, -1) == -1)
+        if (poll (ufd, numfds, -1) == -1)
         {
            if (errno != EINTR)
                msg_Err (demux, "poll error: %m");
            continue;
         }
 
-        block_t *block = block_Alloc (sys->blocksize);
-        if (unlikely(block == NULL))
+        if( ufd[0].revents & POLLIN )
         {
-            msg_Err (demux, "read error: %m");
-            v4l2_read (fd, NULL, 0); /* discard frame */
-            continue;
-        }
-        block->i_pts = block->i_dts = mdate ();
-        block->i_flags |= sys->block_flags;
+            block_t *block = block_Alloc (sys->blocksize);
+            if (unlikely(block == NULL))
+            {
+                msg_Err (demux, "read error: %m");
+                v4l2_read (fd, NULL, 0); /* discard frame */
+                continue;
+            }
+            block->i_pts = block->i_dts = mdate ();
+            block->i_flags |= sys->block_flags;
 
-        int canc = vlc_savecancel ();
-        ssize_t val = v4l2_read (fd, block->p_buffer, block->i_buffer);
-        if (val != -1)
-        {
-            block->i_buffer = val;
-            es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
-            es_out_Send (demux->out, sys->es, block);
+            int canc = vlc_savecancel ();
+            ssize_t val = v4l2_read (fd, block->p_buffer, block->i_buffer);
+            if (val != -1)
+            {
+                block->i_buffer = val;
+                es_out_Control (demux->out, ES_OUT_SET_PCR, block->i_pts);
+                es_out_Send (demux->out, sys->es, block);
+            }
+            else
+                block_Release (block);
+            vlc_restorecancel (canc);
         }
-        else
-            block_Release (block);
-        vlc_restorecancel (canc);
+#ifdef ZVBI_COMPILED
+        if( sys->vbi_cap && (ufd[1].revents & POLLIN) )
+            GrabVBI(demux, sys->vbi_cap, sys->p_es_subt, VBI_NUM_CC_STREAMS);
+#endif
     }
     assert (0);
 }
diff --git a/modules/access/v4l2/v4l2.c b/modules/access/v4l2/v4l2.c
index 878fb81..73044ea 100644
--- a/modules/access/v4l2/v4l2.c
+++ b/modules/access/v4l2/v4l2.c
@@ -43,6 +43,10 @@
 
 #define VIDEO_DEVICE_TEXT N_( "Video capture device" )
 #define VIDEO_DEVICE_LONGTEXT N_("Video capture device node." )
+#define VBI_DEVICE_TEXT N_("VBI capture device")
+#define VBI_DEVICE_LONGTEXT N_( \
+    "The device node where VBI data can be read "   \
+    " (for closed captions) " )
 #define STANDARD_TEXT N_( "Standard" )
 #define STANDARD_LONGTEXT N_( \
     "Video standard (Default, SECAM, PAL, or NTSC)." )
@@ -277,6 +281,10 @@ vlc_module_begin ()
     add_loadfile( CFG_PREFIX "dev", "/dev/video0",
                   VIDEO_DEVICE_TEXT, VIDEO_DEVICE_LONGTEXT, false )
         change_safe()
+#ifdef ZVBI_COMPILED
+    add_loadfile( CFG_PREFIX "vbidev", NULL,
+                  VBI_DEVICE_TEXT, VBI_DEVICE_LONGTEXT, false )
+#endif
     add_string( CFG_PREFIX "standard", "",
                 STANDARD_TEXT, STANDARD_LONGTEXT, false )
         change_string_list( standards_vlc, standards_user )
diff --git a/modules/access/v4l2/v4l2.h b/modules/access/v4l2/v4l2.h
index fa0e4e7..35685f3 100644
--- a/modules/access/v4l2/v4l2.h
+++ b/modules/access/v4l2/v4l2.h
@@ -20,6 +20,10 @@
 
 #include "videodev2.h"
 
+#ifdef ZVBI_COMPILED
+#   include <libzvbi.h>
+#endif
+
 /* libv4l2 functions */
 extern int v4l2_fd_open (int, int);
 extern int (*v4l2_close) (int);
@@ -44,7 +48,7 @@ int OpenDevice (vlc_object_t *, const char *, uint32_t *);
 v4l2_std_id var_InheritStandard (vlc_object_t *, const char *);
 
 /* video.c */
-int SetupInput (vlc_object_t *, int fd);
+int SetupInput (vlc_object_t *, int fd, v4l2_std_id *std);
 int SetupFormat (vlc_object_t *, int, uint32_t,
                  struct v4l2_format *, struct v4l2_streamparm *);
 #define SetupFormat(o,fd,fcc,fmt,p) \
@@ -57,6 +61,14 @@ void StopMmap (int, struct buffer_t *, uint32_t);
 
 block_t* GrabVideo (vlc_object_t *, int, const struct buffer_t *);
 
+#ifdef ZVBI_COMPILED
+/* vbi.c */
+vbi_capture* OpenVBIDev( vlc_object_t *, const char *);
+void GrabVBI( demux_t *p_demux, vbi_capture *vbi_cap,
+              es_out_id_t **p_es_subt, int num_streams);
+#define VBI_NUM_CC_STREAMS 4
+#endif
+
 /* demux.c */
 int DemuxOpen(vlc_object_t *);
 void DemuxClose(vlc_object_t *);
diff --git a/modules/access/v4l2/vbi.c b/modules/access/v4l2/vbi.c
new file mode 100644
index 0000000..335067c
--- /dev/null
+++ b/modules/access/v4l2/vbi.c
@@ -0,0 +1,131 @@
+/*****************************************************************************
+ * vbi.c : Video4Linux2 VBI input module for vlc
+ *****************************************************************************
+ * Copyright (C) 2012 the VideoLAN team
+ *
+ * Author: Devin Heitmueller <dheitmueller at kernellabs dot com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser 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 <errno.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <vlc_common.h>
+#include <vlc_block.h>
+#include <vlc_fs.h>
+#include <vlc_demux.h>
+
+#include "v4l2.h"
+
+#ifdef ZVBI_COMPILED
+
+vbi_capture* OpenVBIDev( vlc_object_t *p_obj, const char *psz_device)
+{
+    vbi_capture *cap;
+    char* errstr = NULL;
+
+    //Can put more in here. See osd.c in zvbi package.
+    unsigned int services = VBI_SLICED_CAPTION_525;
+
+    int rawfd = vlc_open (psz_device, O_RDWR);
+    if (rawfd == -1)
+    {
+        msg_Err ( p_obj, "cannot open device '%s': %m", psz_device );
+        return NULL;
+    }
+    
+    cap = vbi_capture_v4l2k_new (psz_device,
+                                 rawfd,
+                                 /* buffers */ 5,
+                                 &services,
+                                 /* strict */ 1,
+                                 &errstr,
+                                 /* verbose */ 1);
+    if (cap == NULL)
+    {
+        msg_Err( p_obj, "Cannot capture vbi data with v4l2 interface (%s)",
+                 errstr );
+        free(errstr);
+    }
+
+    return cap;
+}
+
+void GrabVBI( demux_t *p_demux, vbi_capture *vbi_cap,
+              es_out_id_t **p_es_subt, int num_streams)
+{
+    block_t     *p_block=NULL;
+    vbi_capture_buffer *sliced_bytes;
+    struct timeval timeout={0,0}; /* poll */
+    int n_lines;
+
+    int r = vbi_capture_pull_sliced (vbi_cap, &sliced_bytes, &timeout);
+    switch (r) {
+        case -1:
+            msg_Err( p_demux, "Error reading VBI (%m)" );
+            break;
+        case  0: /* nothing avail */
+            break;
+        case  1: /* got data */
+            n_lines = sliced_bytes->size / sizeof(vbi_sliced);
+            if (n_lines)
+            {
+                int sliced_size = 2; /* Number of bytes per sliced line */
+
+                int size = (sliced_size + 1) * n_lines;
+                if( !( p_block = block_Alloc( size ) ) )
+                {
+                    msg_Err( p_demux, "cannot get block" );
+                }
+                else
+                {
+                    int field;
+                    uint8_t* data = p_block->p_buffer;
+                    vbi_sliced *sliced_array = sliced_bytes->data;
+                    for(field=0; field<n_lines; field++)
+                    {
+                        *data = field;
+                        data++;
+                        memcpy(data, sliced_array[field].data, sliced_size);
+                        data += sliced_size;
+                    }
+                    p_block->i_buffer = size;
+                    p_block->i_pts = mdate();
+                }
+            }
+    }
+
+    if( p_block )
+    {
+        for (int i = 0; i < num_streams; i++)
+        {
+            block_t *p_sblock;
+            if (p_es_subt[i] == NULL)
+                continue;
+            p_sblock = block_Duplicate(p_block);
+            if (p_sblock)
+                es_out_Send(p_demux->out, p_es_subt[i], p_sblock);
+        }
+        block_Release(p_block);
+    }
+
+    return;
+}
+#endif
diff --git a/modules/access/v4l2/video.c b/modules/access/v4l2/video.c
index 7636937..a38a172 100644
--- a/modules/access/v4l2/video.c
+++ b/modules/access/v4l2/video.c
@@ -39,7 +39,8 @@
 #include "v4l2.h"
 
 static int SetupStandard (vlc_object_t *obj, int fd,
-                          const struct v4l2_input *restrict input)
+                          const struct v4l2_input *restrict input,
+                          v4l2_std_id *std)
 {
     if (!(input->capabilities & V4L2_IN_CAP_STD))
     {
@@ -47,18 +48,22 @@ static int SetupStandard (vlc_object_t *obj, int fd,
         return 0;
     }
 
-    v4l2_std_id std = var_InheritStandard (obj, CFG_PREFIX"standard");
-    if (std == V4L2_STD_UNKNOWN)
+    *std = var_InheritStandard (obj, CFG_PREFIX"standard");
+    if (*std == V4L2_STD_UNKNOWN)
     {
         msg_Warn (obj, "video standard not set");
+
+        /* Grab the currently selected standard */
+        if (v4l2_ioctl (fd, VIDIOC_G_STD, std) < 0)
+            msg_Err (obj, "cannot get video standard");
         return 0;
     }
-    if (v4l2_ioctl (fd, VIDIOC_S_STD, &std) < 0)
+    if (v4l2_ioctl (fd, VIDIOC_S_STD, std) < 0)
     {
-        msg_Err (obj, "cannot set video standard 0x%"PRIx64": %m", std);
+        msg_Err (obj, "cannot set video standard 0x%"PRIx64": %m", *std);
         return -1;
     }
-    msg_Dbg (obj, "video standard set to 0x%"PRIx64":", std);
+    msg_Dbg (obj, "video standard set to 0x%"PRIx64":", *std);
     return 0;
 }
 
@@ -230,7 +235,7 @@ static int ResetCrop (vlc_object_t *obj, int fd)
     return 0;
 }
 
-int SetupInput (vlc_object_t *obj, int fd)
+int SetupInput (vlc_object_t *obj, int fd, v4l2_std_id *std)
 {
     struct v4l2_input input;
 
@@ -263,7 +268,7 @@ int SetupInput (vlc_object_t *obj, int fd)
     }
     msg_Dbg (obj, "selected input %"PRIu32, input.index);
 
-    SetupStandard (obj, fd, &input);
+    SetupStandard (obj, fd, &input, std);
 
     switch (input.type)
     {
-- 
1.7.9.5




More information about the vlc-devel mailing list