[vlc-devel] [PATCH] This patch introduces support for using V4L2 VBI devices for reading NTSC closed captions.

Rémi Denis-Courmont remi at remlab.net
Mon Nov 19 22:06:16 CET 2012


	Hello,

Le lundi 19 novembre 2012 05:49:27, Devin Heitmueller a écrit :
> @@ -439,6 +449,17 @@ static int InitVideo (demux_t *demux, int fd, uint32_t
> caps) return -1;
>      }
> 
> +#ifdef ZVBI_COMPILED
> +    char *vbi_path = var_InheritString (demux, CFG_PREFIX"vbidev");
> +    if (vbi_path != NULL && (std & V4L2_STD_NTSC_M))
> +    {
> +        sys->vbi_cap = OpenVBIDev ((vlc_object_t *) demux, vbi_path);
> +        if (sys->vbi_cap)
> +            InitVBI(demux);
> +        free(vbi_path);
> +    }

This may leak for non-NTSC devices.

> +#endif
> +
>      if (vlc_clone (&sys->thread, entry, demux, VLC_THREAD_PRIORITY_INPUT))
>      {
>          if (sys->bufv != NULL)
> @@ -448,6 +469,31 @@ static int InitVideo (demux_t *demux, int fd, uint32_t
> caps) 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++)
> +    {
> +        es_format_t fmt;
> +
> +        es_format_Init( &fmt, SPU_ES, VLC_FOURCC('c', 'c', '1' + i, ' ')
> ); +        if (asprintf(&fmt.psz_description, "Closed captions %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 )
>  {
>      demux_t *demux = (demux_t *)obj;
> @@ -459,6 +505,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 +558,21 @@ 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;
> +        numfds++;
> +    }
> +#endif
> +
>      int canc = vlc_savecancel ();
>      for (;;)
>      {
> @@ -522,25 +587,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 )

I'm not sure how possile this is for V4L nodes, but POLLERR is not handled 
anymore. This could trigger a live loop. I would just check that revents is 
non-zero.

>          {
> -            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 +623,48 @@ 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;
> +        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 +675,59 @@ 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;
> +        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/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)
>  {

This could use a restrict qualifier.

>      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)

Same here.

>  {
>      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)
>      {

-- 
Rémi Denis-Courmont
http://www.remlab.net/



More information about the vlc-devel mailing list