]> git.sesse.net Git - vlc/blobdiff - modules/access/v4l2/v4l2.c
mmap: Only use MAP_NOCACHE on platforms that support it.
[vlc] / modules / access / v4l2 / v4l2.c
index ad1dfb6c380c0ebf956ce6901ddb5e7bbd507429..2e92127c86491829e08033160a42fce636e3f335 100644 (file)
@@ -42,7 +42,8 @@
 # include "config.h"
 #endif
 
-#include <vlc/vlc.h>
+#include <vlc_common.h>
+#include <vlc_plugin.h>
 #include <vlc_access.h>
 #include <vlc_demux.h>
 #include <vlc_input.h>
@@ -85,7 +86,7 @@ static void AccessClose( vlc_object_t * );
 #define CHROMA_TEXT N_("Video input chroma format")
 #define CHROMA_LONGTEXT N_( \
     "Force the Video4Linux2 video device to use a specific chroma format " \
-    "(eg. I420 or I422 for raw images, MJPEG for M-JPEG compressed input) " \
+    "(eg. I420 or I422 for raw images, MJPG for M-JPEG compressed input) " \
     "(Complete list: GREY, I240, RV16, RV15, RV24, RV32, YUY2, YUYV, UYVY, " \
     "I41N, I422, I420, I411, I410, MJPG)")
 #define INPUT_TEXT N_( "Input" )
@@ -239,21 +240,21 @@ typedef enum {
     IO_METHOD_USERPTR,
 } io_method;
 
-static int i_standards_list[] =
+static const int i_standards_list[] =
     { V4L2_STD_UNKNOWN, V4L2_STD_SECAM, V4L2_STD_PAL, V4L2_STD_NTSC };
-static const char *psz_standards_list_text[] =
+static const char *const psz_standards_list_text[] =
     { N_("Default"), N_("SECAM"), N_("PAL"),  N_("NTSC") };
 
-static int i_iomethod_list[] =
+static const int i_iomethod_list[] =
     { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR };
-static const char *psz_iomethod_list_text[] =
+static const char *const psz_iomethod_list_text[] =
     { N_("READ"), N_("MMAP"),  N_("USERPTR") };
 
-static int i_tuner_audio_modes_list[] =
+static const int i_tuner_audio_modes_list[] =
     { V4L2_TUNER_MODE_MONO, V4L2_TUNER_MODE_STEREO,
       V4L2_TUNER_MODE_LANG1, V4L2_TUNER_MODE_LANG2,
       V4L2_TUNER_MODE_SAP, V4L2_TUNER_MODE_LANG1_LANG2 };
-static const char *psz_tuner_audio_modes_list_text[] =
+static const char *const psz_tuner_audio_modes_list_text[] =
     { N_( "Mono" ),
       N_( "Stereo" ),
       N_( "Primary language (Analog TV tuners only)" ),
@@ -271,8 +272,8 @@ static const char *psz_tuner_audio_modes_list_text[] =
 #define CFG_PREFIX "v4l2-"
 
 vlc_module_begin();
-    set_shortname( _("Video4Linux2") );
-    set_description( _("Video4Linux2 input") );
+    set_shortname( N_("Video4Linux2") );
+    set_description( N_("Video4Linux2 input") );
     set_category( CAT_INPUT );
     set_subcategory( SUBCAT_INPUT_ACCESS );
 
@@ -281,7 +282,7 @@ vlc_module_begin();
                 false );
     add_integer( CFG_PREFIX "standard", 0, NULL, STANDARD_TEXT,
                  STANDARD_LONGTEXT, false );
-        change_integer_list( i_standards_list, psz_standards_list_text, 0 );
+        change_integer_list( i_standards_list, psz_standards_list_text, NULL );
     add_string( CFG_PREFIX "chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
                 true );
     add_integer( CFG_PREFIX "input", 0, NULL, INPUT_TEXT, INPUT_LONGTEXT,
@@ -290,7 +291,7 @@ vlc_module_begin();
                  AUDIO_INPUT_LONGTEXT, true );
     add_integer( CFG_PREFIX "io", IO_METHOD_MMAP, NULL, IOMETHOD_TEXT,
                  IOMETHOD_LONGTEXT, true );
