Commit 97b3335a authored by Jean-Paul Saman's avatar Jean-Paul Saman

Digital Cameras (firewire/1394) support by Andreas Guzzo (xant at xant dot...

Digital Cameras (firewire/1394) support by Andreas Guzzo (xant at xant dot net). I left out the rotation code, because in vlc-trunk there is already a rotation video filter2.
parent faaec5e9
......@@ -11,6 +11,7 @@ The VideoLAN team would like to thank the following contributors:
Alex Antropoff <alant at transtelecom dot md> - RFC3016 (LATM) RTP packetizer extension
Alexander Didebulidze <alexander.didebulidze at stusta dot mhn dot de> - Georgian localization
Alexander Gall <gall at switch dot ch> - Solaris fixes and CDDB fixes
Andrea Guzzo <xant at xant dot net> - dc1394 firewire support
Alex Izvorski <aizvorski at gmail dot com> - some more x264 options
André de Barros Martins Ribeiro <andrerib at ajato.com.br> - Brazilian portuguese localization
Andre Pang <adre.pang at csiro dot au> - Annodex support
......
......@@ -1656,6 +1656,37 @@ if test "${enable_live555}" != "no"; then
fi
fi
dnl
dnl special access module for dc1394 input
dnl
AC_ARG_ENABLE(dc1394,
[ --enable-dc1394 dc1394 access module (default disabled)])
if test "${enable_dc1394}" = "yes"
then
AC_CHECK_HEADERS(libraw1394/raw1394.h, [
AC_CHECK_LIB( raw1394, raw1394_get_nodecount, [
AC_CHECK_HEADERS(libdc1394/dc1394_control.h , [
dnl AC_CHECK_LIB( dc1394_control, dc1394_setup_capture, [
VLC_ADD_PLUGINS([dc1394])
VLC_ADD_LDFLAGS([dc1394],[-ldc1394_control -lraw1394])
dnl ],
dnl [
dnl AC_MSG_ERROR([libdc1394 are mandatory for dc1394 input module. try --disable-dc1394 or install those libraries])
dnl ])
],
[
AC_MSG_ERROR([libdc1394 are mandatory for dc1394 input module. try --disable-dc1394 or install those libraries])
])
],
[
AC_MSG_ERROR([libraw1394 are mandatory for dc1394 input module. try --disable-dc1394 or install those libraries])
])
],
[
AC_MSG_ERROR([libraw1394 is mandatory for dc1394 input module. try --disable-dc1394 or install those libraries])
])
fi
dnl
dnl dv module: digital video module check for libraw1394
dnl
......
......@@ -9,6 +9,7 @@ SOURCES_access_smb = smb.c
SOURCES_access_gnomevfs = gnomevfs.c
SOURCES_dvdnav = dvdnav.c
SOURCES_dvdread = dvdread.c
SOURCES_dc1394 = dc1394.c
SOURCES_access_fake = fake.c
SOURCES_pvr = pvr.c videodev2.h
SOURCES_v4l = v4l.c videodev_mjpeg.h
......
/*****************************************************************************
* 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;
}
}