2002-09-24 06:08:50 +08:00
|
|
|
//
|
2002-12-10 21:21:41 +08:00
|
|
|
// ZoneMinder Capture Daemon, $Date$, $Revision$
|
2008-07-25 17:33:23 +08:00
|
|
|
// Copyright (C) 2001-2008 Philip Coombes
|
2002-09-24 06:08:50 +08:00
|
|
|
//
|
|
|
|
// This program is free software; you can redistribute it and/or
|
|
|
|
// modify it under the terms of the GNU General Public License
|
|
|
|
// as published by the Free Software Foundation; either version 2
|
|
|
|
// of the License, or (at your option) any later version.
|
|
|
|
//
|
|
|
|
// This program 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 General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with this program; if not, write to the Free Software
|
|
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
//
|
|
|
|
|
2002-12-24 20:02:08 +08:00
|
|
|
#include <getopt.h>
|
2003-03-26 20:00:16 +08:00
|
|
|
#include <signal.h>
|
2003-03-27 06:12:25 +08:00
|
|
|
#include <values.h>
|
2003-03-26 20:00:16 +08:00
|
|
|
|
2002-09-16 17:19:24 +08:00
|
|
|
#include "zm.h"
|
2003-03-26 20:00:16 +08:00
|
|
|
#include "zm_db.h"
|
2008-07-16 16:35:59 +08:00
|
|
|
#include "zm_time.h"
|
2006-04-05 20:22:27 +08:00
|
|
|
#include "zm_signal.h"
|
2003-03-26 20:00:16 +08:00
|
|
|
#include "zm_monitor.h"
|
2002-09-16 17:19:24 +08:00
|
|
|
|
2002-12-24 20:02:08 +08:00
|
|
|
void Usage()
|
2002-09-16 17:19:24 +08:00
|
|
|
{
|
2008-07-16 16:35:59 +08:00
|
|
|
fprintf( stderr, "zmc -d <device_path> or -r <proto> -H <host> -P <port> -p <path> or -f <file_path> or -m <monitor_id>\n" );
|
2004-02-16 03:17:38 +08:00
|
|
|
|
2002-12-24 20:02:08 +08:00
|
|
|
fprintf( stderr, "Options:\n" );
|
2008-07-16 16:35:59 +08:00
|
|
|
fprintf( stderr, " -d, --device <device_path> : For local cameras, device to access. E.g /dev/video0 etc\n" );
|
|
|
|
fprintf( stderr, " -r <proto> -H <host> -P <port> -p <path> : For remote cameras\n" );
|
|
|
|
fprintf( stderr, " -f, --file <file_path> : For local images, jpg file to access.\n" );
|
|
|
|
fprintf( stderr, " -m, --monitor <monitor_id> : For sources associated with a single monitor\n" );
|
|
|
|
fprintf( stderr, " -h, --help : This screen\n" );
|
2002-12-24 20:02:08 +08:00
|
|
|
exit( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
int main( int argc, char *argv[] )
|
|
|
|
{
|
2005-10-17 18:58:25 +08:00
|
|
|
const char *device = "";
|
2008-07-16 16:35:59 +08:00
|
|
|
const char *protocol = "";
|
2004-01-15 05:26:47 +08:00
|
|
|
const char *host = "";
|
|
|
|
const char *port = "";
|
|
|
|
const char *path = "";
|
2005-10-18 05:55:02 +08:00
|
|
|
const char *file = "";
|
2004-02-16 03:17:38 +08:00
|
|
|
int monitor_id = -1;
|
2002-12-24 20:02:08 +08:00
|
|
|
|
|
|
|
static struct option long_options[] = {
|
|
|
|
{"device", 1, 0, 'd'},
|
2008-07-16 16:35:59 +08:00
|
|
|
{"protocol", 1, 0, 'r'},
|
2003-03-26 20:00:16 +08:00
|
|
|
{"host", 1, 0, 'H'},
|
|
|
|
{"port", 1, 0, 'P'},
|
2004-02-16 03:17:38 +08:00
|
|
|
{"path", 1, 0, 'p'},
|
2005-10-18 05:55:02 +08:00
|
|
|
{"file", 1, 0, 'f'},
|
2004-02-16 03:17:38 +08:00
|
|
|
{"monitor", 1, 0, 'm'},
|
2002-12-24 20:02:08 +08:00
|
|
|
{"help", 0, 0, 'h'},
|
|
|
|
{0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
{
|
|
|
|
int option_index = 0;
|
|
|
|
|
2005-10-18 05:55:02 +08:00
|
|
|
int c = getopt_long (argc, argv, "d:H:P:p:f:m:h", long_options, &option_index);
|
2002-12-24 20:02:08 +08:00
|
|
|
if (c == -1)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
case 'd':
|
2005-10-17 18:58:25 +08:00
|
|
|
device = optarg;
|
2002-12-24 20:02:08 +08:00
|
|
|
break;
|
2003-03-26 20:00:16 +08:00
|
|
|
case 'H':
|
|
|
|
host = optarg;
|
|
|
|
break;
|
|
|
|
case 'P':
|
|
|
|
port = optarg;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
path = optarg;
|
|
|
|
break;
|
2005-10-18 05:55:02 +08:00
|
|
|
case 'f':
|
|
|
|
file = optarg;
|
|
|
|
break;
|
2004-02-16 03:17:38 +08:00
|
|
|
case 'm':
|
|
|
|
monitor_id = atoi(optarg);
|
|
|
|
break;
|
2002-12-24 20:02:08 +08:00
|
|
|
case 'h':
|
|
|
|
case '?':
|
|
|
|
Usage();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
//fprintf( stderr, "?? getopt returned character code 0%o ??\n", c );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (optind < argc)
|
|
|
|
{
|
|
|
|
fprintf( stderr, "Extraneous options, " );
|
|
|
|
while (optind < argc)
|
|
|
|
printf ("%s ", argv[optind++]);
|
|
|
|
printf ("\n");
|
|
|
|
Usage();
|
|
|
|
}
|
|
|
|
|
2005-10-18 05:55:02 +08:00
|
|
|
int modes = ( device[0]?1:0 + host[0]?1:0 + file[0]?1:0 + (monitor_id>0?1:0) );
|
|
|
|
if ( modes > 1 )
|
2002-12-24 20:02:08 +08:00
|
|
|
{
|
2005-10-18 05:55:02 +08:00
|
|
|
fprintf( stderr, "Only one of device, host/port/path, file or monitor id allowed\n" );
|
2002-12-24 20:02:08 +08:00
|
|
|
Usage();
|
|
|
|
exit( 0 );
|
|
|
|
}
|
2002-09-16 17:19:24 +08:00
|
|
|
|
2005-10-18 05:55:02 +08:00
|
|
|
if ( modes < 1 )
|
2003-03-26 20:00:16 +08:00
|
|
|
{
|
2005-10-18 05:55:02 +08:00
|
|
|
fprintf( stderr, "One of device, host/port/path, file or monitor id must be specified\n" );
|
2003-03-26 20:00:16 +08:00
|
|
|
Usage();
|
|
|
|
exit( 0 );
|
|
|
|
}
|
2002-09-16 17:19:24 +08:00
|
|
|
|
2005-01-16 01:45:51 +08:00
|
|
|
char dbg_id_string[16];
|
2005-10-17 18:58:25 +08:00
|
|
|
if ( device[0] )
|
2003-03-26 20:00:16 +08:00
|
|
|
{
|
2005-10-17 18:58:25 +08:00
|
|
|
const char *slash_ptr = strrchr( device, '/' );
|
|
|
|
snprintf( dbg_id_string, sizeof(dbg_id_string), "d%s", slash_ptr?slash_ptr+1:device );
|
2003-03-26 20:00:16 +08:00
|
|
|
}
|
2004-02-16 03:17:38 +08:00
|
|
|
else if ( host[0] )
|
2002-09-16 17:19:24 +08:00
|
|
|
{
|
2005-01-16 01:45:51 +08:00
|
|
|
snprintf( dbg_id_string, sizeof(dbg_id_string), "h%s", host );
|
2002-09-16 17:19:24 +08:00
|
|
|
}
|
2005-10-18 05:55:02 +08:00
|
|
|
else if ( file[0] )
|
|
|
|
{
|
|
|
|
const char *slash_ptr = strrchr( file, '/' );
|
|
|
|
snprintf( dbg_id_string, sizeof(dbg_id_string), "f%s", slash_ptr?slash_ptr+1:file );
|
|
|
|
}
|
2004-02-16 03:17:38 +08:00
|
|
|
else
|
|
|
|
{
|
2005-01-16 01:45:51 +08:00
|
|
|
snprintf( dbg_id_string, sizeof(dbg_id_string), "m%d", monitor_id );
|
2004-02-16 03:17:38 +08:00
|
|
|
}
|
2003-03-26 20:00:16 +08:00
|
|
|
|
2005-01-16 01:45:51 +08:00
|
|
|
zmDbgInit( "zmc", dbg_id_string, 0 );
|
2003-03-26 20:00:16 +08:00
|
|
|
|
2004-12-29 00:46:48 +08:00
|
|
|
zmLoadConfig();
|
|
|
|
|
2003-03-26 20:00:16 +08:00
|
|
|
Monitor **monitors = 0;
|
|
|
|
int n_monitors = 0;
|
2005-10-17 18:58:25 +08:00
|
|
|
if ( device[0] )
|
2002-09-16 17:19:24 +08:00
|
|
|
{
|
2005-10-18 05:55:02 +08:00
|
|
|
n_monitors = Monitor::LoadLocalMonitors( device, monitors, Monitor::CAPTURE );
|
2002-09-16 17:19:24 +08:00
|
|
|
}
|
2004-02-16 03:17:38 +08:00
|
|
|
else if ( host[0] )
|
2002-09-16 17:19:24 +08:00
|
|
|
{
|
2003-03-26 20:00:16 +08:00
|
|
|
if ( !port )
|
|
|
|
port = "80";
|
2008-07-16 16:35:59 +08:00
|
|
|
n_monitors = Monitor::LoadRemoteMonitors( protocol, host, port, path, monitors, Monitor::CAPTURE );
|
2005-10-18 05:55:02 +08:00
|
|
|
}
|
|
|
|
else if ( file[0] )
|
|
|
|
{
|
|
|
|
n_monitors = Monitor::LoadFileMonitors( file, monitors, Monitor::CAPTURE );
|
2002-09-16 17:19:24 +08:00
|
|
|
}
|
2004-02-16 03:17:38 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
Monitor *monitor = Monitor::Load( monitor_id, true, Monitor::CAPTURE );
|
|
|
|
if ( monitor )
|
|
|
|
{
|
|
|
|
monitors = new Monitor *[1];
|
|
|
|
monitors[0] = monitor;
|
|
|
|
n_monitors = 1;
|
|
|
|
}
|
|
|
|
}
|
2002-09-16 17:19:24 +08:00
|
|
|
|
2003-03-26 20:00:16 +08:00
|
|
|
if ( !n_monitors )
|
|
|
|
{
|
2008-07-14 22:43:47 +08:00
|
|
|
Error( "No monitors found" );
|
2003-03-26 20:00:16 +08:00
|
|
|
exit ( -1 );
|
|
|
|
}
|
2002-09-16 17:19:24 +08:00
|
|
|
|
2008-07-14 22:43:47 +08:00
|
|
|
Info( "Starting Capture" );
|
2006-04-05 20:22:27 +08:00
|
|
|
|
|
|
|
zmSetDefaultTermHandler();
|
|
|
|
zmSetDefaultDieHandler();
|
|
|
|
|
2002-09-16 17:19:24 +08:00
|
|
|
sigset_t block_set;
|
|
|
|
sigemptyset( &block_set );
|
2002-12-24 20:02:08 +08:00
|
|
|
|
2003-04-04 17:55:23 +08:00
|
|
|
sigaddset( &block_set, SIGUSR1 );
|
|
|
|
sigaddset( &block_set, SIGUSR2 );
|
2006-10-24 22:37:34 +08:00
|
|
|
|
|
|
|
if ( monitors[0]->PrimeCapture() < 0 )
|
2002-09-16 17:19:24 +08:00
|
|
|
{
|
2008-07-14 22:43:47 +08:00
|
|
|
Error( "Failed to prime capture of initial monitor" );
|
2006-10-24 22:37:34 +08:00
|
|
|
exit( -1 );
|
2002-09-16 17:19:24 +08:00
|
|
|
}
|
2003-03-27 06:12:25 +08:00
|
|
|
|
2004-01-15 05:26:47 +08:00
|
|
|
long *capture_delays = new long[n_monitors];
|
2006-03-31 20:49:05 +08:00
|
|
|
long *alarm_capture_delays = new long[n_monitors];
|
2004-01-15 05:26:47 +08:00
|
|
|
long *next_delays = new long[n_monitors];
|
|
|
|
struct timeval * last_capture_times = new struct timeval[n_monitors];
|
2003-03-27 06:12:25 +08:00
|
|
|
for ( int i = 0; i < n_monitors; i++ )
|
|
|
|
{
|
|
|
|
last_capture_times[i].tv_sec = last_capture_times[i].tv_usec = 0;
|
2003-05-16 18:17:05 +08:00
|
|
|
capture_delays[i] = monitors[i]->GetCaptureDelay();
|
2006-03-31 20:49:05 +08:00
|
|
|
alarm_capture_delays[i] = monitors[i]->GetAlarmCaptureDelay();
|
2003-03-27 06:12:25 +08:00
|
|
|
}
|
|
|
|
|
2008-12-06 07:14:37 +08:00
|
|
|
int result = 0;
|
2003-03-27 06:12:25 +08:00
|
|
|
struct timeval now;
|
2003-04-07 18:56:38 +08:00
|
|
|
struct DeltaTimeval delta_time;
|
2006-04-05 20:22:27 +08:00
|
|
|
while( !zm_terminate )
|
2002-09-16 17:19:24 +08:00
|
|
|
{
|
|
|
|
sigprocmask( SIG_BLOCK, &block_set, 0 );
|
|
|
|
for ( int i = 0; i < n_monitors; i++ )
|
|
|
|
{
|
2003-03-27 06:12:25 +08:00
|
|
|
long min_delay = MAXINT;
|
2006-03-31 20:49:05 +08:00
|
|
|
|
2008-03-13 21:36:12 +08:00
|
|
|
gettimeofday( &now, NULL );
|
2006-03-31 20:49:05 +08:00
|
|
|
for ( int j = 0; j < n_monitors; j++ )
|
2003-03-31 02:44:15 +08:00
|
|
|
{
|
2006-03-31 20:49:05 +08:00
|
|
|
if ( last_capture_times[j].tv_sec )
|
2003-03-27 06:12:25 +08:00
|
|
|
{
|
2006-03-31 20:49:05 +08:00
|
|
|
DELTA_TIMEVAL( delta_time, now, last_capture_times[j], DT_PREC_3 );
|
|
|
|
if ( monitors[i]->GetState() == Monitor::ALARM )
|
|
|
|
next_delays[j] = alarm_capture_delays[j]-delta_time.delta;
|
2003-03-31 02:44:15 +08:00
|
|
|
else
|
2006-03-31 20:49:05 +08:00
|
|
|
next_delays[j] = capture_delays[j]-delta_time.delta;
|
|
|
|
if ( next_delays[j] < 0 )
|
2003-03-27 06:12:25 +08:00
|
|
|
next_delays[j] = 0;
|
2006-03-31 20:49:05 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
next_delays[j] = 0;
|
|
|
|
}
|
|
|
|
if ( next_delays[j] <= min_delay )
|
|
|
|
{
|
|
|
|
min_delay = next_delays[j];
|
2003-03-27 06:12:25 +08:00
|
|
|
}
|
|
|
|
}
|
2006-03-31 20:49:05 +08:00
|
|
|
|
2003-03-27 06:12:25 +08:00
|
|
|
if ( next_delays[i] <= min_delay || next_delays[i] <= 0 )
|
|
|
|
{
|
2006-01-16 01:39:18 +08:00
|
|
|
if ( monitors[i]->PreCapture() < 0 )
|
|
|
|
{
|
2009-02-18 20:30:17 +08:00
|
|
|
Error( "Failed to pre-capture monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors );
|
2008-07-16 16:35:59 +08:00
|
|
|
zm_terminate = true;
|
2008-12-06 07:14:37 +08:00
|
|
|
result = -1;
|
2009-01-28 17:48:06 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ( monitors[i]->Capture() < 0 )
|
|
|
|
{
|
2009-02-18 20:30:17 +08:00
|
|
|
Error( "Failed to capture image from monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors );
|
2009-01-28 17:48:06 +08:00
|
|
|
zm_terminate = true;
|
|
|
|
result = -1;
|
2008-07-16 16:35:59 +08:00
|
|
|
break;
|
2006-01-16 01:39:18 +08:00
|
|
|
}
|
2006-01-24 05:33:31 +08:00
|
|
|
if ( monitors[i]->PostCapture() < 0 )
|
|
|
|
{
|
2009-02-18 20:30:17 +08:00
|
|
|
Error( "Failed to post-capture monitor %d (%d/%d)", monitors[i]->Id(), i, n_monitors );
|
2008-07-16 16:35:59 +08:00
|
|
|
zm_terminate = true;
|
2008-12-06 07:14:37 +08:00
|
|
|
result = -1;
|
2008-07-16 16:35:59 +08:00
|
|
|
break;
|
2006-01-24 05:33:31 +08:00
|
|
|
}
|
2003-04-07 18:56:38 +08:00
|
|
|
|
|
|
|
if ( next_delays[i] > 0 )
|
|
|
|
{
|
2008-03-13 21:36:12 +08:00
|
|
|
gettimeofday( &now, NULL );
|
2003-05-16 18:17:05 +08:00
|
|
|
DELTA_TIMEVAL( delta_time, now, last_capture_times[i], DT_PREC_3 );
|
|
|
|
long sleep_time = next_delays[i]-delta_time.delta;
|
2003-04-07 18:56:38 +08:00
|
|
|
if ( sleep_time > 0 )
|
|
|
|
{
|
2003-05-16 18:17:05 +08:00
|
|
|
usleep( sleep_time*(DT_MAXGRAN/DT_PREC_3) );
|
2003-04-07 18:56:38 +08:00
|
|
|
}
|
|
|
|
}
|
2008-03-13 21:36:12 +08:00
|
|
|
gettimeofday( &(last_capture_times[i]), NULL );
|
2003-03-27 06:12:25 +08:00
|
|
|
}
|
2002-09-16 17:19:24 +08:00
|
|
|
}
|
|
|
|
sigprocmask( SIG_UNBLOCK, &block_set, 0 );
|
2003-03-26 20:00:16 +08:00
|
|
|
}
|
|
|
|
for ( int i = 0; i < n_monitors; i++ )
|
|
|
|
{
|
|
|
|
delete monitors[i];
|
2002-09-16 17:19:24 +08:00
|
|
|
}
|
2004-01-15 05:26:47 +08:00
|
|
|
delete [] capture_delays;
|
|
|
|
delete [] next_delays;
|
|
|
|
delete [] last_capture_times;
|
|
|
|
|
2008-12-06 07:14:37 +08:00
|
|
|
return( result );
|
2002-09-16 17:19:24 +08:00
|
|
|
}
|