]> git.sesse.net Git - vlc/blobdiff - modules/access/v4l/v4l.c
* modules/misc/dummy/renderer.c:
[vlc] / modules / access / v4l / v4l.c
index 93067cceb8c87003301ef724b3379e479ed6808e..27641684f8836e8d86a57924eb5248fd6bf0a57e 100644 (file)
@@ -2,7 +2,7 @@
  * v4l.c : Video4Linux input module for vlc
  *****************************************************************************
  * Copyright (C) 2002 VideoLAN
- * $Id: v4l.c,v 1.30 2003/11/15 23:21:35 fenrir Exp $
+ * $Id: v4l.c,v 1.36 2003/12/04 16:49:43 sam Exp $
  *
  * Author: Laurent Aimar <fenrir@via.ecp.fr>
  *         Paul Forgey <paulf at aphrodite dot com>
 #include <sys/soundcard.h>
 
 /*****************************************************************************
- * Local prototypes
+ * Module descriptior
  *****************************************************************************/
-static int  AccessOpen  ( vlc_object_t * );
-static void AccessClose ( vlc_object_t * );
-static int  Read        ( input_thread_t *, byte_t *, size_t );
-
-static void ParseMRL    ( input_thread_t * );
-static int  OpenVideoDev( input_thread_t *, char * );
-static int  OpenAudioDev( input_thread_t *, char * );
+static int  AccessOpen ( vlc_object_t * );
+static void AccessClose( vlc_object_t * );
 
 static int  DemuxOpen  ( vlc_object_t * );
 static void DemuxClose ( vlc_object_t * );
-static int  Demux      ( input_thread_t * );
 
-/*****************************************************************************
- * Module descriptior
- *****************************************************************************/
 #define CACHING_TEXT N_("Caching value in ms")
 #define CACHING_LONGTEXT N_( \
     "Allows you to modify the default caching value for v4l streams. This " \
@@ -92,7 +83,11 @@ static int  Demux      ( input_thread_t * );
 #define ADEV_TEXT N_("Audio device name")
 #define ADEV_LONGTEXT N_( \
     "Specify the name of the audio device that will be used. " \
-    "If you don't specify anything, no video device will be used.")
+    "If you don't specify anything, no audio device will be used.")
+#define CHROMA_TEXT N_("Video input chroma format")
+#define CHROMA_LONGTEXT N_( \
+    "Force the Video4Linux video device to use a specific chroma format " \
+    "(eg. I420 (default), RV24, etc.)")
 
 vlc_module_begin();
     set_description( _("Video4Linux input") );
@@ -107,6 +102,8 @@ vlc_module_begin();
                 VLC_FALSE );
     add_string( "v4l-adev", "/dev/dsp", 0, ADEV_TEXT, ADEV_LONGTEXT,
                 VLC_FALSE );
+    add_string( "v4l-chroma", NULL, NULL, CHROMA_TEXT, CHROMA_LONGTEXT,
+                VLC_TRUE );
 
     add_submodule();
         set_description( _("Video4Linux demuxer") );
@@ -116,9 +113,15 @@ vlc_module_begin();
 vlc_module_end();
 
 
-/****************************************************************************
- * I. Access Part
- ****************************************************************************/
+/*****************************************************************************
+ * Access: local prototypes
+ *****************************************************************************/
+static int  Read        ( input_thread_t *, byte_t *, size_t );
+
+static void ParseMRL    ( input_thread_t * );
+static int  OpenVideoDev( input_thread_t *, char * );
+static int  OpenAudioDev( input_thread_t *, char * );
+
 #define MJPEG_BUFFER_SIZE (256*1024)
 
 struct quicktime_mjpeg_app1
@@ -135,6 +138,31 @@ struct quicktime_mjpeg_app1
     uint32_t    i_data_offset;          /* following SOS marker data */
 };
 