-        change_integer_list( i_iomethod_list, psz_iomethod_list_text, 0 );
+        change_integer_list( i_iomethod_list, psz_iomethod_list_text, NULL );
     add_integer( CFG_PREFIX "width", 0, NULL, WIDTH_TEXT,
                 WIDTH_LONGTEXT, true );
     add_integer( CFG_PREFIX "height", 0, NULL, HEIGHT_TEXT,
@@ -378,7 +379,7 @@ vlc_module_begin();
 
     add_submodule();
     add_shortcut( "v4l2c" );
-    set_description( _("Video4Linux2 Compressed A/V") );
+    set_description( N_("Video4Linux2 Compressed A/V") );
     set_capability( "access", 0 );
     /* use these when open as access_demux fails; VLC will use another demux */
     set_callbacks( AccessOpen, AccessClose );
@@ -434,52 +435,65 @@ static int AccessControlResetCallback( vlc_object_t *p_this,
                                        const char *psz_var, vlc_value_t oldval,
                                        vlc_value_t newval, void *p_data );
 
-static struct
+static const struct
 {
     unsigned int i_v4l2;
     int i_fourcc;
+    int i_rmask;
+    int i_gmask;
+    int i_bmask;
 } v4l2chroma_to_fourcc[] =
 {
     /* Raw data types */
-    { V4L2_PIX_FMT_GREY,    VLC_FOURCC('G','R','E','Y') },
-    { V4L2_PIX_FMT_HI240,   VLC_FOURCC('I','2','4','0') },
-    { V4L2_PIX_FMT_RGB565,  VLC_FOURCC('R','V','1','6') },
-    { V4L2_PIX_FMT_RGB555,  VLC_FOURCC('R','V','1','5') },
-    { V4L2_PIX_FMT_BGR24,   VLC_FOURCC('R','V','2','4') },
-    { V4L2_PIX_FMT_BGR32,   VLC_FOURCC('R','V','3','2') },
-    { V4L2_PIX_FMT_YUYV,    VLC_FOURCC('Y','U','Y','2') },
-    { V4L2_PIX_FMT_YUYV,    VLC_FOURCC('Y','U','Y','V') },
-    { V4L2_PIX_FMT_UYVY,    VLC_FOURCC('U','Y','V','Y') },
-    { V4L2_PIX_FMT_Y41P,    VLC_FOURCC('I','4','1','N') },
-    { V4L2_PIX_FMT_YUV422P, VLC_FOURCC('I','4','2','2') },
-    { V4L2_PIX_FMT_YVU420,  VLC_FOURCC('Y','V','1','2') },
-    { V4L2_PIX_FMT_YUV411P, VLC_FOURCC('I','4','1','1') },
-    { V4L2_PIX_FMT_YUV410,  VLC_FOURCC('I','4','1','0') },
+    { V4L2_PIX_FMT_GREY,    VLC_FOURCC('G','R','E','Y'), 0, 0, 0 },
+    { V4L2_PIX_FMT_HI240,   VLC_FOURCC('I','2','4','0'), 0, 0, 0 },
+    { V4L2_PIX_FMT_RGB555,  VLC_FOURCC('R','V','1','5'), 0x001f,0x03e0,0x7c00 },
+    { V4L2_PIX_FMT_RGB565,  VLC_FOURCC('R','V','1','6'), 0x001f,0x07e0,0xf800 },
+    /* Won't work since we don't know how to handle such gmask values
+     * correctly
+    { V4L2_PIX_FMT_RGB555X, VLC_FOURCC('R','V','1','5'), 0x007c,0xe003,0x1f00 },
+    { V4L2_PIX_FMT_RGB565X, VLC_FOURCC('R','V','1','6'), 0x00f8,0xe007,0x1f00 },
+    */
+    { V4L2_PIX_FMT_BGR24,   VLC_FOURCC('R','V','2','4'), 0xff0000,0xff00,0xff },
+    { V4L2_PIX_FMT_RGB24,   VLC_FOURCC('R','V','2','4'), 0xff,0xff00,0xff0000 },
+    { V4L2_PIX_FMT_BGR32,   VLC_FOURCC('R','V','3','2'), 0xff0000,0xff00,0xff },
+    { V4L2_PIX_FMT_RGB32,   VLC_FOURCC('R','V','3','2'), 0xff,0xff00,0xff0000 },
+    { V4L2_PIX_FMT_YUYV,    VLC_FOURCC('Y','U','Y','2'), 0, 0, 0 },
+    { V4L2_PIX_FMT_YUYV,    VLC_FOURCC('Y','U','Y','V'), 0, 0, 0 },
+    { V4L2_PIX_FMT_UYVY,    VLC_FOURCC('U','Y','V','Y'), 0, 0, 0 },
+    { V4L2_PIX_FMT_Y41P,    VLC_FOURCC('I','4','1','N'), 0, 0, 0 },
+    { V4L2_PIX_FMT_YUV422P, VLC_FOURCC('I','4','2','2'), 0, 0, 0 },
+    { V4L2_PIX_FMT_YVU420,  VLC_FOURCC('Y','V','1','2'), 0, 0, 0 },
+    { V4L2_PIX_FMT_YUV411P, VLC_FOURCC('I','4','1','1'), 0, 0, 0 },
+    { V4L2_PIX_FMT_YUV410,  VLC_FOURCC('I','4','1','0'), 0, 0, 0 },
 
     /* Raw data types, not in V4L2 spec but still in videodev2.h and supported
      * by VLC */
-    { V4L2_PIX_FMT_YUV420,  VLC_FOURCC('I','4','2','0') },
+    { V4L2_PIX_FMT_YUV420,  VLC_FOURCC('I','4','2','0'), 0, 0, 0 },
     /* FIXME { V4L2_PIX_FMT_RGB444,  VLC_FOURCC('R','V','3','2') }, */
 
     /* Compressed data types */
-    { V4L2_PIX_FMT_MJPEG,   VLC_FOURCC('M','J','P','G') },
+    { V4L2_PIX_FMT_MJPEG,   VLC_FOURCC('M','J','P','G'), 0, 0, 0 },
 #if 0
     { V4L2_PIX_FMT_JPEG,    VLC_FOURCC('J','P','E','G') },
     { V4L2_PIX_FMT_DV,      VLC_FOURCC('?','?','?','?') },
     { V4L2_PIX_FMT_MPEG,    VLC_FOURCC('?','?','?','?') },
 #endif
-    { 0, 0 }
+    { 0, 0, 0, 0, 0 }
 };
 
 /**
  * List of V4L2 chromas were confident enough to use as fallbacks if the
  * user hasn't provided a --v4l2-chroma value.
+ *
+ * Try YUV chromas first, then RGB little endian and MJPEG as last resort.
  */
 static const __u32 p_chroma_fallbacks[] =
 { V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_YVU420, V4L2_PIX_FMT_YUV422P,
-  V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_MJPEG };
+  V4L2_PIX_FMT_YUYV, V4L2_PIX_FMT_UYVY, V4L2_PIX_FMT_BGR24,
+  V4L2_PIX_FMT_BGR32, V4L2_PIX_FMT_MJPEG };
 
