--- /dev/null
+/*****************************************************************************
+ * dc1394.c: firewire input module
+ *****************************************************************************
+ * Copyright (C) 2006 the VideoLAN team
+ *
+ * Authors: Xant Majere <xant@xant.net>
+ *
+ *****************************************************************************
+ * This library 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;
+ * version 2 of the License.
+ *
+ * This library 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 library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+#include <vlc/vout.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#elif defined( WIN32 ) && !defined( UNDER_CE )
+# include <io.h>
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/soundcard.h>
+
+#include <libraw1394/raw1394.h>
+#include <libdc1394/dc1394_control.h>
+
+#define MAX_IEEE1394_HOSTS 32
+#define MAX_CAMERA_NODES 32
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+static void OpenAudioDev( demux_t *p_demux );
+static inline void CloseAudioDev( demux_t *p_demux );
+
+vlc_module_begin();
+ set_description( _("dc1394 input") );
+ set_capability( "access_demux", 10 );
+ add_shortcut( "dc1394" );
+ set_callbacks( Open, Close );
+vlc_module_end();
+
+typedef struct __dc_camera
+{
+ int port;
+ nodeid_t node;
+ u_int64_t uid;
+} dc_camera;
+
+typedef struct demux_sys_t
+{
+ dc1394_cameracapture camera;
+ picture_t pic;
+ int dma_capture;
+#define DMA_OFF 0
+#define DMA_ON 1
+ int num_ports;
+ int num_cameras;
+ int selected_camera;
+ u_int64_t selected_uid;
+
+ dc_camera *camera_nodes;
+ dc1394_camerainfo camera_info;
+ dc1394_miscinfo misc_info;
+ raw1394handle_t fd_video;
+ quadlet_t supported_framerates;
+
+ int width;
+ int height;
+ int frame_size;
+ int frame_rate;
+ unsigned int brightness;
+ unsigned int focus;
+ char *dma_device;
+ es_out_id_t *p_es_video;
+
+ /* audio stuff */
+ int i_sample_rate;
+ int channels;
+ int i_audio_max_frame_size;
+ int fd_audio;
+ char *audio_device;
+#define NO_ROTATION 0
+#define ROTATION_LEFT 1
+#define ROTATION_RIGHT 2
+ es_out_id_t *p_es_audio;
+} dc1394_sys;
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+static int Demux( demux_t *p_demux );
+static int Control( demux_t *, int, va_list );
+static block_t *GrabVideo( demux_t *p_demux );
+static block_t *GrabAudio( demux_t *p_demux );
+static int process_options( demux_t *p_demux);
+
+/*****************************************************************************
+ * ScanCameras
+ *****************************************************************************/
+static void ScanCameras( dc1394_sys *sys, demux_t *p_demux )
+{
+ struct raw1394_portinfo portinfo[MAX_IEEE1394_HOSTS];
+ raw1394handle_t tempFd;
+ dc1394_camerainfo info;
+ dc_camera *node_list = NULL;
+ nodeid_t *nodes = NULL;
+ int num_ports = 0;
+ int num_cameras = 0;
+ int nodecount;
+ int i, n;
+
+ memset( &portinfo, 0, sizeof(portinfo) );
+
+ msg_Dbg( p_demux, "Scanning for ieee1394 ports ..." );
+
+ tempFd = raw1394_new_handle();
+ if( !tempFd )
+ return VLC_EGENERIC;
+ raw1394_get_port_info( tempFd, portinfo, MAX_IEEE1394_HOSTS);
+ raw1394_destroy_handle( tempFd );
+
+ for( i=0; i < MAX_IEEE1394_HOSTS; i++ )
+ {
+ /* check if port exists and has at least one node*/
+ if( !portinfo[i].nodes )
+ continue;
+ nodes = NULL;
+ nodecount = 0;
+ tempFd = dc1394_create_handle( i );
+
+ /* skip this port if we can't obtain a valid handle */
+ if( !tempFd )
+ continue;
+ msg_Dbg( p_demux, "Found ieee1394 port %d (%s) ... "
+ "checking for camera nodes",
+ i, portinfo[i].name );
+ num_ports++;
+
+ nodes = dc1394_get_camera_nodes( tempFd, &nodecount, 0 );
+ if( nodecount )
+ {
+ msg_Dbg( p_demux, "Found %d dc1394 cameras on port %d (%s)",
+ nodecount, i, portinfo[i].name );
+
+ if( node_list )
+ node_list = realloc( node_list, sizeof(dc_camera) * (num_cameras+nodecount) );
+ else
+ node_list = malloc( sizeof(dc_camera) * nodecount);
+
+ for( n = 0; n < nodecount; n++ )
+ {
+ int result = 0;
+
+ result = dc1394_get_camera_info( tempFd, nodes[n], &info );
+ if( result == DC1394_SUCCESS )
+ {
+ node_list[num_cameras+n].uid = info.euid_64;
+ }
+ node_list[num_cameras+n].node = nodes[n];
+ node_list[num_cameras+n].port = i;
+ }
+ num_cameras += nodecount;
+ }
+ else
+ msg_Dbg( p_demux, "no cameras found on port %d (%s)",
+ i, portinfo[i].name );
+
+ if( tempFd )
+ dc1394_destroy_handle( tempFd );
+ }
+ sys->num_ports = num_ports;
+ sys->num_cameras = num_cameras;
+ sys->camera_nodes = node_list;
+}
+
+/*****************************************************************************
+ * Open:
+ *****************************************************************************/
+static int Open( vlc_object_t *p_this )
+{
+ demux_t *p_demux = (demux_t*)p_this;
+ demux_sys_t *p_sys;
+ es_format_t fmt;
+ int i;
+ int i_width;
+ int i_height;
+ int i_aspect;
+ int result = 0;
+
+ /* Set up p_demux */
+ p_demux->pf_demux = Demux;
+ p_demux->pf_control = Control;
+ p_demux->info.i_update = 0;
+ p_demux->info.i_title = 0;
+ p_demux->info.i_seekpoint = 0;
+
+ p_demux->p_sys = p_sys = malloc( sizeof( demux_sys_t ) );
+ if( !p_sys )
+ {
+ msg_Err( p_demux, "not enough memory available" );
+ return VLC_ENOMEM;
+ }
+ memset( p_sys, 0, sizeof( demux_sys_t ) );
+ memset( &fmt, 0, sizeof( es_format_t ) );
+
+ /* DEFAULTS */
+ p_sys->frame_size = MODE_640x480_YUV422;
+ p_sys->width = 640;
+ p_sys->height = 480;
+ p_sys->frame_rate = FRAMERATE_30;
+ p_sys->brightness = 200;
+ p_sys->focus = 0;
+ p_sys->dma_capture = DMA_ON; /* defaults to VIDEO1394 capture mode */
+ p_sys->fd_audio = -1;
+ p_sys->fd_video = NULL;
+ p_sys->camera_nodes = NULL;
+ p_sys->selected_camera = 0;
+ p_sys->dma_device = NULL;
+ p_sys->selected_uid = 0;
+
+ /* PROCESS INPUT OPTIONS */
+ if( process_options(p_demux) != VLC_SUCCESS )
+ {
+ msg_Err( p_demux, "Bad MRL, please check the option line "
+ "(MRL was: %s)",
+ p_demux->psz_path );
+ free( p_sys );
+ p_demux->p_sys = NULL;
+ return VLC_EGENERIC;
+ }
+
+ msg_Dbg( p_demux, "Selected camera %d", p_sys->selected_camera );
+ msg_Dbg( p_demux, "Selected uid 0x%llx", p_sys->selected_uid );
+
+ ScanCameras( p_sys, p_demux );
+ if( !p_sys->camera_nodes )
+ {
+ msg_Err( p_demux, "No camera found !!" );
+ free( p_sys );
+ p_demux->p_sys = NULL;
+ return VLC_EGENERIC;
+ }
+
+ if( p_sys->selected_uid )
+ {
+ int found = 0;
+ for( i=0; i < p_sys->num_cameras; i++ )
+ {
+ if( p_sys->camera_nodes[i].uid == p_sys->selected_uid )
+ {
+ p_sys->selected_camera = i;
+ found++;
+ break;
+ }
+ }
+ if( !found )
+ {
+ msg_Err( p_demux, "Can't find camera with uid : 0x%llx.",
+ p_sys->selected_uid );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ }
+ else if( p_sys->selected_camera >= p_sys->num_cameras )
+ {
+ msg_Err( p_demux, "there are not this many cameras. (%d/%d)",
+ p_sys->selected_camera, p_sys->num_cameras );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ p_sys->fd_video = dc1394_create_handle(
+ p_sys->camera_nodes[p_sys->selected_camera].port );
+ if( (int)p_sys->fd_video < 0 )
+ {
+ msg_Err( p_demux, "Can't init dc1394 handle" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ /* get camera info */
+ result = dc1394_get_camera_info( p_sys->fd_video,
+ p_sys->camera_nodes[p_sys->selected_camera].node,
+ &p_sys->camera_info );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux ,"unable to get camera info" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ dc1394_print_camera_info( &p_sys->camera_info );
+ result = dc1394_get_camera_misc_info( p_sys->fd_video,
+ p_sys->camera_nodes[p_sys->selected_camera].node,
+ &p_sys->misc_info );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to get camera misc info" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ /* init camera and set some video options */
+ result = dc1394_init_camera( p_sys->camera_info.handle,
+ p_sys->camera_info.id );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to get init dc1394 camera" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ if( p_sys->focus )
+ {
+ result = dc1394_set_focus( p_sys->camera_info.handle,
+ p_sys->camera_nodes[p_sys->selected_camera].node,
+ p_sys->focus );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to set initial focus to %u",
+ p_sys->focus );
+ }
+ msg_Dbg( p_demux, "Initial focus set to %u", p_sys->focus );
+ }
+
+ result = dc1394_set_brightness( p_sys->camera_info.handle,
+ p_sys->camera_nodes[p_sys->selected_camera].node,
+ p_sys->brightness );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to set init brightness to %d",
+ p_sys->brightness);
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ result = dc1394_set_video_framerate( p_sys->camera_info.handle,
+ p_sys->camera_nodes[p_sys->selected_camera].node,
+ p_sys->frame_rate );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to set framerate to %d",
+ p_sys->frame_rate );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ p_sys->misc_info.framerate = p_sys->frame_rate;
+
+ result = dc1394_set_video_format( p_sys->camera_info.handle,
+ p_sys->camera_nodes[p_sys->selected_camera].node,
+ FORMAT_VGA_NONCOMPRESSED );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to set video format to VGA_NONCOMPRESSED" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ p_sys->misc_info.format = FORMAT_VGA_NONCOMPRESSED;
+
+ result = dc1394_set_video_mode( p_sys->camera_info.handle,
+ p_sys->camera_nodes[p_sys->selected_camera].node,
+ p_sys->frame_size );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to set video mode" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ p_sys->misc_info.mode = p_sys->frame_size;
+
+ /* reprobe everything */
+ result = dc1394_get_camera_info( p_sys->camera_info.handle,
+ p_sys->camera_info.id,
+ &p_sys->camera_info );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "Could not get camera basic information!" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ result = dc1394_get_camera_misc_info( p_sys->camera_info.handle,
+ p_sys->camera_info.id,
+ &p_sys->misc_info );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "Could not get camera misc information!" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+
+ /* set iso_channel */
+ result = dc1394_set_iso_channel_and_speed( p_sys->camera_info.handle,
+ p_sys->camera_info.id,
+ p_sys->selected_camera,
+ SPEED_400 );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "Could not set iso channel!" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ msg_Dbg( p_demux, "Using ISO channel %d", p_sys->misc_info.iso_channel );
+ p_sys->misc_info.iso_channel = p_sys->selected_camera;
+
+ /* and setup capture */
+ if( p_sys->dma_capture )
+ {
+ result = dc1394_dma_setup_capture( p_sys->camera_info.handle,
+ p_sys->camera_info.id,
+ p_sys->misc_info.iso_channel,
+ p_sys->misc_info.format,
+ p_sys->misc_info.mode,
+ SPEED_400,
+ p_sys->misc_info.framerate,
+ 10, 0,
+ p_sys->dma_device,
+ &p_sys->camera );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux ,"unable to setup camera" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ }
+ else
+ {
+ result = dc1394_setup_capture( p_sys->camera_info.handle,
+ p_sys->camera_info.id,
+ p_sys->misc_info.iso_channel,
+ p_sys->misc_info.format,
+ p_sys->misc_info.mode,
+ SPEED_400,
+ p_sys->misc_info.framerate,
+ &p_sys->camera );
+ if( result != DC1394_SUCCESS)
+ {
+ msg_Err( p_demux ,"unable to setup camera" );
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ }
+
+ /* TODO - UYV444 chroma converter is missing, when it will be available
+ * fourcc will become variable (and not just a fixed value for UYVY)
+ */
+ i_width = p_sys->camera.frame_width;
+ i_height = p_sys->camera.frame_height;
+
+ i_aspect = vout_InitPicture( VLC_OBJECT(p_demux), &p_sys->pic,
+ VLC_FOURCC('U', 'Y', 'V', 'Y'),
+ i_width, i_height,
+ i_width * VOUT_ASPECT_FACTOR / i_height );
+
+ es_format_Init( &fmt, VIDEO_ES, VLC_FOURCC('U', 'Y', 'V', 'Y') );
+
+ fmt.video.i_width = i_width;
+ fmt.video.i_height = i_height;
+
+ msg_Dbg( p_demux, "added new video es %4.4s %dx%d",
+ (char*)&fmt.i_codec, fmt.video.i_width, fmt.video.i_height );
+
+ p_sys->p_es_video = es_out_Add( p_demux->out, &fmt );
+
+ if( p_sys->audio_device )
+ {
+ OpenAudioDev( p_demux );
+ if( p_sys->fd_audio >= 0 )
+ {
+ es_format_t fmt;
+ es_format_Init( &fmt, AUDIO_ES, VLC_FOURCC('a','r','a','w') );
+
+ fmt.audio.i_channels = p_sys->channels ? p_sys->channels : 1;
+ fmt.audio.i_rate = p_sys->i_sample_rate;
+ fmt.audio.i_bitspersample = 16; /* FIXME: hmm, ?? */
+ 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_demux, "new audio es %d channels %dHz",
+ fmt.audio.i_channels, fmt.audio.i_rate );
+
+ p_sys->p_es_audio = es_out_Add( p_demux->out, &fmt );
+ }
+ }
+
+ /* have the camera start sending us data */
+ result = dc1394_start_iso_transmission( p_sys->camera_info.handle,
+ p_sys->camera_info.id );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to start camera iso transmission" );
+ if( p_sys->dma_capture )
+ {
+ dc1394_dma_release_camera( p_sys->fd_video, &p_sys->camera );
+ }
+ else
+ {
+ dc1394_release_camera( p_sys->fd_video, &p_sys->camera );
+ }
+ Close( p_this );
+ return VLC_EGENERIC;
+ }
+ p_sys->misc_info.is_iso_on = DC1394_TRUE;
+ return VLC_SUCCESS;
+}
+
+static void OpenAudioDev( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ char *psz_device = p_sys->audio_device;
+ int i_format = AFMT_S16_LE;
+ int result;
+
+ p_sys->fd_audio = open( psz_device, O_RDONLY | O_NONBLOCK );
+ if( p_sys->fd_audio < 0 )
+ {
+ msg_Err( p_demux, "cannot open audio device (%s)", psz_device );
+ CloseAudioDev( p_demux );
+ }
+
+ if( !p_sys->i_sample_rate )
+ p_sys->i_sample_rate = 44100;
+
+ result = ioctl( p_sys->fd_audio, SNDCTL_DSP_SETFMT, &i_format );
+ if( (result < 0) || (i_format != AFMT_S16_LE) )
+ {
+ msg_Err( p_demux, "cannot set audio format (16b little endian) "
+ "(%d)", i_format );
+ CloseAudioDev( p_demux );
+ }
+
+ result = ioctl( p_sys->fd_audio, SNDCTL_DSP_CHANNELS, &p_sys->channels );
+ if( result < 0 )
+ {
+ msg_Err( p_demux, "cannot set audio channels count (%d)",
+ p_sys->channels );
+ CloseAudioDev( p_demux );
+ }
+
+ result = ioctl( p_sys->fd_audio, SNDCTL_DSP_SPEED, &p_sys->i_sample_rate );
+ if( result < 0 )
+ {
+ msg_Err( p_demux, "cannot set audio sample rate (%s)", p_sys->i_sample_rate );
+ CloseAudioDev( p_demux );
+ }
+
+ msg_Dbg( p_demux, "openened adev=`%s' %s %dHz",
+ psz_device,
+ (p_sys->channels > 1) ? "stereo" : "mono",
+ p_sys->i_sample_rate );
+
+ p_sys->i_audio_max_frame_size = 32 * 1024;
+}
+
+static inline void CloseAudioDev( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = NULL;
+
+ if( p_demux )
+ {
+ p_sys = p_demux->p_sys;
+ if( p_sys->fd_audio >= 0 )
+ close( p_sys->fd_audio );
+ }
+}
+
+/*****************************************************************************
+ * Close:
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+ demux_t *p_demux = (demux_t*)p_this;
+ demux_sys_t *p_sys = p_demux->p_sys;
+ int result = 0;
+
+ /* Stop data transmission */
+ result = dc1394_stop_iso_transmission( p_sys->fd_video,
+ p_sys->camera.node );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "couldn't stop the camera" );
+ }
+
+ /* Close camera */
+ if( p_sys->dma_capture )
+ {
+ dc1394_dma_unlisten( p_sys->fd_video, &p_sys->camera );
+ dc1394_dma_release_camera( p_sys->fd_video, &p_sys->camera );
+ }
+ else
+ {
+ dc1394_release_camera( p_sys->fd_video, &p_sys->camera );
+ }
+
+ if( p_sys->fd_video )
+ dc1394_destroy_handle( p_sys->fd_video );
+ CloseAudioDev( p_demux );
+
+ if( p_sys->camera_nodes )
+ free( p_sys->camera_nodes );
+ if( p_sys->audio_device )
+ free( p_sys->audio_device );
+
+ free( p_sys );
+}
+
+static void MovePixelUYVY( void *src, int spos, void *dst, int dpos )
+{
+ char u,v,y;
+ u_char *sc;
+ u_char *dc;
+
+ sc = (u_char *)src + (spos*2);
+ if( spos % 2 )
+ {
+ v = sc[0];
+ y = sc[1];
+ u = *(sc -2);
+ }
+ else
+ {
+ u = sc[0];
+ y = sc[1];
+ v = sc[2];
+ }
+ dc = (u_char *)dst+(dpos*2);
+ if( dpos % 2 )
+ {
+ dc[0] = v;
+ dc[1] = y;
+ }
+ else
+ {
+ dc[0] = u;
+ dc[1] = y;
+ }
+}
+
+/*****************************************************************************
+ * Demux:
+ *****************************************************************************/
+static block_t *GrabVideo( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ block_t *p_block = NULL;
+ int result = 0;
+
+ if( p_sys->dma_capture )
+ {
+ result = dc1394_dma_single_capture( &p_sys->camera );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to capture a frame" );
+ return NULL;
+ }
+ }
+ else
+ {
+ result = dc1394_single_capture( p_sys->camera_info.handle,
+ &p_sys->camera );
+ if( result != DC1394_SUCCESS )
+ {
+ msg_Err( p_demux, "unable to capture a frame" );
+ return NULL;
+ }
+ }
+
+ p_block = block_New( p_demux, p_sys->camera.frame_width *
+ p_sys->camera.frame_height * 2 );
+ if( !p_block )
+ {
+ msg_Err( p_demux, "cannot get block" );
+ return NULL;
+ }
+
+ if( !p_sys->camera.capture_buffer )
+ {
+ msg_Err (p_demux, "caputer buffer empty");
+ block_Release( p_block );
+ return NULL;
+ }
+
+ memcpy( p_block->p_buffer, (const char *)p_sys->camera.capture_buffer,
+ p_sys->camera.frame_width * p_sys->camera.frame_height * 2 );
+
+ p_block->i_pts = p_block->i_dts = mdate();
+ if( p_sys->dma_capture )
+ dc1394_dma_done_with_buffer( &p_sys->camera );
+ return p_block;
+}
+
+static block_t *GrabAudio( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ struct audio_buf_info buf_info;
+ block_t *p_block = NULL;
+ int i_read = 0;
+ int i_correct = 0;
+ int result = 0;
+
+ p_block = block_New( p_demux, p_sys->i_audio_max_frame_size );
+ if( !p_block )
+ {
+ msg_Warn( p_demux, "cannot get buffer" );
+ return NULL;
+ }
+
+ i_read = read( p_sys->fd_audio, p_block->p_buffer,
+ p_sys->i_audio_max_frame_size );
+
+ if( i_read <= 0 )
+ return NULL;
+
+ p_block->i_buffer = i_read;
+
+ /* Correct the date because of kernel buffering */
+ i_correct = i_read;
+ result = ioctl( p_sys->fd_audio, SNDCTL_DSP_GETISPACE, &buf_info );
+ if( result == 0 )
+ i_correct += buf_info.bytes;
+
+ p_block->i_pts = p_block->i_dts =
+ mdate() - I64C(1000000) * (mtime_t)i_correct /
+ 2 / p_sys->channels / p_sys->i_sample_rate;
+ return p_block;
+}
+
+static int Demux( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ block_t *p_blocka = NULL;
+ block_t *p_blockv = NULL;
+
+ /* Try grabbing audio frames first */
+ if( p_sys->fd_audio > 0 )
+ p_blocka = GrabAudio( p_demux );
+
+ /* Try grabbing video frame */
+ if( (int)p_sys->fd_video > 0 )
+ p_blockv = GrabVideo( p_demux );
+
+ if( !p_blocka && !p_blockv )
+ {
+ /* Sleep so we do not consume all the cpu, 10ms seems
+ * like a good value (100fps)
+ */
+ msleep( 10000 );
+ return 1;
+ }
+
+ if( p_blocka )
+ {
+ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_blocka->i_pts );
+ es_out_Send( p_demux->out, p_sys->p_es_audio, p_blocka );
+ }
+
+ if( p_blockv )
+ {
+ es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_blockv->i_pts );
+ es_out_Send( p_demux->out, p_sys->p_es_video, p_blockv );
+ }
+ return 1;
+}
+
+/*****************************************************************************
+ * Control:
+ *****************************************************************************/
+static int Control( demux_t *p_demux, int i_query, va_list args )
+{
+ vlc_bool_t *pb;
+ int64_t *pi64;
+
+ switch( i_query )
+ {
+ /* Special for access_demux */
+ case DEMUX_CAN_PAUSE:
+ case DEMUX_SET_PAUSE_STATE:
+ case DEMUX_CAN_CONTROL_PACE:
+ pb = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+ *pb = VLC_FALSE;
+ return VLC_SUCCESS;
+
+ case DEMUX_GET_PTS_DELAY:
+ pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = (int64_t)DEFAULT_PTS_DELAY;
+ return VLC_SUCCESS;
+
+ case DEMUX_GET_TIME:
+ pi64 = (int64_t*)va_arg( args, int64_t * );
+ *pi64 = mdate();
+ return VLC_SUCCESS;
+
+ /* TODO implement others */
+ default:
+ return VLC_EGENERIC;
+ }
+ return VLC_EGENERIC;
+}
+
+static int process_options( demux_t *p_demux )
+{
+ demux_sys_t *p_sys = p_demux->p_sys;
+ char *psz_dup;
+ char *psz_parser;
+ char *token = NULL;
+ char *state = NULL;
+ float rate_f;
+
+ if( strncmp(p_demux->psz_access, "dc1394", 6) != 0 )
+ return VLC_EGENERIC;
+
+ psz_dup = strdup( p_demux->psz_path );
+ psz_parser = psz_dup;
+ for( token = strtok_r( psz_parser,":",&state); token;
+ token = strtok_r( NULL, ":", &state ) )
+ {
+ if( strncmp( token, "size=", strlen("size=") ) == 0 )
+ {
+ token += strlen("size=");
+ if( strncmp( token, "160x120", 7 ) == 0 )
+ {
+ /* TODO - UYV444 chroma converter is needed ...
+ * video size of 160x120 is temporarily disabled
+ */
+ msg_Err( p_demux,
+ "video size of 160x120 is actually disabled for lack of chroma "
+ "support. It will relased ASAP, until then try an higher size "
+ "(320x240 and 640x480 are fully supported)" );
+ free(psz_dup);
+ return VLC_EGENERIC;
+#if 0
+ p_sys->frame_size = MODE_160x120_YUV444;
+ p_sys->width = 160;
+ p_sys->height = 120;
+#endif
+ }
+ else if( strncmp( token, "320x240", 7 ) == 0 )
+ {
+ p_sys->frame_size = MODE_320x240_YUV422;
+ p_sys->width = 320;
+ p_sys->height = 240;
+ }
+ else if( strncmp( token, "640x480", 7 ) == 0 )
+ {
+ p_sys->frame_size = MODE_640x480_YUV422;
+ p_sys->width = 640;
+ p_sys->height = 480;
+ }
+ else
+ {
+ msg_Err( p_demux,
+ "This program currently suppots frame sizes of"
+ " 160x120, 320x240, and 640x480. "
+ "Please specify one of them. You have specified %s.",
+ token );
+ free(psz_dup);
+ return VLC_EGENERIC;
+ }
+ msg_Dbg( p_demux, "Requested video size : %s",token );
+ }
+ else if( strncmp( token, "fps=", strlen( "fps=" ) ) == 0 )
+ {
+ token += strlen("fps=");
+ sscanf( token, "%g", &rate_f );
+ if( rate_f == 1.875 )
+ p_sys->frame_rate = FRAMERATE_1_875;
+ else if( rate_f == 3.75 )
+ p_sys->frame_rate = FRAMERATE_3_75;
+ else if( rate_f == 7.5 )
+ p_sys->frame_rate = FRAMERATE_7_5;
+ else if( rate_f == 15 )
+ p_sys->frame_rate = FRAMERATE_15;
+ else if( rate_f == 30 )
+ p_sys->frame_rate = FRAMERATE_30;
+ else if( rate_f == 60 )
+ p_sys->frame_rate = FRAMERATE_60;
+ else
+ {
+ msg_Err( p_demux ,
+ "This program supports framerates of"
+ " 1.875, 3.75, 7.5, 15, 30, 60. "
+ "Please specify one of them. You have specified %s.",
+ token);
+ free(psz_dup);
+ return VLC_EGENERIC;
+ }
+ msg_Dbg( p_demux, "Requested frame rate : %s",token );
+ }
+ else if( strncmp( token, "brightness=", strlen( "brightness=" ) ) == 0 )
+ {
+ int nr = 0;
+ token += strlen("brightness=");
+ nr = sscanf( token, "%u", &p_sys->brightness);
+ if( nr != 1 )
+ {
+ msg_Err( p_demux, "Bad brightness value '%s', "
+ "must be an unsigned integer.",
+ token );
+ free(psz_dup);
+ return VLC_EGENERIC;
+ }
+ }
+#if 0
+ else if( strncmp( token, "controller=", strlen( "controller=" ) ) == 0 )
+ {
+ int nr = 0;
+ token += strlen("controller=");
+ nr = sscanf( token, "%u", &p_sys->controller );
+ if( nr != 1)
+ {
+ msg_Err(p_demux, "Bad controller value '%s', "
+ "must be an unsigned integer.",
+ token );
+ return VLC_EGENERIC;
+ }
+ }
+#endif
+ else if( strncmp( token, "camera=", strlen( "camera=" ) ) == 0 )
+ {
+ int nr = 0;
+ token += strlen("camera=");
+ nr = sscanf(token,"%u",&p_sys->selected_camera);
+ if( nr != 1)
+ {
+ msg_Err( p_demux, "Bad camera number '%s', "
+ "must be an unsigned integer.",
+ token );
+ free(psz_dup);
+ return VLC_EGENERIC;
+ }
+ }
+ else if( strncmp( token, "capture=", strlen( "capture=" ) ) == 0)
+ {
+ token += strlen("capture=");
+ if( strncmp(token, "raw1394",7) == 0 )
+ {
+ msg_Dbg( p_demux, "DMA capture disabled!" );
+ p_sys->dma_capture = DMA_OFF;
+ }
+ else if( strncmp(token,"video1394",9) == 0 )
+ {
+ msg_Dbg( p_demux, "DMA capture enabled!" );
+ p_sys->dma_capture = DMA_ON;
+ }
+ else
+ {
+ msg_Err(p_demux, "Bad capture method value '%s', "
+ "it can be 'raw1394' or 'video1394'.",
+ token );
+ free(psz_dup);
+ return VLC_EGENERIC;
+ }
+ }
+ else if( strncmp( token, "adev=", strlen( "adev=" ) ) == 0 )
+ {
+ token += strlen("adev=");
+ p_sys->audio_device = strdup(token);
+ msg_Dbg( p_demux, "Using audio device '%s'.", token );
+ }
+ else if( strncmp( token, "samplerate=", strlen( "samplerate=" ) ) == 0 )
+ {
+ token += strlen("samplerate=");
+ sscanf( token, "%d", &p_sys->i_sample_rate );
+ }
+ else if( strncmp( token, "channels=", strlen("channels=" ) ) == 0 )
+ {
+ token += strlen("channels=");
+ sscanf( token, "%d", &p_sys->channels );
+ }
+ else if( strncmp( token, "focus=", strlen("focus=" ) ) == 0)
+ {
+ token += strlen("focus=");
+ sscanf( token, "%u", &p_sys->focus );
+ }
+ else if( strncmp( token, "uid=", strlen("uid=") ) == 0)
+ {
+ token += strlen("uid=");
+ sscanf( token, "0x%llx", &p_sys->selected_uid );
+ }
+ }
+ if( psz_dup ) free( psz_dup );
+ return VLC_SUCCESS;
+}
+