+static struct
+{
+    int i_v4l;
+    int i_fourcc;
+
+} v4lchroma_to_fourcc[] =
+{
+    { VIDEO_PALETTE_GREY, VLC_FOURCC( 'G', 'R', 'E', 'Y' ) },
+    { VIDEO_PALETTE_HI240, VLC_FOURCC( 'I', '2', '4', '0' ) },
+    { VIDEO_PALETTE_RGB565, VLC_FOURCC( 'R', 'V', '1', '6' ) },
+    { VIDEO_PALETTE_RGB555, VLC_FOURCC( 'R', 'V', '1', '5' ) },
+    { VIDEO_PALETTE_RGB24, VLC_FOURCC( 'R', 'V', '2', '4' ) },
+    { VIDEO_PALETTE_RGB32, VLC_FOURCC( 'R', 'V', '3', '2' ) },
+    { VIDEO_PALETTE_YUV422, VLC_FOURCC( 'I', '4', '2', '2' ) },
+    { VIDEO_PALETTE_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', 'V' ) },
+    { VIDEO_PALETTE_UYVY, VLC_FOURCC( 'U', 'Y', 'V', 'Y' ) },
+    { VIDEO_PALETTE_YUV420, VLC_FOURCC( 'I', '4', '2', 'N' ) },
+    { VIDEO_PALETTE_YUV411, VLC_FOURCC( 'I', '4', '1', 'N' ) },
+    { VIDEO_PALETTE_RAW, VLC_FOURCC( 'G', 'R', 'A', 'W' ) },
+    { VIDEO_PALETTE_YUV422P, VLC_FOURCC( 'I', '4', '2', '2' ) },
+    { VIDEO_PALETTE_YUV420P, VLC_FOURCC( 'I', '4', '2', '0' ) },
+    { VIDEO_PALETTE_YUV411P, VLC_FOURCC( 'I', '4', '1', '1' ) },
+    { 0, 0 }
+};
+
 struct access_sys_t
 {
     /* Devices */
@@ -637,6 +665,7 @@ static void ParseMRL( input_thread_t *p_input )
     {
         p_sys->psz_device = strdup( psz_dup );
     }
+    if( psz_dup ) free( psz_dup );
 }
 
 /*****************************************************************************
@@ -901,74 +930,67 @@ int OpenVideoDev( input_thread_t *p_input, char *psz_device )
         /* Find out video format used by device */
         if( ioctl( i_fd, VIDIOCGPICT, &p_sys->vid_picture ) == 0 )
         {
-            int i_chroma = VLC_FOURCC( ' ', ' ', ' ', ' ' );
             struct video_picture vid_picture = p_sys->vid_picture;
+            vlc_value_t val;
+            int i;
+
+            vid_picture.palette = 0;
+            p_sys->i_fourcc = 0;
+
+            var_Create( p_input, "v4l-chroma",
+                        VLC_VAR_STRING | VLC_VAR_DOINHERIT );
+            var_Get( p_input, "v4l-chroma", &val );
+            if( val.psz_string && strlen( val.psz_string ) >= 4 )
+            {
+                int i_chroma =
+                    VLC_FOURCC( val.psz_string[0], val.psz_string[1],
+                                val.psz_string[2], val.psz_string[3] );
+
+                /* Find out v4l chroma code */
+                for( i = 0; v4lchroma_to_fourcc[i].i_v4l != 0; i++ )
+                {
+                    if( v4lchroma_to_fourcc[i].i_fourcc == i_chroma )
+                    {
+                        vid_picture.palette = v4lchroma_to_fourcc[i].i_v4l;
+                        break;
+                    }
+                }
+            }
+            if( val.psz_string ) free( val.psz_string );
 
-            /* Try to set the format to something easy to encode */
-            vid_picture.palette = VIDEO_PALETTE_YUV420P;
-            if( ioctl( i_fd, VIDIOCSPICT, &vid_picture ) == 0 )
+            if( vid_picture.palette &&
+                !ioctl( i_fd, VIDIOCSPICT, &vid_picture ) )
             {
                 p_sys->vid_picture = vid_picture;
             }
             else
             {
-                vid_picture.palette = VIDEO_PALETTE_YUV422P;
+                /* Try to set the format to something easy to encode */
+                vid_picture.palette = VIDEO_PALETTE_YUV420P;
                 if( ioctl( i_fd, VIDIOCSPICT, &vid_picture ) == 0 )
                 {
                     p_sys->vid_picture = vid_picture;
                 }
+                else
+                {
+                    vid_picture.palette = VIDEO_PALETTE_YUV422P;
+                    if( ioctl( i_fd, VIDIOCSPICT, &vid_picture ) == 0 )
+                    {
+                        p_sys->vid_picture = vid_picture;
+                    }
+                }
             }
 
             /* Find out final format */
-            switch( p_sys->vid_picture.palette )
+            for( i = 0; v4lchroma_to_fourcc[i].i_v4l != 0; i++ )
             {
-            case VIDEO_PALETTE_GREY:
-                i_chroma = VLC_FOURCC( 'G', 'R', 'E', 'Y' );
-                break;
-            case VIDEO_PALETTE_HI240:
-                i_chroma = VLC_FOURCC( 'I', '2', '4', '0' );
-                break;
-            case VIDEO_PALETTE_RGB565:
-                i_chroma = VLC_FOURCC( 'R', 'V', '1', '6' );
-                break;
-            case VIDEO_PALETTE_RGB555:
-                i_chroma = VLC_FOURCC( 'R', 'V', '1', '5' );
-                break;
-            case VIDEO_PALETTE_RGB24:
-                i_chroma = VLC_FOURCC( 'R', 'V', '2', '4' );
-                break;
-            case VIDEO_PALETTE_RGB32:
-                i_chroma = VLC_FOURCC( 'R', 'V', '3', '2' );
-                break;
-            case VIDEO_PALETTE_YUV422:
-                i_chroma = VLC_FOURCC( 'I', '4', '2', '2' );
-                break;
-            case VIDEO_PALETTE_YUYV:
-                i_chroma = VLC_FOURCC( 'Y', 'U', 'Y', 'V' );
-                break;
-            case VIDEO_PALETTE_UYVY:
-                i_chroma = VLC_FOURCC( 'U', 'Y', 'V', 'Y' );
-                break;
-            case VIDEO_PALETTE_YUV420:
-                i_chroma = VLC_FOURCC( 'I', '4', '2', 'N' );
-                break;
-            case VIDEO_PALETTE_YUV411:
-                i_chroma = VLC_FOURCC( 'I', '4', '1', 'N' );
-                break;
-            case VIDEO_PALETTE_RAW:
-                i_chroma = VLC_FOURCC( 'G', 'R', 'A', 'W' );
-                break;
-            case VIDEO_PALETTE_YUV422P:
-                i_chroma = VLC_FOURCC( 'I', '4', '2', '2' );
-                break;
-            case VIDEO_PALETTE_YUV420P:
-                i_chroma = VLC_FOURCC( 'I', '4', '2', '0' );
-                break;
-            case VIDEO_PALETTE_YUV411P:
-                i_chroma = VLC_FOURCC( 'I', '4', '1', '1' );
-                break;
+                if( v4lchroma_to_fourcc[i].i_v4l == p_sys->vid_picture.palette)
+                {
+                    p_sys->i_fourcc = v4lchroma_to_fourcc[i].i_fourcc;
+                    break;
+                }
             }
-            p_sys->i_fourcc = i_chroma;
+
         }
         else
         {
@@ -1451,40 +1473,45 @@ static int Read( input_thread_t * p_input, byte_t * p_buffer, size_t i_len )
     return i_data;
 }
 
+
+
+/*****************************************************************************
+ * Demux: local prototypes
+ *****************************************************************************/
+struct demux_sys_t
+{
+    int         i_es;
+    es_out_id_t **es;
+};
+
+static int  Demux      ( input_thread_t * );
+
 /****************************************************************************
- * I. Demux Part
+ * DemuxOpen:
  ****************************************************************************/
 static int DemuxOpen( vlc_object_t *p_this )
 {
     input_thread_t *p_input = (input_thread_t *)p_this;
+    demux_sys_t    *p_sys;
 
     uint8_t        *p_peek;
-    int            i_streams;
+    int            i_es;
     int            i;
 
-    data_packet_t  *p_pk;
-
-    /* Initialize access plug-in structures. */
-    if( p_input->i_mtu == 0 )
-    {
-        /* Improve speed. */
-        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE ;
-    }
-
     /* a little test to see if it's a v4l stream */
-    if( input_Peek( p_input, &p_peek, 8 ) < 8 )
+    if( stream_Peek( p_input->s, &p_peek, 8 ) < 8 )
     {
         msg_Warn( p_input, "v4l plugin discarded (cannot peek)" );
         return VLC_EGENERIC;
     }
 
-    if( strncmp( p_peek, ".v4l", 4 ) || GetDWBE( &p_peek[4] ) <= 0 )
+    if( strncmp( p_peek, ".v4l", 4 ) ||
+        ( i_es = GetDWBE( &p_peek[4] ) ) <= 0 )
     {
         msg_Warn( p_input, "v4l plugin discarded (not a valid stream)" );
         return VLC_EGENERIC;
     }
 
-    /*  create one program */
     vlc_mutex_lock( &p_input->stream.stream_lock );
     if( input_InitStream( p_input, 0 ) == -1)
     {
@@ -1492,189 +1519,127 @@ static int DemuxOpen( vlc_object_t *p_this )
         msg_Err( p_input, "cannot init stream" );
         return( VLC_EGENERIC );
     }
-    if( input_AddProgram( p_input, 0, 0) == NULL )
-    {
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        msg_Err( p_input, "cannot add program" );
-        return VLC_EGENERIC;
-    }
+    p_input->stream.i_mux_rate =  0 / 50;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
-    p_input->stream.i_mux_rate =  0;
+    p_input->pf_demux = Demux;
+    p_input->pf_demux_control = demux_vaControlDefault;
+    p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
+    p_sys->i_es = 0;
+    p_sys->es   = NULL;
 
-    i_streams = GetDWBE( &p_peek[4] );
-    if( input_Peek( p_input, &p_peek, 8 + 20 * i_streams )
-        < 8 + 20 * i_streams )
+    if( stream_Peek( p_input->s, &p_peek, 8 + 20 * i_es ) < 8 + 20 * i_es )
     {
         msg_Err( p_input, "v4l plugin discarded (cannot peek)" );
         return VLC_EGENERIC;
     }
     p_peek += 8;
 
-    for( i = 0; i < i_streams; i++ )
+    for( i = 0; i < i_es; i++ )
     {
-        es_descriptor_t *p_es;
+        es_format_t fmt;
 
         if( !strncmp( p_peek, "auds", 4 ) )
         {
-#define wf ((WAVEFORMATEX*)p_es->p_waveformatex)
-            p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
-                                i + 1, AUDIO_ES, NULL, 0 );
-            p_es->i_stream_id   = i + 1;
-            p_es->i_fourcc      =
-                VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
-
-            p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
-
-            wf->wFormatTag      = WAVE_FORMAT_UNKNOWN;
-            wf->nChannels       = GetDWBE( &p_peek[8] );
-            wf->nSamplesPerSec  = GetDWBE( &p_peek[12] );
-            wf->wBitsPerSample  = GetDWBE( &p_peek[16] );
-            wf->nBlockAlign     = wf->wBitsPerSample * wf->nChannels / 8;
-            wf->nAvgBytesPerSec = wf->nBlockAlign * wf->nSamplesPerSec;
-            wf->cbSize          = 0;
-
-            msg_Dbg( p_input, "added new audio es %d channels %dHz",
-                     wf->nChannels, wf->nSamplesPerSec );
-
-            input_SelectES( p_input, p_es );
-#undef wf
+            es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC( p_peek[4], p_peek[5],
+                                                        p_peek[6], p_peek[7] ) );
+
+            fmt.audio.i_channels = GetDWBE( &p_peek[8] );
+            fmt.audio.i_rate = GetDWBE( &p_peek[12] );
+            fmt.audio.i_bitspersample = GetDWBE( &p_peek[16] );
+            fmt.audio.i_blockalign = fmt.audio.i_channels *
+                                     fmt.audio.i_bitspersample / 8;
+            fmt.i_bitrate = fmt.audio.i_channels *
+                            fmt.audio.i_rate *
+                            fmt.audio.i_bitspersample;
+
+            msg_Dbg( p_input, "new audio es %d channels %dHz",
+                     fmt.audio.i_channels, fmt.audio.i_rate );
+
+            TAB_APPEND( p_sys->i_es, p_sys->es,
+                        es_out_Add( p_input->p_es_out, &fmt ) );
         }
         else if( !strncmp( p_peek, "vids", 4 ) )
         {
-#define bih ((BITMAPINFOHEADER*)p_es->p_bitmapinfoheader)
-            p_es = input_AddES( p_input, p_input->stream.pp_programs[0],
-                                i + 1, VIDEO_ES, NULL, 0 );
-            p_es->i_stream_id   = i + 1;
-            p_es->i_fourcc  =
-                VLC_FOURCC( p_peek[4], p_peek[5], p_peek[6], p_peek[7] );
-
-            p_es->p_bitmapinfoheader = malloc( sizeof( BITMAPINFOHEADER ) );
-
-            bih->biSize     = sizeof( BITMAPINFOHEADER );
-            bih->biWidth    = GetDWBE( &p_peek[8] );
-            bih->biHeight   = GetDWBE( &p_peek[12] );
-            bih->biPlanes   = 0;
-            bih->biBitCount = 0;
-            bih->biCompression      = 0;
-            bih->biSizeImage= 0;
-            bih->biXPelsPerMeter    = 0;
-            bih->biYPelsPerMeter    = 0;
-            bih->biClrUsed  = 0;
-            bih->biClrImportant     = 0;
+            es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC( p_peek[4], p_peek[5],
+                            p_peek[6], p_peek[7] ) );
+            fmt.video.i_width  = GetDWBE( &p_peek[8] );
+            fmt.video.i_height = GetDWBE( &p_peek[12] );
 
             msg_Dbg( p_input, "added new video es %4.4s %dx%d",
-                     (char*)&p_es->i_fourcc, bih->biWidth, bih->biHeight );
-
-            input_SelectES( p_input, p_es );
-#undef bih
+                     (char*)&fmt.i_codec,
+                     fmt.video.i_width, fmt.video.i_height );
+            TAB_APPEND( p_sys->i_es, p_sys->es,
+                        es_out_Add( p_input->p_es_out, &fmt ) );
         }
 
         p_peek += 20;
     }
 
