mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-10-20 13:34:23 -04:00
Merge branch 'feature-h264-videostorage' into storageareas
This commit is contained in:
commit
e29a0ebe71
25 files changed
+1139
-1147
No files matched your search
@@ -266,4 +266,5 @@ if ( $concat_name ) {
|
||||
#unlink $input_file_list;
|
||||
#print( STDOUT $event->{MonitorId}.'/'.$event->{Id}.'/'.$video_file."\n" );
|
||||
#print( STDOUT $event_path . '/' . $video_file ."\n" );
|
||||
#print( STDOUT $video_file."\n" );
|
||||
exit( 0 );
|
||||
+2
-3
@@ -32,7 +32,7 @@ Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_co
|
||||
colour( p_colour ),
|
||||
contrast( p_contrast ),
|
||||
capture( p_capture ),
|
||||
record_audio( p_record_audio )
|
||||
record_audio( p_record_audio )
|
||||
{
|
||||
pixels = width * height;
|
||||
imagesize = pixels * colours;
|
||||
@@ -47,8 +47,7 @@ Camera::Camera( int p_id, SourceType p_type, int p_width, int p_height, int p_co
|
||||
}
|
||||
}
|
||||
|
||||
Camera::~Camera()
|
||||
{
|
||||
Camera::~Camera() {
|
||||
}
|
||||
|
||||
Monitor *Camera::getMonitor() {
|
||||
|
||||
+2
-2
@@ -80,9 +80,9 @@ public:
|
||||
virtual int Contrast( int/*p_contrast*/=-1 ) { return( -1 ); }
|
||||
|
||||
bool CanCapture() const { return( capture ); }
|
||||
|
||||
|
||||
bool SupportsNativeVideo() const { return( (type == FFMPEG_SRC )||(type == REMOTE_SRC)); }
|
||||
|
||||
|
||||
virtual int PrimeCapture() { return( 0 ); }
|
||||
virtual int PreCapture()=0;
|
||||
virtual int Capture( Image &image )=0;
|
||||
|
||||
+21
-40
@@ -31,27 +31,23 @@ size_t content_length_match_len;
|
||||
size_t content_type_match_len;
|
||||
|
||||
cURLCamera::cURLCamera( int p_id, const std::string &p_path, const std::string &p_user, const std::string &p_pass, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
|
||||
Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
|
||||
mPath( p_path ), mUser( p_user ), mPass ( p_pass ), bTerminate( false ), bReset( false ), mode ( MODE_UNSET )
|
||||
Camera( p_id, CURL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
|
||||
mPath( p_path ), mUser( p_user ), mPass ( p_pass ), bTerminate( false ), bReset( false ), mode ( MODE_UNSET )
|
||||
{
|
||||
|
||||
if ( capture )
|
||||
{
|
||||
if ( capture ) {
|
||||
Initialise();
|
||||
}
|
||||
}
|
||||
|
||||
cURLCamera::~cURLCamera()
|
||||
{
|
||||
if ( capture )
|
||||
{
|
||||
cURLCamera::~cURLCamera() {
|
||||
if ( capture ) {
|
||||
|
||||
Terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void cURLCamera::Initialise()
|
||||
{
|
||||
void cURLCamera::Initialise() {
|
||||
content_length_match_len = strlen(content_length_match);
|
||||
content_type_match_len = strlen(content_type_match);
|
||||
|
||||
@@ -88,8 +84,7 @@ void cURLCamera::Initialise()
|
||||
}
|
||||
}
|
||||
|
||||
void cURLCamera::Terminate()
|
||||
{
|
||||
void cURLCamera::Terminate() {
|
||||
/* Signal the thread to terminate */
|
||||
bTerminate = true;
|
||||
|
||||
@@ -108,20 +103,17 @@ void cURLCamera::Terminate()
|
||||
|
||||
}
|
||||
|
||||
int cURLCamera::PrimeCapture()
|
||||
{
|
||||
int cURLCamera::PrimeCapture() {
|
||||
//Info( "Priming capture from %s", mPath.c_str() );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cURLCamera::PreCapture()
|
||||
{
|
||||
int cURLCamera::PreCapture() {
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int cURLCamera::Capture( Image &image )
|
||||
{
|
||||
int cURLCamera::Capture( Image &image ) {
|
||||
bool frameComplete = false;
|
||||
|
||||
/* MODE_STREAM specific variables */
|
||||
@@ -305,22 +297,19 @@ int cURLCamera::Capture( Image &image )
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cURLCamera::PostCapture()
|
||||
{
|
||||
int cURLCamera::PostCapture() {
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int cURLCamera::CaptureAndRecord( Image &image, bool recording, char* event_directory )
|
||||
{
|
||||
int cURLCamera::CaptureAndRecord( Image &image, bool recording, char* event_directory ) {
|
||||
Error("Capture and Record not implemented for the cURL camera type");
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
// Nothing to do here
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
||||
size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
lock();
|
||||
|
||||
/* Append the data we just received to our buffer */
|
||||
@@ -341,8 +330,7 @@ size_t cURLCamera::data_callback(void *buffer, size_t size, size_t nmemb, void *
|
||||
|
||||
|
||||
|
||||
size_t cURLCamera::header_callback( void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t cURLCamera::header_callback( void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
std::string header;
|
||||
header.assign((const char*)buffer, size*nmemb);
|
||||
|
||||
@@ -382,8 +370,7 @@ size_t cURLCamera::header_callback( void *buffer, size_t size, size_t nmemb, voi
|
||||
return size*nmemb;
|
||||
}
|
||||
|
||||
void* cURLCamera::thread_func()
|
||||
{
|
||||
void* cURLCamera::thread_func() {
|
||||
long tRet;
|
||||
double dSize;
|
||||
|
||||
@@ -529,8 +516,7 @@ int cURLCamera::unlock() {
|
||||
return nRet;
|
||||
}
|
||||
|
||||
int cURLCamera::progress_callback(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
{
|
||||
int cURLCamera::progress_callback(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow) {
|
||||
/* Signal the curl thread to terminate */
|
||||
if(bTerminate)
|
||||
return -10;
|
||||
@@ -539,18 +525,15 @@ int cURLCamera::progress_callback(void *userdata, double dltotal, double dlnow,
|
||||
}
|
||||
|
||||
/* These functions call the functions in the class for the correct object */
|
||||
size_t data_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t data_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
return ((cURLCamera*)userdata)->data_callback(buffer,size,nmemb,userdata);
|
||||
}
|
||||
|
||||
size_t header_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata)
|
||||
{
|
||||
size_t header_callback_dispatcher(void *buffer, size_t size, size_t nmemb, void *userdata) {
|
||||
return ((cURLCamera*)userdata)->header_callback(buffer,size,nmemb,userdata);
|
||||
}
|
||||
|
||||
int progress_callback_dispatcher(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
{
|
||||
int progress_callback_dispatcher(void *userdata, double dltotal, double dlnow, double ultotal, double ulnow) {
|
||||
return ((cURLCamera*)userdata)->progress_callback(userdata,dltotal,dlnow,ultotal,ulnow);
|
||||
}
|
||||
|
||||
@@ -558,6 +541,4 @@ void* thread_func_dispatcher(void* object) {
|
||||
return ((cURLCamera*)object)->thread_func();
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // HAVE_LIBCURL
|
||||
@@ -39,8 +39,7 @@
|
||||
// Class representing 'curl' cameras, i.e. those which are
|
||||
// accessed using the curl library
|
||||
//
|
||||
class cURLCamera : public Camera
|
||||
{
|
||||
class cURLCamera : public Camera {
|
||||
protected:
|
||||
typedef enum {MODE_UNSET, MODE_SINGLE, MODE_STREAM} mode_t;
|
||||
|
||||
@@ -79,8 +78,7 @@ public:
|
||||
int PreCapture();
|
||||
int Capture( Image &image );
|
||||
int PostCapture();
|
||||
int CaptureAndRecord( Image &image, bool recording, char* event_directory);
|
||||
|
||||
int CaptureAndRecord( Image &image, bool recording, char* event_directory);
|
||||
|
||||
size_t data_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
||||
size_t header_callback(void *buffer, size_t size, size_t nmemb, void *userdata);
|
||||
|
||||
+135
-284
@@ -74,8 +74,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||
createNotes( notes );
|
||||
|
||||
bool untimedEvent = false;
|
||||
if ( !start_time.tv_sec )
|
||||
{
|
||||
if ( !start_time.tv_sec ) {
|
||||
untimedEvent = true;
|
||||
gettimeofday( &start_time, 0 );
|
||||
}
|
||||
@@ -86,14 +85,12 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||
|
||||
struct tm *stime = localtime( &start_time.tv_sec );
|
||||
snprintf( sql, sizeof(sql), "insert into Events ( MonitorId, StorageId, Name, StartTime, Width, Height, Cause, Notes, Videoed ) values ( %d, %d, 'New Event', from_unixtime( %ld ), %d, %d, '%s', '%s', %d )", monitor->Id(), storage->Id(), start_time.tv_sec, monitor->Width(), monitor->Height(), cause.c_str(), notes.c_str(), videoEvent );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't insert event: %s. sql was (%s)", mysql_error( &dbconn ), sql );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
id = mysql_insert_id( &dbconn );
|
||||
if ( untimedEvent )
|
||||
{
|
||||
if ( untimedEvent ) {
|
||||
Warning( "Event %d has zero time, setting to current", id );
|
||||
}
|
||||
end_time.tv_sec = 0;
|
||||
@@ -102,8 +99,7 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||
tot_score = 0;
|
||||
max_score = 0;
|
||||
|
||||
if ( config.use_deep_storage )
|
||||
{
|
||||
if ( config.use_deep_storage ) {
|
||||
char *path_ptr = path;
|
||||
path_ptr += snprintf( path_ptr, sizeof(path), "%s/%d", storage->Path(), monitor->Id() );
|
||||
|
||||
@@ -118,17 +114,14 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||
char date_path[PATH_MAX] = "";
|
||||
char time_path[PATH_MAX] = "";
|
||||
char *time_path_ptr = time_path;
|
||||
for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ )
|
||||
{
|
||||
for ( unsigned int i = 0; i < sizeof(dt_parts)/sizeof(*dt_parts); i++ ) {
|
||||
path_ptr += snprintf( path_ptr, sizeof(path)-(path_ptr-path), "/%02d", dt_parts[i] );
|
||||
|
||||
struct stat statbuf;
|
||||
errno = 0;
|
||||
if ( stat( path, &statbuf ) ) {
|
||||
if ( errno == ENOENT || errno == ENOTDIR )
|
||||
{
|
||||
if ( mkdir( path, 0755 ) )
|
||||
{
|
||||
if ( errno == ENOENT || errno == ENOTDIR ) {
|
||||
if ( mkdir( path, 0755 ) ) {
|
||||
Fatal( "Can't mkdir %s: %s", path, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
@@ -151,18 +144,14 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||
fclose( id_fp );
|
||||
else
|
||||
Fatal( "Can't fopen %s: %s", id_file, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
snprintf( path, sizeof(path), "%s/%d/%d", storage->Path(), monitor->Id(), id );
|
||||
|
||||
struct stat statbuf;
|
||||
errno = 0;
|
||||
stat( path, &statbuf );
|
||||
if ( errno == ENOENT || errno == ENOTDIR )
|
||||
{
|
||||
if ( mkdir( path, 0755 ) )
|
||||
{
|
||||
if ( errno == ENOENT || errno == ENOTDIR ) {
|
||||
if ( mkdir( path, 0755 ) ) {
|
||||
Error( "Can't mkdir %s: %s", path, strerror(errno));
|
||||
}
|
||||
}
|
||||
@@ -187,7 +176,6 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||
snprintf( timecodes_name, sizeof(timecodes_name), "%d-%s", id, "video.timecodes" );
|
||||
snprintf( timecodes_file, sizeof(timecodes_file), video_file_format, path, timecodes_name );
|
||||
|
||||
|
||||
/* X264 MP4 video writer */
|
||||
if(monitor->GetOptVideoWriter() == 1) {
|
||||
#if ZM_HAVE_VIDEOWRITER_X264MP4
|
||||
@@ -220,18 +208,15 @@ Event::Event( Monitor *p_monitor, struct timeval p_start_time, const std::string
|
||||
|
||||
}
|
||||
|
||||
Event::~Event()
|
||||
{
|
||||
if ( frames > last_db_frame )
|
||||
{
|
||||
Event::~Event() {
|
||||
if ( frames > last_db_frame ) {
|
||||
struct DeltaTimeval delta_time;
|
||||
DELTA_TIMEVAL( delta_time, end_time, start_time, DT_PREC_2 );
|
||||
|
||||
Debug( 1, "Adding closing frame %d to DB", frames );
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ( %d, %d, from_unixtime( %ld ), %s%ld.%02ld )", id, frames, end_time.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't insert frame: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
@@ -266,16 +251,13 @@ Event::~Event()
|
||||
}
|
||||
}
|
||||
|
||||
void Event::createNotes( std::string ¬es )
|
||||
{
|
||||
void Event::createNotes( std::string ¬es ) {
|
||||
notes.clear();
|
||||
for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); mapIter++ )
|
||||
{
|
||||
for ( StringSetMap::const_iterator mapIter = noteSetMap.begin(); mapIter != noteSetMap.end(); mapIter++ ) {
|
||||
notes += mapIter->first;
|
||||
notes += ": ";
|
||||
const StringSet &stringSet = mapIter->second;
|
||||
for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); setIter++ )
|
||||
{
|
||||
for ( StringSet::const_iterator setIter = stringSet.begin(); setIter != stringSet.end(); setIter++ ) {
|
||||
if ( setIter != stringSet.begin() )
|
||||
notes += ", ";
|
||||
notes += *setIter;
|
||||
@@ -285,25 +267,20 @@ void Event::createNotes( std::string ¬es )
|
||||
|
||||
int Event::sd = -1;
|
||||
|
||||
bool Event::OpenFrameSocket( int monitor_id )
|
||||
{
|
||||
if ( sd > 0 )
|
||||
{
|
||||
bool Event::OpenFrameSocket( int monitor_id ) {
|
||||
if ( sd > 0 ) {
|
||||
close( sd );
|
||||
}
|
||||
|
||||
sd = socket( AF_UNIX, SOCK_STREAM, 0);
|
||||
if ( sd < 0 )
|
||||
{
|
||||
if ( sd < 0 ) {
|
||||
Error( "Can't create socket: %s", strerror(errno) );
|
||||
return( false );
|
||||
}
|
||||
|
||||
int socket_buffer_size = config.frame_socket_size;
|
||||
if ( socket_buffer_size > 0 )
|
||||
{
|
||||
if ( setsockopt( sd, SOL_SOCKET, SO_SNDBUF, &socket_buffer_size, sizeof(socket_buffer_size) ) < 0 )
|
||||
{
|
||||
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;
|
||||
@@ -312,16 +289,14 @@ bool Event::OpenFrameSocket( int monitor_id )
|
||||
}
|
||||
|
||||
int flags;
|
||||
if ( (flags = fcntl( sd, F_GETFL )) < 0 )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
if ( fcntl( sd, F_SETFL, flags ) < 0 ) {
|
||||
Error( "Can't set socket flags, error = %s", strerror(errno) );
|
||||
close( sd );
|
||||
sd = -1;
|
||||
@@ -336,8 +311,7 @@ bool Event::OpenFrameSocket( int monitor_id )
|
||||
strncpy( addr.sun_path, sock_path, sizeof(addr.sun_path) );
|
||||
addr.sun_family = AF_UNIX;
|
||||
|
||||
if ( connect( sd, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)+1) < 0 )
|
||||
{
|
||||
if ( connect( sd, (struct sockaddr *)&addr, strlen(addr.sun_path)+sizeof(addr.sun_family)+1) < 0 ) {
|
||||
Warning( "Can't connect to frame server: %s", strerror(errno) );
|
||||
close( sd );
|
||||
sd = -1;
|
||||
@@ -348,19 +322,15 @@ bool Event::OpenFrameSocket( int monitor_id )
|
||||
return( true );
|
||||
}
|
||||
|
||||
bool Event::ValidateFrameSocket( int monitor_id )
|
||||
{
|
||||
if ( sd < 0 )
|
||||
{
|
||||
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() ) )
|
||||
{
|
||||
bool Event::SendFrameImage( const Image *image, bool alarm_frame ) {
|
||||
if ( !ValidateFrameSocket( monitor->Id() ) ) {
|
||||
return( false );
|
||||
}
|
||||
|
||||
@@ -386,23 +356,16 @@ bool Event::SendFrameImage( const Image *image, bool alarm_frame )
|
||||
|
||||
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 )
|
||||
{
|
||||
if ( writev_result < 0 )
|
||||
{
|
||||
if ( errno == EAGAIN )
|
||||
{
|
||||
if ( writev_result != writev_size ) {
|
||||
if ( writev_result < 0 ) {
|
||||
if ( errno == EAGAIN ) {
|
||||
Warning( "Blocking write detected" );
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Error( "Can't write frame: %s", strerror(errno) );
|
||||
close( sd );
|
||||
sd = -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Error( "Incomplete frame write: %zd of %zd bytes written", writev_result, writev_size );
|
||||
close( sd );
|
||||
sd = -1;
|
||||
@@ -414,8 +377,7 @@ bool Event::SendFrameImage( const Image *image, bool alarm_frame )
|
||||
return( true );
|
||||
}
|
||||
|
||||
bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame )
|
||||
{
|
||||
bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame ) {
|
||||
Image* ImgToWrite;
|
||||
Image* ts_image = NULL;
|
||||
|
||||
@@ -424,12 +386,10 @@ bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char
|
||||
ts_image = new Image(*image);
|
||||
monitor->TimestampImage( ts_image, ×tamp );
|
||||
ImgToWrite=ts_image;
|
||||
}
|
||||
else
|
||||
} else
|
||||
ImgToWrite=image;
|
||||
|
||||
if ( !config.opt_frame_server || !SendFrameImage(ImgToWrite, alarm_frame) )
|
||||
{
|
||||
if ( !config.opt_frame_server || !SendFrameImage(ImgToWrite, alarm_frame) ) {
|
||||
int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default
|
||||
ImgToWrite->WriteJpeg( event_file, thisquality, (monitor->Exif() ? timestamp : (timeval){0,0}) ); // exif is only timestamp at present this switches on or off for write
|
||||
}
|
||||
@@ -437,8 +397,7 @@ bool Event::WriteFrameImage( Image *image, struct timeval timestamp, const char
|
||||
return( true );
|
||||
}
|
||||
|
||||
bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow )
|
||||
{
|
||||
bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow ) {
|
||||
const Image* frameimg = image;
|
||||
Image ts_image;
|
||||
|
||||
@@ -471,56 +430,43 @@ bool Event::WriteFrameVideo( const Image *image, const struct timeval timestamp,
|
||||
return( true );
|
||||
}
|
||||
|
||||
void Event::updateNotes( const StringSetMap &newNoteSetMap )
|
||||
{
|
||||
void Event::updateNotes( const StringSetMap &newNoteSetMap ) {
|
||||
bool update = false;
|
||||
|
||||
//Info( "Checking notes, %d <> %d", noteSetMap.size(), newNoteSetMap.size() );
|
||||
if ( newNoteSetMap.size() > 0 )
|
||||
{
|
||||
if ( noteSetMap.size() == 0 )
|
||||
{
|
||||
if ( newNoteSetMap.size() > 0 ) {
|
||||
if ( noteSetMap.size() == 0 ) {
|
||||
noteSetMap = newNoteSetMap;
|
||||
update = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); newNoteSetMapIter++ )
|
||||
{
|
||||
} else {
|
||||
for ( StringSetMap::const_iterator newNoteSetMapIter = newNoteSetMap.begin(); newNoteSetMapIter != newNoteSetMap.end(); newNoteSetMapIter++ ) {
|
||||
const std::string &newNoteGroup = newNoteSetMapIter->first;
|
||||
const StringSet &newNoteSet = newNoteSetMapIter->second;
|
||||
//Info( "Got %d new strings", newNoteSet.size() );
|
||||
if ( newNoteSet.size() > 0 )
|
||||
{
|
||||
if ( newNoteSet.size() > 0 ) {
|
||||
StringSetMap::iterator noteSetMapIter = noteSetMap.find( newNoteGroup );
|
||||
if ( noteSetMapIter == noteSetMap.end() )
|
||||
{
|
||||
if ( noteSetMapIter == noteSetMap.end() ) {
|
||||
//Info( "Can't find note group %s, copying %d strings", newNoteGroup.c_str(), newNoteSet.size() );
|
||||
noteSetMap.insert( StringSetMap::value_type( newNoteGroup, newNoteSet ) );
|
||||
update = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
StringSet ¬eSet = noteSetMapIter->second;
|
||||
//Info( "Found note group %s, got %d strings", newNoteGroup.c_str(), newNoteSet.size() );
|
||||
for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); newNoteSetIter++ )
|
||||
{
|
||||
for ( StringSet::const_iterator newNoteSetIter = newNoteSet.begin(); newNoteSetIter != newNoteSet.end(); newNoteSetIter++ ) {
|
||||
const std::string &newNote = *newNoteSetIter;
|
||||
StringSet::iterator noteSetIter = noteSet.find( newNote );
|
||||
if ( noteSetIter == noteSet.end() )
|
||||
{
|
||||
if ( noteSetIter == noteSet.end() ) {
|
||||
noteSet.insert( newNote );
|
||||
update = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end for
|
||||
} // end if ( noteSetMap.size() == 0
|
||||
} // end if newNoteSetupMap.size() > 0
|
||||
|
||||
if ( update )
|
||||
{
|
||||
if ( update ) {
|
||||
std::string notes;
|
||||
createNotes( notes );
|
||||
|
||||
@@ -532,19 +478,16 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap )
|
||||
char notesStr[ZM_SQL_MED_BUFSIZ] = "";
|
||||
unsigned long notesLen = 0;
|
||||
|
||||
if ( !stmt )
|
||||
{
|
||||
if ( !stmt ) {
|
||||
const char *sql = "update Events set Notes = ? where Id = ?";
|
||||
|
||||
stmt = mysql_stmt_init( &dbconn );
|
||||
if ( mysql_stmt_prepare( stmt, sql, strlen(sql) ) )
|
||||
{
|
||||
if ( mysql_stmt_prepare( stmt, sql, strlen(sql) ) ) {
|
||||
Fatal( "Unable to prepare sql '%s': %s", sql, mysql_stmt_error(stmt) );
|
||||
}
|
||||
|
||||
/* Get the parameter count from the statement */
|
||||
if ( mysql_stmt_param_count( stmt ) != 2 )
|
||||
{
|
||||
if ( mysql_stmt_param_count( stmt ) != 2 ) {
|
||||
Fatal( "Unexpected parameter count %ld in sql '%s'", mysql_stmt_param_count( stmt ), sql );
|
||||
}
|
||||
|
||||
@@ -564,8 +507,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap )
|
||||
bind[1].length= 0;
|
||||
|
||||
/* Bind the buffers */
|
||||
if ( mysql_stmt_bind_param( stmt, bind ) )
|
||||
{
|
||||
if ( mysql_stmt_bind_param( stmt, bind ) ) {
|
||||
Fatal( "Unable to bind sql '%s': %s", sql, mysql_stmt_error(stmt) );
|
||||
}
|
||||
}
|
||||
@@ -573,8 +515,7 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap )
|
||||
strncpy( notesStr, notes.c_str(), sizeof(notesStr) );
|
||||
notesLen = notes.length();
|
||||
|
||||
if ( mysql_stmt_execute( stmt ) )
|
||||
{
|
||||
if ( mysql_stmt_execute( stmt ) ) {
|
||||
Fatal( "Unable to execute sql '%s': %s", sql, mysql_stmt_error(stmt) );
|
||||
}
|
||||
#else
|
||||
@@ -583,30 +524,25 @@ void Event::updateNotes( const StringSetMap &newNoteSetMap )
|
||||
mysql_real_escape_string( &dbconn, escapedNotes, notes.c_str(), notes.length() );
|
||||
|
||||
snprintf( sql, sizeof(sql), "update Events set Notes = '%s' where Id = %d", escapedNotes, id );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't insert event: %s", mysql_error( &dbconn ) );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps )
|
||||
{
|
||||
void Event::AddFrames( int n_frames, Image **images, struct timeval **timestamps ) {
|
||||
for (int i = 0; i < n_frames; i += ZM_SQL_BATCH_SIZE) {
|
||||
AddFramesInternal(n_frames, i, images, timestamps);
|
||||
}
|
||||
}
|
||||
|
||||
void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps )
|
||||
{
|
||||
void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps ) {
|
||||
static char sql[ZM_SQL_LGE_BUFSIZ];
|
||||
strncpy( sql, "insert into Frames ( EventId, FrameId, TimeStamp, Delta ) values ", sizeof(sql) );
|
||||
int frameCount = 0;
|
||||
for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ )
|
||||
{
|
||||
if ( !timestamps[i]->tv_sec )
|
||||
{
|
||||
for ( int i = start_frame; i < n_frames && i - start_frame < ZM_SQL_BATCH_SIZE; i++ ) {
|
||||
if ( !timestamps[i]->tv_sec ) {
|
||||
Debug( 1, "Not adding pre-capture frame %d, zero timestamp", i );
|
||||
continue;
|
||||
}
|
||||
@@ -640,27 +576,21 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st
|
||||
frameCount++;
|
||||
}
|
||||
|
||||
if ( frameCount )
|
||||
{
|
||||
if ( frameCount ) {
|
||||
Debug( 1, "Adding %d/%d frames to DB", frameCount, n_frames );
|
||||
*(sql+strlen(sql)-2) = '\0';
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't insert frames: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
last_db_frame = frames;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Debug( 1, "No valid pre-capture frames to add" );
|
||||
}
|
||||
}
|
||||
|
||||
void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *alarm_image )
|
||||
{
|
||||
if ( !timestamp.tv_sec )
|
||||
{
|
||||
void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *alarm_image ) {
|
||||
if ( !timestamp.tv_sec ) {
|
||||
Debug( 1, "Not adding new frame, zero timestamp" );
|
||||
return;
|
||||
}
|
||||
@@ -694,25 +624,21 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *
|
||||
score = 0;
|
||||
|
||||
bool db_frame = (strcmp(frame_type,"Bulk") != 0) || ((frames%config.bulk_frame_interval)==0) || !frames;
|
||||
if ( db_frame )
|
||||
{
|
||||
if ( db_frame ) {
|
||||
|
||||
Debug( 1, "Adding frame %d of type \"%s\" to DB", frames, frame_type );
|
||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||
snprintf( sql, sizeof(sql), "insert into Frames ( EventId, FrameId, Type, TimeStamp, Delta, Score ) values ( %d, %d, '%s', from_unixtime( %ld ), %s%ld.%02ld, %d )", id, frames, frame_type, timestamp.tv_sec, delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, score );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't insert frame: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
last_db_frame = frames;
|
||||
|
||||
// We are writing a Bulk frame
|
||||
if ( !strcmp( frame_type,"Bulk") )
|
||||
{
|
||||
if ( !strcmp( frame_type,"Bulk") ) {
|
||||
snprintf( sql, sizeof(sql), "update Events set Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d where Id = %d", 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 );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
if ( mysql_query( &dbconn, sql ) ) {
|
||||
Error( "Can't update event: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
@@ -722,16 +648,14 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image *
|
||||
end_time = timestamp;
|
||||
|
||||
// We are writing an Alarm frame
|
||||
if ( !strcmp( frame_type,"Alarm") )
|
||||
{
|
||||
if ( !strcmp( frame_type,"Alarm") ) {
|
||||
alarm_frames++;
|
||||
|
||||
tot_score += score;
|
||||
if ( score > (int)max_score )
|
||||
max_score = score;
|
||||
|
||||
if ( alarm_image )
|
||||
{
|
||||
if ( alarm_image ) {
|
||||
snprintf( event_file, sizeof(event_file), analyse_file_format, path, frames );
|
||||
|
||||
Debug( 1, "Writing analysis frame %d", frames );
|
||||
@@ -798,15 +722,13 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time )
|
||||
}
|
||||
|
||||
MYSQL_RES *result = mysql_store_result( &dbconn );
|
||||
if ( !result )
|
||||
{
|
||||
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 ) )
|
||||
{
|
||||
if ( mysql_errno( &dbconn ) ) {
|
||||
Error( "Can't fetch row: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
@@ -817,17 +739,13 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time )
|
||||
|
||||
loadEventData( init_event_id );
|
||||
|
||||
if ( event_time )
|
||||
{
|
||||
if ( event_time ) {
|
||||
curr_stream_time = event_time;
|
||||
curr_frame_id = 1;
|
||||
if ( event_time >= event_data->start_time )
|
||||
{
|
||||
for (unsigned int i = 0; i < event_data->frame_count; i++ )
|
||||
{
|
||||
if ( event_time >= event_data->start_time ) {
|
||||
for (unsigned int i = 0; i < event_data->frame_count; i++ ) {
|
||||
//Info( "eft %d > et %d", event_data->frames[i].timestamp, event_time );
|
||||
if ( event_data->frames[i].timestamp >= event_time )
|
||||
{
|
||||
if ( event_data->frames[i].timestamp >= event_time ) {
|
||||
curr_frame_id = i+1;
|
||||
Debug( 3, "Set cst:%.2f", curr_stream_time );
|
||||
Debug( 3, "Set cfid:%d", curr_frame_id );
|
||||
@@ -840,51 +758,42 @@ bool EventStream::loadInitialEventData( int monitor_id, time_t event_time )
|
||||
return( true );
|
||||
}
|
||||
|
||||
bool EventStream::loadInitialEventData( int init_event_id, unsigned int init_frame_id )
|
||||
{
|
||||
bool EventStream::loadInitialEventData( int init_event_id, unsigned int init_frame_id ) {
|
||||
loadEventData( init_event_id );
|
||||
|
||||
if ( init_frame_id )
|
||||
{
|
||||
if ( init_frame_id ) {
|
||||
curr_stream_time = event_data->frames[init_frame_id-1].timestamp;
|
||||
curr_frame_id = init_frame_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
curr_stream_time = event_data->start_time;
|
||||
}
|
||||
|
||||
return( true );
|
||||
}
|
||||
|
||||
bool EventStream::loadEventData( int event_id )
|
||||
{
|
||||
bool EventStream::loadEventData( int event_id ) {
|
||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||
|
||||
snprintf( sql, sizeof(sql), "select M.Id, M.Name, E.StorageId, E.Frames, unix_timestamp( StartTime ) as StartTimestamp, max(F.Delta)-min(F.Delta) as Duration,E.DefaultVideo from Events as E inner join Monitors as M on E.MonitorId = M.Id inner join Frames as F on E.Id = F.EventId where E.Id = %d group by E.Id", event_id );
|
||||
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
if ( !result ) {
|
||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
|
||||
if ( !mysql_num_rows( result ) )
|
||||
{
|
||||
if ( !mysql_num_rows( result ) ) {
|
||||
Fatal( "Unable to load event %d, not found in DB", event_id );
|
||||
}
|
||||
|
||||
MYSQL_ROW dbrow = mysql_fetch_row( result );
|
||||
|
||||
if ( mysql_errno( &dbconn ) )
|
||||
{
|
||||
if ( mysql_errno( &dbconn ) ) {
|
||||
Error( "Can't fetch row: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
@@ -899,16 +808,13 @@ bool EventStream::loadEventData( int event_id )
|
||||
Storage * storage = new Storage( event_data->storage_id );
|
||||
const char *storage_path = storage->Path();
|
||||
|
||||
if ( config.use_deep_storage )
|
||||
{
|
||||
if ( config.use_deep_storage ) {
|
||||
struct tm *event_time = localtime( &event_data->start_time );
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
|
||||
else
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%s/%ld/%02d/%02d/%02d/%02d/%02d/%02d", staticConfig.PATH_WEB.c_str(), storage_path, event_data->monitor_id, event_time->tm_year-100, event_time->tm_mon+1, event_time->tm_mday, event_time->tm_hour, event_time->tm_min, event_time->tm_sec );
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if ( storage_path[0] == '/' )
|
||||
snprintf( event_data->path, sizeof(event_data->path), "%s/%ld/%ld", storage_path, event_data->monitor_id, event_data->event_id );
|
||||
else
|
||||
@@ -923,15 +829,13 @@ bool EventStream::loadEventData( int event_id )
|
||||
mysql_free_result( result );
|
||||
|
||||
snprintf( sql, sizeof(sql), "select FrameId, unix_timestamp( `TimeStamp` ), Delta from Frames where EventId = %d order by FrameId asc", event_id );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
if ( !result ) {
|
||||
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
@@ -942,17 +846,14 @@ bool EventStream::loadEventData( int event_id )
|
||||
int id, last_id = 0;
|
||||
time_t timestamp, last_timestamp = event_data->start_time;
|
||||
double delta, last_delta = 0.0;
|
||||
while ( ( dbrow = mysql_fetch_row( result ) ) )
|
||||
{
|
||||
while ( ( dbrow = mysql_fetch_row( result ) ) ) {
|
||||
id = atoi(dbrow[0]);
|
||||
timestamp = atoi(dbrow[1]);
|
||||
delta = atof(dbrow[2]);
|
||||
int id_diff = id - last_id;
|
||||
double frame_delta = (delta-last_delta)/id_diff;
|
||||
if ( id_diff > 1 )
|
||||
{
|
||||
for ( int i = last_id+1; i < id; i++ )
|
||||
{
|
||||
if ( id_diff > 1 ) {
|
||||
for ( int i = last_id+1; i < id; i++ ) {
|
||||
event_data->frames[i-1].timestamp = (time_t)(last_timestamp + ((i-last_id)*frame_delta));
|
||||
event_data->frames[i-1].offset = (time_t)(event_data->frames[i-1].timestamp-event_data->start_time);
|
||||
event_data->frames[i-1].delta = frame_delta;
|
||||
@@ -967,8 +868,7 @@ bool EventStream::loadEventData( int event_id )
|
||||
last_delta = delta;
|
||||
last_timestamp = timestamp;
|
||||
}
|
||||
if ( mysql_errno( &dbconn ) )
|
||||
{
|
||||
if ( mysql_errno( &dbconn ) ) {
|
||||
Error( "Can't fetch row: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
@@ -980,8 +880,7 @@ bool EventStream::loadEventData( int event_id )
|
||||
|
||||
mysql_free_result( result );
|
||||
|
||||
if ( forceEventChange || mode == MODE_ALL_GAPLESS )
|
||||
{
|
||||
if ( forceEventChange || mode == MODE_ALL_GAPLESS ) {
|
||||
if ( replay_rate > 0 )
|
||||
curr_stream_time = event_data->frames[0].timestamp;
|
||||
else
|
||||
@@ -992,12 +891,10 @@ bool EventStream::loadEventData( int event_id )
|
||||
return( true );
|
||||
}
|
||||
|
||||
void EventStream::processCommand( const CmdMsg *msg )
|
||||
{
|
||||
void EventStream::processCommand( const CmdMsg *msg ) {
|
||||
Debug( 2, "Got message, type %d, msg %d", msg->msg_type, msg->msg_data[0] )
|
||||
// Check for incoming command
|
||||
switch( (MsgCommand)msg->msg_data[0] )
|
||||
{
|
||||
switch( (MsgCommand)msg->msg_data[0] ) {
|
||||
case CMD_PAUSE :
|
||||
{
|
||||
Debug( 1, "Got PAUSE command" );
|
||||
@@ -1256,8 +1153,7 @@ void EventStream::processCommand( const CmdMsg *msg )
|
||||
DataMsg status_msg;
|
||||
status_msg.msg_type = MSG_DATA_EVENT;
|
||||
memcpy( &status_msg.msg_data, &status_data, sizeof(status_data) );
|
||||
if ( sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) ) < 0 )
|
||||
{
|
||||
if ( sendto( sd, &status_msg, sizeof(status_msg), MSG_DONTWAIT, (sockaddr *)&rem_addr, sizeof(rem_addr) ) < 0 ) {
|
||||
//if ( errno != EAGAIN )
|
||||
{
|
||||
Error( "Can't sendto on sd %d: %s", sd, strerror(errno) );
|
||||
@@ -1271,49 +1167,39 @@ void EventStream::processCommand( const CmdMsg *msg )
|
||||
updateFrameRate( (double)event_data->frame_count/event_data->duration );
|
||||
}
|
||||
|
||||
void EventStream::checkEventLoaded()
|
||||
{
|
||||
void EventStream::checkEventLoaded() {
|
||||
bool reload_event = false;
|
||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||
|
||||
if ( curr_frame_id <= 0 )
|
||||
{
|
||||
if ( curr_frame_id <= 0 ) {
|
||||
snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id < %ld order by Id desc limit 1", event_data->monitor_id, event_data->event_id );
|
||||
reload_event = true;
|
||||
}
|
||||
else if ( (unsigned int)curr_frame_id > event_data->frame_count )
|
||||
{
|
||||
} else if ( (unsigned int)curr_frame_id > event_data->frame_count ) {
|
||||
snprintf( sql, sizeof(sql), "select Id from Events where MonitorId = %ld and Id > %ld order by Id asc limit 1", event_data->monitor_id, event_data->event_id );
|
||||
reload_event = true;
|
||||
}
|
||||
|
||||
if ( reload_event )
|
||||
{
|
||||
if ( forceEventChange || mode != MODE_SINGLE )
|
||||
{
|
||||
if ( reload_event ) {
|
||||
if ( forceEventChange || mode != MODE_SINGLE ) {
|
||||
//Info( "SQL:%s", sql );
|
||||
if ( mysql_query( &dbconn, sql ) )
|
||||
{
|
||||
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 )
|
||||
{
|
||||
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 ) )
|
||||
{
|
||||
if ( mysql_errno( &dbconn ) ) {
|
||||
Error( "Can't fetch row: %s", mysql_error( &dbconn ) );
|
||||
exit( mysql_errno( &dbconn ) );
|
||||
}
|
||||
|
||||
if ( dbrow )
|
||||
{
|
||||
if ( dbrow ) {
|
||||
int event_id = atoi(dbrow[0]);
|
||||
Debug( 1, "Loading new event %d", event_id );
|
||||
|
||||
@@ -1325,9 +1211,7 @@ void EventStream::checkEventLoaded()
|
||||
else
|
||||
curr_frame_id = 1;
|
||||
Debug( 2, "New frame id = %d", curr_frame_id );
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if ( curr_frame_id <= 0 )
|
||||
curr_frame_id = 1;
|
||||
else
|
||||
@@ -1336,9 +1220,7 @@ void EventStream::checkEventLoaded()
|
||||
}
|
||||
mysql_free_result( result );
|
||||
forceEventChange = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
if ( curr_frame_id <= 0 )
|
||||
curr_frame_id = 1;
|
||||
else
|
||||
@@ -1359,8 +1241,7 @@ Image * EventStream::getImage( ) {
|
||||
return image;
|
||||
}
|
||||
|
||||
bool EventStream::sendFrame( int delta_us )
|
||||
{
|
||||
bool EventStream::sendFrame( int delta_us ) {
|
||||
Debug( 2, "Sending frame %d", curr_frame_id );
|
||||
|
||||
static char filepath[PATH_MAX];
|
||||
@@ -1370,21 +1251,18 @@ bool EventStream::sendFrame( int delta_us )
|
||||
snprintf( filepath, sizeof(filepath), Event::capture_file_format, event_data->path, curr_frame_id );
|
||||
|
||||
#if HAVE_LIBAVCODEC
|
||||
if ( type == STREAM_MPEG )
|
||||
{
|
||||
if ( type == STREAM_MPEG ) {
|
||||
Image image( filepath );
|
||||
|
||||
Image *send_image = prepareImage( &image );
|
||||
|
||||
if ( !vid_stream )
|
||||
{
|
||||
if ( !vid_stream ) {
|
||||
vid_stream = new VideoStream( "pipe:", format, bitrate, effective_fps, send_image->Colours(), send_image->SubpixelOrder(), send_image->Width(), send_image->Height() );
|
||||
fprintf( stdout, "Content-type: %s\r\n\r\n", vid_stream->MimeType() );
|
||||
vid_stream->OpenStream();
|
||||
}
|
||||
/* double pts = */ vid_stream->EncodeFrame( send_image->Buffer(), send_image->Size(), config.mpeg_timed_frames, delta_us*1000 );
|
||||
}
|
||||
else
|
||||
} else
|
||||
#endif // HAVE_LIBAVCODEC
|
||||
{
|
||||
static unsigned char temp_img_buffer[ZM_MAX_IMAGE_SIZE];
|
||||
@@ -1399,11 +1277,9 @@ bool EventStream::sendFrame( int delta_us )
|
||||
if ( type != STREAM_JPEG )
|
||||
send_raw = false;
|
||||
|
||||
if ( send_raw )
|
||||
{
|
||||
if ( send_raw ) {
|
||||
fdj = fopen( filepath, "rb" );
|
||||
if ( !fdj )
|
||||
{
|
||||
if ( !fdj ) {
|
||||
Error( "Can't open %s: %s", filepath, strerror(errno) );
|
||||
return( false );
|
||||
}
|
||||
@@ -1415,15 +1291,12 @@ bool EventStream::sendFrame( int delta_us )
|
||||
#else
|
||||
img_buffer_size = fread( img_buffer, 1, sizeof(temp_img_buffer), fdj );
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Image image( filepath );
|
||||
|
||||
Image *send_image = prepareImage( &image );
|
||||
|
||||
switch( type )
|
||||
{
|
||||
switch( type ) {
|
||||
case STREAM_JPEG :
|
||||
send_image->EncodeJpeg( img_buffer, &img_buffer_size );
|
||||
break;
|
||||
@@ -1447,8 +1320,7 @@ bool EventStream::sendFrame( int delta_us )
|
||||
}
|
||||
}
|
||||
|
||||
switch( type )
|
||||
{
|
||||
switch( type ) {
|
||||
case STREAM_JPEG :
|
||||
fprintf( stdout, "Content-Type: image/jpeg\r\n" );
|
||||
break;
|
||||
@@ -1485,8 +1357,7 @@ bool EventStream::sendFrame( int delta_us )
|
||||
fclose(fdj); /* Close the file handle */
|
||||
} else {
|
||||
fprintf( stdout, "Content-Length: %d\r\n\r\n", img_buffer_size );
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 )
|
||||
{
|
||||
if ( fwrite( img_buffer, img_buffer_size, 1, stdout ) != 1 ) {
|
||||
Error( "Unable to send stream frame: %s", strerror(errno) );
|
||||
return( false );
|
||||
}
|
||||
@@ -1499,8 +1370,7 @@ bool EventStream::sendFrame( int delta_us )
|
||||
return( true );
|
||||
}
|
||||
|
||||
void EventStream::runStream()
|
||||
{
|
||||
void EventStream::runStream() {
|
||||
Event::Initialise();
|
||||
|
||||
openComms();
|
||||
@@ -1512,15 +1382,13 @@ void EventStream::runStream()
|
||||
if ( type == STREAM_JPEG )
|
||||
fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" );
|
||||
|
||||
if ( !event_data )
|
||||
{
|
||||
if ( !event_data ) {
|
||||
sendTextFrame( "No event data found" );
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
unsigned int delta_us = 0;
|
||||
while( !zm_terminate )
|
||||
{
|
||||
while( !zm_terminate ) {
|
||||
gettimeofday( &now, NULL );
|
||||
|
||||
while(checkCommandQueue());
|
||||
@@ -1536,27 +1404,21 @@ void EventStream::runStream()
|
||||
//Info( "cst:%.2f", curr_stream_time );
|
||||
//Info( "cfid:%d", curr_frame_id );
|
||||
//Info( "fdt:%d", frame_data->timestamp );
|
||||
if ( !paused )
|
||||
{
|
||||
if ( !paused ) {
|
||||
bool in_event = true;
|
||||
double time_to_event = 0;
|
||||
if ( replay_rate > 0 )
|
||||
{
|
||||
if ( replay_rate > 0 ) {
|
||||
time_to_event = event_data->frames[0].timestamp - curr_stream_time;
|
||||
if ( time_to_event > 0 )
|
||||
in_event = false;
|
||||
}
|
||||
else if ( replay_rate < 0 )
|
||||
{
|
||||
} else if ( replay_rate < 0 ) {
|
||||
time_to_event = curr_stream_time - event_data->frames[event_data->frame_count-1].timestamp;
|
||||
if ( time_to_event > 0 )
|
||||
in_event = false;
|
||||
}
|
||||
if ( !in_event )
|
||||
{
|
||||
if ( !in_event ) {
|
||||
double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent;
|
||||
if ( actual_delta_time > 1 )
|
||||
{
|
||||
if ( actual_delta_time > 1 ) {
|
||||
static char frame_text[64];
|
||||
snprintf( frame_text, sizeof(frame_text), "Time to next event = %d seconds", (int)time_to_event );
|
||||
if ( !sendTextFrame( frame_text ) )
|
||||
@@ -1574,11 +1436,9 @@ void EventStream::runStream()
|
||||
|
||||
// Figure out if we should send this frame
|
||||
bool send_frame = false;
|
||||
if ( !paused )
|
||||
{
|
||||
if ( !paused ) {
|
||||
// If we are streaming and this frame is due to be sent
|
||||
if ( ((curr_frame_id-1)%frame_mod) == 0 )
|
||||
{
|
||||
if ( ((curr_frame_id-1)%frame_mod) == 0 ) {
|
||||
delta_us = (unsigned int)(frame_data->delta * 1000000);
|
||||
// if effective > base we should speed up frame delivery
|
||||
delta_us = (unsigned int)((delta_us * base_fps)/effective_fps);
|
||||
@@ -1586,19 +1446,14 @@ void EventStream::runStream()
|
||||
delta_us = max(delta_us, 1000000 / maxfps);
|
||||
send_frame = true;
|
||||
}
|
||||
}
|
||||
else if ( step != 0 )
|
||||
{
|
||||
} else if ( step != 0 ) {
|
||||
// We are paused and are just stepping forward or backward one frame
|
||||
step = 0;
|
||||
send_frame = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// We are paused, and doing nothing
|
||||
double actual_delta_time = TV_2_FLOAT( now ) - last_frame_sent;
|
||||
if ( actual_delta_time > MAX_STREAM_DELAY )
|
||||
{
|
||||
if ( actual_delta_time > MAX_STREAM_DELAY ) {
|
||||
// Send keepalive
|
||||
Debug( 2, "Sending keepalive frame" );
|
||||
send_frame = true;
|
||||
@@ -1611,17 +1466,13 @@ void EventStream::runStream()
|
||||
|
||||
curr_stream_time = frame_data->timestamp;
|
||||
|
||||
if ( !paused )
|
||||
{
|
||||
if ( !paused ) {
|
||||
curr_frame_id += replay_rate>0?1:-1;
|
||||
if ( send_frame && type != STREAM_MPEG )
|
||||
{
|
||||
if ( send_frame && type != STREAM_MPEG ) {
|
||||
Debug( 3, "dUs: %d", delta_us );
|
||||
usleep( delta_us );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
usleep( (unsigned long)((1000000 * ZM_RATE_BASE)/((base_fps?base_fps:1)*abs(replay_rate*2))) );
|
||||
}
|
||||
}
|
||||
|
||||
+106
-125
@@ -47,163 +47,149 @@ class Monitor;
|
||||
//
|
||||
// Class describing events, i.e. captured periods of activity.
|
||||
//
|
||||
class Event
|
||||
{
|
||||
class Event {
|
||||
friend class EventStream;
|
||||
|
||||
protected:
|
||||
static bool initialised;
|
||||
static char capture_file_format[PATH_MAX];
|
||||
static char analyse_file_format[PATH_MAX];
|
||||
static char general_file_format[PATH_MAX];
|
||||
static char video_file_format[PATH_MAX];
|
||||
static bool initialised;
|
||||
static char capture_file_format[PATH_MAX];
|
||||
static char analyse_file_format[PATH_MAX];
|
||||
static char general_file_format[PATH_MAX];
|
||||
static char video_file_format[PATH_MAX];
|
||||
|
||||
protected:
|
||||
static int sd;
|
||||
static int sd;
|
||||
|
||||
public:
|
||||
typedef std::set<std::string> StringSet;
|
||||
typedef std::map<std::string,StringSet> StringSetMap;
|
||||
typedef std::set<std::string> StringSet;
|
||||
typedef std::map<std::string,StringSet> StringSetMap;
|
||||
|
||||
protected:
|
||||
typedef enum { NORMAL, BULK, ALARM } FrameType;
|
||||
typedef enum { NORMAL, BULK, ALARM } FrameType;
|
||||
|
||||
struct PreAlarmData
|
||||
{
|
||||
Image *image;
|
||||
struct timeval timestamp;
|
||||
unsigned int score;
|
||||
Image *alarm_frame;
|
||||
};
|
||||
struct PreAlarmData {
|
||||
Image *image;
|
||||
struct timeval timestamp;
|
||||
unsigned int score;
|
||||
Image *alarm_frame;
|
||||
};
|
||||
|
||||
static int pre_alarm_count;
|
||||
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
||||
static int pre_alarm_count;
|
||||
static PreAlarmData pre_alarm_data[MAX_PRE_ALARM_FRAMES];
|
||||
|
||||
protected:
|
||||
unsigned int id;
|
||||
Monitor *monitor;
|
||||
struct timeval start_time;
|
||||
struct timeval end_time;
|
||||
std::string cause;
|
||||
StringSetMap noteSetMap;
|
||||
bool videoEvent;
|
||||
int frames;
|
||||
int alarm_frames;
|
||||
unsigned int tot_score;
|
||||
unsigned int max_score;
|
||||
char path[PATH_MAX];
|
||||
VideoWriter* videowriter;
|
||||
FILE* timecodes_fd;
|
||||
char video_name[PATH_MAX];
|
||||
char video_file[PATH_MAX];
|
||||
char timecodes_name[PATH_MAX];
|
||||
char timecodes_file[PATH_MAX];
|
||||
unsigned int id;
|
||||
Monitor *monitor;
|
||||
struct timeval start_time;
|
||||
struct timeval end_time;
|
||||
std::string cause;
|
||||
StringSetMap noteSetMap;
|
||||
bool videoEvent;
|
||||
int frames;
|
||||
int alarm_frames;
|
||||
unsigned int tot_score;
|
||||
unsigned int max_score;
|
||||
char path[PATH_MAX];
|
||||
VideoWriter* videowriter;
|
||||
FILE* timecodes_fd;
|
||||
char video_name[PATH_MAX];
|
||||
char video_file[PATH_MAX];
|
||||
char timecodes_name[PATH_MAX];
|
||||
char timecodes_file[PATH_MAX];
|
||||
|
||||
protected:
|
||||
int last_db_frame;
|
||||
int last_db_frame;
|
||||
|
||||
protected:
|
||||
static void Initialise()
|
||||
{
|
||||
if ( initialised )
|
||||
return;
|
||||
static void Initialise() {
|
||||
if ( initialised )
|
||||
return;
|
||||
|
||||
snprintf( capture_file_format, sizeof(capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits );
|
||||
snprintf( analyse_file_format, sizeof(analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits );
|
||||
snprintf( general_file_format, sizeof(general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits );
|
||||
snprintf( video_file_format, sizeof(video_file_format), "%%s/%%s");
|
||||
snprintf( capture_file_format, sizeof(capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits );
|
||||
snprintf( analyse_file_format, sizeof(analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits );
|
||||
snprintf( general_file_format, sizeof(general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits );
|
||||
snprintf( video_file_format, sizeof(video_file_format), "%%s/%%s");
|
||||
|
||||
initialised = true;
|
||||
}
|
||||
initialised = true;
|
||||
}
|
||||
|
||||
void createNotes( std::string ¬es );
|
||||
void createNotes( std::string ¬es );
|
||||
|
||||
public:
|
||||
static bool OpenFrameSocket( int );
|
||||
static bool ValidateFrameSocket( int );
|
||||
static bool OpenFrameSocket( int );
|
||||
static bool ValidateFrameSocket( int );
|
||||
|
||||
public:
|
||||
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false );
|
||||
~Event();
|
||||
Event( Monitor *p_monitor, struct timeval p_start_time, const std::string &p_cause, const StringSetMap &p_noteSetMap, bool p_videoEvent=false );
|
||||
~Event();
|
||||
|
||||
int Id() const { return( id ); }
|
||||
const std::string &Cause() { return( cause ); }
|
||||
int Frames() const { return( frames ); }
|
||||
int AlarmFrames() const { return( alarm_frames ); }
|
||||
int Id() const { return( id ); }
|
||||
const std::string &Cause() { return( cause ); }
|
||||
int Frames() const { return( frames ); }
|
||||
int AlarmFrames() const { return( alarm_frames ); }
|
||||
|
||||
const struct timeval &StartTime() const { return( start_time ); }
|
||||
const struct timeval &EndTime() const { return( end_time ); }
|
||||
struct timeval &EndTime() { return( end_time ); }
|
||||
const struct timeval &StartTime() const { return( start_time ); }
|
||||
const struct timeval &EndTime() const { return( end_time ); }
|
||||
struct timeval &EndTime() { return( end_time ); }
|
||||
|
||||
bool SendFrameImage( const Image *image, bool alarm_frame=false );
|
||||
bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false );
|
||||
bool WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow );
|
||||
bool SendFrameImage( const Image *image, bool alarm_frame=false );
|
||||
bool WriteFrameImage( Image *image, struct timeval timestamp, const char *event_file, bool alarm_frame=false );
|
||||
bool WriteFrameVideo( const Image *image, const struct timeval timestamp, VideoWriter* videow );
|
||||
|
||||
void updateNotes( const StringSetMap &stringSetMap );
|
||||
void updateNotes( const StringSetMap &stringSetMap );
|
||||
|
||||
void AddFrames( int n_frames, Image **images, struct timeval **timestamps );
|
||||
void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL );
|
||||
void AddFrames( int n_frames, Image **images, struct timeval **timestamps );
|
||||
void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL );
|
||||
|
||||
private:
|
||||
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );
|
||||
void AddFramesInternal( int n_frames, int start_frame, Image **images, struct timeval **timestamps );
|
||||
|
||||
public:
|
||||
static const char *getSubPath( struct tm *time )
|
||||
{
|
||||
static char subpath[PATH_MAX] = "";
|
||||
snprintf( subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec );
|
||||
return( subpath );
|
||||
}
|
||||
static const char *getSubPath( time_t *time )
|
||||
{
|
||||
return( Event::getSubPath( localtime( time ) ) );
|
||||
}
|
||||
static const char *getSubPath( struct tm *time ) {
|
||||
static char subpath[PATH_MAX] = "";
|
||||
snprintf( subpath, sizeof(subpath), "%02d/%02d/%02d/%02d/%02d/%02d", time->tm_year-100, time->tm_mon+1, time->tm_mday, time->tm_hour, time->tm_min, time->tm_sec );
|
||||
return( subpath );
|
||||
}
|
||||
static const char *getSubPath( time_t *time ) {
|
||||
return( Event::getSubPath( localtime( time ) ) );
|
||||
}
|
||||
|
||||
char* getEventFile(void){
|
||||
return video_file;
|
||||
}
|
||||
char* getEventFile(void) {
|
||||
return video_file;
|
||||
}
|
||||
|
||||
public:
|
||||
static int PreAlarmCount()
|
||||
{
|
||||
return( pre_alarm_count );
|
||||
}
|
||||
static void EmptyPreAlarmFrames()
|
||||
{
|
||||
if ( pre_alarm_count > 0 )
|
||||
{
|
||||
for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ )
|
||||
{
|
||||
delete pre_alarm_data[i].image;
|
||||
delete pre_alarm_data[i].alarm_frame;
|
||||
static int PreAlarmCount() {
|
||||
return( pre_alarm_count );
|
||||
}
|
||||
static void EmptyPreAlarmFrames() {
|
||||
if ( pre_alarm_count > 0 ) {
|
||||
for ( int i = 0; i < MAX_PRE_ALARM_FRAMES; i++ ) {
|
||||
delete pre_alarm_data[i].image;
|
||||
delete pre_alarm_data[i].alarm_frame;
|
||||
}
|
||||
memset( pre_alarm_data, 0, sizeof(pre_alarm_data) );
|
||||
}
|
||||
memset( pre_alarm_data, 0, sizeof(pre_alarm_data) );
|
||||
pre_alarm_count = 0;
|
||||
}
|
||||
pre_alarm_count = 0;
|
||||
}
|
||||
static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL )
|
||||
{
|
||||
pre_alarm_data[pre_alarm_count].image = new Image( *image );
|
||||
pre_alarm_data[pre_alarm_count].timestamp = timestamp;
|
||||
pre_alarm_data[pre_alarm_count].score = score;
|
||||
if ( alarm_frame )
|
||||
{
|
||||
pre_alarm_data[pre_alarm_count].alarm_frame = new Image( *alarm_frame );
|
||||
static void AddPreAlarmFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ) {
|
||||
pre_alarm_data[pre_alarm_count].image = new Image( *image );
|
||||
pre_alarm_data[pre_alarm_count].timestamp = timestamp;
|
||||
pre_alarm_data[pre_alarm_count].score = score;
|
||||
if ( alarm_frame ) {
|
||||
pre_alarm_data[pre_alarm_count].alarm_frame = new Image( *alarm_frame );
|
||||
}
|
||||
pre_alarm_count++;
|
||||
}
|
||||
pre_alarm_count++;
|
||||
}
|
||||
void SavePreAlarmFrames()
|
||||
{
|
||||
for ( int i = 0; i < pre_alarm_count; i++ )
|
||||
{
|
||||
AddFrame( pre_alarm_data[i].image, pre_alarm_data[i].timestamp, pre_alarm_data[i].score, pre_alarm_data[i].alarm_frame );
|
||||
void SavePreAlarmFrames() {
|
||||
for ( int i = 0; i < pre_alarm_count; i++ ) {
|
||||
AddFrame( pre_alarm_data[i].image, pre_alarm_data[i].timestamp, pre_alarm_data[i].score, pre_alarm_data[i].alarm_frame );
|
||||
}
|
||||
EmptyPreAlarmFrames();
|
||||
}
|
||||
EmptyPreAlarmFrames();
|
||||
}
|
||||
};
|
||||
|
||||
class EventStream : public StreamBase
|
||||
{
|
||||
class EventStream : public StreamBase {
|
||||
public:
|
||||
typedef enum { MODE_SINGLE, MODE_ALL, MODE_ALL_GAPLESS } StreamMode;
|
||||
|
||||
@@ -216,8 +202,7 @@ class EventStream : public StreamBase
|
||||
bool in_db;
|
||||
};
|
||||
|
||||
struct EventData
|
||||
{
|
||||
struct EventData {
|
||||
unsigned long event_id;
|
||||
unsigned long monitor_id;
|
||||
unsigned long storage_id;
|
||||
@@ -255,8 +240,7 @@ class EventStream : public StreamBase
|
||||
bool sendFrame( int delta_us );
|
||||
|
||||
public:
|
||||
EventStream()
|
||||
{
|
||||
EventStream() {
|
||||
mode = DEFAULT_MODE;
|
||||
|
||||
forceEventChange = false;
|
||||
@@ -266,18 +250,15 @@ class EventStream : public StreamBase
|
||||
|
||||
event_data = 0;
|
||||
}
|
||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 )
|
||||
{
|
||||
void setStreamStart( int init_event_id, unsigned int init_frame_id=0 ) {
|
||||
loadInitialEventData( init_event_id, init_frame_id );
|
||||
loadMonitor( event_data->monitor_id );
|
||||
}
|
||||
void setStreamStart( int monitor_id, time_t event_time )
|
||||
{
|
||||
void setStreamStart( int monitor_id, time_t event_time ) {
|
||||
loadInitialEventData( monitor_id, event_time );
|
||||
loadMonitor( monitor_id );
|
||||
}
|
||||
void setStreamMode( StreamMode p_mode )
|
||||
{
|
||||
void setStreamMode( StreamMode p_mode ) {
|
||||
mode = p_mode;
|
||||
}
|
||||
void runStream();
|
||||
|
||||
+208
-192
@@ -200,230 +200,246 @@ int SWScale::Convert(const uint8_t* in_buffer, const size_t in_buffer_size, uint
|
||||
(uint8_t*)in_buffer, in_pf, width, height, 1) <= 0)
|
||||
{
|
||||
#else
|
||||
if(avpicture_fill( (AVPicture*)input_avframe, (uint8_t*)in_buffer,
|
||||
in_pf, width, height ) <= 0)
|
||||
{
|
||||
if(avpicture_fill( (AVPicture*)input_avframe, (uint8_t*)in_buffer,
|
||||
in_pf, width, height ) <= 0)
|
||||
{
|
||||
#endif
|
||||
Error("Failed filling input frame with input buffer");
|
||||
return -7;
|
||||
}
|
||||
|
||||
if(!avpicture_fill( (AVPicture*)output_avframe, out_buffer, out_pf, width, height ) ) {
|
||||
Error("Failed filling output frame with output buffer");
|
||||
return -8;
|
||||
}
|
||||
|
||||
/* Do the conversion */
|
||||
if(!sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, 0, height, output_avframe->data, output_avframe->linesize ) ) {
|
||||
Error("swscale conversion failed");
|
||||
return -10;
|
||||
}
|
||||
|
||||
return 0;
|
||||
Error("Failed filling input frame with input buffer");
|
||||
return -7;
|
||||
}
|
||||
|
||||
int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
if(img->Width() != width) {
|
||||
Error("Source image width differs. Source: %d Output: %d",img->Width(), width);
|
||||
return -12;
|
||||
}
|
||||
|
||||
if(img->Height() != height) {
|
||||
Error("Source image height differs. Source: %d Output: %d",img->Height(), height);
|
||||
return -13;
|
||||
}
|
||||
|
||||
return Convert(img->Buffer(),img->Size(),out_buffer,out_buffer_size,in_pf,out_pf,width,height);
|
||||
if(!avpicture_fill( (AVPicture*)output_avframe, out_buffer, out_pf, width, height ) ) {
|
||||
Error("Failed filling output frame with output buffer");
|
||||
return -8;
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(img,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
/* Do the conversion */
|
||||
if(!sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, 0, height, output_avframe->data, output_avframe->linesize ) ) {
|
||||
Error("swscale conversion failed");
|
||||
return -10;
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(in_buffer,in_buffer_size,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
int SWScale::Convert(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size, enum _AVPIXELFORMAT in_pf, enum _AVPIXELFORMAT out_pf, unsigned int width, unsigned int height) {
|
||||
if(img->Width() != width) {
|
||||
Error("Source image width differs. Source: %d Output: %d",img->Width(), width);
|
||||
return -12;
|
||||
}
|
||||
|
||||
if(img->Height() != height) {
|
||||
Error("Source image height differs. Source: %d Output: %d",img->Height(), height);
|
||||
return -13;
|
||||
}
|
||||
|
||||
return Convert(img->Buffer(),img->Size(),out_buffer,out_buffer_size,in_pf,out_pf,width,height);
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const Image* img, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(img,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
}
|
||||
|
||||
int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_size, uint8_t* out_buffer, const size_t out_buffer_size) {
|
||||
|
||||
if(!gotdefaults) {
|
||||
Error("Defaults are not set");
|
||||
return -24;
|
||||
}
|
||||
|
||||
return Convert(in_buffer,in_buffer_size,out_buffer,out_buffer_size,default_input_pf,default_output_pf,default_width,default_height);
|
||||
}
|
||||
#endif // HAVE_LIBSWSCALE && HAVE_LIBAVUTIL
|
||||
|
||||
#endif // HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE
|
||||
|
||||
#if HAVE_LIBAVUTIL
|
||||
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
|
||||
int64_t a, b, this_thing;
|
||||
int64_t av_rescale_delta(AVRational in_tb, int64_t in_ts, AVRational fs_tb, int duration, int64_t *last, AVRational out_tb){
|
||||
int64_t a, b, this_thing;
|
||||
|
||||
av_assert0(in_ts != AV_NOPTS_VALUE);
|
||||
av_assert0(duration >= 0);
|
||||
av_assert0(in_ts != AV_NOPTS_VALUE);
|
||||
av_assert0(duration >= 0);
|
||||
|
||||
if (*last == AV_NOPTS_VALUE || !duration || in_tb.num*(int64_t)out_tb.den <= out_tb.num*(int64_t)in_tb.den) {
|
||||
if (*last == AV_NOPTS_VALUE || !duration || in_tb.num*(int64_t)out_tb.den <= out_tb.num*(int64_t)in_tb.den) {
|
||||
simple_round:
|
||||
*last = av_rescale_q(in_ts, in_tb, fs_tb) + duration;
|
||||
return av_rescale_q(in_ts, in_tb, out_tb);
|
||||
}
|
||||
|
||||
a = av_rescale_q_rnd(2*in_ts-1, in_tb, fs_tb, AV_ROUND_DOWN) >>1;
|
||||
b = (av_rescale_q_rnd(2*in_ts+1, in_tb, fs_tb, AV_ROUND_UP )+1)>>1;
|
||||
if (*last < 2*a - b || *last > 2*b - a)
|
||||
goto simple_round;
|
||||
|
||||
this_thing = av_clip64(*last, a, b);
|
||||
*last = this_thing + duration;
|
||||
|
||||
return av_rescale_q(this_thing, fs_tb, out_tb);
|
||||
*last = av_rescale_q(in_ts, in_tb, fs_tb) + duration;
|
||||
return av_rescale_q(in_ts, in_tb, out_tb);
|
||||
}
|
||||
|
||||
a = av_rescale_q_rnd(2*in_ts-1, in_tb, fs_tb, AV_ROUND_DOWN) >>1;
|
||||
b = (av_rescale_q_rnd(2*in_ts+1, in_tb, fs_tb, AV_ROUND_UP )+1)>>1;
|
||||
if (*last < 2*a - b || *last > 2*b - a)
|
||||
goto simple_round;
|
||||
|
||||
this_thing = av_clip64(*last, a, b);
|
||||
*last = this_thing + duration;
|
||||
|
||||
return av_rescale_q(this_thing, fs_tb, out_tb);
|
||||
}
|
||||
#endif
|
||||
|
||||
int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) {
|
||||
AVFormatContext *s = avformat_alloc_context();
|
||||
int ret = 0;
|
||||
int hacked_up_context2_for_older_ffmpeg(AVFormatContext **avctx, AVOutputFormat *oformat, const char *format, const char *filename) {
|
||||
AVFormatContext *s = avformat_alloc_context();
|
||||
int ret = 0;
|
||||
|
||||
*avctx = NULL;
|
||||
if (!s) {
|
||||
av_log(s, AV_LOG_ERROR, "Out of memory\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
return ret;
|
||||
*avctx = NULL;
|
||||
if (!s) {
|
||||
av_log(s, AV_LOG_ERROR, "Out of memory\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!oformat) {
|
||||
if (format) {
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
if (!oformat) {
|
||||
av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
|
||||
ret = AVERROR(EINVAL);
|
||||
}
|
||||
} else {
|
||||
oformat = av_guess_format(NULL, filename, NULL);
|
||||
if (!oformat) {
|
||||
ret = AVERROR(EINVAL);
|
||||
av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!oformat) {
|
||||
if (format) {
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
if (!oformat) {
|
||||
av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
|
||||
ret = AVERROR(EINVAL);
|
||||
if (!oformat) {
|
||||
if (format) {
|
||||
oformat = av_guess_format(format, NULL, NULL);
|
||||
if (!oformat) {
|
||||
av_log(s, AV_LOG_ERROR, "Requested output format '%s' is not a suitable output format\n", format);
|
||||
ret = AVERROR(EINVAL);
|
||||
}
|
||||
} else {
|
||||
oformat = av_guess_format(NULL, filename, NULL);
|
||||
if (!oformat) {
|
||||
ret = AVERROR(EINVAL);
|
||||
av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
avformat_free_context(s);
|
||||
return ret;
|
||||
} else {
|
||||
s->oformat = oformat;
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if (s->priv_data) {
|
||||
if (s->oformat->priv_class) {
|
||||
*(const AVClass**)s->priv_data= s->oformat->priv_class;
|
||||
av_opt_set_defaults(s->priv_data);
|
||||
}
|
||||
} else {
|
||||
oformat = av_guess_format(NULL, filename, NULL);
|
||||
if (!oformat) {
|
||||
ret = AVERROR(EINVAL);
|
||||
av_log(s, AV_LOG_ERROR, "Unable to find a suitable output format for '%s'\n", filename);
|
||||
}
|
||||
av_log(s, AV_LOG_ERROR, "Out of memory\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
return ret;
|
||||
}
|
||||
s->priv_data = NULL;
|
||||
}
|
||||
|
||||
if (ret) {
|
||||
avformat_free_context(s);
|
||||
return ret;
|
||||
} else {
|
||||
s->oformat = oformat;
|
||||
if (s->oformat->priv_data_size > 0) {
|
||||
s->priv_data = av_mallocz(s->oformat->priv_data_size);
|
||||
if (s->priv_data) {
|
||||
if (s->oformat->priv_class) {
|
||||
*(const AVClass**)s->priv_data= s->oformat->priv_class;
|
||||
av_opt_set_defaults(s->priv_data);
|
||||
}
|
||||
} else {
|
||||
av_log(s, AV_LOG_ERROR, "Out of memory\n");
|
||||
ret = AVERROR(ENOMEM);
|
||||
return ret;
|
||||
}
|
||||
s->priv_data = NULL;
|
||||
}
|
||||
if (filename) strncpy(s->filename, filename, sizeof(s->filename));
|
||||
*avctx = s;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (filename) strncpy(s->filename, filename, sizeof(s->filename));
|
||||
*avctx = s;
|
||||
return 0;
|
||||
}
|
||||
static void zm_log_fps(double d, const char *postfix)
|
||||
{
|
||||
uint64_t v = lrintf(d * 100);
|
||||
if (!v) {
|
||||
Debug(3, "%1.4f %s", d, postfix);
|
||||
} else if (v % 100) {
|
||||
Debug(3, "%3.2f %s", d, postfix);
|
||||
} else if (v % (100 * 1000)) {
|
||||
Debug(3, "%1.0f %s", d, postfix);
|
||||
} else
|
||||
Debug(3, "%1.0fk %s", d / 1000, postfix);
|
||||
}
|
||||
|
||||
/* "user interface" functions */
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
|
||||
char buf[256];
|
||||
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
||||
AVStream *st = ic->streams[i];
|
||||
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
||||
|
||||
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
||||
Debug(3, " Stream #%d:%d", index, i);
|
||||
|
||||
/* the pid is an important information, so we display it */
|
||||
/* XXX: add a generic system */
|
||||
if (flags & AVFMT_SHOW_IDS)
|
||||
Debug(3, "[0x%x]", st->id);
|
||||
if (lang)
|
||||
Debug(3, "(%s)", lang->value);
|
||||
av_log(NULL, AV_LOG_DEBUG, ", %d, %d/%d", st->codec_info_nb_frames,
|
||||
st->time_base.num, st->time_base.den);
|
||||
Debug(3, ": %s", buf);
|
||||
|
||||
if (st->sample_aspect_ratio.num && // default
|
||||
av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) {
|
||||
AVRational display_aspect_ratio;
|
||||
av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
|
||||
st->codec->width * (int64_t)st->sample_aspect_ratio.num,
|
||||
st->codec->height * (int64_t)st->sample_aspect_ratio.den,
|
||||
1024 * 1024);
|
||||
Debug(3, ", SAR %d:%d DAR %d:%d",
|
||||
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
|
||||
display_aspect_ratio.num, display_aspect_ratio.den);
|
||||
}
|
||||
|
||||
static void zm_log_fps(double d, const char *postfix)
|
||||
{
|
||||
uint64_t v = lrintf(d * 100);
|
||||
if (!v) {
|
||||
Debug(3, "%1.4f %s", d, postfix);
|
||||
} else if (v % 100) {
|
||||
Debug(3, "%3.2f %s", d, postfix);
|
||||
} else if (v % (100 * 1000)) {
|
||||
Debug(3, "%1.0f %s", d, postfix);
|
||||
} else
|
||||
Debug(3, "%1.0fk %s", d / 1000, postfix);
|
||||
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
int fps = st->avg_frame_rate.den && st->avg_frame_rate.num;
|
||||
int tbr = st->r_frame_rate.den && st->r_frame_rate.num;
|
||||
int tbn = st->time_base.den && st->time_base.num;
|
||||
int tbc = st->codec->time_base.den && st->codec->time_base.num;
|
||||
|
||||
if (fps || tbr || tbn || tbc)
|
||||
Debug(3, "\n" );
|
||||
|
||||
if (fps)
|
||||
zm_log_fps(av_q2d(st->avg_frame_rate), tbr || tbn || tbc ? "fps, " : "fps");
|
||||
if (tbr)
|
||||
zm_log_fps(av_q2d(st->r_frame_rate), tbn || tbc ? "tbr, " : "tbr");
|
||||
if (tbn)
|
||||
zm_log_fps(1 / av_q2d(st->time_base), tbc ? "tbn, " : "tbn");
|
||||
if (tbc)
|
||||
zm_log_fps(1 / av_q2d(st->codec->time_base), "tbc");
|
||||
}
|
||||
|
||||
/* "user interface" functions */
|
||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
|
||||
char buf[256];
|
||||
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
||||
AVStream *st = ic->streams[i];
|
||||
AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL, 0);
|
||||
if (st->disposition & AV_DISPOSITION_DEFAULT)
|
||||
Debug(3, " (default)");
|
||||
if (st->disposition & AV_DISPOSITION_DUB)
|
||||
Debug(3, " (dub)");
|
||||
if (st->disposition & AV_DISPOSITION_ORIGINAL)
|
||||
Debug(3, " (original)");
|
||||
if (st->disposition & AV_DISPOSITION_COMMENT)
|
||||
Debug(3, " (comment)");
|
||||
if (st->disposition & AV_DISPOSITION_LYRICS)
|
||||
Debug(3, " (lyrics)");
|
||||
if (st->disposition & AV_DISPOSITION_KARAOKE)
|
||||
Debug(3, " (karaoke)");
|
||||
if (st->disposition & AV_DISPOSITION_FORCED)
|
||||
Debug(3, " (forced)");
|
||||
if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
|
||||
Debug(3, " (hearing impaired)");
|
||||
if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
|
||||
Debug(3, " (visual impaired)");
|
||||
if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS)
|
||||
Debug(3, " (clean effects)");
|
||||
Debug(3, "\n");
|
||||
|
||||
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
||||
Debug(3, " Stream #%d:%d", index, i);
|
||||
//dump_metadata(NULL, st->metadata, " ");
|
||||
|
||||
/* the pid is an important information, so we display it */
|
||||
/* XXX: add a generic system */
|
||||
if (flags & AVFMT_SHOW_IDS)
|
||||
Debug(3, "[0x%x]", st->id);
|
||||
if (lang)
|
||||
Debug(3, "(%s)", lang->value);
|
||||
av_log(NULL, AV_LOG_DEBUG, ", %d, %d/%d", st->codec_info_nb_frames,
|
||||
st->time_base.num, st->time_base.den);
|
||||
Debug(3, ": %s", buf);
|
||||
|
||||
if (st->sample_aspect_ratio.num && // default
|
||||
av_cmp_q(st->sample_aspect_ratio, st->codec->sample_aspect_ratio)) {
|
||||
AVRational display_aspect_ratio;
|
||||
av_reduce(&display_aspect_ratio.num, &display_aspect_ratio.den,
|
||||
st->codec->width * (int64_t)st->sample_aspect_ratio.num,
|
||||
st->codec->height * (int64_t)st->sample_aspect_ratio.den,
|
||||
1024 * 1024);
|
||||
Debug(3, ", SAR %d:%d DAR %d:%d",
|
||||
st->sample_aspect_ratio.num, st->sample_aspect_ratio.den,
|
||||
display_aspect_ratio.num, display_aspect_ratio.den);
|
||||
}
|
||||
|
||||
if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
|
||||
int fps = st->avg_frame_rate.den && st->avg_frame_rate.num;
|
||||
int tbr = st->r_frame_rate.den && st->r_frame_rate.num;
|
||||
int tbn = st->time_base.den && st->time_base.num;
|
||||
int tbc = st->codec->time_base.den && st->codec->time_base.num;
|
||||
|
||||
if (fps || tbr || tbn || tbc)
|
||||
Debug(3, "\n" );
|
||||
|
||||
if (fps)
|
||||
zm_log_fps(av_q2d(st->avg_frame_rate), tbr || tbn || tbc ? "fps, " : "fps");
|
||||
if (tbr)
|
||||
zm_log_fps(av_q2d(st->r_frame_rate), tbn || tbc ? "tbr, " : "tbr");
|
||||
if (tbn)
|
||||
zm_log_fps(1 / av_q2d(st->time_base), tbc ? "tbn, " : "tbn");
|
||||
if (tbc)
|
||||
zm_log_fps(1 / av_q2d(st->codec->time_base), "tbc");
|
||||
}
|
||||
|
||||
if (st->disposition & AV_DISPOSITION_DEFAULT)
|
||||
Debug(3, " (default)");
|
||||
if (st->disposition & AV_DISPOSITION_DUB)
|
||||
Debug(3, " (dub)");
|
||||
if (st->disposition & AV_DISPOSITION_ORIGINAL)
|
||||
Debug(3, " (original)");
|
||||
if (st->disposition & AV_DISPOSITION_COMMENT)
|
||||
Debug(3, " (comment)");
|
||||
if (st->disposition & AV_DISPOSITION_LYRICS)
|
||||
Debug(3, " (lyrics)");
|
||||
if (st->disposition & AV_DISPOSITION_KARAOKE)
|
||||
Debug(3, " (karaoke)");
|
||||
if (st->disposition & AV_DISPOSITION_FORCED)
|
||||
Debug(3, " (forced)");
|
||||
if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
|
||||
Debug(3, " (hearing impaired)");
|
||||
if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
|
||||
Debug(3, " (visual impaired)");
|
||||
if (st->disposition & AV_DISPOSITION_CLEAN_EFFECTS)
|
||||
Debug(3, " (clean effects)");
|
||||
Debug(3, "\n");
|
||||
|
||||
//dump_metadata(NULL, st->metadata, " ");
|
||||
|
||||
//dump_sidedata(NULL, st, " ");
|
||||
}
|
||||
//dump_sidedata(NULL, st, " ");
|
||||
}
|
||||
+10
-13
@@ -63,7 +63,7 @@ FfmpegCamera::FfmpegCamera( int p_id, const std::string &p_path, const std::stri
|
||||
wasRecording = false;
|
||||
videoStore = NULL;
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
#if HAVE_LIBSWSCALE
|
||||
mConvertContext = NULL;
|
||||
#endif
|
||||
/* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */
|
||||
@@ -274,9 +274,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
Warning( "Error trying to set option %d '%s' to '%s'", i, parts[0].c_str(), parts[1].c_str() );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
Warning( "Unable to parse ffmpeg option %d '%s', expecting key=value", i, opVect[i].c_str() );
|
||||
}
|
||||
}
|
||||
@@ -356,7 +354,7 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||
if ( mVideoStreamId == -1 )
|
||||
Fatal( "Unable to locate video stream in %s", mPath.c_str() );
|
||||
if ( mAudioStreamId == -1 )
|
||||
Debug( 2, "Unable to locate audio stream in %s", mPath.c_str() );
|
||||
Debug( 3, "Unable to locate audio stream in %s", mPath.c_str() );
|
||||
|
||||
Debug ( 3, "Found video stream at index %d", mVideoStreamId );
|
||||
Debug ( 3, "Found audio stream at index %d", mAudioStreamId );
|
||||
@@ -523,12 +521,11 @@ void *FfmpegCamera::ReopenFfmpegThreadCallback(void *ctx){
|
||||
}
|
||||
|
||||
//Function to handle capture and store
|
||||
int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_file )
|
||||
{
|
||||
int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_file ) {
|
||||
if (!mCanCapture){
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// If the reopen thread has a value, but mCanCapture != 0, then we have just reopened the connection to the ffmpeg device, and we can clean up the thread.
|
||||
if (mReopenThread != 0) {
|
||||
void *retval = 0;
|
||||
@@ -568,9 +565,9 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
||||
(avResult == AVERROR_EOF || (mFormatContext->pb && mFormatContext->pb->eof_reached)) ||
|
||||
// Check for Connection failure.
|
||||
(avResult == -110)
|
||||
) {
|
||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf);
|
||||
ReopenFfmpeg();
|
||||
) {
|
||||
Info( "av_read_frame returned \"%s\". Reopening stream.", errbuf);
|
||||
ReopenFfmpeg();
|
||||
}
|
||||
|
||||
Error( "Unable to read packet from stream %d: error %d \"%s\".", packet.stream_index, avResult, errbuf );
|
||||
@@ -581,9 +578,9 @@ int FfmpegCamera::CaptureAndRecord( Image &image, bool recording, char* event_fi
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
if ( avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet ) < 0 )
|
||||
#else
|
||||
if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 )
|
||||
if ( avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size ) < 0 )
|
||||
#endif
|
||||
Fatal( "Unable to decode frame at frame %d", frameCount );
|
||||
Fatal( "Unable to decode frame at frame %d", frameCount );
|
||||
|
||||
Debug( 4, "Decoded video packet at frame %d", frameCount );
|
||||
|
||||
|
||||
@@ -41,6 +41,7 @@ class FfmpegCamera : public Camera
|
||||
int frameCount;
|
||||
|
||||
#if HAVE_LIBAVFORMAT
|
||||
<<<<<<< HEAD
|
||||
AVFormatContext *mFormatContext;
|
||||
int mVideoStreamId;
|
||||
int mAudioStreamId;
|
||||
|
||||
+19
-19
@@ -287,25 +287,25 @@ AVFrame **LocalCamera::capturePictures = 0;
|
||||
LocalCamera *LocalCamera::last_camera = NULL;
|
||||
|
||||
LocalCamera::LocalCamera(
|
||||
int p_id,
|
||||
const std::string &p_device,
|
||||
int p_channel,
|
||||
int p_standard,
|
||||
bool p_v4l_multi_buffer,
|
||||
unsigned int p_v4l_captures_per_frame,
|
||||
const std::string &p_method,
|
||||
int p_width,
|
||||
int p_height,
|
||||
int p_colours,
|
||||
int p_palette,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio,
|
||||
unsigned int p_extras) :
|
||||
Camera( p_id, LOCAL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
|
||||
int p_id,
|
||||
const std::string &p_device,
|
||||
int p_channel,
|
||||
int p_standard,
|
||||
bool p_v4l_multi_buffer,
|
||||
unsigned int p_v4l_captures_per_frame,
|
||||
const std::string &p_method,
|
||||
int p_width,
|
||||
int p_height,
|
||||
int p_colours,
|
||||
int p_palette,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio,
|
||||
unsigned int p_extras) :
|
||||
Camera( p_id, LOCAL_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
|
||||
device( p_device ),
|
||||
channel( p_channel ),
|
||||
standard( p_standard ),
|
||||
|
||||
@@ -36,6 +36,11 @@
|
||||
#include <linux/videodev2.h>
|
||||
#endif // HAVE_LINUX_VIDEODEV2_H
|
||||
|
||||
// Required on systems with v4l1 but without v4l2 headers
|
||||
#ifndef VIDEO_MAX_FRAME
|
||||
#define VIDEO_MAX_FRAME 32
|
||||
#endif
|
||||
|
||||
#include "zm_ffmpeg.h"
|
||||
|
||||
//
|
||||
|
||||
+28
-17
@@ -75,7 +75,12 @@ std::vector<std::string> split(const std::string &s, char delim) {
|
||||
|
||||
|
||||
|
||||
<<<<<<< HEAD
|
||||
Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id ) {
|
||||
=======
|
||||
Monitor::MonitorLink::MonitorLink( int p_id, const char *p_name ) : id( p_id )
|
||||
{
|
||||
>>>>>>> feature-h264-videostorage
|
||||
strncpy( name, p_name, sizeof(name) );
|
||||
|
||||
#if ZM_MEM_MAPPED
|
||||
@@ -232,7 +237,12 @@ bool Monitor::MonitorLink::inAlarm() {
|
||||
|
||||
bool Monitor::MonitorLink::hasAlarmed()
|
||||
{
|
||||
<<<<<<< HEAD
|
||||
if ( shared_data->state == ALARM ) {
|
||||
=======
|
||||
if ( shared_data->state == ALARM )
|
||||
{
|
||||
>>>>>>> feature-h264-videostorage
|
||||
return( true );
|
||||
} else if ( shared_data->last_event != (unsigned int)last_event ) {
|
||||
last_event = shared_data->last_event;
|
||||
@@ -1303,10 +1313,10 @@ bool Monitor::Analyse()
|
||||
if ( read_margin < 0 ) read_margin += image_buffer_count;
|
||||
|
||||
int step = 1;
|
||||
// Isn't read_margin always > 0 here?
|
||||
// Isn't read_margin always > 0 here?
|
||||
if ( read_margin > 0 )
|
||||
{
|
||||
// TODO explain this so... 90% of image buffer / 50% of read margin?
|
||||
// TODO explain this so... 90% of image buffer / 50% of read margin?
|
||||
step = (9*image_buffer_count)/(5*read_margin);
|
||||
}
|
||||
|
||||
@@ -1401,10 +1411,11 @@ bool Monitor::Analyse()
|
||||
{
|
||||
bool signal = shared_data->signal;
|
||||
bool signal_change = (signal != last_signal);
|
||||
Debug(3, "Motion detection is enabled signal(%d) signal_change(%d)", signal, signal_change);
|
||||
|
||||
Debug(3, "Motion detection is enabled signal(%d) signal_change(%d)", signal, signal_change);
|
||||
|
||||
//Set video recording flag for event start constructor and easy reference in code
|
||||
// TODO: Use enum instead of the # 2. Makes for easier reading
|
||||
// TODO: Use enum instead of the # 2. Makes for easier reading
|
||||
bool videoRecording = ((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo());
|
||||
|
||||
if ( trigger_data->trigger_state != TRIGGER_OFF )
|
||||
@@ -1561,7 +1572,7 @@ bool Monitor::Analyse()
|
||||
//set up video store data
|
||||
snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile());
|
||||
video_store_data->recording = true;
|
||||
|
||||
|
||||
Info( "%s: %03d - Opening new event %d, section start", name, image_count, event->Id() );
|
||||
|
||||
/* To prevent cancelling out an existing alert\prealarm\alarm state */
|
||||
@@ -2326,7 +2337,7 @@ int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const c
|
||||
int videowriter = atoi(dbrow[col]); col++;
|
||||
std::string encoderparams = dbrow[col]; col++;
|
||||
bool record_audio = (*dbrow[col] != '0'); col++;
|
||||
|
||||
|
||||
int brightness = atoi(dbrow[col]); col++;
|
||||
int contrast = atoi(dbrow[col]); col++;
|
||||
int hue = atoi(dbrow[col]); col++;
|
||||
@@ -4412,14 +4423,14 @@ void Monitor::SingleImageZip( int scale)
|
||||
fwrite( img_buffer, img_buffer_size, 1, stdout );
|
||||
}
|
||||
unsigned int Monitor::Colours() const { return( camera->Colours() ); }
|
||||
unsigned int Monitor::SubpixelOrder() const { return( camera->SubpixelOrder() ); }
|
||||
int Monitor::PrimeCapture() {
|
||||
return( camera->PrimeCapture() );
|
||||
}
|
||||
int Monitor::PreCapture() {
|
||||
return( camera->PreCapture() );
|
||||
}
|
||||
int Monitor::PostCapture() {
|
||||
return( camera->PostCapture() );
|
||||
}
|
||||
Monitor::Orientation Monitor::getOrientation()const { return orientation; }
|
||||
unsigned int Monitor::SubpixelOrder() const { return( camera->SubpixelOrder() ); }
|
||||
int Monitor::PrimeCapture() {
|
||||
return( camera->PrimeCapture() );
|
||||
}
|
||||
int Monitor::PreCapture() {
|
||||
return( camera->PreCapture() );
|
||||
}
|
||||
int Monitor::PostCapture() {
|
||||
return( camera->PostCapture() );
|
||||
}
|
||||
Monitor::Orientation Monitor::getOrientation()const { return orientation; }
|
||||
+2
-2
@@ -505,9 +505,9 @@ public:
|
||||
class MonitorStream : public StreamBase {
|
||||
protected:
|
||||
typedef struct SwapImage {
|
||||
bool valid;
|
||||
bool valid;
|
||||
struct timeval timestamp;
|
||||
char file_name[PATH_MAX];
|
||||
char file_name[PATH_MAX];
|
||||
} SwapImage;
|
||||
|
||||
private:
|
||||
|
||||
+14
-14
@@ -22,20 +22,20 @@
|
||||
#include "zm_utils.h"
|
||||
|
||||
RemoteCamera::RemoteCamera(
|
||||
int p_id,
|
||||
const std::string &p_protocol,
|
||||
const std::string &p_host,
|
||||
const std::string &p_port,
|
||||
const std::string &p_path,
|
||||
int p_width,
|
||||
int p_height,
|
||||
int p_colours,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio
|
||||
int p_id,
|
||||
const std::string &p_protocol,
|
||||
const std::string &p_host,
|
||||
const std::string &p_port,
|
||||
const std::string &p_path,
|
||||
int p_width,
|
||||
int p_height,
|
||||
int p_colours,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio
|
||||
) :
|
||||
Camera( p_id, REMOTE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ),
|
||||
protocol( p_protocol ),
|
||||
|
||||
@@ -31,8 +31,35 @@
|
||||
#include <sys/filio.h> // FIONREAD and friends
|
||||
#endif
|
||||
|
||||
RemoteCameraHttp::RemoteCameraHttp( int p_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) :
|
||||
RemoteCamera( p_id, "http", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio )
|
||||
RemoteCameraHttp::RemoteCameraHttp(
|
||||
int p_id,
|
||||
const std::string &p_method,
|
||||
const std::string &p_host,
|
||||
const std::string &p_port,
|
||||
const std::string &p_path,
|
||||
int p_width, int p_height,
|
||||
int p_colours,
|
||||
int p_brightness,
|
||||
int p_contrast,
|
||||
int p_hue,
|
||||
int p_colour,
|
||||
bool p_capture,
|
||||
bool p_record_audio ) :
|
||||
RemoteCamera(
|
||||
p_id,
|
||||
"http",
|
||||
p_host,
|
||||
p_port,
|
||||
p_path,
|
||||
p_width,
|
||||
p_height,
|
||||
p_colours,
|
||||
p_brightness,
|
||||
p_contrast,
|
||||
p_hue,
|
||||
p_colour,
|
||||
p_capture,
|
||||
p_record_audio )
|
||||
{
|
||||
sd = -1;
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ void RemoteCameraRtsp::Initialise()
|
||||
int max_size = width*height*colours;
|
||||
|
||||
// This allocates a buffer able to hold a raw fframe, which is a little artbitrary. Might be nice to get some
|
||||
// decent data on how large a buffer is really needed. I think in ffmpeg there are now some functions to do that.
|
||||
// decent data on how large a buffer is really needed. I think in ffmpeg there are now some functions to do that.
|
||||
buffer.size( max_size );
|
||||
|
||||
if ( logDebugging() )
|
||||
@@ -172,41 +172,41 @@ int RemoteCameraRtsp::PrimeCapture()
|
||||
|
||||
// Find first video stream present
|
||||
mVideoStreamId = -1;
|
||||
mAudioStreamId = -1;
|
||||
mAudioStreamId = -1;
|
||||
|
||||
// Find the first video stream.
|
||||
for ( unsigned int i = 0; i < mFormatContext->nb_streams; i++ ) {
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO )
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_VIDEO )
|
||||
#endif
|
||||
{
|
||||
if ( mVideoStreamId == -1 ) {
|
||||
mVideoStreamId = i;
|
||||
continue;
|
||||
} else {
|
||||
Debug(2, "Have another video stream." );
|
||||
}
|
||||
if ( mVideoStreamId == -1 ) {
|
||||
mVideoStreamId = i;
|
||||
continue;
|
||||
} else {
|
||||
Debug(2, "Have another video stream." );
|
||||
}
|
||||
}
|
||||
#if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0))
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO )
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO )
|
||||
#else
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO )
|
||||
if ( mFormatContext->streams[i]->codec->codec_type == CODEC_TYPE_AUDIO )
|
||||
#endif
|
||||
{
|
||||
if ( mAudioStreamId == -1 ) {
|
||||
mAudioStreamId = i;
|
||||
} else {
|
||||
Debug(2, "Have another audio stream." );
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
if ( mAudioStreamId == -1 ) {
|
||||
mAudioStreamId = i;
|
||||
} else {
|
||||
Debug(2, "Have another audio stream." );
|
||||
}
|
||||
}
|
||||
} // end foreach stream
|
||||
|
||||
if ( mVideoStreamId == -1 )
|
||||
Fatal( "Unable to locate video stream" );
|
||||
if ( mAudioStreamId == -1 )
|
||||
Debug( 3, "Unable to locate audio stream" );
|
||||
if ( mAudioStreamId == -1 )
|
||||
Debug( 3, "Unable to locate audio stream" );
|
||||
|
||||
// Get a pointer to the codec context for the video stream
|
||||
mCodecContext = mFormatContext->streams[mVideoStreamId]->codec;
|
||||
@@ -331,17 +331,17 @@ int RemoteCameraRtsp::Capture( Image &image ) {
|
||||
}
|
||||
|
||||
av_init_packet( &packet );
|
||||
|
||||
|
||||
while ( !frameComplete && buffer.size() > 0 ) {
|
||||
packet.data = buffer.head();
|
||||
packet.size = buffer.size();
|
||||
|
||||
// So I think this is the magic decode step. Result is a raw image?
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||
int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet );
|
||||
#else
|
||||
#else
|
||||
int len = avcodec_decode_video( mCodecContext, mRawFrame, &frameComplete, packet.data, packet.size );
|
||||
#endif
|
||||
#endif
|
||||
if ( len < 0 ) {
|
||||
Error( "Error while decoding frame %d", frameCount );
|
||||
Hexdump( Logger::ERROR, buffer.head(), buffer.size()>256?256:buffer.size() );
|
||||
@@ -350,8 +350,8 @@ int RemoteCameraRtsp::Capture( Image &image ) {
|
||||
}
|
||||
Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() );
|
||||
//if ( buffer.size() < 400 )
|
||||
//Hexdump( 0, buffer.head(), buffer.size() );
|
||||
|
||||
//Hexdump( 0, buffer.head(), buffer.size() );
|
||||
|
||||
buffer -= len;
|
||||
}
|
||||
// At this point, we either have a frame or ran out of buffer. What happens if we run out of buffer?
|
||||
@@ -395,17 +395,6 @@ int RemoteCameraRtsp::Capture( Image &image ) {
|
||||
return (0) ;
|
||||
}
|
||||
|
||||
//int RemoteCameraRtsp::ReadData(void *opaque, uint8_t *buf, int bufSize) {
|
||||
|
||||
//if ( buffer.size() > bufSize ) {
|
||||
//buf = buffer.head();
|
||||
//buffer -= bufSize;
|
||||
//} else {
|
||||
//Error("Implement me");
|
||||
//return -1;
|
||||
//}
|
||||
//}
|
||||
|
||||
//Function to handle capture and store
|
||||
int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* event_file ) {
|
||||
AVPacket packet;
|
||||
@@ -457,7 +446,7 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even
|
||||
av_init_packet( &packet );
|
||||
|
||||
// Why are we checking for it being the video stream? Because it might be audio or something else.
|
||||
// Um... we just initialized packet... we can't be testing for what it is yet....
|
||||
// Um... we just initialized packet... we can't be testing for what it is yet....
|
||||
if ( packet.stream_index == mVideoStreamId ) {
|
||||
|
||||
while ( !frameComplete && buffer.size() > 0 ) {
|
||||
@@ -495,7 +484,7 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even
|
||||
imagePixFormat, width, height);
|
||||
#endif
|
||||
|
||||
//Video recording
|
||||
//Video recording
|
||||
if ( recording && !wasRecording ) {
|
||||
//Instantiate the video storage module
|
||||
|
||||
@@ -533,7 +522,7 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even
|
||||
}
|
||||
|
||||
#if HAVE_LIBSWSCALE
|
||||
// Why are we re-scaling after writing out the packet?
|
||||
// Why are we re-scaling after writing out the packet?
|
||||
if(mConvertContext == NULL) {
|
||||
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
|
||||
|
||||
@@ -549,7 +538,7 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even
|
||||
|
||||
frameCount++;
|
||||
|
||||
} /* frame complete */
|
||||
} /* frame complete */
|
||||
} else if ( packet.stream_index == mAudioStreamId ) {
|
||||
Debug( 4, "Got audio packet" );
|
||||
if ( videoStore && recording ) {
|
||||
@@ -563,10 +552,8 @@ int RemoteCameraRtsp::CaptureAndRecord( Image &image, bool recording, char* even
|
||||
#else
|
||||
av_free_packet( &packet );
|
||||
#endif
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
Debug( 4, "Not storing audio" );
|
||||
}
|
||||
}
|
||||
} // end if video or audio packet
|
||||
|
||||
@@ -33,11 +33,11 @@ extern "C"{
|
||||
}
|
||||
|
||||
VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||
AVStream *input_st,
|
||||
AVStream *inpaud_st,
|
||||
int64_t nStartTime,
|
||||
Monitor::Orientation orientation
|
||||
) {
|
||||
AVStream *input_st,
|
||||
AVStream *inpaud_st,
|
||||
int64_t nStartTime,
|
||||
Monitor::Orientation orientation
|
||||
) {
|
||||
|
||||
AVDictionary *pmetadata = NULL;
|
||||
int dsr;
|
||||
@@ -96,6 +96,7 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||
if (oc->oformat->flags & AVFMT_GLOBALHEADER) {
|
||||
video_st->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
}
|
||||
|
||||
if ( orientation ) {
|
||||
if ( orientation == Monitor::ROTATE_90 ) {
|
||||
dsr = av_dict_set( &video_st->metadata, "rotate", "90", 0);
|
||||
@@ -112,7 +113,6 @@ VideoStore::VideoStore(const char *filename_in, const char *format_in,
|
||||
}
|
||||
|
||||
if (inpaud_st) {
|
||||
|
||||
audio_st = avformat_new_stream(oc, (AVCodec *)inpaud_st->codec->codec);
|
||||
if (!audio_st) {
|
||||
Error("Unable to create audio out stream\n");
|
||||
@@ -222,6 +222,9 @@ void VideoStore::dumpPacket( AVPacket *pkt ){
|
||||
|
||||
int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_st){//, AVPacket *lastKeyframePkt){
|
||||
|
||||
Debug(3, "before ost_tbcket %d", startTime );
|
||||
zm_dump_stream_format( oc, ipkt->stream_index, 0, 1 );
|
||||
Debug(3, "before ost_tbcket %d", startTime );
|
||||
int64_t ost_tb_start_time = av_rescale_q(startTime, AV_TIME_BASE_Q, video_st->time_base);
|
||||
|
||||
AVPacket opkt, safepkt;
|
||||
@@ -285,7 +288,6 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt, AVStream *input_st){//, AV
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
av_free_packet(&opkt);
|
||||
|
||||
return 0;
|
||||
@@ -310,7 +312,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt, AVStream *input_st){
|
||||
av_init_packet(&opkt);
|
||||
Debug(3, "after init packet" );
|
||||
|
||||
|
||||
//Scale the PTS of the outgoing packet to be the correct time base
|
||||
if (ipkt->pts != AV_NOPTS_VALUE) {
|
||||
Debug(3, "Rescaling output pts");
|
||||
|
||||
@@ -1 +1,5 @@
|
||||
<<<<<<< HEAD
|
||||
1.30.3
|
||||
=======
|
||||
1.30.0
|
||||
>>>>>>> feature-h264-videostorage
|
||||
+1
-1
@@ -394,7 +394,7 @@ tr.log-dbg td {
|
||||
}
|
||||
|
||||
$exportFile = "zm-log.$exportExt";
|
||||
$exportPath = "temp/zm-log-$exportKey.$exportExt";
|
||||
$exportPath = ZM_PATH_SWAP."/zm-log-$exportKey.$exportExt";
|
||||
|
||||
header( "Pragma: public" );
|
||||
header( "Expires: 0" );
|
||||
|
||||
@@ -962,13 +962,18 @@ function zmaCheck( $monitor ) {
|
||||
}
|
||||
|
||||
function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $overwrite=false ) {
|
||||
<<<<<<< HEAD
|
||||
$Storage = new Storage( $event['StorageId'] );
|
||||
$Event = new Event( $event );
|
||||
$eventPath = $Event->Path();
|
||||
=======
|
||||
$eventPath = getEventPath( $event );
|
||||
>>>>>>> feature-h264-videostorage
|
||||
|
||||
if ( !is_array($frame) )
|
||||
$frame = array( 'FrameId'=>$frame, 'Type'=>'' );
|
||||
|
||||
<<<<<<< HEAD
|
||||
|
||||
if ( file_exists( $eventPath.'/snapshot.jpg' ) ) {
|
||||
$captImage = "snapshot.jpg";
|
||||
@@ -987,6 +992,21 @@ function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $ov
|
||||
Error("Can't create frame images from video becuase there is no video file for this event (".$Event->DefaultVideo() );
|
||||
}
|
||||
}
|
||||
=======
|
||||
if ( file_exists( $eventPath.'/snapshot.jpg' ) ) {
|
||||
$captImage = "snapshot.jpg";
|
||||
} else {
|
||||
$captImage = sprintf( "%0".ZM_EVENT_IMAGE_DIGITS."d-capture.jpg", $frame['FrameId'] );
|
||||
if ( ! file_exists( $eventPath.'/'.$captImage ) ) {
|
||||
# Generate the frame JPG
|
||||
if ( $event['DefaultVideo'] ) {
|
||||
$command ='ffmpeg -v 0 -i '.$eventPath.'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$frame['FrameId'].'),setpts=PTS-STARTPTS" '.$eventPath.'/'.$captImage;
|
||||
system( $command, $output, $retval );
|
||||
} else {
|
||||
Error("Can't create frame images from video because there is no video file for this event " );
|
||||
}
|
||||
}
|
||||
>>>>>>> feature-h264-videostorage
|
||||
}
|
||||
|
||||
$captPath = $eventPath.'/'.$captImage;
|
||||
@@ -1000,7 +1020,10 @@ function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $ov
|
||||
|
||||
$analImage = sprintf( "%0".ZM_EVENT_IMAGE_DIGITS."d-analyse.jpg", $frame['FrameId'] );
|
||||
$analPath = $eventPath.'/'.$analImage;
|
||||
<<<<<<< HEAD
|
||||
|
||||
=======
|
||||
>>>>>>> feature-h264-videostorage
|
||||
$thumbAnalPath = ZM_DIR_IMAGES.'/'.$event['Id'].'-'.$analImage;
|
||||
//echo "AI:$analImage, AP:$analPath, TAP:$thumbAnalPath<br>";
|
||||
|
||||
@@ -1031,21 +1054,24 @@ function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $ov
|
||||
$thumbPath = $thumbCaptPath;
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
$imageFile = $imagePath;
|
||||
=======
|
||||
>>>>>>> feature-h264-videostorage
|
||||
$thumbFile = $thumbPath;
|
||||
if ( $overwrite || !file_exists( $thumbFile ) || !filesize( $thumbFile ) )
|
||||
{
|
||||
// Get new dimensions
|
||||
list( $imageWidth, $imageHeight ) = getimagesize( $imageFile );
|
||||
list( $imageWidth, $imageHeight ) = getimagesize( $imagePath );
|
||||
$thumbWidth = $imageWidth * $fraction;
|
||||
$thumbHeight = $imageHeight * $fraction;
|
||||
|
||||
// Resample
|
||||
$thumbImage = imagecreatetruecolor( $thumbWidth, $thumbHeight );
|
||||
$image = imagecreatefromjpeg( $imageFile );
|
||||
$image = imagecreatefromjpeg( $imagePath );
|
||||
imagecopyresampled( $thumbImage, $image, 0, 0, 0, 0, $thumbWidth, $thumbHeight, $imageWidth, $imageHeight );
|
||||
|
||||
if ( !imagejpeg( $thumbImage, $thumbFile ) )
|
||||
if ( !imagejpeg( $thumbImage, $thumbPath ) )
|
||||
Error( "Can't create thumbnail '$thumbPath'" );
|
||||
}
|
||||
}
|
||||
@@ -1054,7 +1080,7 @@ function getImageSrc( $event, $frame, $scale=SCALE_BASE, $captureOnly=false, $ov
|
||||
'eventPath' => $eventPath,
|
||||
'imagePath' => $imagePath,
|
||||
'thumbPath' => $thumbPath,
|
||||
'imageFile' => $imageFile,
|
||||
'imageFile' => $imagePath,
|
||||
'thumbFile' => $thumbFile,
|
||||
'imageClass' => $alarmFrame?"alarm":"normal",
|
||||
'isAnalImage' => $isAnalImage,
|
||||
|
||||
+352
-352
File diff suppressed because it is too large.
Load diff
@@ -125,29 +125,29 @@ if ( canEdit( 'Events' ) )
|
||||
if ( canView( 'Events' ) )
|
||||
{
|
||||
?>
|
||||
<div id="framesEvent"><a href="#" onclick="showEventFrames()"><?php echo translate('Frames') ?></a></div>
|
||||
<div id="framesEvent"><a href="#" onclick="showEventFrames()"><?php echo translate('Frames') ?></a></div>
|
||||
<?php
|
||||
if ( $event['SaveJPEGs'] & 3 )
|
||||
{
|
||||
?>
|
||||
<div id="stillsEvent"<?php if ( $streamMode == 'still' ) { ?> class="hidden"<?php } ?>><a href="#" onclick="showStills()"><?php echo translate('Stills') ?></a></div>
|
||||
<div id="stillsEvent"<?php if ( $streamMode == 'still' ) { ?> class="hidden"<?php } ?>><a href="#" onclick="showStills()"><?php echo translate('Stills') ?></a></div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<div id="videoEvent"<?php if ( $streamMode == 'video' ) { ?> class="hidden"<?php } ?>><a href="#" onclick="showVideo()"><?php echo translate('Video') ?></a></div>
|
||||
<div id="exportEvent"><a href="#" onclick="exportEvent()"><?php echo translate('Export') ?></a></div>
|
||||
</div>
|
||||
<div id="eventVideo" class="">
|
||||
<?php
|
||||
<div id="videoEvent"<?php if ( $streamMode == 'video' ) { ?> class="hidden"<?php } ?>><a href="#" onclick="showVideo()"><?php echo translate('Video') ?></a></div>
|
||||
<div id="exportEvent"><a href="#" onclick="exportEvent()"><?php echo translate('Export') ?></a></div>
|
||||
</div>
|
||||
<div id="eventVideo" class="">
|
||||
<?php
|
||||
if ( $event['DefaultVideo'] )
|
||||
{
|
||||
{
|
||||
?>
|
||||
<div id="videoFeed">
|
||||
<video id="videoobj" class="video-js vjs-default-skin" width="<?php echo reScale( $event['Width'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $scale ) ?>" data-setup='{ "controls": true, "playbackRates": [0.5, 1, 1.5, 2, 4, 8, 16, 32, 64, 128, 256], "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "rotate": "<?php echo $Rotation ?>", "zoom": "<?php echo $Zoom ?>"}}}'>
|
||||
<source src="<?php echo getEventDefaultVideoPath($event) ?>" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<div id="videoFeed">
|
||||
<video id="videoobj" class="video-js vjs-default-skin" width="<?php echo reScale( $event['Width'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $scale ) ?>" data-setup='{ "controls": true, "playbackRates": [0.5, 1, 1.5, 2, 4, 8, 16, 32, 64, 128, 256], "autoplay": true, "preload": "auto", "plugins": { "zoomrotate": { "rotate": "<?php echo $Rotation ?>", "zoom": "<?php echo $Zoom ?>"}}}'>
|
||||
<source src="<?php echo getEventDefaultVideoPath($event) ?>" type="video/mp4">
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
</div>
|
||||
<!--script>includeVideoJs();</script-->
|
||||
<link href="//vjs.zencdn.net/4.11/video-js.css" rel="stylesheet">
|
||||
<script src="//vjs.zencdn.net/4.11/video.js"></script>
|
||||
@@ -166,7 +166,7 @@ addVideoTimingTrack(document.getElementById('videoobj'), LabelFormat, monitorNam
|
||||
else
|
||||
{
|
||||
?>
|
||||
<div id="imageFeed">
|
||||
<div id="imageFeed">
|
||||
<?php
|
||||
if ( ZM_WEB_STREAM_METHOD == 'mpeg' && ZM_MPEG_LIVE_FORMAT )
|
||||
{
|
||||
@@ -213,12 +213,12 @@ else
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
if ($event['SaveJPEGs'] & 3)
|
||||
{
|
||||
|
||||
@@ -83,9 +83,15 @@ xhtmlHeaders(__FILE__, translate('Frame')." - ".$event['Id']." - ".$frame->Frame
|
||||
<img src="?view=image&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame->FrameId() ?>&scale=<?php echo $event['DefaultScale'] ?>" class="<?php echo $imageData['imageClass'] ?>" width="<?php echo reScale( $event['Width'], $event['DefaultScale'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $event['DefaultScale'], $scale ) ?>" alt="<?php echo $frame->EventId()."-".$frame->FrameId() ?>">
|
||||
<?php } else {
|
||||
if ( $imageData['hasAnalImage'] ) { ?>
|
||||
<<<<<<< HEAD
|
||||
<a href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame->FrameId() ?>&scale=<?php echo $scale ?>&show=<?php echo $imageData['isAnalImage']?"capt":"anal" ?>">
|
||||
<?php } ?>
|
||||
<img src="<?php echo $frame->getImageSrc() ?>" width="<?php echo reScale( $event['Width'], $event['DefaultScale'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $event['DefaultScale'], $scale ) ?>" alt="<?php echo $frame->EventId()."-".$frame->FrameId() ?>" class="<?php echo $imageData['imageClass'] ?>"/>
|
||||
=======
|
||||
<a href="?view=frame&eid=<?php echo $event['Id'] ?>&fid=<?php echo $frame['FrameId'] ?>&scale=<?php echo $scale ?>&show=<?php echo $imageData['isAnalImage']?"capt":"anal" ?>">
|
||||
<?php } ?>
|
||||
<img src="<?php echo $frame->getImageSrc() ?>" width="<?php echo reScale( $event['Width'], $event['DefaultScale'], $scale ) ?>" height="<?php echo reScale( $event['Height'], $event['DefaultScale'], $scale ) ?>" alt="<?php echo $frame['EventId']."-".$frame['FrameId'] ?>" class="<?php echo $imageData['imageClass'] ?>"/>
|
||||
>>>>>>> feature-h264-videostorage
|
||||
<?php if ( $imageData['hasAnalImage'] ) { ?></a><?php } ?>
|
||||
<?php } ?>
|
||||
</p>
|
||||
|
||||
@@ -58,6 +58,7 @@ if ( ! empty($_REQUEST['mid']) ) {
|
||||
} else {
|
||||
|
||||
$nextId = getTableAutoInc( 'Monitors' );
|
||||
<<<<<<< HEAD
|
||||
if ( ! empty( $_REQUEST['dupId'] ) ) {
|
||||
$monitor = new Monitor( $_REQUEST['dupId'] );
|
||||
if ( ZM_OPT_X10 )
|
||||
@@ -151,6 +152,105 @@ if ( ZM_OPT_X10 && empty($x10Monitor) ) {
|
||||
|
||||
function fourcc( $a, $b, $c, $d ) {
|
||||
return( ord($a) | (ord($b) << 8) | (ord($c) << 16) | (ord($d) << 24) );
|
||||
=======
|
||||
$monitor = getMonitorObject($_REQUEST['dupId']);
|
||||
$clonedName = $monitor['Name'];
|
||||
$monitor['Name'] = translate('Monitor').'-'.$nextId;
|
||||
$monitor['Id']='0';
|
||||
}
|
||||
|
||||
if ( ZM_OPT_X10 && empty($x10Monitor) )
|
||||
{
|
||||
$x10Monitor = array(
|
||||
'Activation' => '',
|
||||
'AlarmInput' => '',
|
||||
'AlarmOutput' => '',
|
||||
);
|
||||
}
|
||||
|
||||
function getMonitorObject( $mid = null)
|
||||
{
|
||||
if ($mid !== null)
|
||||
{
|
||||
$monitor = dbFetchMonitor($mid);
|
||||
}
|
||||
else
|
||||
{
|
||||
$monitor = array(
|
||||
'Id' => 0,
|
||||
'Name' => "willbereplaced",
|
||||
'Function' => "Monitor",
|
||||
'Enabled' => true,
|
||||
'LinkedMonitors' => "",
|
||||
'Type' => "",
|
||||
'Device' => "/dev/video0",
|
||||
'Channel' => "0",
|
||||
'Format' => 0x000000ff,
|
||||
'Protocol' => "",
|
||||
'Method' => "",
|
||||
'Host' => "",
|
||||
'Path' => "",
|
||||
'Options' => "",
|
||||
'Port' => "80",
|
||||
'User' => "",
|
||||
'Pass' => "",
|
||||
'Colours' => 3,
|
||||
'Palette' => 0,
|
||||
'Width' => "320",
|
||||
'Height' => "240",
|
||||
'Orientation' => "0",
|
||||
'Deinterlacing' => 0,
|
||||
'RTSPDescribe' => 0,
|
||||
'SaveJPEGs' => "3",
|
||||
'VideoWriter' => "0",
|
||||
'EncoderParameters' => "# Lines beginning with # are a comment \n# For changing quality, use the crf option\n# 1 is best, 51 is worst quality\n#crf=23\n",
|
||||
'RecordAudio' => "0",
|
||||
'LabelFormat' => '%N - %d/%m/%y %H:%M:%S',
|
||||
'LabelX' => 0,
|
||||
'LabelY' => 0,
|
||||
'LabelSize' => 1,
|
||||
'ImageBufferCount' => 50,
|
||||
'WarmupCount' => 25,
|
||||
'PreEventCount' => 25,
|
||||
'PostEventCount' => 25,
|
||||
'StreamReplayBuffer' => 1000,
|
||||
'AlarmFrameCount' => 1,
|
||||
'Controllable' => 0,
|
||||
'ControlId' => "",
|
||||
'ControlType' => 0,
|
||||
'ControlDevice' => "",
|
||||
'ControlAddress' => "",
|
||||
'AutoStopTimeout' => "",
|
||||
'TrackMotion' => 0,
|
||||
'TrackDelay' => "",
|
||||
'ReturnLocation' => -1,
|
||||
'ReturnDelay' => "",
|
||||
'SectionLength' => 600,
|
||||
'FrameSkip' => 0,
|
||||
'MotionFrameSkip' => 0,
|
||||
'EventPrefix' => 'Event-',
|
||||
'AnalysisFPS' => "",
|
||||
'AnalysisUpdateDelay' => 0,
|
||||
'MaxFPS' => "",
|
||||
'AlarmMaxFPS' => "",
|
||||
'FPSReportInterval' => 1000,
|
||||
'RefBlendPerc' => 6,
|
||||
'AlarmRefBlendPerc' => 6,
|
||||
'DefaultView' => 'Events',
|
||||
'DefaultRate' => '100',
|
||||
'DefaultScale' => '100',
|
||||
'SignalCheckColour' => '#0000c0',
|
||||
'WebColour' => 'red',
|
||||
'Exif' => '0',
|
||||
'Triggers' => "",
|
||||
'V4LMultiBuffer' => '',
|
||||
'V4LCapturesPerFrame' => 1,
|
||||
'ServerId' => $Server['Id'],
|
||||
);
|
||||
}
|
||||
return ($monitor);
|
||||
}
|
||||
>>>>>>> feature-h264-videostorage
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user