2003-03-26 19:57:29 +08:00
|
|
|
//
|
2003-04-22 22:15:01 +08:00
|
|
|
// ZoneMinder Event Class Implementation, $Date$, $Revision$
|
2003-03-26 19:57:29 +08:00
|
|
|
// Copyright (C) 2003 Philip Coombes
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
|
|
|
|
2003-04-22 22:15:01 +08:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <sys/socket.h>
|
|
|
|
#include <sys/un.h>
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#include <getopt.h>
|
2004-01-28 01:03:45 +08:00
|
|
|
#include <glob.h>
|
2003-04-22 22:15:01 +08:00
|
|
|
|
2003-03-26 19:57:29 +08:00
|
|
|
#include "zm.h"
|
|
|
|
#include "zm_db.h"
|
2004-03-04 23:05:54 +08:00
|
|
|
#include "zm_mpeg.h"
|
2003-03-26 19:57:29 +08:00
|
|
|
#include "zm_event.h"
|
|
|
|
#include "zm_monitor.h"
|
|
|
|
|
2003-04-22 22:15:01 +08:00
|
|
|
#include "zmf.h"
|
|
|
|
|
2004-02-16 04:07:16 +08:00
|
|
|
bool Event::initialised = false;
|
|
|
|
bool Event::timestamp_on_capture;
|
2004-03-05 18:23:01 +08:00
|
|
|
int Event::bulk_frame_interval;
|
2004-02-16 04:07:16 +08:00
|
|
|
|
2003-03-26 19:57:29 +08:00
|
|
|
Event::Event( Monitor *p_monitor, struct timeval p_start_time ) : monitor( p_monitor ), start_time( p_start_time )
|
|
|
|
{
|
2004-02-16 04:07:16 +08:00
|
|
|
if ( !initialised )
|
|
|
|
Initialise();
|
|
|
|
|
2003-07-04 04:39:47 +08:00
|
|
|
static char sql[BUFSIZ];
|
2003-03-26 19:57:29 +08:00
|
|
|
static char start_time_str[32];
|
|
|
|
|
|
|
|
strftime( start_time_str, sizeof(start_time_str), "%Y-%m-%d %H:%M:%S", localtime( &start_time.tv_sec ) );
|
2003-10-08 20:54:35 +08:00
|
|
|
sprintf( sql, "insert into Events ( MonitorId, Name, StartTime ) values ( %d, 'New Event', '%s' )", monitor->Id(), start_time_str );
|
2003-03-26 19:57:29 +08:00
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
2003-04-15 17:04:38 +08:00
|
|
|
Error(( "Can't insert event: %s", mysql_error( &dbconn ) ));
|
2003-03-26 19:57:29 +08:00
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
id = mysql_insert_id( &dbconn );
|
2003-09-23 17:52:45 +08:00
|
|
|
end_time.tv_sec = 0;
|
2003-03-26 19:57:29 +08:00
|
|
|
frames = 0;
|
|
|
|
alarm_frames = 0;
|
|
|
|
tot_score = 0;
|
|
|
|
max_score = 0;
|
2003-07-04 20:31:36 +08:00
|
|
|
sprintf( path, "%s/%s/%d", (const char *)config.Item( ZM_DIR_EVENTS ), monitor->Name(), id );
|
2003-03-26 19:57:29 +08:00
|
|
|
|
|
|
|
struct stat statbuf;
|
|
|
|
errno = 0;
|
|
|
|
stat( path, &statbuf );
|
|
|
|
if ( errno == ENOENT || errno == ENOTDIR )
|
|
|
|
{
|
|
|
|
if ( mkdir( path, 0755 ) )
|
|
|
|
{
|
2003-04-15 17:04:38 +08:00
|
|
|
Error(( "Can't make %s: %s", path, strerror(errno)));
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Event::~Event()
|
|
|
|
{
|
2003-07-04 04:39:47 +08:00
|
|
|
static char sql[BUFSIZ];
|
2003-03-26 19:57:29 +08:00
|
|
|
static char end_time_str[32];
|
|
|
|
|
|
|
|
struct DeltaTimeval delta_time;
|
2003-05-16 18:17:05 +08:00
|
|
|
DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 );
|
2003-03-26 19:57:29 +08:00
|
|
|
|
|
|
|
strftime( end_time_str, sizeof(end_time_str), "%Y-%m-%d %H:%M:%S", localtime( &end_time.tv_sec ) );
|
|
|
|
|
2003-09-23 17:52:45 +08:00
|
|
|
sprintf( sql, "update Events set Name='Event-%d', EndTime = '%s', Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", id, end_time_str, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, id );
|
2003-03-26 19:57:29 +08:00
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
2003-04-15 17:04:38 +08:00
|
|
|
Error(( "Can't update event: %s", mysql_error( &dbconn ) ));
|
2003-03-26 19:57:29 +08:00
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-22 22:15:01 +08:00
|
|
|
int Event::sd = -1;
|
|
|
|
|
|
|
|
bool Event::OpenFrameSocket( int monitor_id )
|
|
|
|
{
|
|
|
|
if ( sd > 0 )
|
|
|
|
{
|
|
|
|
close( sd );
|
|
|
|
}
|
|
|
|
|
|
|
|
sd = socket( AF_UNIX, SOCK_STREAM, 0);
|
|
|
|
if ( sd < 0 )
|
|
|
|
{
|
|
|
|
Error(( "Can't create socket: %s", strerror(errno) ));
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
|
2004-03-04 20:50:42 +08:00
|
|
|
int socket_buffer_size = (int)config.Item( ZM_FRAME_SOCKET_SIZE );
|
|
|
|
if ( socket_buffer_size > 0 )
|
|
|
|
{
|
|
|
|
if ( setsockopt( sd, SOL_SOCKET, SO_SNDBUF, &socket_buffer_size, sizeof(socket_buffer_size) ) < 0 )
|
|
|
|
{
|
|
|
|
Error(( "Can't get socket buffer size to %d, error = %s", socket_buffer_size, strerror(errno) ));
|
|
|
|
close( sd );
|
|
|
|
sd = -1;
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-04-22 22:15:01 +08:00
|
|
|
int flags;
|
|
|
|
if ( (flags = fcntl( sd, F_GETFL )) < 0 )
|
|
|
|
{
|
|
|
|
Error(( "Can't get socket flags, error = %s", strerror(errno) ));
|
|
|
|
close( sd );
|
|
|
|
sd = -1;
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
flags |= O_NONBLOCK;
|
|
|
|
if ( fcntl( sd, F_SETFL, flags ) < 0 )
|
|
|
|
{
|
|
|
|
Error(( "Can't set socket flags, error = %s", strerror(errno) ));
|
|
|
|
close( sd );
|
|
|
|
sd = -1;
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
char sock_path[PATH_MAX] = "";
|
2003-07-04 20:31:36 +08:00
|
|
|
sprintf( sock_path, "%s/zmf-%d.sock", (const char *)config.Item( ZM_PATH_SOCKS ), monitor_id );
|
2003-04-22 22:15:01 +08:00
|
|
|
|
|
|
|
struct sockaddr_un addr;
|
|
|
|
|
|
|
|
strcpy( addr.sun_path, sock_path );
|
|
|
|
addr.sun_family = AF_UNIX;
|
|
|
|
|
|
|
|
if ( connect( sd, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)) < 0 )
|
|
|
|
{
|
2004-03-17 18:28:07 +08:00
|
|
|
Warning(( "Can't connect to frame server: %s", strerror(errno) ));
|
2003-04-22 22:15:01 +08:00
|
|
|
close( sd );
|
|
|
|
sd = -1;
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
|
2004-03-17 18:28:07 +08:00
|
|
|
Debug( 1, ( "Opened connection to frame server" ));
|
2003-04-22 22:15:01 +08:00
|
|
|
return( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Event::ValidateFrameSocket( int monitor_id )
|
|
|
|
{
|
|
|
|
if ( sd < 0 )
|
|
|
|
{
|
|
|
|
return( OpenFrameSocket( monitor_id ) );
|
|
|
|
}
|
|
|
|
return( true );
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Event::SendFrameImage( const Image *image, bool alarm_frame )
|
|
|
|
{
|
|
|
|
if ( !ValidateFrameSocket( monitor->Id() ) )
|
|
|
|
{
|
|
|
|
return( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
static int jpg_buffer_size = 0;
|
2003-05-02 23:03:16 +08:00
|
|
|
static unsigned char jpg_buffer[ZM_MAX_IMAGE_SIZE];
|
2003-04-22 22:15:01 +08:00
|
|
|
|
|
|
|
image->EncodeJpeg( jpg_buffer, &jpg_buffer_size );
|
|
|
|
|
|
|
|
static FrameHeader frame_header;
|
|
|
|
|
|
|
|
frame_header.event_id = id;
|
|
|
|
frame_header.frame_id = frames;
|
|
|
|
frame_header.alarm_frame = alarm_frame;
|
|
|
|
frame_header.image_length = jpg_buffer_size;
|
|
|
|
|
|
|
|
struct iovec iovecs[2];
|
|
|
|
iovecs[0].iov_base = &frame_header;
|
|
|
|
iovecs[0].iov_len = sizeof(frame_header);
|
|
|
|
iovecs[1].iov_base = jpg_buffer;
|
|
|
|
iovecs[1].iov_len = jpg_buffer_size;
|
|
|
|
|
2004-01-15 05:26:47 +08:00
|
|
|
ssize_t writev_size = sizeof(frame_header)+jpg_buffer_size;
|
|
|
|
ssize_t writev_result = writev( sd, iovecs, sizeof(iovecs)/sizeof(*iovecs));
|
|
|
|
if ( writev_result != writev_size )
|
2003-04-22 22:15:01 +08:00
|
|
|
{
|
2004-01-15 05:26:47 +08:00
|
|
|
if ( writev_result < 0 )
|
2003-04-22 22:15:01 +08:00
|
|
|
{
|
2004-01-15 05:26:47 +08:00
|
|
|
if ( errno == EAGAIN )
|
|
|
|
{
|
|
|
|
Warning(( "Blocking write detected" ));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Error(( "Can't write frame: %s", strerror(errno) ));
|
|
|
|
close( sd );
|
|
|
|
sd = -1;
|
|
|
|
}
|
2003-04-22 22:15:01 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-01-15 05:26:47 +08:00
|
|
|
Error(( "Incomplete frame write: %d of %d bytes written", writev_result, writev_size ));
|
2003-04-22 22:15:01 +08:00
|
|
|
close( sd );
|
|
|
|
sd = -1;
|
|
|
|
}
|
|
|
|
return( false );
|
|
|
|
}
|
2003-10-19 17:48:10 +08:00
|
|
|
Debug( 1, ( "Wrote frame image, %d bytes", jpg_buffer_size ));
|
2003-04-22 22:15:01 +08:00
|
|
|
|
|
|
|
return( true );
|
|
|
|
}
|
|
|
|
|
2004-02-16 04:07:16 +08:00
|
|
|
bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame )
|
2003-04-22 22:15:01 +08:00
|
|
|
{
|
2004-02-16 19:12:28 +08:00
|
|
|
if ( timestamp_on_capture )
|
2004-02-16 04:07:16 +08:00
|
|
|
{
|
2004-02-16 19:12:28 +08:00
|
|
|
if ( !(bool)config.Item( ZM_OPT_FRAME_SERVER ) || !SendFrameImage( image, alarm_frame) )
|
|
|
|
{
|
|
|
|
image->WriteJpeg( event_file );
|
|
|
|
}
|
2004-02-16 04:07:16 +08:00
|
|
|
}
|
2004-02-16 19:12:28 +08:00
|
|
|
else
|
2003-04-22 22:15:01 +08:00
|
|
|
{
|
2004-02-16 19:12:28 +08:00
|
|
|
Image ts_image( *image );
|
|
|
|
monitor->TimestampImage( &ts_image, timestamp.tv_sec );
|
2004-02-19 23:51:02 +08:00
|
|
|
if ( !(bool)config.Item( ZM_OPT_FRAME_SERVER ) || !SendFrameImage( &ts_image, alarm_frame) )
|
2004-02-16 19:12:28 +08:00
|
|
|
{
|
|
|
|
ts_image.WriteJpeg( event_file );
|
|
|
|
}
|
2003-04-22 22:15:01 +08:00
|
|
|
}
|
|
|
|
return( true );
|
|
|
|
}
|
|
|
|
|
2004-02-16 04:07:16 +08:00
|
|
|
void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps )
|
2003-04-17 23:38:21 +08:00
|
|
|
{
|
2003-11-05 22:49:55 +08:00
|
|
|
static char sql[BUFSIZ];
|
2004-01-28 01:03:45 +08:00
|
|
|
strcpy( sql, "insert into Frames ( EventId, FrameId, Delta ) values " );
|
2003-04-17 23:38:21 +08:00
|
|
|
for ( int i = 0; i < n_frames; i++ )
|
|
|
|
{
|
|
|
|
frames++;
|
2003-04-22 22:15:01 +08:00
|
|
|
|
2003-04-17 23:38:21 +08:00
|
|
|
static char event_file[PATH_MAX];
|
2004-01-28 01:03:45 +08:00
|
|
|
sprintf( event_file, "%s/%03d-capture.jpg", path, frames );
|
2003-04-22 22:15:01 +08:00
|
|
|
|
|
|
|
Debug( 1, ( "Writing pre-capture frame %d", frames ));
|
2004-02-16 04:07:16 +08:00
|
|
|
WriteFrameImage( images[i], *(timestamps[i]), event_file );
|
2003-04-17 23:38:21 +08:00
|
|
|
|
|
|
|
struct DeltaTimeval delta_time;
|
2003-05-16 18:17:05 +08:00
|
|
|
DELTA_TIMEVAL( delta_time, *(timestamps[i]), start_time, DT_PREC_2 );
|
2003-04-17 23:38:21 +08:00
|
|
|
|
2004-01-28 01:03:45 +08:00
|
|
|
sprintf( sql+strlen(sql), "( %d, %d, %s%ld.%02ld ), ", id, frames, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
2003-04-17 23:38:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Debug( 1, ( "Adding %d frames to DB", n_frames ));
|
|
|
|
*(sql+strlen(sql)-2) = '\0';
|
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't insert frames: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-03-04 23:13:10 +08:00
|
|
|
void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *alarm_image )
|
2003-03-26 19:57:29 +08:00
|
|
|
{
|
|
|
|
frames++;
|
|
|
|
|
|
|
|
static char event_file[PATH_MAX];
|
2004-01-28 01:03:45 +08:00
|
|
|
sprintf( event_file, "%s/%03d-capture.jpg", path, frames );
|
2003-04-22 22:15:01 +08:00
|
|
|
|
|
|
|
Debug( 1, ( "Writing capture frame %d", frames ));
|
2004-02-16 04:07:16 +08:00
|
|
|
WriteFrameImage( image, timestamp, event_file );
|
2003-03-26 19:57:29 +08:00
|
|
|
|
|
|
|
struct DeltaTimeval delta_time;
|
2003-05-16 18:17:05 +08:00
|
|
|
DELTA_TIMEVAL( delta_time, timestamp, start_time, DT_PREC_2 );
|
2003-03-26 19:57:29 +08:00
|
|
|
|
2004-03-05 18:23:01 +08:00
|
|
|
bool db_frame = (score>=0) || ((frames%bulk_frame_interval)==0) || !frames;
|
2004-03-04 23:13:10 +08:00
|
|
|
|
|
|
|
if ( db_frame )
|
2003-03-26 19:57:29 +08:00
|
|
|
{
|
2004-03-05 18:31:39 +08:00
|
|
|
const char *frame_type = score>0?"Alarm":(score<0?"Bulk":"Normal");
|
2004-03-04 23:13:10 +08:00
|
|
|
|
|
|
|
Debug( 1, ( "Adding frame %d to DB", frames ));
|
|
|
|
static char sql[BUFSIZ];
|
2004-03-05 18:23:01 +08:00
|
|
|
sprintf( sql, "insert into Frames ( EventId, FrameId, Type, Delta, Score ) values ( %d, %d, '%s', %s%ld.%02ld, %d )", id, frames, frame_type, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score );
|
2004-03-04 23:13:10 +08:00
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't insert frame: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
|
|
|
|
2004-03-04 23:13:10 +08:00
|
|
|
if ( score > 0 )
|
2003-03-26 19:57:29 +08:00
|
|
|
{
|
|
|
|
end_time = timestamp;
|
|
|
|
|
|
|
|
alarm_frames++;
|
2003-04-22 22:15:01 +08:00
|
|
|
|
2003-03-26 19:57:29 +08:00
|
|
|
tot_score += score;
|
|
|
|
if ( score > max_score )
|
|
|
|
max_score = score;
|
2003-11-21 18:38:41 +08:00
|
|
|
|
|
|
|
if ( alarm_image )
|
|
|
|
{
|
2004-01-28 01:03:45 +08:00
|
|
|
sprintf( event_file, "%s/%03d-analyse.jpg", path, frames );
|
2003-11-21 18:38:41 +08:00
|
|
|
|
|
|
|
Debug( 1, ( "Writing analysis frame %d", frames ));
|
2004-02-16 04:07:16 +08:00
|
|
|
WriteFrameImage( alarm_image, timestamp, event_file, true );
|
2003-11-21 18:38:41 +08:00
|
|
|
}
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
2004-01-28 01:03:45 +08:00
|
|
|
|
2004-01-28 01:07:20 +08:00
|
|
|
if ( (bool)config.Item( ZM_RECORD_DIAG_IMAGES ) )
|
2004-01-28 01:03:45 +08:00
|
|
|
{
|
|
|
|
char diag_glob[PATH_MAX] = "";
|
|
|
|
|
|
|
|
sprintf( diag_glob, "%s/%s/diag-*.jpg", (const char *)config.Item( ZM_DIR_EVENTS ), monitor->Name() );
|
|
|
|
glob_t pglob;
|
|
|
|
int glob_status = glob( diag_glob, 0, 0, &pglob );
|
|
|
|
if ( glob_status != 0 )
|
|
|
|
{
|
|
|
|
if ( glob_status < 0 )
|
|
|
|
{
|
|
|
|
Error(( "Can't glob '%s': %s", diag_glob, strerror(errno) ));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-03-17 18:28:07 +08:00
|
|
|
Debug( 1, ( "Can't glob '%s': %d", diag_glob, glob_status ));
|
2004-01-28 01:03:45 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
char new_diag_path[PATH_MAX] = "";
|
|
|
|
for ( int i = 0; i < pglob.gl_pathc; i++ )
|
|
|
|
{
|
|
|
|
char *diag_path = pglob.gl_pathv[i];
|
|
|
|
|
|
|
|
char *diag_file = strstr( diag_path, "diag-" );
|
|
|
|
|
|
|
|
if ( diag_file )
|
|
|
|
{
|
|
|
|
sprintf( new_diag_path, "%s/%03d-%s", path, frames, diag_file );
|
|
|
|
|
|
|
|
if ( rename( diag_path, new_diag_path ) < 0 )
|
|
|
|
{
|
|
|
|
Error(( "Can't rename '%s' to '%s': %s", diag_path, new_diag_path, strerror(errno) ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
globfree( &pglob );
|
|
|
|
}
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
|
|
|
|
2004-03-15 17:37:21 +08:00
|
|
|
void Event::StreamEvent( int event_id, int scale, int rate, int maxfps )
|
2003-03-26 19:57:29 +08:00
|
|
|
{
|
2003-07-04 04:39:47 +08:00
|
|
|
static char sql[BUFSIZ];
|
2004-02-06 05:58:44 +08:00
|
|
|
static char eventpath[PATH_MAX];
|
2004-01-28 01:03:45 +08:00
|
|
|
|
2004-03-15 16:48:52 +08:00
|
|
|
sprintf( sql, "select M.Id, M.Name, E.Length, E.Frames from Events as E inner join Monitors as M on E.MonitorId = M.Id where E.Id = %d", event_id );
|
2003-03-26 19:57:29 +08:00
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
2003-04-15 17:04:38 +08:00
|
|
|
Error(( "Can't run query: %s", mysql_error( &dbconn ) ));
|
2003-03-26 19:57:29 +08:00
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
MYSQL_RES *result = mysql_store_result( &dbconn );
|
|
|
|
if ( !result )
|
|
|
|
{
|
2003-04-15 17:04:38 +08:00
|
|
|
Error(( "Can't use query result: %s", mysql_error( &dbconn ) ));
|
2003-03-26 19:57:29 +08:00
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
2004-02-06 05:58:44 +08:00
|
|
|
MYSQL_ROW dbrow = mysql_fetch_row( result );
|
|
|
|
|
|
|
|
if ( mysql_errno( &dbconn ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't fetch row: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf( eventpath, "%s/%s/%s/%d", ZM_PATH_WEB, (const char *)config.Item( ZM_DIR_EVENTS ), dbrow[1], event_id );
|
2004-03-15 16:48:52 +08:00
|
|
|
int duration = atoi(dbrow[2]);
|
|
|
|
int frames = atoi(dbrow[3]);
|
|
|
|
|
|
|
|
int min_fps = 1;
|
|
|
|
int max_fps = maxfps;
|
|
|
|
int base_fps = frames/duration;
|
|
|
|
int effective_fps = (base_fps*rate)/ZM_RATE_SCALE;
|
|
|
|
|
|
|
|
int frame_mod = 1;
|
|
|
|
// Min frame repeat?
|
|
|
|
while( effective_fps > max_fps )
|
|
|
|
{
|
|
|
|
effective_fps /= 2;
|
|
|
|
frame_mod *= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
Debug( 1, ( "Duration:%d, Frames:%d, BFPS:%d, EFPS:%d, FM:%d", atoi(dbrow[2]), atoi(dbrow[3]), base_fps, effective_fps, frame_mod ));
|
2004-02-06 05:58:44 +08:00
|
|
|
|
|
|
|
mysql_free_result( result );
|
|
|
|
|
|
|
|
sprintf( sql, "select FrameId, EventId, Delta from Frames where EventId = %d order by FrameId", event_id );
|
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't run query: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
result = mysql_store_result( &dbconn );
|
|
|
|
if ( !result )
|
|
|
|
{
|
|
|
|
Error(( "Can't use query result: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
2003-03-26 19:57:29 +08:00
|
|
|
|
2004-03-04 23:05:54 +08:00
|
|
|
fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" );
|
2004-03-13 22:07:23 +08:00
|
|
|
fprintf( stdout, "--ZoneMinderFrame\r\n" );
|
2003-03-26 19:57:29 +08:00
|
|
|
|
|
|
|
FILE *fdj = NULL;
|
|
|
|
int n_bytes = 0;
|
2004-03-15 16:48:52 +08:00
|
|
|
int id = 1, db_id, last_db_id = 0;
|
|
|
|
double base_delta, last_delta = 0.0L;
|
|
|
|
double db_delta, last_db_delta = 0.0L;
|
|
|
|
unsigned int delta_us =0;
|
2003-10-16 17:00:53 +08:00
|
|
|
static unsigned char buffer[ZM_MAX_IMAGE_SIZE];
|
2004-03-15 16:48:52 +08:00
|
|
|
while( (id <= frames) && (dbrow = mysql_fetch_row( result )) )
|
2003-03-26 19:57:29 +08:00
|
|
|
{
|
2004-03-15 16:48:52 +08:00
|
|
|
if ( id == 1 )
|
2003-05-23 00:34:22 +08:00
|
|
|
{
|
2004-03-15 16:48:52 +08:00
|
|
|
base_delta = atof(dbrow[2]);
|
2003-05-23 00:34:22 +08:00
|
|
|
}
|
2003-10-16 17:00:53 +08:00
|
|
|
|
2004-03-15 16:48:52 +08:00
|
|
|
db_id = atoi( dbrow[0] );
|
|
|
|
db_delta = atof( dbrow[2] )-base_delta;
|
|
|
|
bool db_written = false;
|
|
|
|
while( db_id >= id )
|
2003-03-26 19:57:29 +08:00
|
|
|
{
|
2004-03-15 16:48:52 +08:00
|
|
|
if ( (frame_mod == 1) || (((id-1)%frame_mod) == 0) )
|
2003-10-16 17:00:53 +08:00
|
|
|
{
|
2004-03-15 16:48:52 +08:00
|
|
|
double this_delta = last_db_delta+(((id-last_db_id)*(db_delta-last_db_delta))/(db_id-last_db_id));
|
|
|
|
delta_us = (unsigned int)((this_delta-last_delta) * 1000000);
|
|
|
|
if ( rate != ZM_RATE_SCALE )
|
|
|
|
delta_us = (delta_us*ZM_RATE_SCALE)/rate;
|
|
|
|
Debug( 2, ( "I:%d, DI:%d, LDBI:%d, DD:%lf, LD:%lf, LDBD:%lf, TD:%lf, DU:%d", id, db_id, last_db_id, db_delta, last_delta, last_db_delta, this_delta, delta_us ));
|
|
|
|
|
|
|
|
static char filepath[PATH_MAX];
|
|
|
|
sprintf( filepath, "%s/%03d-capture.jpg", eventpath, id );
|
|
|
|
|
|
|
|
fprintf( stdout, "Content-Length: %d\r\n", n_bytes );
|
|
|
|
fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" );
|
|
|
|
if ( scale == 100 )
|
|
|
|
{
|
|
|
|
if ( (fdj = fopen( filepath, "r" )) )
|
|
|
|
{
|
|
|
|
while ( (n_bytes = fread( buffer, 1, sizeof(buffer), fdj )) )
|
|
|
|
{
|
|
|
|
write( fileno(stdout), buffer, n_bytes );
|
|
|
|
}
|
|
|
|
fclose( fdj );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Error(( "Can't open %s: %s", filepath, strerror(errno) ));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2003-10-16 17:00:53 +08:00
|
|
|
{
|
2004-03-15 16:48:52 +08:00
|
|
|
Image image( filepath );
|
|
|
|
|
|
|
|
image.Scale( scale );
|
|
|
|
|
|
|
|
image.EncodeJpeg( buffer, &n_bytes );
|
|
|
|
|
2004-03-04 23:05:54 +08:00
|
|
|
write( fileno(stdout), buffer, n_bytes );
|
2003-10-16 17:00:53 +08:00
|
|
|
}
|
2004-03-15 16:48:52 +08:00
|
|
|
fprintf( stdout, "\r\n\r\n--ZoneMinderFrame\r\n" );
|
|
|
|
fflush( stdout );
|
|
|
|
last_delta = this_delta;
|
|
|
|
db_written = true;
|
|
|
|
usleep( delta_us );
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
2004-03-15 16:48:52 +08:00
|
|
|
id++;
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
2004-03-15 16:48:52 +08:00
|
|
|
if ( db_written )
|
2003-03-26 19:57:29 +08:00
|
|
|
{
|
2004-03-15 16:48:52 +08:00
|
|
|
last_db_id = db_id;
|
|
|
|
last_db_delta = db_delta;
|
2004-03-04 23:05:54 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( mysql_errno( &dbconn ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't fetch row: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
// Yadda yadda
|
|
|
|
mysql_free_result( result );
|
|
|
|
}
|
|
|
|
|
|
|
|
#if HAVE_LIBAVCODEC
|
|
|
|
|
2004-03-15 17:37:21 +08:00
|
|
|
void Event::StreamMpeg( int event_id, const char *format, int scale, int rate, int maxfps, int bitrate )
|
2004-03-04 23:05:54 +08:00
|
|
|
{
|
|
|
|
static char sql[BUFSIZ];
|
|
|
|
static char eventpath[PATH_MAX];
|
|
|
|
|
2004-03-15 07:27:36 +08:00
|
|
|
bool timed_frames = (bool)config.Item( ZM_VIDEO_TIMED_FRAMES );
|
2004-03-11 19:18:14 +08:00
|
|
|
|
2004-03-08 18:33:19 +08:00
|
|
|
sprintf( sql, "select M.Id, M.Name, E.Length, E.Frames from Events as E inner join Monitors as M on E.MonitorId = M.Id where E.Id = %d", event_id );
|
2004-03-04 23:05:54 +08:00
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't run query: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
MYSQL_RES *result = mysql_store_result( &dbconn );
|
|
|
|
if ( !result )
|
|
|
|
{
|
|
|
|
Error(( "Can't use query result: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
MYSQL_ROW dbrow = mysql_fetch_row( result );
|
|
|
|
|
|
|
|
if ( mysql_errno( &dbconn ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't fetch row: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf( eventpath, "%s/%s/%s/%d", ZM_PATH_WEB, (const char *)config.Item( ZM_DIR_EVENTS ), dbrow[1], event_id );
|
2004-03-08 18:33:19 +08:00
|
|
|
int duration = atoi(dbrow[2]);
|
|
|
|
int frames = atoi(dbrow[3]);
|
|
|
|
|
|
|
|
int min_fps = 1;
|
2004-03-11 19:18:14 +08:00
|
|
|
int max_fps = maxfps;
|
2004-03-08 18:33:19 +08:00
|
|
|
int base_fps = frames/duration;
|
|
|
|
int effective_fps = (base_fps*rate)/ZM_RATE_SCALE;
|
|
|
|
|
|
|
|
int frame_mod = 1;
|
|
|
|
// Min frame repeat?
|
|
|
|
while( effective_fps > max_fps )
|
2004-03-04 23:05:54 +08:00
|
|
|
{
|
2004-03-08 18:33:19 +08:00
|
|
|
effective_fps /= 2;
|
|
|
|
frame_mod *= 2;
|
2004-03-04 23:05:54 +08:00
|
|
|
}
|
2004-03-08 18:33:19 +08:00
|
|
|
|
2004-03-15 16:48:52 +08:00
|
|
|
Debug( 1, ( "Duration:%d, Frames:%d, BFPS:%d, EFPS:%d, FM:%d", atoi(dbrow[2]), atoi(dbrow[3]), base_fps, effective_fps, frame_mod ));
|
2004-03-04 23:05:54 +08:00
|
|
|
|
|
|
|
mysql_free_result( result );
|
|
|
|
|
|
|
|
sprintf( sql, "select FrameId, EventId, Delta from Frames where EventId = %d order by FrameId", event_id );
|
|
|
|
if ( mysql_query( &dbconn, sql ) )
|
|
|
|
{
|
|
|
|
Error(( "Can't run query: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
result = mysql_store_result( &dbconn );
|
|
|
|
if ( !result )
|
|
|
|
{
|
|
|
|
Error(( "Can't use query result: %s", mysql_error( &dbconn ) ));
|
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
|
2004-03-15 06:49:12 +08:00
|
|
|
const char *mime_type = "video/mpeg";
|
|
|
|
if ( !strcmp( format, "asf" ) )
|
|
|
|
{
|
|
|
|
mime_type = "video/x-ms-asf";
|
|
|
|
}
|
|
|
|
else if ( !strcmp( format, "mpeg" ) || !strcmp( format, "mpg" ) )
|
|
|
|
{
|
|
|
|
mime_type = "video/x-mpeg";
|
|
|
|
}
|
|
|
|
else if ( !strcmp( format, "mpv2" ) || !strcmp( format, "mpev2" ) )
|
|
|
|
{
|
|
|
|
mime_type = "video/x-mpeg2";
|
|
|
|
}
|
|
|
|
else if ( !strcmp( format, "avi" ) )
|
|
|
|
{
|
|
|
|
mime_type = "video/x-msvideo";
|
|
|
|
}
|
|
|
|
else if ( !strcmp( format, "mov" ) )
|
|
|
|
{
|
|
|
|
mime_type = "video/x-quicktime";
|
|
|
|
}
|
|
|
|
fprintf( stdout, "Content-type: %s\r\n\r\n", mime_type );
|
2004-03-04 23:05:54 +08:00
|
|
|
|
|
|
|
VideoStream *vid_stream = 0;
|
2004-03-08 18:33:19 +08:00
|
|
|
int id = 1, last_id = 0;
|
|
|
|
double base_delta, last_delta = 0.0L;
|
|
|
|
unsigned int delta_ms =0;
|
|
|
|
while( (id <= frames) && (dbrow = mysql_fetch_row( result )) )
|
2004-03-04 23:05:54 +08:00
|
|
|
{
|
2004-03-08 18:33:19 +08:00
|
|
|
if ( id == 1 )
|
2004-03-04 23:05:54 +08:00
|
|
|
{
|
2004-03-08 18:33:19 +08:00
|
|
|
base_delta = last_delta = atof(dbrow[2]);
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
2004-03-04 23:05:54 +08:00
|
|
|
|
2004-03-08 18:33:19 +08:00
|
|
|
int db_id = atoi( dbrow[0] );
|
|
|
|
double db_delta = atof( dbrow[2] )-base_delta;
|
2004-03-15 16:48:52 +08:00
|
|
|
bool db_written = false;
|
2004-03-08 18:33:19 +08:00
|
|
|
while( db_id >= id )
|
2004-03-04 23:05:54 +08:00
|
|
|
{
|
2004-03-08 18:33:19 +08:00
|
|
|
if ( (frame_mod == 1) || (((id-1)%frame_mod) == 0) )
|
|
|
|
{
|
|
|
|
static char filepath[PATH_MAX];
|
|
|
|
sprintf( filepath, "%s/%03d-capture.jpg", eventpath, id );
|
|
|
|
|
|
|
|
Image image( filepath );
|
|
|
|
|
|
|
|
if ( !vid_stream )
|
|
|
|
{
|
|
|
|
vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, image.Colours(), (image.Width()*scale)/ZM_SCALE_SCALE, (image.Height()*scale)/ZM_SCALE_SCALE );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( scale != 100 )
|
|
|
|
{
|
|
|
|
image.Scale( scale );
|
|
|
|
}
|
|
|
|
|
|
|
|
double temp_delta = ((id-last_id)*(db_delta-last_delta))/(db_id-last_id);
|
|
|
|
delta_ms = (unsigned int)((last_delta+temp_delta)*1000);
|
|
|
|
if ( rate != ZM_RATE_SCALE )
|
|
|
|
delta_ms = (delta_ms*ZM_RATE_SCALE)/rate;
|
2004-03-11 19:18:14 +08:00
|
|
|
double pts = vid_stream->EncodeFrame( image.Buffer(), image.Size(), timed_frames, delta_ms );
|
2004-03-08 18:33:19 +08:00
|
|
|
|
2004-03-15 16:48:52 +08:00
|
|
|
Debug( 2, ( "I:%d, DI:%d, LI:%d, DD:%lf, LD:%lf, TD:%lf, DM:%d, PTS:%lf", id, db_id, last_id, db_delta, last_delta, temp_delta, delta_ms, pts ));
|
|
|
|
|
|
|
|
db_written = true;
|
2004-03-08 18:33:19 +08:00
|
|
|
}
|
|
|
|
id++;
|
2004-03-04 23:05:54 +08:00
|
|
|
}
|
2004-03-15 16:48:52 +08:00
|
|
|
if ( db_written )
|
|
|
|
{
|
|
|
|
last_id = db_id;
|
|
|
|
last_delta = db_delta;
|
2004-03-15 17:37:21 +08:00
|
|
|
}
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
|
|
|
if ( mysql_errno( &dbconn ) )
|
|
|
|
{
|
2003-04-15 17:04:38 +08:00
|
|
|
Error(( "Can't fetch row: %s", mysql_error( &dbconn ) ));
|
2003-03-26 19:57:29 +08:00
|
|
|
exit( mysql_errno( &dbconn ) );
|
|
|
|
}
|
|
|
|
// Yadda yadda
|
|
|
|
mysql_free_result( result );
|
2004-03-04 23:05:54 +08:00
|
|
|
|
|
|
|
delete vid_stream;
|
2003-03-26 19:57:29 +08:00
|
|
|
}
|
2004-03-04 23:05:54 +08:00
|
|
|
|
|
|
|
#endif // HAVE_LIBAVCODEC
|
|
|
|
|