-    p_input->stream.p_selected_program->b_is_ok = 1;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
+    /* Skip header */
+    stream_Read( p_input->s, NULL, 8 + 20 * i_es );
 
-    if( input_SplitBuffer( p_input, &p_pk, 8 + i_streams * 20 ) > 0 )
-    {
-        input_DeletePacket( p_input->p_method_data, p_pk );
-    }
-
-    p_input->pf_demux = Demux;
-    p_input->pf_demux_control = demux_vaControlDefault;
     return VLC_SUCCESS;
 }
 
+/****************************************************************************
+ * DemuxClose:
+ ****************************************************************************/
 static void DemuxClose( vlc_object_t *p_this )
 {
-    return;
-}
+    input_thread_t *p_input = (input_thread_t *)p_this;
+    demux_sys_t    *p_sys = p_input->p_demux_data;
 
-#define MAX_PACKETS_IN_FIFO 3
+    if( p_sys->i_es > 0 )
+    {
+        free( p_sys->es );
+    }
+    free( p_sys );
+}
 
+/****************************************************************************
+ * Demux:
+ ****************************************************************************/
 static int Demux( input_thread_t *p_input )
 {
-    es_descriptor_t *p_es;
-    pes_packet_t    *p_pes;
+    demux_sys_t *p_sys = p_input->p_demux_data;
+    block_t     *p_block;
 
-    int i_stream;
+    int i_es;
     int i_size;
 
     uint8_t *p_peek;
     mtime_t i_pts;
 
-    if( input_Peek( p_input, &p_peek, 16 ) < 16 )
+    if( stream_Peek( p_input->s, &p_peek, 16 ) < 16 )
     {
         msg_Warn( p_input, "cannot peek (EOF ?)" );
-        return( 0 );
+        return 0;
     }
 
-    i_stream = GetDWBE( &p_peek[0] );
-    i_size   = GetDWBE( &p_peek[4] );
-    i_pts    = GetQWBE( &p_peek[8] );
-
-    p_es = p_input->stream.p_selected_program->pp_es[i_stream];
-    if( !p_es )
+    i_es   = GetDWBE( &p_peek[0] );
+    if( i_es < 0 || i_es >= p_sys->i_es )
     {
         msg_Err( p_input, "cannot find ES" );
+        return -1;
     }
 
-    p_pes = input_NewPES( p_input->p_method_data );
-    if( p_pes == NULL )
+    i_size = GetDWBE( &p_peek[4] );
+    i_pts  = GetQWBE( &p_peek[8] );
+
+    if( ( p_block = stream_Block( p_input->s, 16 + i_size ) ) == NULL )
     {
-        msg_Warn( p_input, "cannot allocate PES" );
-        msleep( 1000 );
-        return( 1 );
+        msg_Warn( p_input, "cannot read data" );
+        return 0;
     }
-    i_size += 16;
-    while( i_size > 0 )
-    {
-        data_packet_t   *p_data;
-        int i_read;
 
-        if( (i_read = input_SplitBuffer( p_input, &p_data,
-                                         __MIN( i_size, 10000 ) ) ) <= 0 )
-        {
-            input_DeletePES( p_input->p_method_data, p_pes );
-            return( 0 );
-        }
-        if( !p_pes->p_first )
-        {
-            p_pes->p_first = p_data;
-            p_pes->i_nb_data = 1;
-            p_pes->i_pes_size = i_read;
-        }
-        else
-        {
-            p_pes->p_last->p_next  = p_data;
-            p_pes->i_nb_data++;
-            p_pes->i_pes_size += i_read;
-        }
-        p_pes->p_last  = p_data;
-        i_size -= i_read;
-    }
-    p_pes->p_first->p_payload_start += 16;
-    p_pes->i_pes_size               -= 16;
+    p_block->p_buffer += 16;
+    p_block->i_buffer -= 16;
 
-    if( p_es && p_es->p_decoder_fifo )
-    {
-        vlc_mutex_lock( &p_es->p_decoder_fifo->data_lock );
-        if( p_es->p_decoder_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
-        {
-            /* Wait for the decoder. */
-            vlc_cond_wait( &p_es->p_decoder_fifo->data_wait,
-                           &p_es->p_decoder_fifo->data_lock );
-        }
-        vlc_mutex_unlock( &p_es->p_decoder_fifo->data_lock );
-        p_pes->i_pts = p_pes->i_dts = i_pts + p_input->i_pts_delay;
+    p_block->i_dts =
+    p_block->i_pts = i_pts + p_input->i_pts_delay;
 
-        input_DecodePES( p_es->p_decoder_fifo, p_pes );
-    }
-    else
-    {
-        input_DeletePES( p_input->p_method_data, p_pes );
-    }
+    es_out_Send( p_input->p_es_out, p_sys->es[i_es], p_block );
 
     return 1;
 }