-static struct
+static const struct
 {
     const char *psz_name;
     unsigned int i_cid;
@@ -1139,6 +1153,7 @@ static void DemuxClose( vlc_object_t *p_this )
 
 static void CommonClose( vlc_object_t *p_this, demux_sys_t *p_sys )
 {
+    (void)p_this;
     /* Close */
     if( p_sys->i_fd_video >= 0 ) close( p_sys->i_fd_video );
 #ifdef HAVE_ALSA
@@ -1322,7 +1337,7 @@ static ssize_t AccessRead( access_t * p_access, uint8_t * p_buffer, size_t i_len
 
     do
     {
-        if( p_access->b_die )
+        if( !vlc_object_alive (p_access) )
             return 0;
 
         ufd.revents = 0;
@@ -1369,7 +1384,9 @@ static int Demux( demux_t *p_demux )
     {
         /* Sleep so we do not consume all the cpu, 10ms seems
          * like a good value (100fps) */
-        msleep( 10 );
+        /* Yeah, nevermind this was sleeping 10 microseconds! This is
+         * completely brain damaged anyway. Use poll() or mwait() FIXME. */
+        msleep(10000);
         return 1;
     }
 
@@ -1455,7 +1472,8 @@ static block_t* GrabVideo( demux_t *p_demux )
         /* Unlock */
         if( ioctl( p_sys->i_fd_video, VIDIOC_QBUF, &buf ) < 0 )
         {
-            msg_Err (p_demux, "Failed to unlock (VIDIOC_QBUF)");
+            msg_Err( p_demux, "Failed to unlock (VIDIOC_QBUF)" );
+            block_Release( p_block );
             return 0;
         }
 
@@ -1502,7 +1520,8 @@ static block_t* GrabVideo( demux_t *p_demux )
         /* Unlock */
         if( ioctl( p_sys->i_fd_video, VIDIOC_QBUF, &buf ) < 0 )
         {
-            msg_Err (p_demux, "Failed to unlock (VIDIOC_QBUF)");
+            msg_Err( p_demux, "Failed to unlock (VIDIOC_QBUF)" );
+            block_Release( p_block );
             return 0;
         }
 
@@ -1628,7 +1647,7 @@ static block_t* GrabAudio( demux_t *p_demux )
             /* Test for overrun */
             if( i_correction_delta > p_sys->i_audio_max_frame_size )
             {
-                msg_Warn( p_demux, "ALSA read overrun (%d > %d)",
+                msg_Warn( p_demux, "ALSA read overrun (%zu > %zu)",
                           i_correction_delta, p_sys->i_audio_max_frame_size );
                 i_correction_delta = p_sys->i_audio_max_frame_size;
                 snd_pcm_prepare( p_sys->p_alsa_pcm );
@@ -1646,7 +1665,7 @@ static block_t* GrabAudio( demux_t *p_demux )
 
     /* Timestamp */
     p_block->i_pts = p_block->i_dts =
-        mdate() - I64C(1000000) * (mtime_t)i_correct /
+        mdate() - INT64_C(1000000) * (mtime_t)i_correct /
         2 / ( p_sys->b_stereo ? 2 : 1) / p_sys->i_sample_rate;
 
     return p_block;
@@ -1661,18 +1680,12 @@ static int InitRead( demux_t *p_demux, int i_fd, unsigned int i_buffer_size )
 
     p_sys->p_buffers = calloc( 1, sizeof( *p_sys->p_buffers ) );
     if( !p_sys->p_buffers )
-    {
-        msg_Err( p_demux, "Out of memory" );
         goto open_failed;
-    }
 
     p_sys->p_buffers[0].length = i_buffer_size;
     p_sys->p_buffers[0].start = malloc( i_buffer_size );
     if( !p_sys->p_buffers[0].start )
-    {
-        msg_Err( p_demux, "Out of memory" );
         goto open_failed;
-    }
 
     return VLC_SUCCESS;
 
@@ -1766,32 +1779,25 @@ static int InitUserP( demux_t *p_demux, int i_fd, unsigned int i_buffer_size )
     if( ioctl( i_fd, VIDIOC_REQBUFS, &req ) < 0 )
     {
         msg_Err( p_demux, "device does not support user pointer i/o" );
-        goto open_failed;
+        return VLC_EGENERIC;
     }
 
     p_sys->p_buffers = calloc( 4, sizeof( *p_sys->p_buffers ) );
     if( !p_sys->p_buffers )
-    {
-        msg_Err( p_demux, "Out of memory" );
         goto open_failed;
-    }
 
     for( p_sys->i_nbuffers = 0; p_sys->i_nbuffers < 4; ++p_sys->i_nbuffers )
     {
         p_sys->p_buffers[p_sys->i_nbuffers].length = i_buffer_size;
-        posix_memalign( &p_sys->p_buffers[p_sys->i_nbuffers].start,
-                /* boundary */ i_page_size, i_buffer_size );
-
-        if( !p_sys->p_buffers[p_sys->i_nbuffers].start )
-        {
-            msg_Err( p_demux, "out of memory" );
+        if( posix_memalign( &p_sys->p_buffers[p_sys->i_nbuffers].start,
+                /* boundary */ i_page_size, i_buffer_size ) )
             goto open_failed;
-        }
     }
 
     return VLC_SUCCESS;
 
 open_failed:
+    free( p_sys->p_buffers );
     return VLC_EGENERIC;
 
 }
@@ -1825,6 +1831,7 @@ static int OpenVideoDev( vlc_object_t *p_obj, demux_sys_t *p_sys, bool b_demux )
     unsigned int i_min;
     enum v4l2_buf_type buf_type;
     char *psz_device = p_sys->psz_vdev;
+    es_format_t es_fmt;
 
     if( ( i_fd = open( psz_device, O_RDWR ) ) < 0 )
     {
@@ -2063,6 +2070,10 @@ static int OpenVideoDev( vlc_object_t *p_obj, demux_sys_t *p_sys, bool b_demux )
         if( v4l2chroma_to_fourcc[i].i_v4l2 == fmt.fmt.pix.pixelformat )
         {
             p_sys->i_fourcc = v4l2chroma_to_fourcc[i].i_fourcc;
+            es_format_Init( &es_fmt, VIDEO_ES, p_sys->i_fourcc );
+            es_fmt.video.i_rmask = v4l2chroma_to_fourcc[i].i_rmask;
+            es_fmt.video.i_gmask = v4l2chroma_to_fourcc[i].i_gmask;
+            es_fmt.video.i_bmask = v4l2chroma_to_fourcc[i].i_bmask;
             break;
         }
     }
@@ -2140,21 +2151,10 @@ static int OpenVideoDev( vlc_object_t *p_obj, demux_sys_t *p_sys, bool b_demux )
     }
 
     /* Add */
-    es_format_t es_fmt;
-    es_format_Init( &es_fmt, VIDEO_ES, p_sys->i_fourcc );
     es_fmt.video.i_width  = p_sys->i_width;
     es_fmt.video.i_height = p_sys->i_height;
     es_fmt.video.i_aspect = 4 * VOUT_ASPECT_FACTOR / 3;
 
-    /* Setup rgb mask for RGB formats */
-    if( p_sys->i_fourcc == VLC_FOURCC( 'R','V','2','4' ) )
-    {
-        /* This is in BGR format */
-        es_fmt.video.i_bmask = 0x00ff0000;
-        es_fmt.video.i_gmask = 0x0000ff00;
-        es_fmt.video.i_rmask = 0x000000ff;
-    }
-
     msg_Dbg( p_demux, "added new video es %4.4s %dx%d",
         (char*)&es_fmt.i_codec, es_fmt.video.i_width, es_fmt.video.i_height );
     p_sys->p_es_video = es_out_Add( p_demux->out, &es_fmt );
@@ -2259,7 +2259,6 @@ static int OpenAudioDevAlsa( vlc_object_t *p_this, demux_sys_t *p_sys,
                              bool b_demux )
 {
     char *psz_device = p_sys->psz_adev;
-    int i_fd = 0;
     p_sys->p_alsa_pcm = NULL;
     char* psz_alsa_device_name = NULL;
     snd_pcm_hw_params_t *p_hw_params = NULL;
@@ -2426,18 +2425,15 @@ static int OpenAudioDevAlsa( vlc_object_t *p_this, demux_sys_t *p_sys,
         goto adev_fail;
     }
 
-    /* Return a fake handle so other tests work */
-    i_fd = 1;
-
     free( psz_alsa_device_name );
 
     if( !p_sys->psz_adev )
         p_sys->psz_adev = strdup( ALSA_DEFAULT );
-    return i_fd;
 
- adev_fail:
+    /* Return a fake handle so other tests work */
+    return 1;
 
-    if( i_fd >= 0 ) close( i_fd );
+ adev_fail:
 
     if( p_hw_params ) snd_pcm_hw_params_free( p_hw_params );
     if( p_sys->p_alsa_pcm ) snd_pcm_close( p_sys->p_alsa_pcm );
@@ -3115,10 +3111,10 @@ static void ControlListPrint( vlc_object_t *p_obj, int i_fd,
 
     if( b_demux )
         var_AddCallback( p_obj, psz_name,
-                        DemuxControlCallback, (void*)queryctrl.id );
+                        DemuxControlCallback, (void*)(intptr_t)queryctrl.id );
     else
         var_AddCallback( p_obj, psz_name,
-                        AccessControlCallback, (void*)queryctrl.id );
+                        AccessControlCallback, (void*)(intptr_t)queryctrl.id );
 
     free( psz_name );
 }
@@ -3490,6 +3486,7 @@ static int DemuxControlCallback( vlc_object_t *p_this,
     const char *psz_var, vlc_value_t oldval, vlc_value_t newval,
     void *p_data )
 {
+    (void)oldval;
     demux_t *p_demux = (demux_t*)p_this;
     demux_sys_t *p_sys = p_demux->p_sys;
     int i_cid = (int)p_data;
@@ -3505,9 +3502,9 @@ static int DemuxControlCallback( vlc_object_t *p_this,
 }
 
 static int DemuxControlResetCallback( vlc_object_t *p_this,
-    const char *psz_var, vlc_value_t oldval, vlc_value_t newval,
-    void *p_data )
+    const char *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
+    (void)psz_var;    (void)oldval;    (void)newval;    (void)p_data;
     demux_t *p_demux = (demux_t*)p_this;
     demux_sys_t *p_sys = p_demux->p_sys;
 
@@ -3525,6 +3522,7 @@ static int AccessControlCallback( vlc_object_t *p_this,
     const char *psz_var, vlc_value_t oldval, vlc_value_t newval,
     void *p_data )
 {
+    (void)oldval;
     access_t *p_access = (access_t *)p_this;
     demux_sys_t *p_sys = (demux_sys_t *) p_access->p_sys;
     int i_cid = (int)p_data;
@@ -3540,9 +3538,9 @@ static int AccessControlCallback( vlc_object_t *p_this,
 }
 
 static int AccessControlResetCallback( vlc_object_t *p_this,
-    const char *psz_var, vlc_value_t oldval, vlc_value_t newval,
-    void *p_data )
+    const char *psz_var, vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
+    (void)psz_var;     (void)oldval;     (void)newval;     (void)p_data;
     access_t *p_access = (access_t *)p_this;
     demux_sys_t *p_sys = (demux_sys_t *) p_access->p_sys;