Merge branch 'master' of github.com:ZoneMinder/zoneminder
This commit is contained in:
commit
224fcd2cd3
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
#include "zm_exception.h"
|
#include "zm_exception.h"
|
||||||
#include "zm_logger.h"
|
#include "zm_logger.h"
|
||||||
|
#include <cerrno>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
#include "zm_logger.h"
|
#include "zm_logger.h"
|
||||||
#include "zm_utils.h"
|
#include "zm_utils.h"
|
||||||
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
|
|
@ -19,10 +19,12 @@
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
|
|
||||||
#include "zm_logger.h"
|
#include "zm_logger.h"
|
||||||
|
#include "zm_signal.h"
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
MYSQL dbconn;
|
MYSQL dbconn;
|
||||||
RecursiveMutex db_mutex;
|
std::mutex db_mutex;
|
||||||
|
zmDbQueue dbQueue;
|
||||||
|
|
||||||
bool zmDbConnected = false;
|
bool zmDbConnected = false;
|
||||||
|
|
||||||
|
@ -106,46 +108,36 @@ bool zmDbConnect() {
|
||||||
|
|
||||||
void zmDbClose() {
|
void zmDbClose() {
|
||||||
if (zmDbConnected) {
|
if (zmDbConnected) {
|
||||||
db_mutex.lock();
|
std::lock_guard<std::mutex> lck(db_mutex);
|
||||||
mysql_close(&dbconn);
|
mysql_close(&dbconn);
|
||||||
// mysql_init() call implicitly mysql_library_init() but
|
// mysql_init() call implicitly mysql_library_init() but
|
||||||
// mysql_close() does not call mysql_library_end()
|
// mysql_close() does not call mysql_library_end()
|
||||||
mysql_library_end();
|
mysql_library_end();
|
||||||
zmDbConnected = false;
|
zmDbConnected = false;
|
||||||
db_mutex.unlock();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MYSQL_RES * zmDbFetch(const char * query) {
|
MYSQL_RES * zmDbFetch(const char * query) {
|
||||||
if ( !zmDbConnected ) {
|
std::lock_guard<std::mutex> lck(db_mutex);
|
||||||
Error("Not connected.");
|
if (!zmDbConnected) {
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
db_mutex.lock();
|
|
||||||
// Might have been disconnected while we waited for the lock
|
|
||||||
if ( !zmDbConnected ) {
|
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Not connected.");
|
Error("Not connected.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( mysql_query(&dbconn, query) ) {
|
if (mysql_query(&dbconn, query)) {
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
Debug(4, "Success running query: %s", query);
|
|
||||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||||
if ( !result ) {
|
if (!result) {
|
||||||
Error("Can't use query result: %s for query %s", mysql_error(&dbconn), query);
|
Error("Can't use query result: %s for query %s", mysql_error(&dbconn), query);
|
||||||
}
|
}
|
||||||
db_mutex.unlock();
|
|
||||||
return result;
|
return result;
|
||||||
} // end MYSQL_RES * zmDbFetch(const char * query);
|
} // end MYSQL_RES * zmDbFetch(const char * query);
|
||||||
|
|
||||||
zmDbRow *zmDbFetchOne(const char *query) {
|
zmDbRow *zmDbFetchOne(const char *query) {
|
||||||
zmDbRow *row = new zmDbRow();
|
zmDbRow *row = new zmDbRow();
|
||||||
if ( row->fetch(query) ) {
|
if (row->fetch(query)) {
|
||||||
return row;
|
return row;
|
||||||
}
|
}
|
||||||
delete row;
|
delete row;
|
||||||
|
@ -154,10 +146,10 @@ zmDbRow *zmDbFetchOne(const char *query) {
|
||||||
|
|
||||||
MYSQL_RES *zmDbRow::fetch(const char *query) {
|
MYSQL_RES *zmDbRow::fetch(const char *query) {
|
||||||
result_set = zmDbFetch(query);
|
result_set = zmDbFetch(query);
|
||||||
if ( ! result_set ) return result_set;
|
if (!result_set) return result_set;
|
||||||
|
|
||||||
int n_rows = mysql_num_rows(result_set);
|
int n_rows = mysql_num_rows(result_set);
|
||||||
if ( n_rows != 1 ) {
|
if (n_rows != 1) {
|
||||||
Error("Bogus number of lines return from query, %d returned for query %s.", n_rows, query);
|
Error("Bogus number of lines return from query, %d returned for query %s.", n_rows, query);
|
||||||
mysql_free_result(result_set);
|
mysql_free_result(result_set);
|
||||||
result_set = nullptr;
|
result_set = nullptr;
|
||||||
|
@ -165,7 +157,7 @@ MYSQL_RES *zmDbRow::fetch(const char *query) {
|
||||||
}
|
}
|
||||||
|
|
||||||
row = mysql_fetch_row(result_set);
|
row = mysql_fetch_row(result_set);
|
||||||
if ( !row ) {
|
if (!row) {
|
||||||
mysql_free_result(result_set);
|
mysql_free_result(result_set);
|
||||||
result_set = nullptr;
|
result_set = nullptr;
|
||||||
Error("Error getting row from query %s. Error is %s", query, mysql_error(&dbconn));
|
Error("Error getting row from query %s. Error is %s", query, mysql_error(&dbconn));
|
||||||
|
@ -176,40 +168,69 @@ MYSQL_RES *zmDbRow::fetch(const char *query) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmDbDo(const char *query) {
|
int zmDbDo(const char *query) {
|
||||||
db_mutex.lock();
|
std::lock_guard<std::mutex> lck(db_mutex);
|
||||||
|
if (!zmDbConnected)
|
||||||
|
return 0;
|
||||||
int rc;
|
int rc;
|
||||||
while ( rc = mysql_query(&dbconn, query) ) {
|
while ((rc = mysql_query(&dbconn, query)) and !zm_terminate) {
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Can't run query %s: %s", query, mysql_error(&dbconn));
|
Error("Can't run query %s: %s", query, mysql_error(&dbconn));
|
||||||
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) )
|
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) ) {
|
||||||
return rc;
|
return rc;
|
||||||
|
}
|
||||||
db_mutex.lock();
|
|
||||||
}
|
}
|
||||||
db_mutex.unlock();
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int zmDbDoInsert(const char *query) {
|
int zmDbDoInsert(const char *query) {
|
||||||
db_mutex.lock();
|
std::lock_guard<std::mutex> lck(db_mutex);
|
||||||
|
if (!zmDbConnected) return 0;
|
||||||
int rc;
|
int rc;
|
||||||
while ( rc = mysql_query(&dbconn, query) ) {
|
while ( (rc = mysql_query(&dbconn, query)) and !zm_terminate) {
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Can't run query %s: %s", query, mysql_error(&dbconn));
|
Error("Can't run query %s: %s", query, mysql_error(&dbconn));
|
||||||
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) )
|
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
db_mutex.lock();
|
|
||||||
}
|
}
|
||||||
int id = mysql_insert_id(&dbconn);
|
int id = mysql_insert_id(&dbconn);
|
||||||
db_mutex.unlock();
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
zmDbRow::~zmDbRow() {
|
zmDbRow::~zmDbRow() {
|
||||||
if ( result_set ) {
|
if (result_set) {
|
||||||
mysql_free_result(result_set);
|
mysql_free_result(result_set);
|
||||||
result_set = nullptr;
|
result_set = nullptr;
|
||||||
}
|
}
|
||||||
row = nullptr;
|
row = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
zmDbQueue::zmDbQueue() :
|
||||||
|
mThread(&zmDbQueue::process, this),
|
||||||
|
mTerminate(false)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
zmDbQueue::~zmDbQueue() {
|
||||||
|
mTerminate = true;
|
||||||
|
mCondition.notify_all();
|
||||||
|
mThread.join();
|
||||||
|
}
|
||||||
|
void zmDbQueue::process() {
|
||||||
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
|
|
||||||
|
while (!mTerminate and !zm_terminate) {
|
||||||
|
if (mQueue.empty()) {
|
||||||
|
mCondition.wait(lock);
|
||||||
|
}
|
||||||
|
if (!mQueue.empty()) {
|
||||||
|
std::string sql = mQueue.front();
|
||||||
|
mQueue.pop();
|
||||||
|
lock.unlock();
|
||||||
|
zmDbDo(sql.c_str());
|
||||||
|
lock.lock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end void zmDbQueue::process()
|
||||||
|
|
||||||
|
void zmDbQueue::push(std::string sql) {
|
||||||
|
std::unique_lock<std::mutex> lock(mMutex);
|
||||||
|
mQueue.push(sql);
|
||||||
|
mCondition.notify_all();
|
||||||
|
}
|
||||||
|
|
27
src/zm_db.h
27
src/zm_db.h
|
@ -23,6 +23,26 @@
|
||||||
#include "zm_thread.h"
|
#include "zm_thread.h"
|
||||||
#include <mysql/mysql.h>
|
#include <mysql/mysql.h>
|
||||||
#include <mysql/mysqld_error.h>
|
#include <mysql/mysqld_error.h>
|
||||||
|
#include <string>
|
||||||
|
#include <thread>
|
||||||
|
#include <queue>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
|
class zmDbQueue {
|
||||||
|
private:
|
||||||
|
std::queue<std::string> mQueue;
|
||||||
|
std::thread mThread;
|
||||||
|
std::mutex mMutex;
|
||||||
|
std::condition_variable mCondition;
|
||||||
|
bool mTerminate;
|
||||||
|
public:
|
||||||
|
zmDbQueue();
|
||||||
|
~zmDbQueue();
|
||||||
|
void push(const char *sql) { return push(std::string(sql)); };
|
||||||
|
void push(std::string);
|
||||||
|
void process();
|
||||||
|
};
|
||||||
|
|
||||||
class zmDbRow {
|
class zmDbRow {
|
||||||
private:
|
private:
|
||||||
|
@ -42,7 +62,8 @@ class zmDbRow {
|
||||||
};
|
};
|
||||||
|
|
||||||
extern MYSQL dbconn;
|
extern MYSQL dbconn;
|
||||||
extern RecursiveMutex db_mutex;
|
extern std::mutex db_mutex;
|
||||||
|
extern zmDbQueue dbQueue;
|
||||||
|
|
||||||
extern bool zmDbConnected;
|
extern bool zmDbConnected;
|
||||||
|
|
||||||
|
@ -51,7 +72,7 @@ void zmDbClose();
|
||||||
int zmDbDo(const char *query);
|
int zmDbDo(const char *query);
|
||||||
int zmDbDoInsert(const char *query);
|
int zmDbDoInsert(const char *query);
|
||||||
|
|
||||||
MYSQL_RES * zmDbFetch( const char *query );
|
MYSQL_RES * zmDbFetch(const char *query);
|
||||||
zmDbRow *zmDbFetchOne( const char *query );
|
zmDbRow *zmDbFetchOne(const char *query);
|
||||||
|
|
||||||
#endif // ZM_DB_H
|
#endif // ZM_DB_H
|
||||||
|
|
|
@ -251,30 +251,25 @@ Event::~Event() {
|
||||||
frames, alarm_frames,
|
frames, alarm_frames,
|
||||||
tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score,
|
tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score,
|
||||||
id);
|
id);
|
||||||
db_mutex.lock();
|
{ // scope for lock
|
||||||
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
|
std::lock_guard<std::mutex> lck(db_mutex);
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn));
|
|
||||||
sleep(1);
|
|
||||||
db_mutex.lock();
|
|
||||||
}
|
|
||||||
if ( !mysql_affected_rows(&dbconn) ) {
|
|
||||||
// Name might have been changed during recording, so just do the update without changing the name.
|
|
||||||
snprintf(sql, sizeof(sql),
|
|
||||||
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
|
|
||||||
end_time.tv_sec,
|
|
||||||
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);
|
|
||||||
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
|
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn));
|
Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn));
|
||||||
sleep(1);
|
|
||||||
db_mutex.lock();
|
|
||||||
}
|
}
|
||||||
} // end if no changed rows due to Name change during recording
|
if ( !mysql_affected_rows(&dbconn) ) {
|
||||||
db_mutex.unlock();
|
// Name might have been changed during recording, so just do the update without changing the name.
|
||||||
|
snprintf(sql, sizeof(sql),
|
||||||
|
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
|
||||||
|
end_time.tv_sec,
|
||||||
|
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);
|
||||||
|
while ( mysql_query(&dbconn, sql) && !zm_terminate ) {
|
||||||
|
Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn));
|
||||||
|
}
|
||||||
|
} // end if no changed rows due to Name change during recording
|
||||||
|
}
|
||||||
} // Event::~Event()
|
} // Event::~Event()
|
||||||
|
|
||||||
void Event::createNotes(std::string ¬es) {
|
void Event::createNotes(std::string ¬es) {
|
||||||
|
@ -427,11 +422,7 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) {
|
||||||
mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length());
|
mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length());
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql), "UPDATE `Events` SET `Notes` = '%s' WHERE `Id` = %" PRIu64, escapedNotes, id);
|
snprintf(sql, sizeof(sql), "UPDATE `Events` SET `Notes` = '%s' WHERE `Id` = %" PRIu64, escapedNotes, id);
|
||||||
db_mutex.lock();
|
zmDbDo(sql);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
|
||||||
Error("Can't insert event: %s", mysql_error(&dbconn));
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
#endif
|
#endif
|
||||||
} // end if update
|
} // end if update
|
||||||
} // void Event::updateNotes(const StringSetMap &newNoteSetMap)
|
} // void Event::updateNotes(const StringSetMap &newNoteSetMap)
|
||||||
|
@ -495,14 +486,7 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
|
||||||
|
|
||||||
if ( frameCount ) {
|
if ( frameCount ) {
|
||||||
*(frame_insert_values-1) = '\0';
|
*(frame_insert_values-1) = '\0';
|
||||||
db_mutex.lock();
|
zmDbDo(frame_insert_sql);
|
||||||
int rc = mysql_query(&dbconn, frame_insert_sql);
|
|
||||||
db_mutex.unlock();
|
|
||||||
if ( rc ) {
|
|
||||||
Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), frame_insert_sql);
|
|
||||||
} else {
|
|
||||||
Debug(1, "INSERT %d/%d frames sql %s", frameCount, n_frames, frame_insert_sql);
|
|
||||||
}
|
|
||||||
last_db_frame = frames;
|
last_db_frame = frames;
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "No valid pre-capture frames to add");
|
Debug(1, "No valid pre-capture frames to add");
|
||||||
|
@ -512,7 +496,9 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str
|
||||||
|
|
||||||
void Event::AddPacket(ZMPacket *packet) {
|
void Event::AddPacket(ZMPacket *packet) {
|
||||||
|
|
||||||
have_video_keyframe = have_video_keyframe || ( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) && packet->keyframe );
|
have_video_keyframe = have_video_keyframe ||
|
||||||
|
( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) &&
|
||||||
|
( packet->keyframe || monitor->GetOptVideoWriter() == Monitor::ENCODE) );
|
||||||
Debug(2, "have_video_keyframe %d codec_type %d == video? %d packet keyframe %d",
|
Debug(2, "have_video_keyframe %d codec_type %d == video? %d packet keyframe %d",
|
||||||
have_video_keyframe, packet->codec_type, (packet->codec_type == AVMEDIA_TYPE_VIDEO), packet->keyframe);
|
have_video_keyframe, packet->codec_type, (packet->codec_type == AVMEDIA_TYPE_VIDEO), packet->keyframe);
|
||||||
ZM_DUMP_PACKET(packet->packet, "Adding to event");
|
ZM_DUMP_PACKET(packet->packet, "Adding to event");
|
||||||
|
@ -552,38 +538,9 @@ void Event::WriteDbFrames() {
|
||||||
delete frame;
|
delete frame;
|
||||||
}
|
}
|
||||||
*(frame_insert_values_ptr-1) = '\0'; // The -1 is for the extra , added for values above
|
*(frame_insert_values_ptr-1) = '\0'; // The -1 is for the extra , added for values above
|
||||||
db_mutex.lock();
|
zmDbDo(frame_insert_sql);
|
||||||
int rc = mysql_query(&dbconn, frame_insert_sql);
|
|
||||||
db_mutex.unlock();
|
|
||||||
|
|
||||||
if ( rc ) {
|
|
||||||
Error("Can't insert frames: %s, sql was %s", mysql_error(&dbconn), frame_insert_sql);
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
Debug(1, "INSERT FRAMES: sql was %s", frame_insert_sql);
|
|
||||||
}
|
|
||||||
} // end void Event::WriteDbFrames()
|
} // end void Event::WriteDbFrames()
|
||||||
|
|
||||||
// Subtract an offset time from frames deltas to match with video start time
|
|
||||||
void Event::UpdateFramesDelta(double offset) {
|
|
||||||
char sql[ZM_SQL_MED_BUFSIZ];
|
|
||||||
|
|
||||||
if ( offset == 0.0 ) return;
|
|
||||||
// the table is set to auto update timestamp so we force it to keep current value
|
|
||||||
snprintf(sql, sizeof(sql),
|
|
||||||
"UPDATE Frames SET timestamp = timestamp, Delta = Delta - (%.4f) WHERE EventId = %" PRIu64,
|
|
||||||
offset, id);
|
|
||||||
|
|
||||||
db_mutex.lock();
|
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Can't update frames: %s, sql was %s", mysql_error(&dbconn), sql);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
Info("Updating frames delta by %0.2f sec to match video file", offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) {
|
void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) {
|
||||||
if (!timestamp.tv_sec) {
|
if (!timestamp.tv_sec) {
|
||||||
Warning("Not adding new frame, zero timestamp");
|
Warning("Not adding new frame, zero timestamp");
|
||||||
|
@ -686,14 +643,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||||
max_score,
|
max_score,
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
db_mutex.lock();
|
zmDbDo(sql);
|
||||||
while (mysql_query(&dbconn, sql) && !zm_terminate) {
|
|
||||||
Error("Can't update event: %s", mysql_error(&dbconn));
|
|
||||||
db_mutex.unlock();
|
|
||||||
sleep(1);
|
|
||||||
db_mutex.lock();
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "Not Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK",
|
Debug(1, "Not Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK",
|
||||||
frame_data.size(), write_to_db, fps);
|
frame_data.size(), write_to_db, fps);
|
||||||
|
|
|
@ -134,7 +134,6 @@ class Event {
|
||||||
Image **images,
|
Image **images,
|
||||||
struct timeval **timestamps);
|
struct timeval **timestamps);
|
||||||
void WriteDbFrames();
|
void WriteDbFrames();
|
||||||
void UpdateFramesDelta(double offset);
|
|
||||||
bool SetPath(Storage *storage);
|
bool SetPath(Storage *storage);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -27,6 +27,9 @@
|
||||||
#include "zm_storage.h"
|
#include "zm_storage.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
const std::string EventStream::StreamMode_Strings[4] = {
|
const std::string EventStream::StreamMode_Strings[4] = {
|
||||||
"None",
|
"None",
|
||||||
|
@ -348,7 +351,7 @@ void EventStream::processCommand(const CmdMsg *msg) {
|
||||||
curr_frame_id = 1;
|
curr_frame_id = 1;
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "mode is %s, current frame is %ld, frame count is %ld, last frame id is %ld",
|
Debug(1, "mode is %s, current frame is %ld, frame count is %ld, last frame id is %ld",
|
||||||
StreamMode_Strings[(int)mode], curr_frame_id, event_data->frame_count );
|
StreamMode_Strings[(int)mode].c_str(), curr_frame_id, event_data->frame_count );
|
||||||
}
|
}
|
||||||
|
|
||||||
replay_rate = ZM_RATE_BASE;
|
replay_rate = ZM_RATE_BASE;
|
||||||
|
|
|
@ -90,7 +90,7 @@ class EventStream : public StreamBase {
|
||||||
bool loadInitialEventData(int monitor_id, time_t event_time);
|
bool loadInitialEventData(int monitor_id, time_t event_time);
|
||||||
|
|
||||||
bool checkEventLoaded();
|
bool checkEventLoaded();
|
||||||
void processCommand(const CmdMsg *msg);
|
void processCommand(const CmdMsg *msg) override;
|
||||||
bool sendFrame(int delta_us);
|
bool sendFrame(int delta_us);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -64,11 +64,15 @@ void log_libav_callback(void *ptr, int level, const char *fmt, va_list vargs) {
|
||||||
|
|
||||||
if ( log ) {
|
if ( log ) {
|
||||||
char logString[8192];
|
char logString[8192];
|
||||||
vsnprintf(logString, sizeof(logString)-1, fmt, vargs);
|
int length = vsnprintf(logString, sizeof(logString)-1, fmt, vargs);
|
||||||
int length = strlen(logString);
|
if ( length > 0 ) {
|
||||||
// ffmpeg logs have a carriage return, so replace it with terminator
|
if ( static_cast<size_t>(length) > sizeof(logString)-1 ) length = sizeof(logString)-1;
|
||||||
logString[length-1] = 0;
|
// ffmpeg logs have a carriage return, so replace it with terminator
|
||||||
log->logPrint(false, __FILE__, __LINE__, log_level, logString);
|
logString[length-1] = 0;
|
||||||
|
log->logPrint(false, __FILE__, __LINE__, log_level, logString);
|
||||||
|
} else {
|
||||||
|
log->logPrint(false, __FILE__, __LINE__, AV_LOG_ERROR, "Can't encode log from av. fmt was %s", fmt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -385,8 +389,9 @@ enum AVPixelFormat fix_deprecated_pix_fmt(enum AVPixelFormat fmt) {
|
||||||
return AV_PIX_FMT_YUV440P;
|
return AV_PIX_FMT_YUV440P;
|
||||||
case AV_PIX_FMT_NONE :
|
case AV_PIX_FMT_NONE :
|
||||||
case AV_PIX_FMT_YUVJ420P :
|
case AV_PIX_FMT_YUVJ420P :
|
||||||
default:
|
|
||||||
return AV_PIX_FMT_YUV420P;
|
return AV_PIX_FMT_YUV420P;
|
||||||
|
default:
|
||||||
|
return fmt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -369,10 +369,12 @@ void zm_dump_codecpar(const AVCodecParameters *par);
|
||||||
if (logDebugging()) { \
|
if (logDebugging()) { \
|
||||||
double pts_time = static_cast<double>(av_rescale_q(pkt.pts, stream->time_base, AV_TIME_BASE_Q)) / AV_TIME_BASE; \
|
double pts_time = static_cast<double>(av_rescale_q(pkt.pts, stream->time_base, AV_TIME_BASE_Q)) / AV_TIME_BASE; \
|
||||||
\
|
\
|
||||||
Debug(2, "%s: pts: %" PRId64 "=%f, dts: %" PRId64 \
|
Debug(2, "%s: pts: %" PRId64 " * %u/%u=%f, dts: %" PRId64 \
|
||||||
", size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64", duration: %" AV_PACKET_DURATION_FMT, \
|
", size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64", duration: %" AV_PACKET_DURATION_FMT, \
|
||||||
text, \
|
text, \
|
||||||
pkt.pts, \
|
pkt.pts, \
|
||||||
|
stream->time_base.num, \
|
||||||
|
stream->time_base.den, \
|
||||||
pts_time, \
|
pts_time, \
|
||||||
pkt.dts, \
|
pkt.dts, \
|
||||||
pkt.size, \
|
pkt.size, \
|
||||||
|
|
|
@ -44,7 +44,6 @@ int zmFifoDbgInit(Monitor * monitor);
|
||||||
class FifoStream : public StreamBase {
|
class FifoStream : public StreamBase {
|
||||||
private:
|
private:
|
||||||
char * stream_path;
|
char * stream_path;
|
||||||
int fd;
|
|
||||||
int total_read;
|
int total_read;
|
||||||
int bytes_read;
|
int bytes_read;
|
||||||
unsigned int frame_count;
|
unsigned int frame_count;
|
||||||
|
@ -59,12 +58,11 @@ class FifoStream : public StreamBase {
|
||||||
StreamType stream_type;
|
StreamType stream_type;
|
||||||
bool sendMJEGFrames();
|
bool sendMJEGFrames();
|
||||||
bool sendRAWFrames();
|
bool sendRAWFrames();
|
||||||
void processCommand(const CmdMsg *msg) {}
|
void processCommand(const CmdMsg *msg) override {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
FifoStream() :
|
FifoStream() :
|
||||||
stream_path(nullptr),
|
stream_path(nullptr),
|
||||||
fd(0),
|
|
||||||
total_read(0),
|
total_read(0),
|
||||||
bytes_read(0),
|
bytes_read(0),
|
||||||
frame_count(0),
|
frame_count(0),
|
||||||
|
|
|
@ -276,13 +276,15 @@ void Image::Assign(const AVFrame *frame) {
|
||||||
AVFrame *dest_frame = zm_av_frame_alloc();
|
AVFrame *dest_frame = zm_av_frame_alloc();
|
||||||
PopulateFrame(dest_frame);
|
PopulateFrame(dest_frame);
|
||||||
zm_dump_video_frame(frame, "source frame before convert");
|
zm_dump_video_frame(frame, "source frame before convert");
|
||||||
zm_dump_video_frame(dest_frame, "dest frame before convert");
|
dest_frame->pts = frame->pts;
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
sws_convert_context = sws_getCachedContext(
|
sws_convert_context = sws_getCachedContext(
|
||||||
sws_convert_context,
|
sws_convert_context,
|
||||||
frame->width, frame->height, (AVPixelFormat)frame->format,
|
frame->width, frame->height, (AVPixelFormat)frame->format,
|
||||||
width, height, format,
|
width, height, format,
|
||||||
SWS_BICUBIC, nullptr, nullptr, nullptr);
|
//SWS_BICUBIC,
|
||||||
|
SWS_POINT | SWS_BITEXACT,
|
||||||
|
nullptr, nullptr, nullptr);
|
||||||
if ( sws_convert_context == nullptr )
|
if ( sws_convert_context == nullptr )
|
||||||
Fatal("Unable to create conversion context");
|
Fatal("Unable to create conversion context");
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,10 @@ LibvlcCamera::~LibvlcCamera() {
|
||||||
(*libvlc_release_f)(mLibvlcInstance);
|
(*libvlc_release_f)(mLibvlcInstance);
|
||||||
mLibvlcInstance = nullptr;
|
mLibvlcInstance = nullptr;
|
||||||
}
|
}
|
||||||
|
if (libvlc_lib) {
|
||||||
|
dlclose(libvlc_lib);
|
||||||
|
libvlc_lib = nullptr;
|
||||||
|
}
|
||||||
if ( mOptArgV != nullptr ) {
|
if ( mOptArgV != nullptr ) {
|
||||||
delete[] mOptArgV;
|
delete[] mOptArgV;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,11 +18,11 @@ static int (*WaitForMessage_f)(rfbClient*, unsigned int) = nullptr;
|
||||||
static rfbBool (*HandleRFBServerMessage_f)(rfbClient*) = nullptr;
|
static rfbBool (*HandleRFBServerMessage_f)(rfbClient*) = nullptr;
|
||||||
|
|
||||||
void bind_libvnc_symbols() {
|
void bind_libvnc_symbols() {
|
||||||
if ( libvnc_lib != nullptr ) // Safe-check
|
if (libvnc_lib != nullptr) // Safe-check
|
||||||
return;
|
return;
|
||||||
|
|
||||||
libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL);
|
libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL);
|
||||||
if ( !libvnc_lib ) {
|
if (!libvnc_lib) {
|
||||||
Error("Error loading libvncclient: %s", dlerror());
|
Error("Error loading libvncclient: %s", dlerror());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -43,14 +43,14 @@ static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, in
|
||||||
x,y,w,h, rfb->width, rfb->height, rfb->frameBuffer);
|
x,y,w,h, rfb->width, rfb->height, rfb->frameBuffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static char* GetPasswordCallback(rfbClient* cl){
|
static char* GetPasswordCallback(rfbClient* cl) {
|
||||||
Debug(1, "Getcredentials: %s", (*rfbClientGetClientData_f)(cl, &TAG_1));
|
Debug(1, "Getcredentials: %s", (*rfbClientGetClientData_f)(cl, &TAG_1));
|
||||||
return strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
|
return strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
|
static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
|
||||||
rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential));
|
rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential));
|
||||||
if ( credentialType != rfbCredentialTypeUser ) {
|
if (credentialType != rfbCredentialTypeUser) {
|
||||||
free(c);
|
free(c);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -61,6 +61,21 @@ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rfbBool resize(rfbClient* client) {
|
||||||
|
if (client->frameBuffer) {
|
||||||
|
Debug(1, "Freeing old frame buffer");
|
||||||
|
av_free(client->frameBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bufferSize = 4*client->width*client->height;
|
||||||
|
// libVNC doesn't do alignment or padding in each line
|
||||||
|
//SWScale::GetBufferSize(AV_PIX_FMT_RGBA, client->width, client->height);
|
||||||
|
client->frameBuffer = (uint8_t *)av_malloc(bufferSize);
|
||||||
|
Debug(1, "Allocing new frame buffer %dx%d = %d", client->width, client->height, bufferSize);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
VncCamera::VncCamera(
|
VncCamera::VncCamera(
|
||||||
const Monitor *monitor,
|
const Monitor *monitor,
|
||||||
const std::string &host,
|
const std::string &host,
|
||||||
|
@ -96,22 +111,20 @@ VncCamera::VncCamera(
|
||||||
mUser(user),
|
mUser(user),
|
||||||
mPass(pass)
|
mPass(pass)
|
||||||
{
|
{
|
||||||
Debug(2, "Host:%s Port: %s User: %s Pass:%s", mHost.c_str(), mPort.c_str(), mUser.c_str(), mPass.c_str());
|
if (colours == ZM_COLOUR_RGB32) {
|
||||||
|
|
||||||
if ( colours == ZM_COLOUR_RGB32 ) {
|
|
||||||
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
|
subpixelorder = ZM_SUBPIX_ORDER_RGBA;
|
||||||
mImgPixFmt = AV_PIX_FMT_RGBA;
|
mImgPixFmt = AV_PIX_FMT_RGBA;
|
||||||
} else if ( colours == ZM_COLOUR_RGB24 ) {
|
} else if (colours == ZM_COLOUR_RGB24) {
|
||||||
subpixelorder = ZM_SUBPIX_ORDER_RGB;
|
subpixelorder = ZM_SUBPIX_ORDER_RGB;
|
||||||
mImgPixFmt = AV_PIX_FMT_RGB24;
|
mImgPixFmt = AV_PIX_FMT_RGB24;
|
||||||
} else if ( colours == ZM_COLOUR_GRAY8 ) {
|
} else if (colours == ZM_COLOUR_GRAY8) {
|
||||||
subpixelorder = ZM_SUBPIX_ORDER_NONE;
|
subpixelorder = ZM_SUBPIX_ORDER_NONE;
|
||||||
mImgPixFmt = AV_PIX_FMT_GRAY8;
|
mImgPixFmt = AV_PIX_FMT_GRAY8;
|
||||||
} else {
|
} else {
|
||||||
Panic("Unexpected colours: %d", colours);
|
Panic("Unexpected colours: %d", colours);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( capture ) {
|
if (capture) {
|
||||||
Debug(3, "Initializing Client");
|
Debug(3, "Initializing Client");
|
||||||
bind_libvnc_symbols();
|
bind_libvnc_symbols();
|
||||||
scale.init();
|
scale.init();
|
||||||
|
@ -119,11 +132,15 @@ VncCamera::VncCamera(
|
||||||
}
|
}
|
||||||
|
|
||||||
VncCamera::~VncCamera() {
|
VncCamera::~VncCamera() {
|
||||||
if ( capture ) {
|
if (capture and mRfb) {
|
||||||
if ( mRfb->frameBuffer )
|
if (mRfb->frameBuffer)
|
||||||
free(mRfb->frameBuffer);
|
free(mRfb->frameBuffer);
|
||||||
(*rfbClientCleanup_f)(mRfb);
|
(*rfbClientCleanup_f)(mRfb);
|
||||||
}
|
}
|
||||||
|
if (libvnc_lib) {
|
||||||
|
dlclose(libvnc_lib);
|
||||||
|
libvnc_lib = nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int VncCamera::PrimeCapture() {
|
int VncCamera::PrimeCapture() {
|
||||||
|
@ -134,12 +151,9 @@ int VncCamera::PrimeCapture() {
|
||||||
mVncData.width = 0;
|
mVncData.width = 0;
|
||||||
mVncData.height = 0;
|
mVncData.height = 0;
|
||||||
|
|
||||||
mBufferSize = SWScale::GetBufferSize(AV_PIX_FMT_RGBA, width, height);
|
// TODO, support 8bit or 24bit
|
||||||
|
|
||||||
mRfb = (*rfbGetClient_f)(8 /* bits per sample */, 3 /* samples per pixel */, 4 /* bytes Per Pixel */);
|
mRfb = (*rfbGetClient_f)(8 /* bits per sample */, 3 /* samples per pixel */, 4 /* bytes Per Pixel */);
|
||||||
mRfb->frameBuffer = nullptr;
|
mRfb->MallocFrameBuffer = resize;
|
||||||
//(uint8_t *)av_malloc(mBufferSize);
|
|
||||||
mRfb->canHandleNewFBSize = false;
|
|
||||||
|
|
||||||
(*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData);
|
(*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData);
|
||||||
(*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str());
|
(*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str());
|
||||||
|
@ -150,16 +164,17 @@ int VncCamera::PrimeCapture() {
|
||||||
mRfb->GetCredential = GetCredentialsCallback;
|
mRfb->GetCredential = GetCredentialsCallback;
|
||||||
|
|
||||||
mRfb->programName = "Zoneminder VNC Monitor";
|
mRfb->programName = "Zoneminder VNC Monitor";
|
||||||
|
if ( mRfb->serverHost ) free(mRfb->serverHost);
|
||||||
mRfb->serverHost = strdup(mHost.c_str());
|
mRfb->serverHost = strdup(mHost.c_str());
|
||||||
mRfb->serverPort = atoi(mPort.c_str());
|
mRfb->serverPort = atoi(mPort.c_str());
|
||||||
}
|
}
|
||||||
if ( ! (*rfbInitClient_f)(mRfb, 0, nullptr) ) {
|
if (!(*rfbInitClient_f)(mRfb, 0, nullptr)) {
|
||||||
/* IF rfbInitClient fails, it calls rdbClientCleanup which will free mRfb */
|
/* IF rfbInitClient fails, it calls rdbClientCleanup which will free mRfb */
|
||||||
Warning("Failed to Prime capture from %s", mHost.c_str());
|
Warning("Failed to Prime capture from %s", mHost.c_str());
|
||||||
mRfb = nullptr;
|
mRfb = nullptr;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if ( ((unsigned int)mRfb->width != width) or ((unsigned int)mRfb->height != height) ) {
|
if (((unsigned int)mRfb->width != width) or ((unsigned int)mRfb->height != height)) {
|
||||||
Warning("Specified dimensions do not match screen size monitor: (%dx%d) != vnc: (%dx%d)",
|
Warning("Specified dimensions do not match screen size monitor: (%dx%d) != vnc: (%dx%d)",
|
||||||
width, height, mRfb->width, mRfb->height);
|
width, height, mRfb->width, mRfb->height);
|
||||||
}
|
}
|
||||||
|
@ -170,9 +185,9 @@ int VncCamera::PrimeCapture() {
|
||||||
|
|
||||||
int VncCamera::PreCapture() {
|
int VncCamera::PreCapture() {
|
||||||
int rc = (*WaitForMessage_f)(mRfb, 500);
|
int rc = (*WaitForMessage_f)(mRfb, 500);
|
||||||
if ( rc < 0 ) {
|
if (rc < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if ( !rc ) {
|
} else if (!rc) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
rfbBool res = (*HandleRFBServerMessage_f)(mRfb);
|
rfbBool res = (*HandleRFBServerMessage_f)(mRfb);
|
||||||
|
@ -181,12 +196,12 @@ int VncCamera::PreCapture() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int VncCamera::Capture(ZMPacket &zm_packet) {
|
int VncCamera::Capture(ZMPacket &zm_packet) {
|
||||||
if ( !mVncData.buffer ) {
|
if (!mVncData.buffer) {
|
||||||
Debug(1, "No buffer");
|
Debug(1, "No buffer");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( !zm_packet.image ) {
|
if (!zm_packet.image) {
|
||||||
Debug(1, "Allocating image %dx%d %dcolours = %d", width, height, colours, pixels);
|
Debug(1, "Allocating image %dx%d %dcolours = %d", width, height, colours, colours*pixels);
|
||||||
zm_packet.image = new Image(width, height, colours, subpixelorder);
|
zm_packet.image = new Image(width, height, colours, subpixelorder);
|
||||||
}
|
}
|
||||||
zm_packet.keyframe = 1;
|
zm_packet.keyframe = 1;
|
||||||
|
@ -194,9 +209,20 @@ int VncCamera::Capture(ZMPacket &zm_packet) {
|
||||||
zm_packet.packet.stream_index = mVideoStreamId;
|
zm_packet.packet.stream_index = mVideoStreamId;
|
||||||
|
|
||||||
uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder);
|
uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder);
|
||||||
|
Debug(1, "scale src %p, %d, dest %p %d %d %dx%d %dx%d", mVncData.buffer,
|
||||||
|
mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4,
|
||||||
|
directbuffer,
|
||||||
|
width * height * colours,
|
||||||
|
mImgPixFmt,
|
||||||
|
mRfb->si.framebufferWidth,
|
||||||
|
mRfb->si.framebufferHeight,
|
||||||
|
width,
|
||||||
|
height);
|
||||||
|
|
||||||
int rc = scale.Convert(
|
int rc = scale.Convert(
|
||||||
mVncData.buffer,
|
mVncData.buffer,
|
||||||
mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4,
|
mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4,
|
||||||
|
//SWScale::GetBufferSize(AV_PIX_FMT_RGBA, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight),
|
||||||
directbuffer,
|
directbuffer,
|
||||||
width * height * colours,
|
width * height * colours,
|
||||||
AV_PIX_FMT_RGBA,
|
AV_PIX_FMT_RGBA,
|
||||||
|
|
|
@ -26,7 +26,6 @@ class VncCamera : public Camera {
|
||||||
protected:
|
protected:
|
||||||
rfbClient *mRfb;
|
rfbClient *mRfb;
|
||||||
VncPrivateData mVncData;
|
VncPrivateData mVncData;
|
||||||
int mBufferSize;
|
|
||||||
SWScale scale;
|
SWScale scale;
|
||||||
AVPixelFormat mImgPixFmt;
|
AVPixelFormat mImgPixFmt;
|
||||||
std::string mHost;
|
std::string mHost;
|
||||||
|
@ -48,7 +47,7 @@ public:
|
||||||
int p_hue,
|
int p_hue,
|
||||||
int p_colour,
|
int p_colour,
|
||||||
bool p_capture,
|
bool p_capture,
|
||||||
bool p_record_audio );
|
bool p_record_audio);
|
||||||
|
|
||||||
~VncCamera();
|
~VncCamera();
|
||||||
|
|
||||||
|
|
|
@ -341,7 +341,7 @@ LocalCamera::LocalCamera(
|
||||||
Debug(2, "V4L support enabled, using V4L%d api", v4l_version);
|
Debug(2, "V4L support enabled, using V4L%d api", v4l_version);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !last_camera || channel != last_camera->channel ) {
|
if ( (!last_camera) || (channel != last_camera->channel) ) {
|
||||||
// We are the first, or only, input that uses this channel
|
// We are the first, or only, input that uses this channel
|
||||||
channel_prime = true;
|
channel_prime = true;
|
||||||
channel_index = channel_count++;
|
channel_index = channel_count++;
|
||||||
|
@ -383,19 +383,19 @@ LocalCamera::LocalCamera(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( capture ) {
|
if (capture) {
|
||||||
if ( last_camera ) {
|
if (last_camera) {
|
||||||
if ( (p_method == "v4l2" && v4l_version != 2) || (p_method == "v4l1" && v4l_version != 1) )
|
if ((p_method == "v4l2" && v4l_version != 2) || (p_method == "v4l1" && v4l_version != 1))
|
||||||
Fatal( "Different Video For Linux version used for monitors sharing same device" );
|
Fatal("Different Video For Linux version used for monitors sharing same device");
|
||||||
|
|
||||||
if ( standard != last_camera->standard )
|
if (standard != last_camera->standard)
|
||||||
Warning( "Different video standards defined for monitors sharing same device, results may be unpredictable or completely wrong" );
|
Warning("Different video standards defined for monitors sharing same device, results may be unpredictable or completely wrong");
|
||||||
|
|
||||||
if ( palette != last_camera->palette )
|
if (palette != last_camera->palette)
|
||||||
Warning( "Different video palettes defined for monitors sharing same device, results may be unpredictable or completely wrong" );
|
Warning("Different video palettes defined for monitors sharing same device, results may be unpredictable or completely wrong");
|
||||||
|
|
||||||
if ( width != last_camera->width || height != last_camera->height )
|
if (width != last_camera->width or height != last_camera->height)
|
||||||
Warning( "Different capture sizes defined for monitors sharing same device, results may be unpredictable or completely wrong" );
|
Warning("Different capture sizes defined for monitors sharing same device, results may be unpredictable or completely wrong");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LIBSWSCALE
|
#if HAVE_LIBSWSCALE
|
||||||
|
@ -677,7 +677,8 @@ LocalCamera::LocalCamera(
|
||||||
imgConversionContext = nullptr;
|
imgConversionContext = nullptr;
|
||||||
} // end if capture and conversion_tye == swscale
|
} // end if capture and conversion_tye == swscale
|
||||||
#endif
|
#endif
|
||||||
get_VideoStream();
|
if ( capture and device_prime )
|
||||||
|
Initialise();
|
||||||
} // end LocalCamera::LocalCamera
|
} // end LocalCamera::LocalCamera
|
||||||
|
|
||||||
LocalCamera::~LocalCamera() {
|
LocalCamera::~LocalCamera() {
|
||||||
|
@ -1974,9 +1975,9 @@ int LocalCamera::Contrast( int p_contrast ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
int LocalCamera::PrimeCapture() {
|
int LocalCamera::PrimeCapture() {
|
||||||
if ( primed ) return 1;
|
get_VideoStream();
|
||||||
|
if ( !device_prime )
|
||||||
Initialise();
|
return 1;
|
||||||
|
|
||||||
Debug(2, "Priming capture");
|
Debug(2, "Priming capture");
|
||||||
#if ZM_HAS_V4L2
|
#if ZM_HAS_V4L2
|
||||||
|
@ -1994,8 +1995,10 @@ int LocalCamera::PrimeCapture() {
|
||||||
vid_buf.memory = v4l2_data.reqbufs.memory;
|
vid_buf.memory = v4l2_data.reqbufs.memory;
|
||||||
vid_buf.index = frame;
|
vid_buf.index = frame;
|
||||||
|
|
||||||
if ( vidioctl(vid_fd, VIDIOC_QBUF, &vid_buf) < 0 )
|
if (vidioctl(vid_fd, VIDIOC_QBUF, &vid_buf) < 0) {
|
||||||
Fatal("Failed to queue buffer %d: %s", frame, strerror(errno));
|
Error("Failed to queue buffer %d: %s", frame, strerror(errno));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
v4l2_data.bufptr = nullptr;
|
v4l2_data.bufptr = nullptr;
|
||||||
|
|
||||||
|
@ -2003,9 +2006,11 @@ int LocalCamera::PrimeCapture() {
|
||||||
//enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
//enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||||
//enum v4l2_buf_type type = v4l2_data.fmt.type;
|
//enum v4l2_buf_type type = v4l2_data.fmt.type;
|
||||||
enum v4l2_buf_type type = (v4l2_buf_type)v4l2_data.fmt.type;
|
enum v4l2_buf_type type = (v4l2_buf_type)v4l2_data.fmt.type;
|
||||||
if ( vidioctl(vid_fd, VIDIOC_STREAMON, &type) < 0 )
|
if (vidioctl(vid_fd, VIDIOC_STREAMON, &type) < 0) {
|
||||||
Fatal("Failed to start capture stream: %s", strerror(errno));
|
Error("Failed to start capture stream: %s", strerror(errno));
|
||||||
}
|
return -1;
|
||||||
|
}
|
||||||
|
} // end if v4l_version == 2
|
||||||
#endif // ZM_HAS_V4L2
|
#endif // ZM_HAS_V4L2
|
||||||
#if ZM_HAS_V4L1
|
#if ZM_HAS_V4L1
|
||||||
if ( v4l_version == 1 ) {
|
if ( v4l_version == 1 ) {
|
||||||
|
@ -2018,8 +2023,6 @@ int LocalCamera::PrimeCapture() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // ZM_HAS_V4L1
|
#endif // ZM_HAS_V4L1
|
||||||
mVideoStreamId = 0;
|
|
||||||
primed = true;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} // end LocalCamera::PrimeCapture
|
} // end LocalCamera::PrimeCapture
|
||||||
|
@ -2052,7 +2055,6 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
|
||||||
memset(&vid_buf, 0, sizeof(vid_buf));
|
memset(&vid_buf, 0, sizeof(vid_buf));
|
||||||
|
|
||||||
vid_buf.type = v4l2_data.fmt.type;
|
vid_buf.type = v4l2_data.fmt.type;
|
||||||
//vid_buf.memory = V4L2_MEMORY_MMAP;
|
|
||||||
vid_buf.memory = v4l2_data.reqbufs.memory;
|
vid_buf.memory = v4l2_data.reqbufs.memory;
|
||||||
|
|
||||||
Debug(3, "Capturing %d frames", captures_per_frame);
|
Debug(3, "Capturing %d frames", captures_per_frame);
|
||||||
|
@ -2120,6 +2122,65 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
|
||||||
buffer = v4l1_data.bufptr+v4l1_data.frames.offsets[capture_frame];
|
buffer = v4l1_data.bufptr+v4l1_data.frames.offsets[capture_frame];
|
||||||
}
|
}
|
||||||
#endif // ZM_HAS_V4L1
|
#endif // ZM_HAS_V4L1
|
||||||
|
#if ZM_HAS_V4L2
|
||||||
|
if ( v4l_version == 2 ) {
|
||||||
|
if ( channel_count > 1 ) {
|
||||||
|
int next_channel = (channel_index+1)%channel_count;
|
||||||
|
Debug(3, "Switching video source to %d", channels[next_channel]);
|
||||||
|
if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channels[next_channel]) < 0 ) {
|
||||||
|
Error("Failed to set camera source %d: %s", channels[next_channel], strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
v4l2_std_id stdId = standards[next_channel];
|
||||||
|
if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) {
|
||||||
|
Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( v4l2_data.bufptr ) {
|
||||||
|
Debug(3, "Requeueing buffer %d", v4l2_data.bufptr->index);
|
||||||
|
if ( vidioctl(vid_fd, VIDIOC_QBUF, v4l2_data.bufptr) < 0 ) {
|
||||||
|
Error("Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Error("Unable to requeue buffer due to not v4l2_data")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if ZM_HAS_V4L1
|
||||||
|
else
|
||||||
|
#endif // ZM_HAS_V4L1
|
||||||
|
#endif // ZM_HAS_V4L2
|
||||||
|
#if ZM_HAS_V4L1
|
||||||
|
if ( v4l_version == 1 ) {
|
||||||
|
if ( channel_count > 1 ) {
|
||||||
|
Debug(3, "Switching video source");
|
||||||
|
int next_channel = (channel_index+1)%channel_count;
|
||||||
|
struct video_channel vid_src;
|
||||||
|
memset(&vid_src, 0, sizeof(vid_src));
|
||||||
|
vid_src.channel = channel;
|
||||||
|
if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) {
|
||||||
|
Error("Failed to get camera source %d: %s", channel, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
vid_src.channel = channels[next_channel];
|
||||||
|
vid_src.norm = standards[next_channel];
|
||||||
|
vid_src.flags = 0;
|
||||||
|
vid_src.type = VIDEO_TYPE_CAMERA;
|
||||||
|
if ( ioctl(vid_fd, VIDIOCSCHAN, &vid_src) < 0 ) {
|
||||||
|
Error("Failed to set camera source %d: %s", channel, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Debug(3, "Requeueing frame %d", v4l1_data.active_frame);
|
||||||
|
if ( ioctl(vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame]) < 0 ) {
|
||||||
|
Error("Capture failure for frame %d: %s", v4l1_data.active_frame, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
v4l1_data.active_frame = (v4l1_data.active_frame+1)%v4l1_data.frames.frames;
|
||||||
|
}
|
||||||
|
#endif // ZM_HAS_V4L1
|
||||||
|
|
||||||
} /* prime capture */
|
} /* prime capture */
|
||||||
|
|
||||||
|
@ -2185,69 +2246,8 @@ int LocalCamera::Capture(ZMPacket &zm_packet) {
|
||||||
} // end int LocalCamera::Capture()
|
} // end int LocalCamera::Capture()
|
||||||
|
|
||||||
int LocalCamera::PostCapture() {
|
int LocalCamera::PostCapture() {
|
||||||
|
return 1;
|
||||||
Debug(4, "Post-capturing");
|
Debug(4, "Post-capturing");
|
||||||
// Requeue the buffer unless we need to switch or are a duplicate camera on a channel
|
|
||||||
if ( channel_count > 1 || channel_prime ) {
|
|
||||||
#if ZM_HAS_V4L2
|
|
||||||
if ( v4l_version == 2 ) {
|
|
||||||
if ( channel_count > 1 ) {
|
|
||||||
int next_channel = (channel_index+1)%channel_count;
|
|
||||||
Debug(3, "Switching video source to %d", channels[next_channel]);
|
|
||||||
if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channels[next_channel]) < 0 ) {
|
|
||||||
Error("Failed to set camera source %d: %s", channels[next_channel], strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
v4l2_std_id stdId = standards[next_channel];
|
|
||||||
if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) {
|
|
||||||
Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( v4l2_data.bufptr ) {
|
|
||||||
Debug(3, "Requeueing buffer %d", v4l2_data.bufptr->index);
|
|
||||||
if ( vidioctl(vid_fd, VIDIOC_QBUF, v4l2_data.bufptr) < 0 ) {
|
|
||||||
Error("Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Error("Unable to requeue buffer due to not v4l2_data")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#if ZM_HAS_V4L1
|
|
||||||
else
|
|
||||||
#endif // ZM_HAS_V4L1
|
|
||||||
#endif // ZM_HAS_V4L2
|
|
||||||
#if ZM_HAS_V4L1
|
|
||||||
if ( v4l_version == 1 ) {
|
|
||||||
if ( channel_count > 1 ) {
|
|
||||||
Debug(3, "Switching video source");
|
|
||||||
int next_channel = (channel_index+1)%channel_count;
|
|
||||||
struct video_channel vid_src;
|
|
||||||
memset(&vid_src, 0, sizeof(vid_src));
|
|
||||||
vid_src.channel = channel;
|
|
||||||
if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) {
|
|
||||||
Error("Failed to get camera source %d: %s", channel, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
vid_src.channel = channels[next_channel];
|
|
||||||
vid_src.norm = standards[next_channel];
|
|
||||||
vid_src.flags = 0;
|
|
||||||
vid_src.type = VIDEO_TYPE_CAMERA;
|
|
||||||
if ( ioctl(vid_fd, VIDIOCSCHAN, &vid_src) < 0 ) {
|
|
||||||
Error("Failed to set camera source %d: %s", channel, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Debug(3, "Requeueing frame %d", v4l1_data.active_frame);
|
|
||||||
if ( ioctl(vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame]) < 0 ) {
|
|
||||||
Error("Capture failure for frame %d: %s", v4l1_data.active_frame, strerror(errno));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
v4l1_data.active_frame = (v4l1_data.active_frame+1)%v4l1_data.frames.frames;
|
|
||||||
}
|
|
||||||
#endif // ZM_HAS_V4L1
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,7 @@
|
||||||
|
|
||||||
#include "zm_db.h"
|
#include "zm_db.h"
|
||||||
#include "zm_utils.h"
|
#include "zm_utils.h"
|
||||||
#include <csignal>
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstring>
|
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -31,6 +29,11 @@
|
||||||
#ifdef __FreeBSD__
|
#ifdef __FreeBSD__
|
||||||
#include <sys/thr.h>
|
#include <sys/thr.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <cerrno>
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
|
||||||
bool Logger::smInitialised = false;
|
bool Logger::smInitialised = false;
|
||||||
Logger *Logger::smInstance = nullptr;
|
Logger *Logger::smInstance = nullptr;
|
||||||
|
@ -56,16 +59,15 @@ Logger::Logger() :
|
||||||
mEffectiveLevel(NOLOG),
|
mEffectiveLevel(NOLOG),
|
||||||
mDbConnected(false),
|
mDbConnected(false),
|
||||||
mLogPath(staticConfig.PATH_LOGS.c_str()),
|
mLogPath(staticConfig.PATH_LOGS.c_str()),
|
||||||
//mLogFile( mLogPath+"/"+mId+".log" ),
|
// mLogFile( mLogPath+"/"+mId+".log" ),
|
||||||
mLogFileFP(nullptr),
|
mLogFileFP(nullptr),
|
||||||
mHasTerminal(false),
|
mHasTerminal(false),
|
||||||
mFlush(false) {
|
mFlush(false) {
|
||||||
|
if (smInstance) {
|
||||||
if ( smInstance ) {
|
|
||||||
Panic("Attempt to create second instance of Logger class");
|
Panic("Attempt to create second instance of Logger class");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !smInitialised ) {
|
if (!smInitialised) {
|
||||||
smCodes[INFO] = "INF";
|
smCodes[INFO] = "INF";
|
||||||
smCodes[WARNING] = "WAR";
|
smCodes[WARNING] = "WAR";
|
||||||
smCodes[ERROR] = "ERR";
|
smCodes[ERROR] = "ERR";
|
||||||
|
@ -80,16 +82,16 @@ Logger::Logger() :
|
||||||
smSyslogPriorities[PANIC] = LOG_ERR;
|
smSyslogPriorities[PANIC] = LOG_ERR;
|
||||||
|
|
||||||
char code[4] = "";
|
char code[4] = "";
|
||||||
for ( int i = DEBUG1; i <= DEBUG9; i++ ) {
|
for (int i = DEBUG1; i <= DEBUG9; i++) {
|
||||||
snprintf(code, sizeof(code), "DB%d", i);
|
snprintf(code, sizeof(code), "DB%d", i);
|
||||||
smCodes[i] = code;
|
smCodes[i] = code;
|
||||||
smSyslogPriorities[i] = LOG_DEBUG;
|
smSyslogPriorities[i] = LOG_DEBUG;
|
||||||
}
|
}
|
||||||
|
|
||||||
smInitialised = true;
|
smInitialised = true;
|
||||||
}
|
} // end if ! smInitialised
|
||||||
|
|
||||||
if ( fileno(stderr) && isatty(fileno(stderr)) ) {
|
if (fileno(stderr) && isatty(fileno(stderr))) {
|
||||||
mHasTerminal = true;
|
mHasTerminal = true;
|
||||||
mTerminalLevel = WARNING;
|
mTerminalLevel = WARNING;
|
||||||
}
|
}
|
||||||
|
@ -100,14 +102,6 @@ Logger::~Logger() {
|
||||||
smCodes.clear();
|
smCodes.clear();
|
||||||
smSyslogPriorities.clear();
|
smSyslogPriorities.clear();
|
||||||
smInitialised = false;
|
smInitialised = false;
|
||||||
#if 0
|
|
||||||
for ( StringMap::iterator itr = smCodes.begin(); itr != smCodes.end(); itr ++ ) {
|
|
||||||
smCodes.erase( itr );
|
|
||||||
}
|
|
||||||
for ( IntMap::iterator itr = smSyslogPriorities.begin(); itr != smSyslogPriorities.end(); itr ++ ) {
|
|
||||||
smSyslogPriorities.erase(itr);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::initialise(const std::string &id, const Options &options) {
|
void Logger::initialise(const std::string &id, const Options &options) {
|
||||||
|
@ -184,7 +178,7 @@ void Logger::initialise(const std::string &id, const Options &options) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // end foreach target
|
} // end foreach target
|
||||||
} else {
|
} else {
|
||||||
// if we don't have debug turned on, then the max effective log level is INFO
|
// if we don't have debug turned on, then the max effective log level is INFO
|
||||||
if ( tempSyslogLevel > INFO ) tempSyslogLevel = INFO;
|
if ( tempSyslogLevel > INFO ) tempSyslogLevel = INFO;
|
||||||
|
@ -192,7 +186,7 @@ void Logger::initialise(const std::string &id, const Options &options) {
|
||||||
if ( tempTerminalLevel > INFO ) tempTerminalLevel = INFO;
|
if ( tempTerminalLevel > INFO ) tempTerminalLevel = INFO;
|
||||||
if ( tempDatabaseLevel > INFO ) tempDatabaseLevel = INFO;
|
if ( tempDatabaseLevel > INFO ) tempDatabaseLevel = INFO;
|
||||||
if ( tempLevel > INFO ) tempLevel = INFO;
|
if ( tempLevel > INFO ) tempLevel = INFO;
|
||||||
} // end if config.log_debug
|
} // end if config.log_debug
|
||||||
|
|
||||||
logFile(tempLogFile);
|
logFile(tempLogFile);
|
||||||
|
|
||||||
|
@ -354,11 +348,11 @@ Logger::Level Logger::databaseLevel(Logger::Level databaseLevel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Level Logger::fileLevel(Logger::Level fileLevel) {
|
Logger::Level Logger::fileLevel(Logger::Level fileLevel) {
|
||||||
if ( fileLevel > NOOPT ) {
|
if (fileLevel > NOOPT) {
|
||||||
fileLevel = limit(fileLevel);
|
fileLevel = limit(fileLevel);
|
||||||
// Always close, because we may have changed file names
|
// Always close, because we may have changed file names
|
||||||
if ( mFileLevel > NOLOG )
|
if (mFileLevel > NOLOG)
|
||||||
closeFile();
|
closeFile();
|
||||||
mFileLevel = fileLevel;
|
mFileLevel = fileLevel;
|
||||||
// Don't try to open it here because it will create the log file even if we never write to it.
|
// Don't try to open it here because it will create the log file even if we never write to it.
|
||||||
}
|
}
|
||||||
|
@ -366,13 +360,13 @@ Logger::Level Logger::fileLevel(Logger::Level fileLevel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Level Logger::syslogLevel(Logger::Level syslogLevel) {
|
Logger::Level Logger::syslogLevel(Logger::Level syslogLevel) {
|
||||||
if ( syslogLevel > NOOPT ) {
|
if (syslogLevel > NOOPT) {
|
||||||
syslogLevel = limit(syslogLevel);
|
syslogLevel = limit(syslogLevel);
|
||||||
if ( mSyslogLevel != syslogLevel ) {
|
if (mSyslogLevel != syslogLevel) {
|
||||||
if ( mSyslogLevel > NOLOG )
|
if (mSyslogLevel > NOLOG)
|
||||||
closeSyslog();
|
closeSyslog();
|
||||||
mSyslogLevel = syslogLevel;
|
mSyslogLevel = syslogLevel;
|
||||||
if ( mSyslogLevel > NOLOG )
|
if (mSyslogLevel > NOLOG)
|
||||||
openSyslog();
|
openSyslog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -382,31 +376,31 @@ Logger::Level Logger::syslogLevel(Logger::Level syslogLevel) {
|
||||||
void Logger::logFile(const std::string &logFile) {
|
void Logger::logFile(const std::string &logFile) {
|
||||||
bool addLogPid = false;
|
bool addLogPid = false;
|
||||||
std::string tempLogFile = logFile;
|
std::string tempLogFile = logFile;
|
||||||
if ( tempLogFile[tempLogFile.length()-1] == '+' ) {
|
if (tempLogFile[tempLogFile.length()-1] == '+') {
|
||||||
tempLogFile.resize(tempLogFile.length()-1);
|
tempLogFile.resize(tempLogFile.length()-1);
|
||||||
addLogPid = true;
|
addLogPid = true;
|
||||||
}
|
}
|
||||||
if ( addLogPid )
|
if (addLogPid)
|
||||||
mLogFile = stringtf("%s.%05d", tempLogFile.c_str(), getpid());
|
mLogFile = stringtf("%s.%05d", tempLogFile.c_str(), getpid());
|
||||||
else
|
else
|
||||||
mLogFile = tempLogFile;
|
mLogFile = tempLogFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::openFile() {
|
void Logger::openFile() {
|
||||||
if ( mLogFile.size() ) {
|
if (mLogFile.size()) {
|
||||||
if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == nullptr ) {
|
if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == nullptr ) {
|
||||||
mFileLevel = NOLOG;
|
mFileLevel = NOLOG;
|
||||||
Error("fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno));
|
Error("fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
puts("Called Logger::openFile() without a filename");
|
puts("Called Logger::openFile() without a filename");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::closeFile() {
|
void Logger::closeFile() {
|
||||||
if ( mLogFileFP ) {
|
if (mLogFileFP) {
|
||||||
fflush(mLogFileFP);
|
fflush(mLogFileFP);
|
||||||
if ( fclose(mLogFileFP) < 0 ) {
|
if (fclose(mLogFileFP) < 0) {
|
||||||
mLogFileFP = nullptr;
|
mLogFileFP = nullptr;
|
||||||
Error("fclose(), error = %s", strerror(errno));
|
Error("fclose(), error = %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
@ -415,7 +409,6 @@ void Logger::closeFile() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::closeDatabase() {
|
void Logger::closeDatabase() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::openSyslog() {
|
void Logger::openSyslog() {
|
||||||
|
@ -427,24 +420,21 @@ void Logger::closeSyslog() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::logPrint(bool hex, const char * const filepath, const int line, const int level, const char *fstring, ...) {
|
void Logger::logPrint(bool hex, const char * const filepath, const int line, const int level, const char *fstring, ...) {
|
||||||
|
if (level > mEffectiveLevel) return;
|
||||||
if ( level > mEffectiveLevel ) {
|
if (level < PANIC || level > DEBUG9)
|
||||||
return;
|
Panic("Invalid logger level %d", level);
|
||||||
}
|
|
||||||
|
|
||||||
log_mutex.lock();
|
log_mutex.lock();
|
||||||
|
// Can we save some cycles by having these as members and not allocate them on the fly? I think so.
|
||||||
char timeString[64];
|
char timeString[64];
|
||||||
char logString[8192];
|
char logString[8192];
|
||||||
va_list argPtr;
|
va_list argPtr;
|
||||||
struct timeval timeVal;
|
struct timeval timeVal;
|
||||||
|
|
||||||
char *filecopy = strdup(filepath);
|
const char *base = strrchr(filepath, '/');
|
||||||
const char * const file = basename(filecopy);
|
const char *file = base ? base+1 : filepath;
|
||||||
const char *classString = smCodes[level].c_str();
|
const char *classString = smCodes[level].c_str();
|
||||||
|
|
||||||
if ( level < PANIC || level > DEBUG9 )
|
|
||||||
Panic("Invalid logger level %d", level);
|
|
||||||
|
|
||||||
gettimeofday(&timeVal, nullptr);
|
gettimeofday(&timeVal, nullptr);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
@ -473,12 +463,12 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con
|
||||||
#else
|
#else
|
||||||
#ifdef HAVE_SYSCALL
|
#ifdef HAVE_SYSCALL
|
||||||
#ifdef __FreeBSD_kernel__
|
#ifdef __FreeBSD_kernel__
|
||||||
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
|
if ((syscall(SYS_thr_self, &tid)) < 0) // Thread/Process id
|
||||||
|
|
||||||
# else
|
# else
|
||||||
// SOLARIS doesn't have SYS_gettid; don't assume
|
// SOLARIS doesn't have SYS_gettid; don't assume
|
||||||
#ifdef SYS_gettid
|
#ifdef SYS_gettid
|
||||||
if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id
|
if ((tid = syscall(SYS_gettid)) < 0) // Thread/Process id
|
||||||
#endif // SYS_gettid
|
#endif // SYS_gettid
|
||||||
#endif
|
#endif
|
||||||
#endif // HAVE_SYSCALL
|
#endif // HAVE_SYSCALL
|
||||||
|
@ -512,75 +502,63 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con
|
||||||
char *syslogEnd = logPtr;
|
char *syslogEnd = logPtr;
|
||||||
strncpy(logPtr, "]\n", sizeof(logString)-(logPtr-logString));
|
strncpy(logPtr, "]\n", sizeof(logString)-(logPtr-logString));
|
||||||
|
|
||||||
if ( level <= mTerminalLevel ) {
|
if (level <= mTerminalLevel) {
|
||||||
puts(logString);
|
puts(logString);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( level <= mFileLevel ) {
|
if (level <= mFileLevel) {
|
||||||
if ( !mLogFileFP ) {
|
if (!mLogFileFP) {
|
||||||
// We do this here so that we only create the file if we ever write to it.
|
// FIXME unlocking here is a problem. Another thread could sneak in.
|
||||||
log_mutex.unlock();
|
log_mutex.unlock();
|
||||||
|
// We do this here so that we only create the file if we ever write to it.
|
||||||
openFile();
|
openFile();
|
||||||
log_mutex.lock();
|
log_mutex.lock();
|
||||||
}
|
}
|
||||||
if ( mLogFileFP ) {
|
if (mLogFileFP) {
|
||||||
fputs(logString, mLogFileFP);
|
fputs(logString, mLogFileFP);
|
||||||
if ( mFlush )
|
if (mFlush) fflush(mLogFileFP);
|
||||||
fflush(mLogFileFP);
|
|
||||||
} else {
|
} else {
|
||||||
puts("Logging to file, but failed to open it\n");
|
puts("Logging to file, but failed to open it\n");
|
||||||
}
|
}
|
||||||
} // end if level <= mFileLevel
|
} // end if level <= mFileLevel
|
||||||
|
|
||||||
if ( level <= mDatabaseLevel ) {
|
if (level <= mDatabaseLevel) {
|
||||||
if (db_mutex.try_lock_for(1)) {
|
if (zmDbConnected) {
|
||||||
char escapedString[(strlen(syslogStart)*2)+1];
|
int syslogSize = syslogEnd-syslogStart;
|
||||||
mysql_real_escape_string(&dbconn, escapedString, syslogStart, strlen(syslogStart));
|
char escapedString[(syslogSize*2)+1];
|
||||||
|
mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize);
|
||||||
|
|
||||||
char sql[ZM_SQL_MED_BUFSIZ];
|
std::string sql_string = stringtf(
|
||||||
snprintf(sql, sizeof(sql),
|
|
||||||
"INSERT INTO `Logs` "
|
"INSERT INTO `Logs` "
|
||||||
"( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )"
|
"( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )"
|
||||||
" VALUES "
|
" VALUES "
|
||||||
"( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )",
|
"( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )",
|
||||||
timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line
|
timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line
|
||||||
);
|
);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
dbQueue.push(sql_string);
|
||||||
Level tempDatabaseLevel = mDatabaseLevel;
|
|
||||||
databaseLevel(NOLOG);
|
|
||||||
Error("Can't insert log entry: sql(%s) error(%s)", sql, mysql_error(&dbconn));
|
|
||||||
databaseLevel(tempDatabaseLevel);
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
} else {
|
} else {
|
||||||
Level tempDatabaseLevel = mDatabaseLevel;
|
puts("Db is closed");
|
||||||
databaseLevel(NOLOG);
|
|
||||||
Error("Can't insert log entry since the DB lock could not be obtained. Message: %s", syslogStart);
|
|
||||||
databaseLevel(tempDatabaseLevel);
|
|
||||||
}
|
}
|
||||||
} // end if level <= mDatabaseLevel
|
} // end if level <= mDatabaseLevel
|
||||||
|
|
||||||
if ( level <= mSyslogLevel ) {
|
if (level <= mSyslogLevel) {
|
||||||
*syslogEnd = '\0';
|
*syslogEnd = '\0';
|
||||||
syslog(smSyslogPriorities[level], "%s [%s] [%s]", classString, mId.c_str(), syslogStart);
|
syslog(smSyslogPriorities[level], "%s [%s] [%s]", classString, mId.c_str(), syslogStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(filecopy);
|
|
||||||
log_mutex.unlock();
|
log_mutex.unlock();
|
||||||
if ( level <= FATAL ) {
|
if (level <= FATAL) {
|
||||||
logTerm();
|
logTerm();
|
||||||
zmDbClose();
|
zmDbClose();
|
||||||
if ( level <= PANIC )
|
if (level <= PANIC) abort();
|
||||||
abort();
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
} // end logPrint
|
} // end logPrint
|
||||||
|
|
||||||
void logInit(const char *name, const Logger::Options &options) {
|
void logInit(const char *name, const Logger::Options &options) {
|
||||||
if ( Logger::smInstance ) {
|
if (Logger::smInstance) {
|
||||||
delete Logger::smInstance;
|
delete Logger::smInstance;
|
||||||
Logger::smInstance = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::smInstance = new Logger();
|
Logger::smInstance = new Logger();
|
||||||
|
@ -588,7 +566,7 @@ void logInit(const char *name, const Logger::Options &options) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void logTerm() {
|
void logTerm() {
|
||||||
if ( Logger::smInstance ) {
|
if (Logger::smInstance) {
|
||||||
delete Logger::smInstance;
|
delete Logger::smInstance;
|
||||||
Logger::smInstance = nullptr;
|
Logger::smInstance = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,18 +153,12 @@ public:
|
||||||
void terminate();
|
void terminate();
|
||||||
|
|
||||||
const std::string &id(const std::string &id);
|
const std::string &id(const std::string &id);
|
||||||
const std::string &id() const {
|
const std::string &id() const { return mId; }
|
||||||
return mId;
|
|
||||||
}
|
|
||||||
|
|
||||||
Level level() const {
|
Level level() const { return mLevel; }
|
||||||
return mLevel;
|
|
||||||
}
|
|
||||||
Level level(Level=NOOPT);
|
Level level(Level=NOOPT);
|
||||||
|
|
||||||
bool debugOn() const {
|
bool debugOn() const { return mEffectiveLevel >= DEBUG1; }
|
||||||
return mEffectiveLevel >= DEBUG1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Level terminalLevel(Level=NOOPT);
|
Level terminalLevel(Level=NOOPT);
|
||||||
Level databaseLevel(Level=NOOPT);
|
Level databaseLevel(Level=NOOPT);
|
||||||
|
|
|
@ -651,6 +651,7 @@ void Monitor::LoadCamera() {
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LOCAL: {
|
case LOCAL: {
|
||||||
|
#if ZM_HAS_V4L
|
||||||
int extras = (deinterlacing >> 24) & 0xff;
|
int extras = (deinterlacing >> 24) & 0xff;
|
||||||
|
|
||||||
camera = ZM::make_unique<LocalCamera>(this,
|
camera = ZM::make_unique<LocalCamera>(this,
|
||||||
|
@ -672,6 +673,9 @@ void Monitor::LoadCamera() {
|
||||||
record_audio,
|
record_audio,
|
||||||
extras
|
extras
|
||||||
);
|
);
|
||||||
|
#else
|
||||||
|
Fatal("Not compiled with local v4l camera support");
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case REMOTE: {
|
case REMOTE: {
|
||||||
|
@ -1071,11 +1075,6 @@ Monitor::~Monitor() {
|
||||||
Close();
|
Close();
|
||||||
|
|
||||||
if (mem_ptr != nullptr) {
|
if (mem_ptr != nullptr) {
|
||||||
std::lock_guard<std::mutex> lck(event_mutex);
|
|
||||||
if (event) {
|
|
||||||
Info("%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name, image_count, event->Id());
|
|
||||||
closeEvent();
|
|
||||||
}
|
|
||||||
if (purpose != QUERY) {
|
if (purpose != QUERY) {
|
||||||
shared_data->state = state = IDLE;
|
shared_data->state = state = IDLE;
|
||||||
shared_data->last_read_index = image_buffer_count;
|
shared_data->last_read_index = image_buffer_count;
|
||||||
|
@ -1317,25 +1316,17 @@ void Monitor::actionReload() {
|
||||||
void Monitor::actionEnable() {
|
void Monitor::actionEnable() {
|
||||||
shared_data->action |= RELOAD;
|
shared_data->action |= RELOAD;
|
||||||
|
|
||||||
db_mutex.lock();
|
char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
|
||||||
snprintf(sql, sizeof(sql), "UPDATE `Monitors` SET `Enabled` = 1 WHERE `Id` = %d", id);
|
snprintf(sql, sizeof(sql), "UPDATE `Monitors` SET `Enabled` = 1 WHERE `Id` = %d", id);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
zmDbDo(sql);
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monitor::actionDisable() {
|
void Monitor::actionDisable() {
|
||||||
shared_data->action |= RELOAD;
|
shared_data->action |= RELOAD;
|
||||||
|
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
snprintf(sql, sizeof(sql), "UPDATE `Monitors` SET `Enabled` = 0 WHERE `Id` = %d", id);
|
snprintf(sql, sizeof(sql), "UPDATE `Monitors` SET `Enabled` = 0 WHERE `Id` = %d", id);
|
||||||
db_mutex.lock();
|
zmDbDo(sql);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Monitor::actionSuspend() {
|
void Monitor::actionSuspend() {
|
||||||
|
@ -1705,7 +1696,6 @@ void Monitor::UpdateCaptureFPS() {
|
||||||
last_fps_time = now_double;
|
last_fps_time = now_double;
|
||||||
last_capture_image_count = image_count;
|
last_capture_image_count = image_count;
|
||||||
|
|
||||||
db_mutex.lock();
|
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
// The reason we update the Status as well is because if mysql restarts, the Monitor_Status table is lost,
|
// The reason we update the Status as well is because if mysql restarts, the Monitor_Status table is lost,
|
||||||
// and nothing else will update the status until zmc restarts. Since we are successfully capturing we can
|
// and nothing else will update the status until zmc restarts. Since we are successfully capturing we can
|
||||||
|
@ -1715,10 +1705,7 @@ void Monitor::UpdateCaptureFPS() {
|
||||||
"VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE "
|
"VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE "
|
||||||
"CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'",
|
"CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'",
|
||||||
id, new_capture_fps, new_capture_bandwidth, new_capture_fps, new_capture_bandwidth);
|
id, new_capture_fps, new_capture_bandwidth, new_capture_fps, new_capture_bandwidth);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
dbQueue.push(sql);
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
} // now != last_fps_time
|
} // now != last_fps_time
|
||||||
} // end if report fps
|
} // end if report fps
|
||||||
} // void Monitor::UpdateCaptureFPS()
|
} // void Monitor::UpdateCaptureFPS()
|
||||||
|
@ -1759,11 +1746,7 @@ void Monitor::UpdateAnalysisFPS() {
|
||||||
"INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf)"
|
"INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf)"
|
||||||
" ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf",
|
" ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf",
|
||||||
id, new_analysis_fps, new_analysis_fps);
|
id, new_analysis_fps, new_analysis_fps);
|
||||||
db_mutex.lock();
|
dbQueue.push(sql);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
|
||||||
}
|
|
||||||
db_mutex.unlock();
|
|
||||||
last_analysis_fps_time = now_double;
|
last_analysis_fps_time = now_double;
|
||||||
last_motion_frame_count = motion_frame_count;
|
last_motion_frame_count = motion_frame_count;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1844,7 +1827,7 @@ bool Monitor::Analyse() {
|
||||||
} // end if trigger_on
|
} // end if trigger_on
|
||||||
|
|
||||||
if ( signal_change ) {
|
if ( signal_change ) {
|
||||||
Debug(2, "Signal change");
|
Debug(2, "Signal change, new signal is %d", signal);
|
||||||
const char *signalText = "Unknown";
|
const char *signalText = "Unknown";
|
||||||
if ( !signal ) {
|
if ( !signal ) {
|
||||||
signalText = "Lost";
|
signalText = "Lost";
|
||||||
|
@ -1954,7 +1937,7 @@ bool Monitor::Analyse() {
|
||||||
// If doing record, check to see if we need to close the event or not.
|
// If doing record, check to see if we need to close the event or not.
|
||||||
|
|
||||||
if ( event ) {
|
if ( event ) {
|
||||||
Debug(2, "Have event in mocord");
|
Debug(2, "Have event %" PRIu64 " in mocord", event->Id());
|
||||||
if ( section_length
|
if ( section_length
|
||||||
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length )
|
&& ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length )
|
||||||
&& ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) )
|
&& ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) )
|
||||||
|
@ -2233,6 +2216,7 @@ bool Monitor::Analyse() {
|
||||||
shared_data->last_read_time = time(nullptr);
|
shared_data->last_read_time = time(nullptr);
|
||||||
analysis_image_count++;
|
analysis_image_count++;
|
||||||
UpdateAnalysisFPS();
|
UpdateAnalysisFPS();
|
||||||
|
packetqueue.clearPackets(snap);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} // end Monitor::Analyse
|
} // end Monitor::Analyse
|
||||||
|
@ -2338,7 +2322,7 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
||||||
for ( int i = 0; i < n_link_ids; i++ ) {
|
for ( int i = 0; i < n_link_ids; i++ ) {
|
||||||
Debug(1, "Checking linked monitor %d", link_ids[i]);
|
Debug(1, "Checking linked monitor %d", link_ids[i]);
|
||||||
|
|
||||||
db_mutex.lock();
|
std::lock_guard<std::mutex> lck(db_mutex);
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"SELECT `Id`, `Name` FROM `Monitors`"
|
"SELECT `Id`, `Name` FROM `Monitors`"
|
||||||
|
@ -2347,14 +2331,12 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
||||||
" AND `Function` != 'Monitor'"
|
" AND `Function` != 'Monitor'"
|
||||||
" AND `Enabled`=1",
|
" AND `Enabled`=1",
|
||||||
link_ids[i]);
|
link_ids[i]);
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
if (mysql_query(&dbconn, sql)) {
|
||||||
db_mutex.unlock();
|
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
MYSQL_RES *result = mysql_store_result(&dbconn);
|
||||||
db_mutex.unlock();
|
|
||||||
if ( !result ) {
|
if ( !result ) {
|
||||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||||
continue;
|
continue;
|
||||||
|
@ -2368,11 +2350,11 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) {
|
||||||
Warning("Can't link to monitor %d, invalid id, function or not enabled", link_ids[i]);
|
Warning("Can't link to monitor %d, invalid id, function or not enabled", link_ids[i]);
|
||||||
}
|
}
|
||||||
mysql_free_result(result);
|
mysql_free_result(result);
|
||||||
} // end foreach link_id
|
} // end foreach link_id
|
||||||
n_linked_monitors = count;
|
n_linked_monitors = count;
|
||||||
} // end if has link_ids
|
} // end if has link_ids
|
||||||
} // end if p_linked_monitors
|
} // end if p_linked_monitors
|
||||||
} // end void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors)
|
} // end void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors)
|
||||||
|
|
||||||
std::vector<std::shared_ptr<Monitor>> Monitor::LoadMonitors(std::string sql, Purpose purpose) {
|
std::vector<std::shared_ptr<Monitor>> Monitor::LoadMonitors(std::string sql, Purpose purpose) {
|
||||||
Debug(1, "Loading Monitors with %s", sql.c_str());
|
Debug(1, "Loading Monitors with %s", sql.c_str());
|
||||||
|
@ -2516,6 +2498,7 @@ int Monitor::Capture() {
|
||||||
Debug(2, "Queueing audio packet");
|
Debug(2, "Queueing audio packet");
|
||||||
packetqueue.queuePacket(packet);
|
packetqueue.queuePacket(packet);
|
||||||
} else {
|
} else {
|
||||||
|
Debug(4, "Not Queueing audio packet");
|
||||||
delete packet;
|
delete packet;
|
||||||
}
|
}
|
||||||
// Don't update last_write_index because that is used for live streaming
|
// Don't update last_write_index because that is used for live streaming
|
||||||
|
@ -2934,10 +2917,16 @@ int Monitor::PrimeCapture() {
|
||||||
int Monitor::PreCapture() const { return camera->PreCapture(); }
|
int Monitor::PreCapture() const { return camera->PreCapture(); }
|
||||||
int Monitor::PostCapture() const { return camera->PostCapture(); }
|
int Monitor::PostCapture() const { return camera->PostCapture(); }
|
||||||
int Monitor::Close() {
|
int Monitor::Close() {
|
||||||
|
std::lock_guard<std::mutex> lck(event_mutex);
|
||||||
|
if (event) {
|
||||||
|
Info("%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name, image_count, event->Id());
|
||||||
|
closeEvent();
|
||||||
|
}
|
||||||
if (camera) camera->Close();
|
if (camera) camera->Close();
|
||||||
packetqueue.clear();
|
packetqueue.clear();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Monitor::Orientation Monitor::getOrientation() const { return orientation; }
|
Monitor::Orientation Monitor::getOrientation() const { return orientation; }
|
||||||
|
|
||||||
// Wait for camera to get an image, and then assign it as the base reference image.
|
// Wait for camera to get an image, and then assign it as the base reference image.
|
||||||
|
|
|
@ -24,7 +24,11 @@
|
||||||
#include "zm_time.h"
|
#include "zm_time.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <glob.h>
|
#include <glob.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
const int MAX_SLEEP_USEC = 1000000; // 1 sec
|
const int MAX_SLEEP_USEC = 1000000; // 1 sec
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ class MonitorStream : public StreamBase {
|
||||||
bool checkSwapPath(const char *path, bool create_path);
|
bool checkSwapPath(const char *path, bool create_path);
|
||||||
bool sendFrame(const char *filepath, struct timeval *timestamp);
|
bool sendFrame(const char *filepath, struct timeval *timestamp);
|
||||||
bool sendFrame(Image *image, struct timeval *timestamp);
|
bool sendFrame(Image *image, struct timeval *timestamp);
|
||||||
void processCommand(const CmdMsg *msg);
|
void processCommand(const CmdMsg *msg) override;
|
||||||
void SingleImage(int scale=100);
|
void SingleImage(int scale=100);
|
||||||
void SingleImageRaw(int scale=100);
|
void SingleImageRaw(int scale=100);
|
||||||
#ifdef HAVE_ZLIB_H
|
#ifdef HAVE_ZLIB_H
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define ZM_MPEG_H
|
#define ZM_MPEG_H
|
||||||
|
|
||||||
#include "zm_ffmpeg.h"
|
#include "zm_ffmpeg.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
#if HAVE_LIBAVCODEC
|
#if HAVE_LIBAVCODEC
|
||||||
|
|
||||||
|
|
|
@ -159,90 +159,95 @@ int ZMPacket::decode(AVCodecContext *ctx) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int bytes_consumed = ret;
|
int bytes_consumed = ret;
|
||||||
if ( ret > 0 )
|
if ( ret > 0 ) {
|
||||||
zm_dump_video_frame(in_frame, "got frame");
|
zm_dump_video_frame(in_frame, "got frame");
|
||||||
|
|
||||||
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
#if HAVE_LIBAVUTIL_HWCONTEXT_H
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0)
|
||||||
|
|
||||||
if ( ctx->sw_pix_fmt != in_frame->format ) {
|
if ( fix_deprecated_pix_fmt(ctx->sw_pix_fmt) != fix_deprecated_pix_fmt(static_cast<AVPixelFormat>(in_frame->format)) ) {
|
||||||
Debug(1, "Have different format %s != %s.",
|
Debug(1, "Have different format ctx->pix_fmt %s ?= ctx->sw_pix_fmt %s in_frame->format %s.",
|
||||||
av_get_pix_fmt_name(ctx->pix_fmt),
|
av_get_pix_fmt_name(ctx->pix_fmt),
|
||||||
av_get_pix_fmt_name(ctx->sw_pix_fmt)
|
av_get_pix_fmt_name(ctx->sw_pix_fmt),
|
||||||
);
|
av_get_pix_fmt_name(static_cast<AVPixelFormat>(in_frame->format))
|
||||||
|
);
|
||||||
#if 0
|
#if 0
|
||||||
if ( target_format == AV_PIX_FMT_NONE and ctx->hw_frames_ctx and (image->Colours() == 4) ) {
|
if ( target_format == AV_PIX_FMT_NONE and ctx->hw_frames_ctx and (image->Colours() == 4) ) {
|
||||||
// Look for rgb0 in list of supported formats
|
// Look for rgb0 in list of supported formats
|
||||||
enum AVPixelFormat *formats;
|
enum AVPixelFormat *formats;
|
||||||
if ( 0 <= av_hwframe_transfer_get_formats(
|
if ( 0 <= av_hwframe_transfer_get_formats(
|
||||||
ctx->hw_frames_ctx,
|
ctx->hw_frames_ctx,
|
||||||
AV_HWFRAME_TRANSFER_DIRECTION_FROM,
|
AV_HWFRAME_TRANSFER_DIRECTION_FROM,
|
||||||
&formats,
|
&formats,
|
||||||
0
|
0
|
||||||
) ) {
|
) ) {
|
||||||
for (int i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
|
for (int i = 0; formats[i] != AV_PIX_FMT_NONE; i++) {
|
||||||
Debug(1, "Available dest formats %d %s",
|
Debug(1, "Available dest formats %d %s",
|
||||||
formats[i],
|
formats[i],
|
||||||
av_get_pix_fmt_name(formats[i])
|
av_get_pix_fmt_name(formats[i])
|
||||||
);
|
);
|
||||||
if ( formats[i] == AV_PIX_FMT_RGB0 ) {
|
if ( formats[i] == AV_PIX_FMT_RGB0 ) {
|
||||||
target_format = formats[i];
|
target_format = formats[i];
|
||||||
break;
|
break;
|
||||||
} // endif RGB0
|
} // endif RGB0
|
||||||
} // end foreach support format
|
} // end foreach support format
|
||||||
av_freep(&formats);
|
av_freep(&formats);
|
||||||
} // endif success getting list of formats
|
} // endif success getting list of formats
|
||||||
} // end if target_format not set
|
} // end if target_format not set
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
AVFrame *new_frame = zm_av_frame_alloc();
|
AVFrame *new_frame = zm_av_frame_alloc();
|
||||||
#if 0
|
#if 0
|
||||||
if ( target_format == AV_PIX_FMT_RGB0 ) {
|
if ( target_format == AV_PIX_FMT_RGB0 ) {
|
||||||
if ( image ) {
|
if ( image ) {
|
||||||
if ( 0 > image->PopulateFrame(new_frame) ) {
|
if ( 0 > image->PopulateFrame(new_frame) ) {
|
||||||
delete new_frame;
|
delete new_frame;
|
||||||
new_frame = zm_av_frame_alloc();
|
new_frame = zm_av_frame_alloc();
|
||||||
delete image;
|
delete image;
|
||||||
image = nullptr;
|
image = nullptr;
|
||||||
new_frame->format = target_format;
|
new_frame->format = target_format;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
/* retrieve data from GPU to CPU */
|
/* retrieve data from GPU to CPU */
|
||||||
zm_dump_video_frame(in_frame, "Before hwtransfer");
|
zm_dump_video_frame(in_frame, "Before hwtransfer");
|
||||||
ret = av_hwframe_transfer_data(new_frame, in_frame, 0);
|
ret = av_hwframe_transfer_data(new_frame, in_frame, 0);
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
Error("Unable to transfer frame: %s, continuing",
|
Error("Unable to transfer frame: %s, continuing",
|
||||||
av_make_error_string(ret).c_str());
|
av_make_error_string(ret).c_str());
|
||||||
av_frame_free(&in_frame);
|
av_frame_free(&in_frame);
|
||||||
av_frame_free(&new_frame);
|
av_frame_free(&new_frame);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
new_frame->pts = in_frame->pts;
|
ret = av_frame_copy_props(new_frame, in_frame);
|
||||||
zm_dump_video_frame(new_frame, "After hwtransfer");
|
if ( ret < 0 ) {
|
||||||
|
Error("Unable to copy props: %s, continuing",
|
||||||
|
av_make_error_string(ret).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
zm_dump_video_frame(new_frame, "After hwtransfer");
|
||||||
#if 0
|
#if 0
|
||||||
if ( new_frame->format == AV_PIX_FMT_RGB0 ) {
|
if ( new_frame->format == AV_PIX_FMT_RGB0 ) {
|
||||||
new_frame->format = AV_PIX_FMT_RGBA;
|
new_frame->format = AV_PIX_FMT_RGBA;
|
||||||
zm_dump_video_frame(new_frame, "After hwtransfer setting to rgba");
|
zm_dump_video_frame(new_frame, "After hwtransfer setting to rgba");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
av_frame_free(&in_frame);
|
av_frame_free(&in_frame);
|
||||||
in_frame = new_frame;
|
in_frame = new_frame;
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if ( ret > 0 ) {
|
Debug(2, "Same pix format %s so not hwtransferring. sw_pix_fmt is %s",
|
||||||
Debug(2, "Same pix format %s so not hwtransferring. sw_pix_fmt is %s",
|
av_get_pix_fmt_name(ctx->pix_fmt),
|
||||||
av_get_pix_fmt_name(ctx->pix_fmt),
|
av_get_pix_fmt_name(ctx->sw_pix_fmt)
|
||||||
av_get_pix_fmt_name(ctx->sw_pix_fmt)
|
);
|
||||||
);
|
|
||||||
#if 0
|
#if 0
|
||||||
if ( image ) {
|
if ( image ) {
|
||||||
image->Assign(in_frame);
|
image->Assign(in_frame);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
} // end if if ( ret > 0 ) {
|
||||||
return bytes_consumed;
|
return bytes_consumed;
|
||||||
} // end ZMPacket::decode
|
} // end ZMPacket::decode
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,15 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) {
|
||||||
--(*iterator_it);
|
--(*iterator_it);
|
||||||
}
|
}
|
||||||
} // end foreach iterator
|
} // end foreach iterator
|
||||||
|
mutex.unlock();
|
||||||
|
// We signal on every packet because someday we may analyze sound
|
||||||
|
Debug(4, "packetqueue queuepacket, unlocked signalling");
|
||||||
|
condition.notify_all();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet)
|
||||||
|
|
||||||
|
void PacketQueue::clearPackets(ZMPacket *add_packet) {
|
||||||
// Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one.
|
// Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one.
|
||||||
// No good. Have to satisfy two conditions:
|
// No good. Have to satisfy two conditions:
|
||||||
// 1. packetqueue starts with a video keyframe
|
// 1. packetqueue starts with a video keyframe
|
||||||
|
@ -109,77 +117,74 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) {
|
||||||
//
|
//
|
||||||
// So start at the beginning, counting video packets until the next keyframe.
|
// So start at the beginning, counting video packets until the next keyframe.
|
||||||
// Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them.
|
// Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them.
|
||||||
if ( add_packet->packet.stream_index == video_stream_id
|
if ( ! (
|
||||||
|
add_packet->packet.stream_index == video_stream_id
|
||||||
and
|
and
|
||||||
add_packet->keyframe
|
add_packet->keyframe
|
||||||
and
|
and
|
||||||
(packet_counts[video_stream_id] > max_video_packet_count)
|
(packet_counts[video_stream_id] > max_video_packet_count)
|
||||||
and
|
and
|
||||||
*(pktQueue.begin()) != add_packet
|
*(pktQueue.begin()) != add_packet
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
packetqueue_iterator it = pktQueue.begin();
|
return;
|
||||||
packetqueue_iterator next_front = pktQueue.begin();
|
}
|
||||||
|
std::unique_lock<std::mutex> lck(mutex);
|
||||||
|
|
||||||
// First packet is special because we know it is a video keyframe and only need to check for lock
|
packetqueue_iterator it = pktQueue.begin();
|
||||||
ZMPacket *zm_packet = *it;
|
packetqueue_iterator next_front = pktQueue.begin();
|
||||||
if ( zm_packet->trylock() ) {
|
|
||||||
++it;
|
// First packet is special because we know it is a video keyframe and only need to check for lock
|
||||||
|
ZMPacket *zm_packet = *it;
|
||||||
|
if ( zm_packet->trylock() ) {
|
||||||
|
++it;
|
||||||
|
zm_packet->unlock();
|
||||||
|
|
||||||
|
// Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that
|
||||||
|
while ( *it != add_packet ) {
|
||||||
|
zm_packet = *it;
|
||||||
|
if ( !zm_packet->trylock() ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
zm_packet->unlock();
|
zm_packet->unlock();
|
||||||
|
|
||||||
// Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that
|
if ( is_there_an_iterator_pointing_to_packet(zm_packet) ) {
|
||||||
while ( *it != add_packet ) {
|
Warning("Found iterator at beginning of queue. Some thread isn't keeping up");
|
||||||
zm_packet = *it;
|
break;
|
||||||
Debug(1, "Checking packet to see if we can delete them");
|
|
||||||
if ( !zm_packet->trylock() ) {
|
|
||||||
Debug(1, "Have locked packet %d", zm_packet->image_index);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
zm_packet->unlock();
|
|
||||||
|
|
||||||
if ( is_there_an_iterator_pointing_to_packet(zm_packet) ) {
|
|
||||||
Debug(4, "Found IT at beginning of queue. Threads not keeping up");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( zm_packet->packet.stream_index == video_stream_id ) {
|
|
||||||
if ( zm_packet->keyframe ) {
|
|
||||||
Debug(1, "Have a video keyframe so breaking out");
|
|
||||||
next_front = it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
it++;
|
|
||||||
} // end while
|
|
||||||
} // end if first packet not locked
|
|
||||||
Debug(1, "Resulting pointing at latest packet? %d, have next front? %d",
|
|
||||||
( *it == add_packet ),
|
|
||||||
( next_front == pktQueue.begin() )
|
|
||||||
);
|
|
||||||
if ( next_front != pktQueue.begin() ) {
|
|
||||||
Debug(1, "Deleting packets");
|
|
||||||
// It is enough to delete the packets tested above. A subsequent queuePacket can clear a second set
|
|
||||||
while ( pktQueue.begin() != next_front ) {
|
|
||||||
ZMPacket *zm_packet = *pktQueue.begin();
|
|
||||||
if ( !zm_packet ) {
|
|
||||||
Error("NULL zm_packet in queue");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d",
|
|
||||||
zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size());
|
|
||||||
pktQueue.pop_front();
|
|
||||||
packet_counts[zm_packet->packet.stream_index] -= 1;
|
|
||||||
delete zm_packet;
|
|
||||||
}
|
}
|
||||||
} // end if have at least max_video_packet_count video packets remaining
|
|
||||||
} // end if this is a video keyframe
|
|
||||||
|
|
||||||
mutex.unlock();
|
if ( zm_packet->packet.stream_index == video_stream_id ) {
|
||||||
|
if ( zm_packet->keyframe ) {
|
||||||
|
Debug(1, "Have a video keyframe so setting next front to it");
|
||||||
|
next_front = it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
} // end while
|
||||||
|
} // end if first packet not locked
|
||||||
|
Debug(1, "Resulting pointing at latest packet? %d, next front points to begin? %d",
|
||||||
|
( *it == add_packet ),
|
||||||
|
( next_front == pktQueue.begin() )
|
||||||
|
);
|
||||||
|
if ( next_front != pktQueue.begin() ) {
|
||||||
|
while ( pktQueue.begin() != next_front ) {
|
||||||
|
ZMPacket *zm_packet = *pktQueue.begin();
|
||||||
|
if ( !zm_packet ) {
|
||||||
|
Error("NULL zm_packet in queue");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d",
|
||||||
|
zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size());
|
||||||
|
pktQueue.pop_front();
|
||||||
|
packet_counts[zm_packet->packet.stream_index] -= 1;
|
||||||
|
delete zm_packet;
|
||||||
|
}
|
||||||
|
} // end if have at least max_video_packet_count video packets remaining
|
||||||
// We signal on every packet because someday we may analyze sound
|
// We signal on every packet because someday we may analyze sound
|
||||||
Debug(4, "packetqueue queuepacket, unlocked signalling");
|
|
||||||
condition.notify_all();
|
|
||||||
|
|
||||||
return true;
|
return;
|
||||||
} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet)
|
} // end voidPacketQueue::clearPackets(ZMPacket* zm_packet)
|
||||||
|
|
||||||
ZMPacket* PacketQueue::popPacket( ) {
|
ZMPacket* PacketQueue::popPacket( ) {
|
||||||
Debug(4, "pktQueue size %d", pktQueue.size());
|
Debug(4, "pktQueue size %d", pktQueue.size());
|
||||||
|
@ -421,11 +426,11 @@ unsigned int PacketQueue::size() {
|
||||||
|
|
||||||
int PacketQueue::packet_count(int stream_id) {
|
int PacketQueue::packet_count(int stream_id) {
|
||||||
if ( stream_id < 0 or stream_id > max_stream_id ) {
|
if ( stream_id < 0 or stream_id > max_stream_id ) {
|
||||||
Error("Invalid stream_id %d", stream_id);
|
Error("Invalid stream_id %d max is %d", stream_id, max_stream_id);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return packet_counts[stream_id];
|
return packet_counts[stream_id];
|
||||||
} // end int PacketQueue::packet_count(int stream_id)
|
} // end int PacketQueue::packet_count(int stream_id)
|
||||||
|
|
||||||
|
|
||||||
// Returns a packet. Packet will be locked
|
// Returns a packet. Packet will be locked
|
||||||
|
@ -461,7 +466,7 @@ ZMPacket *PacketQueue::get_packet(packetqueue_iterator *it) {
|
||||||
}
|
}
|
||||||
Debug(2, "Locked packet, unlocking packetqueue mutex");
|
Debug(2, "Locked packet, unlocking packetqueue mutex");
|
||||||
return p;
|
return p;
|
||||||
} // end ZMPacket *PacketQueue::get_packet(it)
|
} // end ZMPacket *PacketQueue::get_packet(it)
|
||||||
|
|
||||||
bool PacketQueue::increment_it(packetqueue_iterator *it) {
|
bool PacketQueue::increment_it(packetqueue_iterator *it) {
|
||||||
Debug(2, "Incrementing %p, queue size %d, end? %d", it, pktQueue.size(), ((*it) == pktQueue.end()));
|
Debug(2, "Incrementing %p, queue size %d, end? %d", it, pktQueue.size(), ((*it) == pktQueue.end()));
|
||||||
|
@ -500,6 +505,8 @@ packetqueue_iterator *PacketQueue::get_event_start_packet_it(
|
||||||
unsigned int pre_event_count
|
unsigned int pre_event_count
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lck(mutex);
|
||||||
|
|
||||||
packetqueue_iterator *it = new packetqueue_iterator;
|
packetqueue_iterator *it = new packetqueue_iterator;
|
||||||
iterators.push_back(it);
|
iterators.push_back(it);
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ class PacketQueue {
|
||||||
unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; };
|
unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; };
|
||||||
|
|
||||||
void clear_unwanted_packets(timeval *recording, int pre_event_count, int mVideoStreamId);
|
void clear_unwanted_packets(timeval *recording, int pre_event_count, int mVideoStreamId);
|
||||||
|
void clearPackets(ZMPacket *);
|
||||||
int packet_count(int stream_id);
|
int packet_count(int stream_id);
|
||||||
|
|
||||||
bool increment_it(packetqueue_iterator *it);
|
bool increment_it(packetqueue_iterator *it);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "zm_utils.h"
|
#include "zm_utils.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
RemoteCamera::RemoteCamera(
|
RemoteCamera::RemoteCamera(
|
||||||
const Monitor *monitor,
|
const Monitor *monitor,
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "zm_utils.h"
|
#include "zm_utils.h"
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#include <netdb.h>
|
#include <netdb.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
#ifdef SOLARIS
|
#ifdef SOLARIS
|
||||||
#include <sys/filio.h> // FIONREAD and friends
|
#include <sys/filio.h> // FIONREAD and friends
|
||||||
|
@ -540,10 +541,8 @@ int RemoteCameraHttp::GetResponse() {
|
||||||
}
|
}
|
||||||
case HEADERCONT :
|
case HEADERCONT :
|
||||||
case SUBHEADERCONT :
|
case SUBHEADERCONT :
|
||||||
{
|
|
||||||
// Ignore
|
// Ignore
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
|
@ -1062,7 +1061,6 @@ int RemoteCameraHttp::PreCapture() {
|
||||||
if ( mode == SINGLE_IMAGE ) {
|
if ( mode == SINGLE_IMAGE ) {
|
||||||
if ( SendRequest() < 0 ) {
|
if ( SendRequest() < 0 ) {
|
||||||
Error("Unable to send request");
|
Error("Unable to send request");
|
||||||
Disconnect();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1072,12 +1070,11 @@ int RemoteCameraHttp::PreCapture() {
|
||||||
int RemoteCameraHttp::Capture(ZMPacket &packet) {
|
int RemoteCameraHttp::Capture(ZMPacket &packet) {
|
||||||
int content_length = GetResponse();
|
int content_length = GetResponse();
|
||||||
if ( content_length == 0 ) {
|
if ( content_length == 0 ) {
|
||||||
Warning( "Unable to capture image, retrying" );
|
Warning("Unable to capture image, retrying");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if ( content_length < 0 ) {
|
if ( content_length < 0 ) {
|
||||||
Error( "Unable to get response, disconnecting" );
|
Error("Unable to get response, disconnecting");
|
||||||
Disconnect();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,7 +1091,6 @@ int RemoteCameraHttp::Capture(ZMPacket &packet) {
|
||||||
case JPEG :
|
case JPEG :
|
||||||
if ( !image->DecodeJpeg(buffer.extract(content_length), content_length, colours, subpixelorder) ) {
|
if ( !image->DecodeJpeg(buffer.extract(content_length), content_length, colours, subpixelorder) ) {
|
||||||
Error("Unable to decode jpeg");
|
Error("Unable to decode jpeg");
|
||||||
Disconnect();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -1102,7 +1098,6 @@ int RemoteCameraHttp::Capture(ZMPacket &packet) {
|
||||||
if ( content_length != (long)image->Size() ) {
|
if ( content_length != (long)image->Size() ) {
|
||||||
Error("Image length mismatch, expected %d bytes, content length was %d",
|
Error("Image length mismatch, expected %d bytes, content length was %d",
|
||||||
image->Size(), content_length);
|
image->Size(), content_length);
|
||||||
Disconnect();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
||||||
|
@ -1110,14 +1105,12 @@ int RemoteCameraHttp::Capture(ZMPacket &packet) {
|
||||||
case X_RGBZ :
|
case X_RGBZ :
|
||||||
if ( !image->Unzip( buffer.extract( content_length ), content_length ) ) {
|
if ( !image->Unzip( buffer.extract( content_length ), content_length ) ) {
|
||||||
Error("Unable to unzip RGB image");
|
Error("Unable to unzip RGB image");
|
||||||
Disconnect();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
image->Assign(width, height, colours, subpixelorder, buffer, imagesize);
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
Error("Unexpected image format encountered");
|
Error("Unexpected image format encountered");
|
||||||
Disconnect();
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -91,25 +91,7 @@ int SWScale::Convert(
|
||||||
AVFrame *out_frame
|
AVFrame *out_frame
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// THe J formats are deprecated, so we need to convert
|
AVPixelFormat format = fix_deprecated_pix_fmt((AVPixelFormat)in_frame->format);
|
||||||
AVPixelFormat format;
|
|
||||||
switch ( in_frame->format ) {
|
|
||||||
case AV_PIX_FMT_YUVJ420P :
|
|
||||||
format = AV_PIX_FMT_YUV420P;
|
|
||||||
break;
|
|
||||||
case AV_PIX_FMT_YUVJ422P :
|
|
||||||
format = AV_PIX_FMT_YUV422P;
|
|
||||||
break;
|
|
||||||
case AV_PIX_FMT_YUVJ444P :
|
|
||||||
format = AV_PIX_FMT_YUV444P;
|
|
||||||
break;
|
|
||||||
case AV_PIX_FMT_YUVJ440P :
|
|
||||||
format = AV_PIX_FMT_YUV440P;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
format = (AVPixelFormat)in_frame->format;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* Get the context */
|
/* Get the context */
|
||||||
swscale_ctx = sws_getCachedContext(swscale_ctx,
|
swscale_ctx = sws_getCachedContext(swscale_ctx,
|
||||||
in_frame->width, in_frame->height, format,
|
in_frame->width, in_frame->height, format,
|
||||||
|
@ -120,7 +102,9 @@ int SWScale::Convert(
|
||||||
return -6;
|
return -6;
|
||||||
}
|
}
|
||||||
/* Do the conversion */
|
/* Do the conversion */
|
||||||
if ( !sws_scale(swscale_ctx, in_frame->data, in_frame->linesize, 0, in_frame->height, out_frame->data, out_frame->linesize ) ) {
|
if (!sws_scale(swscale_ctx,
|
||||||
|
in_frame->data, in_frame->linesize, 0, in_frame->height,
|
||||||
|
out_frame->data, out_frame->linesize)) {
|
||||||
Error("swscale conversion failed");
|
Error("swscale conversion failed");
|
||||||
return -10;
|
return -10;
|
||||||
}
|
}
|
||||||
|
@ -140,8 +124,9 @@ int SWScale::Convert(
|
||||||
unsigned int new_width,
|
unsigned int new_width,
|
||||||
unsigned int new_height
|
unsigned int new_height
|
||||||
) {
|
) {
|
||||||
Debug(1, "Convert: in_buffer %p in_buffer_size %d out_buffer %p size %d width %d height %d width %d height %d",
|
Debug(1, "Convert: in_buffer %p in_buffer_size %d out_buffer %p size %d width %d height %d width %d height %d %d %d",
|
||||||
in_buffer, in_buffer_size, out_buffer, out_buffer_size, width, height, new_width, new_height);
|
in_buffer, in_buffer_size, out_buffer, out_buffer_size, width, height, new_width, new_height,
|
||||||
|
in_pf, out_pf);
|
||||||
/* Parameter checking */
|
/* Parameter checking */
|
||||||
if ( in_buffer == nullptr ) {
|
if ( in_buffer == nullptr ) {
|
||||||
Error("NULL Input buffer");
|
Error("NULL Input buffer");
|
||||||
|
@ -160,23 +145,7 @@ int SWScale::Convert(
|
||||||
return -3;
|
return -3;
|
||||||
}
|
}
|
||||||
|
|
||||||
// THe J formats are deprecated, so we need to convert
|
in_pf = fix_deprecated_pix_fmt(in_pf);
|
||||||
switch ( in_pf ) {
|
|
||||||
case AV_PIX_FMT_YUVJ420P :
|
|
||||||
in_pf = AV_PIX_FMT_YUV420P;
|
|
||||||
break;
|
|
||||||
case AV_PIX_FMT_YUVJ422P :
|
|
||||||
in_pf = AV_PIX_FMT_YUV422P;
|
|
||||||
break;
|
|
||||||
case AV_PIX_FMT_YUVJ444P :
|
|
||||||
in_pf = AV_PIX_FMT_YUV444P;
|
|
||||||
break;
|
|
||||||
case AV_PIX_FMT_YUVJ440P :
|
|
||||||
in_pf = AV_PIX_FMT_YUV440P;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
|
#if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0)
|
||||||
/* Warn if the input or output pixelformat is not supported */
|
/* Warn if the input or output pixelformat is not supported */
|
||||||
|
@ -190,21 +159,24 @@ int SWScale::Convert(
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int alignment = 1;
|
||||||
/* Check the buffer sizes */
|
/* Check the buffer sizes */
|
||||||
size_t insize = GetBufferSize(in_pf, width, height);
|
size_t needed_insize = GetBufferSize(in_pf, width, height);
|
||||||
if ( insize != in_buffer_size ) {
|
if ( needed_insize > in_buffer_size ) {
|
||||||
Debug(1, "The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size);
|
Debug(1, "The input buffer size does not match the expected size for the input format. Required: %d for %dx%d %d Available: %d",
|
||||||
|
needed_insize, width, height, in_pf, in_buffer_size);
|
||||||
}
|
}
|
||||||
size_t outsize = GetBufferSize(out_pf, new_width, new_height);
|
size_t needed_outsize = GetBufferSize(out_pf, new_width, new_height);
|
||||||
if ( outsize < out_buffer_size ) {
|
if ( needed_outsize > out_buffer_size ) {
|
||||||
Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size);
|
Error("The output buffer is undersized for the output format. Required: %d Available: %d", needed_outsize, out_buffer_size);
|
||||||
return -5;
|
return -5;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the context */
|
/* Get the context */
|
||||||
swscale_ctx = sws_getCachedContext(
|
swscale_ctx = sws_getCachedContext(swscale_ctx,
|
||||||
swscale_ctx, width, height, in_pf, new_width, new_height,
|
width, height, in_pf,
|
||||||
out_pf, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
|
new_width, new_height, out_pf,
|
||||||
|
SWS_FAST_BILINEAR, nullptr, nullptr, nullptr);
|
||||||
if ( swscale_ctx == nullptr ) {
|
if ( swscale_ctx == nullptr ) {
|
||||||
Error("Failed getting swscale context");
|
Error("Failed getting swscale context");
|
||||||
return -6;
|
return -6;
|
||||||
|
@ -212,8 +184,8 @@ int SWScale::Convert(
|
||||||
|
|
||||||
/* Fill in the buffers */
|
/* Fill in the buffers */
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
if ( av_image_fill_arrays(input_avframe->data, input_avframe->linesize,
|
if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize,
|
||||||
(uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) {
|
(uint8_t*) in_buffer, in_pf, width, height, alignment) <= 0) {
|
||||||
#else
|
#else
|
||||||
if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer,
|
if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer,
|
||||||
in_pf, width, height) <= 0) {
|
in_pf, width, height) <= 0) {
|
||||||
|
@ -222,10 +194,10 @@ int SWScale::Convert(
|
||||||
return -7;
|
return -7;
|
||||||
}
|
}
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
if ( av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
|
if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize,
|
||||||
out_buffer, out_pf, new_width, new_height, 1) <= 0) {
|
out_buffer, out_pf, new_width, new_height, alignment) <= 0) {
|
||||||
#else
|
#else
|
||||||
if ( avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width,
|
if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width,
|
||||||
new_height) <= 0) {
|
new_height) <= 0) {
|
||||||
#endif
|
#endif
|
||||||
Error("Failed filling output frame with output buffer");
|
Error("Failed filling output frame with output buffer");
|
||||||
|
@ -235,7 +207,8 @@ int SWScale::Convert(
|
||||||
/* Do the conversion */
|
/* Do the conversion */
|
||||||
if ( !sws_scale(swscale_ctx,
|
if ( !sws_scale(swscale_ctx,
|
||||||
input_avframe->data, input_avframe->linesize,
|
input_avframe->data, input_avframe->linesize,
|
||||||
0, height, output_avframe->data, output_avframe->linesize ) ) {
|
0, height,
|
||||||
|
output_avframe->data, output_avframe->linesize) ) {
|
||||||
Error("swscale conversion failed");
|
Error("swscale conversion failed");
|
||||||
return -10;
|
return -10;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +271,7 @@ int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_si
|
||||||
|
|
||||||
size_t SWScale::GetBufferSize(enum _AVPIXELFORMAT pf, unsigned int width, unsigned int height) {
|
size_t SWScale::GetBufferSize(enum _AVPIXELFORMAT pf, unsigned int width, unsigned int height) {
|
||||||
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
#if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0)
|
||||||
return av_image_get_buffer_size(pf, width, height, 32);
|
return av_image_get_buffer_size(pf, width, height, 1);
|
||||||
#else
|
#else
|
||||||
return outsize = avpicture_get_size(pf, width,height);
|
return outsize = avpicture_get_size(pf, width,height);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#include "zm_logger.h"
|
#include "zm_logger.h"
|
||||||
#include "zm_utils.h"
|
#include "zm_utils.h"
|
||||||
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
|
@ -190,12 +190,8 @@ bool VideoStore::open() {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
video_out_ctx->time_base = video_in_ctx ? video_in_ctx->time_base : AV_TIME_BASE_Q;
|
// When encoding, we are going to use the timestamp values instead of packet pts/dts
|
||||||
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
|
video_out_ctx->time_base = AV_TIME_BASE_Q;
|
||||||
Debug(2, "No timebase found in video in context, defaulting to Q which is microseconds");
|
|
||||||
video_out_ctx->time_base = AV_TIME_BASE_Q;
|
|
||||||
}
|
|
||||||
|
|
||||||
video_out_ctx->codec_id = codec_data[i].codec_id;
|
video_out_ctx->codec_id = codec_data[i].codec_id;
|
||||||
video_out_ctx->pix_fmt = codec_data[i].pix_fmt;
|
video_out_ctx->pix_fmt = codec_data[i].pix_fmt;
|
||||||
video_out_ctx->level = 32;
|
video_out_ctx->level = 32;
|
||||||
|
@ -209,14 +205,6 @@ bool VideoStore::open() {
|
||||||
video_out_ctx->bit_rate = 2000000;
|
video_out_ctx->bit_rate = 2000000;
|
||||||
video_out_ctx->gop_size = 12;
|
video_out_ctx->gop_size = 12;
|
||||||
video_out_ctx->max_b_frames = 1;
|
video_out_ctx->max_b_frames = 1;
|
||||||
|
|
||||||
ret = av_opt_set(video_out_ctx, "crf", "36", AV_OPT_SEARCH_CHILDREN);
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
Error("Could not set 'crf' for output codec %s. %s",
|
|
||||||
codec_data[i].codec_name,
|
|
||||||
av_make_error_string(ret).c_str()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if ( video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ) {
|
} else if ( video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ) {
|
||||||
/* just for testing, we also add B frames */
|
/* just for testing, we also add B frames */
|
||||||
video_out_ctx->max_b_frames = 2;
|
video_out_ctx->max_b_frames = 2;
|
||||||
|
@ -241,10 +229,17 @@ bool VideoStore::open() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
|
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
|
||||||
Warning("Can't open video codec (%s) %s",
|
if ( wanted_encoder != "" and wanted_encoder != "auto" ) {
|
||||||
video_out_codec->name,
|
Warning("Can't open video codec (%s) %s",
|
||||||
av_make_error_string(ret).c_str()
|
video_out_codec->name,
|
||||||
);
|
av_make_error_string(ret).c_str()
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
Debug(1, "Can't open video codec (%s) %s",
|
||||||
|
video_out_codec->name,
|
||||||
|
av_make_error_string(ret).c_str()
|
||||||
|
);
|
||||||
|
}
|
||||||
video_out_codec = nullptr;
|
video_out_codec = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +249,7 @@ bool VideoStore::open() {
|
||||||
}
|
}
|
||||||
//av_dict_free(&opts);
|
//av_dict_free(&opts);
|
||||||
if ( video_out_codec ) break;
|
if ( video_out_codec ) break;
|
||||||
|
avcodec_free_context(&video_out_ctx);
|
||||||
} // end foreach codec
|
} // end foreach codec
|
||||||
|
|
||||||
if ( !video_out_codec ) {
|
if ( !video_out_codec ) {
|
||||||
|
@ -1015,21 +1011,25 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
|
||||||
//zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 };
|
//zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 };
|
||||||
// Do this to allow the encoder to choose whether to use I/P/B frame
|
// Do this to allow the encoder to choose whether to use I/P/B frame
|
||||||
//zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE;
|
//zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE;
|
||||||
zm_packet->out_frame->key_frame = zm_packet->keyframe;
|
//zm_packet->out_frame->key_frame = zm_packet->keyframe;
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
zm_packet->out_frame->pkt_duration = 0;
|
zm_packet->out_frame->pkt_duration = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int64_t in_pts = zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec;
|
||||||
if ( !video_first_pts ) {
|
if ( !video_first_pts ) {
|
||||||
video_first_pts = zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec;
|
video_first_pts = in_pts;
|
||||||
Debug(2, "No video_first_pts, set to (%" PRId64 ") secs(%d) usecs(%d)",
|
Debug(2, "No video_first_pts, set to (%" PRId64 ") secs(%d) usecs(%d)",
|
||||||
video_first_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec);
|
video_first_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec);
|
||||||
zm_packet->out_frame->pts = 0;
|
zm_packet->out_frame->pts = 0;
|
||||||
} else {
|
} else {
|
||||||
uint64_t useconds = ( zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_first_pts;
|
uint64_t useconds = in_pts - video_first_pts;
|
||||||
zm_packet->out_frame->pts = av_rescale_q(useconds, video_in_stream->time_base, video_out_ctx->time_base);
|
zm_packet->out_frame->pts = av_rescale_q(useconds, AV_TIME_BASE_Q, video_out_ctx->time_base);
|
||||||
Debug(2, " Setting pts for frame(%d) to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)",
|
Debug(2, " Setting pts for frame(%d) to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d) @ %d/%d",
|
||||||
frame_count, zm_packet->out_frame->pts, video_first_pts, useconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec);
|
frame_count, zm_packet->out_frame->pts, video_first_pts, useconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec,
|
||||||
|
video_out_ctx->time_base.num,
|
||||||
|
video_out_ctx->time_base.den
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
av_init_packet(&opkt);
|
av_init_packet(&opkt);
|
||||||
|
@ -1097,7 +1097,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) {
|
||||||
|
|
||||||
} else { // Passthrough
|
} else { // Passthrough
|
||||||
AVPacket *ipkt = &zm_packet->packet;
|
AVPacket *ipkt = &zm_packet->packet;
|
||||||
Debug(3, "Doing passthrough, just copy packet");
|
ZM_DUMP_STREAM_PACKET(video_in_stream, (*ipkt), "Doing passthrough, just copy packet");
|
||||||
// Just copy it because the codec is the same
|
// Just copy it because the codec is the same
|
||||||
av_init_packet(&opkt);
|
av_init_packet(&opkt);
|
||||||
opkt.data = ipkt->data;
|
opkt.data = ipkt->data;
|
||||||
|
@ -1149,10 +1149,8 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||||
audio_next_pts = audio_out_ctx->frame_size;
|
audio_next_pts = audio_out_ctx->frame_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Debug(3, "audio first_dts to %" PRId64, audio_first_dts);
|
||||||
// Need to adjust pts before feeding to decoder.... should really copy the pkt instead of modifying it
|
// Need to adjust pts before feeding to decoder.... should really copy the pkt instead of modifying it
|
||||||
ipkt->pts -= audio_first_dts;
|
|
||||||
ipkt->dts -= audio_first_dts;
|
|
||||||
ZM_DUMP_STREAM_PACKET(audio_in_stream, (*ipkt), "after pts adjustment");
|
|
||||||
|
|
||||||
if ( audio_out_codec ) {
|
if ( audio_out_codec ) {
|
||||||
// I wonder if we can get multiple frames per packet? Probably
|
// I wonder if we can get multiple frames per packet? Probably
|
||||||
|
@ -1206,8 +1204,10 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) {
|
||||||
opkt.flags = ipkt->flags;
|
opkt.flags = ipkt->flags;
|
||||||
|
|
||||||
opkt.duration = ipkt->duration;
|
opkt.duration = ipkt->duration;
|
||||||
opkt.pts = ipkt->pts;
|
opkt.pts = ipkt->pts - audio_first_dts;
|
||||||
opkt.dts = ipkt->dts;
|
opkt.dts = ipkt->dts - audio_first_dts;
|
||||||
|
|
||||||
|
ZM_DUMP_STREAM_PACKET(audio_in_stream, (*ipkt), "after pts adjustment");
|
||||||
av_packet_rescale_ts(&opkt, audio_in_stream->time_base, audio_out_stream->time_base);
|
av_packet_rescale_ts(&opkt, audio_in_stream->time_base, audio_out_stream->time_base);
|
||||||
ZM_DUMP_STREAM_PACKET(audio_out_stream, opkt, "after stream pts adjustment");
|
ZM_DUMP_STREAM_PACKET(audio_out_stream, opkt, "after stream pts adjustment");
|
||||||
write_packet(&opkt, audio_out_stream);
|
write_packet(&opkt, audio_out_stream);
|
||||||
|
|
|
@ -134,16 +134,11 @@ Zone::~Zone() {
|
||||||
|
|
||||||
void Zone::RecordStats(const Event *event) {
|
void Zone::RecordStats(const Event *event) {
|
||||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
db_mutex.lock();
|
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d",
|
"INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d",
|
||||||
monitor->Id(), id, event->Id(), event->Frames(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score
|
monitor->Id(), id, event->Id(), event->Frames(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score
|
||||||
);
|
);
|
||||||
int rc = mysql_query(&dbconn, sql);
|
zmDbDo(sql);
|
||||||
db_mutex.unlock();
|
|
||||||
if ( rc ) {
|
|
||||||
Error("Can't insert event stats: %s", mysql_error(&dbconn));
|
|
||||||
}
|
|
||||||
} // end void Zone::RecordStats( const Event *event )
|
} // end void Zone::RecordStats( const Event *event )
|
||||||
|
|
||||||
bool Zone::CheckOverloadCount() {
|
bool Zone::CheckOverloadCount() {
|
||||||
|
@ -824,23 +819,24 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P
|
||||||
|
|
||||||
int Zone::Load(Monitor *monitor, Zone **&zones) {
|
int Zone::Load(Monitor *monitor, Zone **&zones) {
|
||||||
static char sql[ZM_SQL_MED_BUFSIZ];
|
static char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
|
MYSQL_RES *result;
|
||||||
|
|
||||||
db_mutex.lock();
|
{ // scope for lock
|
||||||
snprintf(sql, sizeof(sql), "SELECT Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,"
|
std::lock_guard<std::mutex> lck(db_mutex);
|
||||||
"MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,"
|
snprintf(sql, sizeof(sql), "SELECT Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0,"
|
||||||
"FilterX,FilterY,MinFilterPixels,MaxFilterPixels,"
|
"MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels,"
|
||||||
"MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,"
|
"FilterX,FilterY,MinFilterPixels,MaxFilterPixels,"
|
||||||
"OverloadFrames,ExtendAlarmFrames"
|
"MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs,"
|
||||||
" FROM Zones WHERE MonitorId = %d ORDER BY Type, Id", monitor->Id());
|
"OverloadFrames,ExtendAlarmFrames"
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
" FROM Zones WHERE MonitorId = %d ORDER BY Type, Id", monitor->Id());
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
db_mutex.unlock();
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = mysql_store_result(&dbconn);
|
||||||
}
|
}
|
||||||
|
if (!result) {
|
||||||
MYSQL_RES *result = mysql_store_result(&dbconn);
|
|
||||||
db_mutex.unlock();
|
|
||||||
if ( !result ) {
|
|
||||||
Error("Can't use query result: %s", mysql_error(&dbconn));
|
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -848,7 +844,7 @@ int Zone::Load(Monitor *monitor, Zone **&zones) {
|
||||||
Debug(1, "Got %d zones for monitor %s", n_zones, monitor->Name());
|
Debug(1, "Got %d zones for monitor %s", n_zones, monitor->Name());
|
||||||
delete[] zones;
|
delete[] zones;
|
||||||
zones = new Zone *[n_zones];
|
zones = new Zone *[n_zones];
|
||||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
for(int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) {
|
||||||
int col = 0;
|
int col = 0;
|
||||||
|
|
||||||
int Id = atoi(dbrow[col++]);
|
int Id = atoi(dbrow[col++]);
|
||||||
|
|
55
src/zmc.cpp
55
src/zmc.cpp
|
@ -214,7 +214,6 @@ int main(int argc, char *argv[]) {
|
||||||
exit(-1);
|
exit(-1);
|
||||||
} else {
|
} else {
|
||||||
Debug(2, "%d monitors loaded", monitors.size());
|
Debug(2, "%d monitors loaded", monitors.size());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Info("Starting Capture version %s", ZM_VERSION);
|
Info("Starting Capture version %s", ZM_VERSION);
|
||||||
|
@ -230,10 +229,9 @@ int main(int argc, char *argv[]) {
|
||||||
sigaddset(&block_set, SIGUSR2);
|
sigaddset(&block_set, SIGUSR2);
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
int prime_capture_log_count = 0;
|
int prime_capture_log_count = 0;
|
||||||
|
|
||||||
while ( !zm_terminate ) {
|
while (!zm_terminate) {
|
||||||
result = 0;
|
result = 0;
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
|
|
||||||
|
@ -247,37 +245,29 @@ int main(int argc, char *argv[]) {
|
||||||
monitor->setStartupTime(now);
|
monitor->setStartupTime(now);
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"INSERT INTO Monitor_Status (MonitorId,Status,CaptureFPS,AnalysisFPS) VALUES (%d, 'Running',0,0) ON DUPLICATE KEY UPDATE Status='Running',CaptureFPS=0,AnalysisFPS=0",
|
"INSERT INTO Monitor_Status (MonitorId,Status,CaptureFPS,AnalysisFPS)"
|
||||||
monitor->Id());
|
" VALUES (%d, 'Running',0,0) ON DUPLICATE KEY UPDATE Status='Running',CaptureFPS=0,AnalysisFPS=0",
|
||||||
if (mysql_query(&dbconn, sql)) {
|
monitor->Id());
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
zmDbDo(sql);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const std::shared_ptr<Monitor> &monitor : monitors) {
|
while (monitor->PrimeCapture() <= 0) {
|
||||||
|
|
||||||
// Outer primary loop, handles connection to camera
|
|
||||||
if (monitor->PrimeCapture() <= 0) {
|
|
||||||
if (prime_capture_log_count % 60) {
|
if (prime_capture_log_count % 60) {
|
||||||
Error("Failed to prime capture of initial monitor");
|
Error("Failed to prime capture of initial monitor");
|
||||||
} else {
|
} else {
|
||||||
Debug(1, "Failed to prime capture of initial monitor");
|
Debug(1, "Failed to prime capture of initial monitor");
|
||||||
}
|
}
|
||||||
prime_capture_log_count ++;
|
prime_capture_log_count ++;
|
||||||
monitor->disconnect();
|
if (zm_terminate) break;
|
||||||
if (!zm_terminate) {
|
sleep(1);
|
||||||
Debug(1, "Sleeping");
|
|
||||||
sleep(5);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
if (zm_terminate) break;
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='Connected'",
|
"INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='Connected'",
|
||||||
monitor->Id());
|
monitor->Id());
|
||||||
if ( mysql_query(&dbconn, sql) ) {
|
zmDbDo(sql);
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
} // end foreach monitor
|
||||||
}
|
if (zm_terminate) break;
|
||||||
}
|
|
||||||
|
|
||||||
#if HAVE_RTSP_SERVER
|
#if HAVE_RTSP_SERVER
|
||||||
RTSPServerThread ** rtsp_server_threads = nullptr;
|
RTSPServerThread ** rtsp_server_threads = nullptr;
|
||||||
|
@ -303,12 +293,12 @@ int main(int argc, char *argv[]) {
|
||||||
capture_delays[i], alarm_capture_delays[i]);
|
capture_delays[i], alarm_capture_delays[i]);
|
||||||
|
|
||||||
Monitor::Function function = monitors[0]->GetFunction();
|
Monitor::Function function = monitors[0]->GetFunction();
|
||||||
if ( function != Monitor::MONITOR ) {
|
if (function != Monitor::MONITOR) {
|
||||||
Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id());
|
Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id());
|
||||||
analysis_threads.emplace_back(ZM::make_unique<AnalysisThread>(monitors[i]));
|
analysis_threads.emplace_back(ZM::make_unique<AnalysisThread>(monitors[i]));
|
||||||
}
|
}
|
||||||
#if HAVE_RTSP_SERVER
|
#if HAVE_RTSP_SERVER
|
||||||
if ( rtsp_server_threads ) {
|
if (rtsp_server_threads) {
|
||||||
rtsp_server_threads[i] = new RTSPServerThread(monitors[i]);
|
rtsp_server_threads[i] = new RTSPServerThread(monitors[i]);
|
||||||
rtsp_server_threads[i]->addStream(monitors[i]->GetVideoStream(), monitors[i]->GetAudioStream());
|
rtsp_server_threads[i]->addStream(monitors[i]->GetVideoStream(), monitors[i]->GetAudioStream());
|
||||||
rtsp_server_threads[i]->start();
|
rtsp_server_threads[i]->start();
|
||||||
|
@ -366,17 +356,12 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
} // end if has a last_capture time
|
} // end if has a last_capture time
|
||||||
last_capture_times[i] = now;
|
last_capture_times[i] = now;
|
||||||
|
|
||||||
} // end foreach n_monitors
|
} // end foreach n_monitors
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0 or zm_reload) {
|
||||||
// Failure, try reconnecting
|
// Failure, try reconnecting
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( zm_reload ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} // end while ! zm_terminate and connected
|
} // end while ! zm_terminate and connected
|
||||||
|
|
||||||
for (std::unique_ptr<AnalysisThread> &analysis_thread: analysis_threads)
|
for (std::unique_ptr<AnalysisThread> &analysis_thread: analysis_threads)
|
||||||
|
@ -413,7 +398,7 @@ int main(int argc, char *argv[]) {
|
||||||
delete [] capture_delays;
|
delete [] capture_delays;
|
||||||
delete [] last_capture_times;
|
delete [] last_capture_times;
|
||||||
|
|
||||||
if (result < 0) {
|
if (result < 0 and !zm_terminate) {
|
||||||
// Failure, try reconnecting
|
// Failure, try reconnecting
|
||||||
Debug(1, "Sleeping for 5");
|
Debug(1, "Sleeping for 5");
|
||||||
sleep(5);
|
sleep(5);
|
||||||
|
@ -435,9 +420,7 @@ int main(int argc, char *argv[]) {
|
||||||
snprintf(sql, sizeof(sql),
|
snprintf(sql, sizeof(sql),
|
||||||
"INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='NotRunning'",
|
"INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='NotRunning'",
|
||||||
monitor->Id());
|
monitor->Id());
|
||||||
if (mysql_query(&dbconn, sql)) {
|
zmDbDo(sql);
|
||||||
Error("Can't run query: %s", mysql_error(&dbconn));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::Deinitialise();
|
Image::Deinitialise();
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef
|
Subproject commit 14292374ccf1328f2d5db20897bd06f99ba4d938
|
|
@ -349,6 +349,8 @@ class Filter extends ZM_Object {
|
||||||
'![]' => 2,
|
'![]' => 2,
|
||||||
'and' => 3,
|
'and' => 3,
|
||||||
'or' => 4,
|
'or' => 4,
|
||||||
|
'IS' => 2,
|
||||||
|
'IS NOT' => 2,
|
||||||
);
|
);
|
||||||
|
|
||||||
for ( $i = 0; $i < count($terms); $i++ ) {
|
for ( $i = 0; $i < count($terms); $i++ ) {
|
||||||
|
@ -476,6 +478,7 @@ class Filter extends ZM_Object {
|
||||||
}
|
}
|
||||||
} # end if attr
|
} # end if attr
|
||||||
|
|
||||||
|
$sqlValue = '';
|
||||||
if ( isset($term['op']) ) {
|
if ( isset($term['op']) ) {
|
||||||
if ( empty($term['op']) ) {
|
if ( empty($term['op']) ) {
|
||||||
$term['op'] = '=';
|
$term['op'] = '=';
|
||||||
|
@ -507,11 +510,11 @@ class Filter extends ZM_Object {
|
||||||
case 'IS' :
|
case 'IS' :
|
||||||
case 'IS NOT' :
|
case 'IS NOT' :
|
||||||
if ( $term['val'] == 'Odd' ) {
|
if ( $term['val'] == 'Odd' ) {
|
||||||
$sqlValue .= ' % 2 = 1';
|
$sqlValue = ' % 2 = 1';
|
||||||
} else if ( $term['val'] == 'Even' ) {
|
} else if ( $term['val'] == 'Even' ) {
|
||||||
$sqlValue .= ' % 2 = 0';
|
$sqlValue = ' % 2 = 0';
|
||||||
} else {
|
} else {
|
||||||
$sqlValue .= ' '.$term['op'];
|
$sqlValue = ' '.$term['op'];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
|
@ -522,10 +525,10 @@ class Filter extends ZM_Object {
|
||||||
if ( !count($postfixStack) ) {
|
if ( !count($postfixStack) ) {
|
||||||
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
|
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
|
||||||
break;
|
break;
|
||||||
} elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) {
|
} else if ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) {
|
||||||
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
|
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue);
|
||||||
break;
|
break;
|
||||||
} elseif ( $priorities[$term['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) {
|
} else if ( $priorities[$term['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) {
|
||||||
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue );
|
$postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue );
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -537,6 +540,7 @@ class Filter extends ZM_Object {
|
||||||
if ( isset($term['val']) ) {
|
if ( isset($term['val']) ) {
|
||||||
$valueList = array();
|
$valueList = array();
|
||||||
foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) {
|
foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) {
|
||||||
|
$value_upper = strtoupper($value);
|
||||||
switch ( $term['attr'] ) {
|
switch ( $term['attr'] ) {
|
||||||
case 'MonitorName':
|
case 'MonitorName':
|
||||||
case 'Name':
|
case 'Name':
|
||||||
|
@ -551,9 +555,9 @@ class Filter extends ZM_Object {
|
||||||
case 'FilterServerId':
|
case 'FilterServerId':
|
||||||
case 'StorageServerId':
|
case 'StorageServerId':
|
||||||
case 'ServerId':
|
case 'ServerId':
|
||||||
if ( $value == 'ZM_SERVER_ID' ) {
|
if ( $value_upper == 'ZM_SERVER_ID' ) {
|
||||||
$value = ZM_SERVER_ID;
|
$value = ZM_SERVER_ID;
|
||||||
} else if ( $value == 'NULL' ) {
|
} else if ( $value_upper == 'NULL' ) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$value = dbEscape($value);
|
$value = dbEscape($value);
|
||||||
|
@ -567,7 +571,8 @@ class Filter extends ZM_Object {
|
||||||
case 'DateTime':
|
case 'DateTime':
|
||||||
case 'EndDateTime':
|
case 'EndDateTime':
|
||||||
case 'StartDateTime':
|
case 'StartDateTime':
|
||||||
$value = "'".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."'";
|
if ( $value_upper != 'NULL' )
|
||||||
|
$value = "'".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."'";
|
||||||
break;
|
break;
|
||||||
case 'Date':
|
case 'Date':
|
||||||
case 'EndDate':
|
case 'EndDate':
|
||||||
|
@ -580,7 +585,7 @@ class Filter extends ZM_Object {
|
||||||
$value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
|
$value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
if ( $value != 'NULL' )
|
if ( $value_upper != 'NULL' )
|
||||||
$value = dbEscape($value);
|
$value = dbEscape($value);
|
||||||
} // end switch attribute
|
} // end switch attribute
|
||||||
$valueList[] = $value;
|
$valueList[] = $value;
|
||||||
|
|
|
@ -68,7 +68,7 @@ class FilterTerm {
|
||||||
|
|
||||||
$vals = is_array($this->val) ? $this->val : preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val));
|
$vals = is_array($this->val) ? $this->val : preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val));
|
||||||
foreach ( $vals as $value ) {
|
foreach ( $vals as $value ) {
|
||||||
|
$value_upper = strtoupper($value);
|
||||||
switch ( $this->attr ) {
|
switch ( $this->attr ) {
|
||||||
|
|
||||||
case 'AlarmedZoneId':
|
case 'AlarmedZoneId':
|
||||||
|
@ -96,36 +96,36 @@ class FilterTerm {
|
||||||
case 'ServerId':
|
case 'ServerId':
|
||||||
if ( $value == 'ZM_SERVER_ID' ) {
|
if ( $value == 'ZM_SERVER_ID' ) {
|
||||||
$value = ZM_SERVER_ID;
|
$value = ZM_SERVER_ID;
|
||||||
} else if ( $value == 'NULL' ) {
|
} else if ( $value_upper == 'NULL' ) {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$value = dbEscape($value);
|
$value = dbEscape($value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'StorageId':
|
case 'StorageId':
|
||||||
if ( $value != 'NULL' ) {
|
if ( $value_upper != 'NULL' ) {
|
||||||
$value = dbEscape($value);
|
$value = dbEscape($value);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'DateTime':
|
case 'DateTime':
|
||||||
case 'StartDateTime':
|
case 'StartDateTime':
|
||||||
case 'EndDateTime':
|
case 'EndDateTime':
|
||||||
if ( $value != 'NULL' )
|
if ( $value_upper != 'NULL' )
|
||||||
$value = '\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\'';
|
$value = '\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\'';
|
||||||
break;
|
break;
|
||||||
case 'Date':
|
case 'Date':
|
||||||
case 'StartDate':
|
case 'StartDate':
|
||||||
case 'EndDate':
|
case 'EndDate':
|
||||||
if ( $value == 'CURDATE()' or $value == 'NOW()' ) {
|
if ( $value_upper == 'CURDATE()' or $value_upper == 'NOW()' ) {
|
||||||
$value = 'to_days('.$value.')';
|
$value = 'to_days('.$value.')';
|
||||||
} else if ( $value != 'NULL' ) {
|
} else if ( $value_upper != 'NULL' ) {
|
||||||
$value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
|
$value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'Time':
|
case 'Time':
|
||||||
case 'StartTime':
|
case 'StartTime':
|
||||||
case 'EndTime':
|
case 'EndTime':
|
||||||
if ( $value != 'NULL' )
|
if ( $value_upper != 'NULL' )
|
||||||
$value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
|
$value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')';
|
||||||
break;
|
break;
|
||||||
default :
|
default :
|
||||||
|
@ -133,7 +133,7 @@ class FilterTerm {
|
||||||
$value = 1;
|
$value = 1;
|
||||||
} else if ( $value == 'Even' ) {
|
} else if ( $value == 'Even' ) {
|
||||||
$value = 0;
|
$value = 0;
|
||||||
} else if ( $value != 'NULL' )
|
} else if ( $value_upper != 'NULL' )
|
||||||
$value = dbEscape($value);
|
$value = dbEscape($value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,19 +132,7 @@ class Storage extends ZM_Object {
|
||||||
public function event_disk_space() {
|
public function event_disk_space() {
|
||||||
# This isn't a function like this in php, so we have to add up the space used in each event.
|
# This isn't a function like this in php, so we have to add up the space used in each event.
|
||||||
if ( (! property_exists($this, 'DiskSpace')) or (!isset($this->{'DiskSpace'})) ) {
|
if ( (! property_exists($this, 'DiskSpace')) or (!isset($this->{'DiskSpace'})) ) {
|
||||||
$used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()));
|
$this->{'DiskSpace'} = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id()));
|
||||||
|
|
||||||
do {
|
|
||||||
# Do in batches of 1000 so as to not useup all ram, Event will do caching though...
|
|
||||||
$events = Event::find(array('StorageId'=>$this->Id(), 'DiskSpace'=>null), array('limit'=>1000));
|
|
||||||
foreach ( $events as $Event ) {
|
|
||||||
$Event->Storage($this); // Prevent further db hit
|
|
||||||
# DiskSpace will update the event
|
|
||||||
$used += $Event->DiskSpace();
|
|
||||||
} #end foreach
|
|
||||||
Event::clear_cache();
|
|
||||||
} while ( count($events) == 1000 );
|
|
||||||
$this->{'DiskSpace'} = $used;
|
|
||||||
}
|
}
|
||||||
return $this->{'DiskSpace'};
|
return $this->{'DiskSpace'};
|
||||||
} // end function event_disk_space
|
} // end function event_disk_space
|
||||||
|
|
|
@ -867,6 +867,7 @@ function xhtmlFooter() {
|
||||||
<script src="skins/<?php echo $skin; ?>/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
|
<script src="skins/<?php echo $skin; ?>/js/jquery-ui-1.12.1/jquery-ui.min.js"></script>
|
||||||
<script src="skins/<?php echo $skin; ?>/js/bootstrap.min.js"></script>
|
<script src="skins/<?php echo $skin; ?>/js/bootstrap.min.js"></script>
|
||||||
<?php echo output_script_if_exists(array(
|
<?php echo output_script_if_exists(array(
|
||||||
|
'js/tableExport.min.js',
|
||||||
'js/bootstrap-table.min.js',
|
'js/bootstrap-table.min.js',
|
||||||
'js/bootstrap-table-locale-all.min.js',
|
'js/bootstrap-table-locale-all.min.js',
|
||||||
'js/bootstrap-table-export.min.js',
|
'js/bootstrap-table-export.min.js',
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
/*
|
||||||
|
tableExport.jquery.plugin
|
||||||
|
|
||||||
|
Version 1.10.21
|
||||||
|
|
||||||
|
Copyright (c) 2015-2020 hhurz, https://github.com/hhurz/tableExport.jquery.plugin
|
||||||
|
|
||||||
|
Based on https://github.com/kayalshri/tableExport.jquery.plugin
|
||||||
|
|
||||||
|
Licensed under the MIT License
|
||||||
|
*/
|
||||||
|
var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.findInternal=function(d,k,y){d instanceof String&&(d=String(d));for(var C=d.length,v=0;v<C;v++){var R=d[v];if(k.call(y,R,v,d))return{i:v,v:R}}return{i:-1,v:void 0}};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(d,k,y){d!=Array.prototype&&d!=Object.prototype&&(d[k]=y.value)};
|
||||||
|
$jscomp.getGlobal=function(d){return"undefined"!=typeof window&&window===d?d:"undefined"!=typeof global&&null!=global?global:d};$jscomp.global=$jscomp.getGlobal(this);$jscomp.polyfill=function(d,k,y,C){if(k){y=$jscomp.global;d=d.split(".");for(C=0;C<d.length-1;C++){var v=d[C];v in y||(y[v]={});y=y[v]}d=d[d.length-1];C=y[d];k=k(C);k!=C&&null!=k&&$jscomp.defineProperty(y,d,{configurable:!0,writable:!0,value:k})}};
|
||||||
|
$jscomp.polyfill("Array.prototype.find",function(d){return d?d:function(d,y){return $jscomp.findInternal(this,d,y).v}},"es6","es3");
|
||||||
|
(function(d){d.fn.tableExport=function(k){function y(b){var c=[];v(b,"thead").each(function(){c.push.apply(c,v(d(this),a.theadSelector).toArray())});return c}function C(b){var c=[];v(b,"tbody").each(function(){c.push.apply(c,v(d(this),a.tbodySelector).toArray())});a.tfootSelector.length&&v(b,"tfoot").each(function(){c.push.apply(c,v(d(this),a.tfootSelector).toArray())});return c}function v(b,a){var c=b[0].tagName,p=b.parents(c).length;return b.find(a).filter(function(){return p===d(this).closest(c).parents(c).length})}
|
||||||
|
function R(b){var a=[],e=0,p=0,f=0;d(b).find("thead").first().find("th").each(function(b,c){b=void 0!==d(c).attr("data-field");"undefined"!==typeof c.parentNode.rowIndex&&p!==c.parentNode.rowIndex&&(p=c.parentNode.rowIndex,e=f=0);var l=J(c);for(e+=l?l:1;f<e;)a[f]=b?d(c).attr("data-field"):f.toString(),f++});return a}function I(b){var a="undefined"!==typeof b[0].rowIndex,e=!1===a&&"undefined"!==typeof b[0].cellIndex,p=e||a?Ja(b):b.is(":visible"),f=b.attr("data-tableexport-display");e&&"none"!==f&&
|
||||||
|
"always"!==f&&(b=d(b[0].parentNode),a="undefined"!==typeof b[0].rowIndex,f=b.attr("data-tableexport-display"));a&&"none"!==f&&"always"!==f&&(f=b.closest("table").attr("data-tableexport-display"));return"none"!==f&&(!0===p||"always"===f)}function Ja(b){var a=[];U&&(a=K.filter(function(){var a=!1;this.nodeType===b[0].nodeType&&("undefined"!==typeof this.rowIndex&&this.rowIndex===b[0].rowIndex?a=!0:"undefined"!==typeof this.cellIndex&&this.cellIndex===b[0].cellIndex&&"undefined"!==typeof this.parentNode.rowIndex&&
|
||||||
|
"undefined"!==typeof b[0].parentNode.rowIndex&&this.parentNode.rowIndex===b[0].parentNode.rowIndex&&(a=!0));return a}));return!1===U||0===a.length}function ta(b,c,e){var p=!1;I(b)?0<a.ignoreColumn.length&&(-1!==d.inArray(e,a.ignoreColumn)||-1!==d.inArray(e-c,a.ignoreColumn)||S.length>e&&"undefined"!==typeof S[e]&&-1!==d.inArray(S[e],a.ignoreColumn))&&(p=!0):p=!0;return p}function E(b,c,e,p,f){if("function"===typeof f){var l=!1;"function"===typeof a.onIgnoreRow&&(l=a.onIgnoreRow(d(b),e));if(!1===l&&
|
||||||
|
(0===a.ignoreRow.length||-1===d.inArray(e,a.ignoreRow)&&-1===d.inArray(e-p,a.ignoreRow))&&I(d(b))){b=v(d(b),c);var q=b.length,h=0,u=0;b.each(function(){var b=d(this),a=J(this),c=T(this),l;d.each(G,function(){if(e>this.s.r&&e<=this.e.r&&h>=this.s.c&&h<=this.e.c)for(l=0;l<=this.e.c-this.s.c;++l)q++,u++,f(null,e,h++)});if(c||a)a=a||1,G.push({s:{r:e,c:h},e:{r:e+(c||1)-1,c:h+a-1}});!1===ta(b,q,u++)&&f(this,e,h++);if(1<a)for(l=0;l<a-1;++l)u++,f(null,e,h++)});d.each(G,function(){if(e>=this.s.r&&e<=this.e.r&&
|
||||||
|
h>=this.s.c&&h<=this.e.c)for(da=0;da<=this.e.c-this.s.c;++da)f(null,e,h++)})}}}function ua(b,a,e,d){if("undefined"!==typeof d.images&&(e=d.images[e],"undefined"!==typeof e)){a=a.getBoundingClientRect();var c=b.width/b.height,l=a.width/a.height,p=b.width,h=b.height,u=19.049976/25.4,g=0;l<=c?(h=Math.min(b.height,a.height),p=a.width*h/a.height):l>c&&(p=Math.min(b.width,a.width),h=a.height*p/a.width);p*=u;h*=u;h<b.height&&(g=(b.height-h)/2);try{d.doc.addImage(e.src,b.textPos.x,b.y+g,p,h)}catch(Pa){}b.textPos.x+=
|
||||||
|
p}}function va(b,c){if("string"===a.outputMode)return b.output();if("base64"===a.outputMode)return L(b.output());if("window"===a.outputMode)window.URL=window.URL||window.webkitURL,window.open(window.URL.createObjectURL(b.output("blob")));else try{var e=b.output("blob");saveAs(e,a.fileName+".pdf")}catch(p){ka(a.fileName+".pdf","data:application/pdf"+(c?"":";base64")+",",c?b.output("blob"):b.output())}}function wa(b,a,e){var c=0;"undefined"!==typeof e&&(c=e.colspan);if(0<=c){for(var d=b.width,l=b.textPos.x,
|
||||||
|
q=a.table.columns.indexOf(a.column),h=1;h<c;h++)d+=a.table.columns[q+h].width;1<c&&("right"===b.styles.halign?l=b.textPos.x+d-b.width:"center"===b.styles.halign&&(l=b.textPos.x+(d-b.width)/2));b.width=d;b.textPos.x=l;"undefined"!==typeof e&&1<e.rowspan&&(b.height*=e.rowspan);if("middle"===b.styles.valign||"bottom"===b.styles.valign)e=("string"===typeof b.text?b.text.split(/\r\n|\r|\n/g):b.text).length||1,2<e&&(b.textPos.y-=(2-1.15)/2*a.row.styles.fontSize*(e-2)/3);return!0}return!1}function xa(b,
|
||||||
|
a,e){"undefined"!==typeof b&&null!==b&&(b.hasAttribute("data-tableexport-canvas")?(a=(new Date).getTime(),d(b).attr("data-tableexport-canvas",a),e.images[a]={url:'[data-tableexport-canvas="'+a+'"]',src:null}):"undefined"!==a&&null!=a&&a.each(function(){if(d(this).is("img")){var a=ya(this.src);e.images[a]={url:this.src,src:this.src}}xa(b,d(this).children(),e)}))}function Ka(b,a){function c(b){if(b.url)if(b.src){var c=new Image;p=++f;c.crossOrigin="Anonymous";c.onerror=c.onload=function(){if(c.complete&&
|
||||||
|
(0===c.src.indexOf("data:image/")&&(c.width=b.width||c.width||0,c.height=b.height||c.height||0),c.width+c.height)){var e=document.createElement("canvas"),d=e.getContext("2d");e.width=c.width;e.height=c.height;d.drawImage(c,0,0);b.src=e.toDataURL("image/png")}--f||a(p)};c.src=b.url}else{var e=d(b.url);e.length&&(p=++f,html2canvas(e[0]).then(function(c){b.src=c.toDataURL("image/png");--f||a(p)}))}}var p=0,f=0;if("undefined"!==typeof b.images)for(var l in b.images)b.images.hasOwnProperty(l)&&c(b.images[l]);
|
||||||
|
(b=f)||(a(p),b=void 0);return b}function za(b,c,e){c.each(function(){if(d(this).is("div")){var c=ea(M(this,"background-color"),[255,255,255]),f=ea(M(this,"border-top-color"),[0,0,0]),l=fa(this,"border-top-width",a.jspdf.unit),q=this.getBoundingClientRect(),h=this.offsetLeft*e.wScaleFactor,u=this.offsetTop*e.hScaleFactor,g=q.width*e.wScaleFactor;q=q.height*e.hScaleFactor;e.doc.setDrawColor.apply(void 0,f);e.doc.setFillColor.apply(void 0,c);e.doc.setLineWidth(l);e.doc.rect(b.x+h,b.y+u,g,q,l?"FD":"F")}else d(this).is("img")&&
|
||||||
|
(c=ya(this.src),ua(b,this,c,e));za(b,d(this).children(),e)})}function Aa(b,c,e){if("function"===typeof e.onAutotableText)e.onAutotableText(e.doc,b,c);else{var p=b.textPos.x,f=b.textPos.y,l={halign:b.styles.halign,valign:b.styles.valign};if(c.length){for(c=c[0];c.previousSibling;)c=c.previousSibling;for(var q=!1,h=!1;c;){var u=c.innerText||c.textContent||"",g=u.length&&" "===u[0]?" ":"",k=1<u.length&&" "===u[u.length-1]?" ":"";!0!==a.preserve.leadingWS&&(u=g+la(u));!0!==a.preserve.trailingWS&&(u=ma(u)+
|
||||||
|
k);d(c).is("br")&&(p=b.textPos.x,f+=e.doc.internal.getFontSize());d(c).is("b")?q=!0:d(c).is("i")&&(h=!0);(q||h)&&e.doc.setFontType(q&&h?"bolditalic":q?"bold":"italic");if(g=e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize()){"linebreak"===b.styles.overflow&&p>b.textPos.x&&p+g>b.textPos.x+b.width&&(0<=".,!%*;:=-".indexOf(u.charAt(0))&&(k=u.charAt(0),g=e.doc.getStringUnitWidth(k)*e.doc.internal.getFontSize(),p+g<=b.textPos.x+b.width&&(e.doc.autoTableText(k,p,f,l),u=u.substring(1,u.length)),g=
|
||||||
|
e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize()),p=b.textPos.x,f+=e.doc.internal.getFontSize());if("visible"!==b.styles.overflow)for(;u.length&&p+g>b.textPos.x+b.width;)u=u.substring(0,u.length-1),g=e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize();e.doc.autoTableText(u,p,f,l);p+=g}if(q||h)d(c).is("b")?q=!1:d(c).is("i")&&(h=!1),e.doc.setFontType(q||h?q?"bold":"italic":"normal");c=c.nextSibling}b.textPos.x=p;b.textPos.y=f}else e.doc.autoTableText(b.text,b.textPos.x,b.textPos.y,l)}}
|
||||||
|
function V(b,a,e){return null==b?"":b.toString().replace(new RegExp(null==a?"":a.toString().replace(/([.*+?^=!:${}()|\[\]\/\\])/g,"\\$1"),"g"),e)}function la(b){return null==b?"":b.toString().replace(/^\s+/,"")}function ma(b){return null==b?"":b.toString().replace(/\s+$/,"")}function La(b){if(0===a.date.html.length)return!1;a.date.pattern.lastIndex=0;var c=a.date.pattern.exec(b);if(null==c)return!1;b=+c[a.date.match_y];if(0>b||8099<b)return!1;var e=1*c[a.date.match_m];c=1*c[a.date.match_d];if(!isFinite(c))return!1;
|
||||||
|
var d=new Date(b,e-1,c,0,0,0);return d.getFullYear()===b&&d.getMonth()===e-1&&d.getDate()===c?new Date(Date.UTC(b,e-1,c,0,0,0)):!1}function na(b){b=b||"0";""!==a.numbers.html.thousandsSeparator&&(b=V(b,a.numbers.html.thousandsSeparator,""));"."!==a.numbers.html.decimalMark&&(b=V(b,a.numbers.html.decimalMark,"."));return"number"===typeof b||!1!==jQuery.isNumeric(b)?b:!1}function Ma(b){-1<b.indexOf("%")?(b=na(b.replace(/%/g,"")),!1!==b&&(b/=100)):b=!1;return b}function D(b,c,e,p){var f="",l="text";
|
||||||
|
if(null!==b){var q=d(b);q.removeData("teUserDefText");if(q[0].hasAttribute("data-tableexport-canvas"))var h="";else if(q[0].hasAttribute("data-tableexport-value"))h=(h=q.attr("data-tableexport-value"))?h+"":"",q.data("teUserDefText",1);else if(h=q.html(),"function"===typeof a.onCellHtmlData)h=a.onCellHtmlData(q,c,e,h),q.data("teUserDefText",1);else if(""!==h){b=d.parseHTML(h);var g=0,k=0;h="";d.each(b,function(){if(d(this).is("input"))h+=q.find("input").eq(g++).val();else if(d(this).is("select"))h+=
|
||||||
|
q.find("select option:selected").eq(k++).text();else if(d(this).is("br"))h+="<br>";else{if("undefined"===typeof d(this).html())h+=d(this).text();else if(void 0===jQuery().bootstrapTable||!1===d(this).hasClass("fht-cell")&&!1===d(this).hasClass("filterControl")&&0===q.parents(".detail-view").length)h+=d(this).html();if(d(this).is("a")){var b=q.find("a").attr("href")||"";f="function"===typeof a.onCellHtmlHyperlink?f+a.onCellHtmlHyperlink(q,c,e,b,h):"href"===a.htmlHyperlink?f+b:f+h;h=""}}})}if(h&&""!==
|
||||||
|
h&&!0===a.htmlContent)f=d.trim(h);else if(h&&""!==h)if(""!==q.attr("data-tableexport-cellformat")){var m=h.replace(/\n/g,"\u2028").replace(/(<\s*br([^>]*)>)/gi,"\u2060"),n=d("<div/>").html(m).contents();b=!1;m="";d.each(n.text().split("\u2028"),function(b,c){0<b&&(m+=" ");!0!==a.preserve.leadingWS&&(c=la(c));m+=!0!==a.preserve.trailingWS?ma(c):c});d.each(m.split("\u2060"),function(b,c){0<b&&(f+="\n");!0!==a.preserve.leadingWS&&(c=la(c));!0!==a.preserve.trailingWS&&(c=ma(c));f+=c.replace(/\u00AD/g,
|
||||||
|
"")});f=f.replace(/\u00A0/g," ");if("json"===a.type||"excel"===a.type&&"xmlss"===a.mso.fileFormat||!1===a.numbers.output)b=na(f),!1!==b&&(l="number",f=Number(b));else if(a.numbers.html.decimalMark!==a.numbers.output.decimalMark||a.numbers.html.thousandsSeparator!==a.numbers.output.thousandsSeparator)if(b=na(f),!1!==b){n=(""+b.substr(0>b?1:0)).split(".");1===n.length&&(n[1]="");var t=3<n[0].length?n[0].length%3:0;l="number";f=(0>b?"-":"")+(a.numbers.output.thousandsSeparator?(t?n[0].substr(0,t)+a.numbers.output.thousandsSeparator:
|
||||||
|
"")+n[0].substr(t).replace(/(\d{3})(?=\d)/g,"$1"+a.numbers.output.thousandsSeparator):n[0])+(n[1].length?a.numbers.output.decimalMark+n[1]:"")}}else f=h;!0===a.escape&&(f=escape(f));"function"===typeof a.onCellData&&(f=a.onCellData(q,c,e,f,l),q.data("teUserDefText",1))}void 0!==p&&(p.type=l);return f}function Ba(b){return 0<b.length&&!0===a.preventInjection&&0<="=+-@".indexOf(b.charAt(0))?"'"+b:b}function Na(b,a,e){return a+"-"+e.toLowerCase()}function ea(b,a){(b=/^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)$/.exec(b))&&
|
||||||
|
(a=[parseInt(b[1]),parseInt(b[2]),parseInt(b[3])]);return a}function Ca(b){var a=M(b,"text-align"),e=M(b,"font-weight"),d=M(b,"font-style"),f="";"start"===a&&(a="rtl"===M(b,"direction")?"right":"left");700<=e&&(f="bold");"italic"===d&&(f+=d);""===f&&(f="normal");a={style:{align:a,bcolor:ea(M(b,"background-color"),[255,255,255]),color:ea(M(b,"color"),[0,0,0]),fstyle:f},colspan:J(b),rowspan:T(b)};null!==b&&(b=b.getBoundingClientRect(),a.rect={width:b.width,height:b.height});return a}function J(b){var a=
|
||||||
|
d(b).attr("data-tableexport-colspan");"undefined"===typeof a&&d(b).is("[colspan]")&&(a=d(b).attr("colspan"));return parseInt(a)||0}function T(b){var a=d(b).attr("data-tableexport-rowspan");"undefined"===typeof a&&d(b).is("[rowspan]")&&(a=d(b).attr("rowspan"));return parseInt(a)||0}function M(a,c){try{return window.getComputedStyle?(c=c.replace(/([a-z])([A-Z])/,Na),window.getComputedStyle(a,null).getPropertyValue(c)):a.currentStyle?a.currentStyle[c]:a.style[c]}catch(e){}return""}function fa(a,c,e){c=
|
||||||
|
M(a,c).match(/\d+/);if(null!==c){c=c[0];a=a.parentElement;var b=document.createElement("div");b.style.overflow="hidden";b.style.visibility="hidden";a.appendChild(b);b.style.width=100+e;e=100/b.offsetWidth;a.removeChild(b);return c*e}return 0}function Oa(a){for(var b=new ArrayBuffer(a.length),e=new Uint8Array(b),d=0;d!==a.length;++d)e[d]=a.charCodeAt(d)&255;return b}function oa(a){var b=a.c,e="";for(++b;b;b=Math.floor((b-1)/26))e=String.fromCharCode((b-1)%26+65)+e;return e+(""+(a.r+1))}function pa(a,
|
||||||
|
c){if("undefined"===typeof c||"number"===typeof c)return pa(a.s,a.e);"string"!==typeof a&&(a=oa(a));"string"!==typeof c&&(c=oa(c));return a===c?a:a+":"+c}function Da(a,c){var b=Number(a);if(isFinite(b))return b;var d=1;""!==c.thousandsSeparator&&(a=a.replace(new RegExp("([\\d])"+c.thousandsSeparator+"([\\d])","g"),"$1$2"));"."!==c.decimalMark&&(a=a.replace(new RegExp("([\\d])"+c.decimalMark+"([\\d])","g"),"$1.$2"));a=a.replace(/[$]/g,"").replace(/[%]/g,function(){d*=100;return""});if(isFinite(b=Number(a)))return b/
|
||||||
|
d;a=a.replace(/[(](.*)[)]/,function(a,b){d=-d;return b});return isFinite(b=Number(a))?b/d:b}function ya(a){var b=0,d;if(0===a.length)return b;var p=0;for(d=a.length;p<d;p++){var f=a.charCodeAt(p);b=(b<<5)-b+f;b|=0}return b}function N(b,c,d,p,f,l){var e=!0;"function"===typeof a.onBeforeSaveToFile&&(e=a.onBeforeSaveToFile(b,c,d,p,f),"boolean"!==typeof e&&(e=!0));if(e)try{if(Ea=new Blob([b],{type:d+";charset="+p}),saveAs(Ea,c,!1===l),"function"===typeof a.onAfterSaveToFile)a.onAfterSaveToFile(b,c)}catch(h){ka(c,
|
||||||
|
"data:"+d+(p.length?";charset="+p:"")+(f.length?";"+f:"")+",",l?"\ufeff"+b:b)}}function ka(b,c,d){var e=window.navigator.userAgent;if(!1!==b&&window.navigator.msSaveOrOpenBlob)window.navigator.msSaveOrOpenBlob(new Blob([d]),b);else if(!1!==b&&(0<e.indexOf("MSIE ")||e.match(/Trident.*rv\:11\./))){if(c=document.createElement("iframe")){document.body.appendChild(c);c.setAttribute("style","display:none");c.contentDocument.open("txt/plain","replace");c.contentDocument.write(d);c.contentDocument.close();
|
||||||
|
c.contentWindow.focus();switch(b.substr(b.lastIndexOf(".")+1)){case "doc":case "json":case "png":case "pdf":case "xls":case "xlsx":b+=".txt"}c.contentDocument.execCommand("SaveAs",!0,b);document.body.removeChild(c)}}else{var f=document.createElement("a");if(f){var l=null;f.style.display="none";!1!==b?f.download=b:f.target="_blank";"object"===typeof d?(window.URL=window.URL||window.webkitURL,e=[],e.push(d),l=window.URL.createObjectURL(new Blob(e,{type:c})),f.href=l):0<=c.toLowerCase().indexOf("base64,")?
|
||||||
|
f.href=c+L(d):f.href=c+encodeURIComponent(d);document.body.appendChild(f);if(document.createEvent)null===ha&&(ha=document.createEvent("MouseEvents")),ha.initEvent("click",!0,!1),f.dispatchEvent(ha);else if(document.createEventObject)f.fireEvent("onclick");else if("function"===typeof f.onclick)f.onclick();setTimeout(function(){l&&window.URL.revokeObjectURL(l);document.body.removeChild(f);if("function"===typeof a.onAfterSaveToFile)a.onAfterSaveToFile(d,b)},100)}}}function L(a){var b,d="",p=0;if("string"===
|
||||||
|
typeof a){a=a.replace(/\x0d\x0a/g,"\n");var f="";for(b=0;b<a.length;b++){var l=a.charCodeAt(b);128>l?f+=String.fromCharCode(l):(127<l&&2048>l?f+=String.fromCharCode(l>>6|192):(f+=String.fromCharCode(l>>12|224),f+=String.fromCharCode(l>>6&63|128)),f+=String.fromCharCode(l&63|128))}a=f}for(;p<a.length;){var q=a.charCodeAt(p++);f=a.charCodeAt(p++);b=a.charCodeAt(p++);l=q>>2;q=(q&3)<<4|f>>4;var h=(f&15)<<2|b>>6;var g=b&63;isNaN(f)?h=g=64:isNaN(b)&&(g=64);d=d+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(l)+
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(q)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(g)}return d}var a={csvEnclosure:'"',csvSeparator:",",csvUseBOM:!0,date:{html:"dd/mm/yyyy"},displayTableName:!1,escape:!1,exportHiddenCells:!1,fileName:"tableExport",htmlContent:!1,htmlHyperlink:"content",ignoreColumn:[],ignoreRow:[],jsonScope:"all",jspdf:{orientation:"p",
|
||||||
|
unit:"pt",format:"a4",margins:{left:20,right:10,top:10,bottom:10},onDocCreated:null,autotable:{styles:{cellPadding:2,rowHeight:12,fontSize:8,fillColor:255,textColor:50,fontStyle:"normal",overflow:"ellipsize",halign:"inherit",valign:"middle"},headerStyles:{fillColor:[52,73,94],textColor:255,fontStyle:"bold",halign:"inherit",valign:"middle"},alternateRowStyles:{fillColor:245},tableExport:{doc:null,onAfterAutotable:null,onBeforeAutotable:null,onAutotableText:null,onTable:null,outputImages:!0}}},mso:{fileFormat:"xlshtml",
|
||||||
|
onMsoNumberFormat:null,pageFormat:"a4",pageOrientation:"portrait",rtl:!1,styles:[],worksheetName:"",xslx:{formatId:{date:14,numbers:2}}},numbers:{html:{decimalMark:".",thousandsSeparator:","},output:{decimalMark:".",thousandsSeparator:","}},onAfterSaveToFile:null,onBeforeSaveToFile:null,onCellData:null,onCellHtmlData:null,onCellHtmlHyperlink:null,onIgnoreRow:null,onTableExportBegin:null,onTableExportEnd:null,outputMode:"file",pdfmake:{enabled:!1,docDefinition:{pageOrientation:"portrait",defaultStyle:{font:"Roboto"}},
|
||||||
|
fonts:{}},preserve:{leadingWS:!1,trailingWS:!1},preventInjection:!0,sql:{tableEnclosure:"`",columnEnclosure:"`"},tbodySelector:"tr",tfootSelector:"tr",theadSelector:"tr",tableName:"Table",type:"csv"},O={a0:[2383.94,3370.39],a1:[1683.78,2383.94],a2:[1190.55,1683.78],a3:[841.89,1190.55],a4:[595.28,841.89],a5:[419.53,595.28],a6:[297.64,419.53],a7:[209.76,297.64],a8:[147.4,209.76],a9:[104.88,147.4],a10:[73.7,104.88],b0:[2834.65,4008.19],b1:[2004.09,2834.65],b2:[1417.32,2004.09],b3:[1000.63,1417.32],b4:[708.66,
|
||||||
|
1000.63],b5:[498.9,708.66],b6:[354.33,498.9],b7:[249.45,354.33],b8:[175.75,249.45],b9:[124.72,175.75],b10:[87.87,124.72],c0:[2599.37,3676.54],c1:[1836.85,2599.37],c2:[1298.27,1836.85],c3:[918.43,1298.27],c4:[649.13,918.43],c5:[459.21,649.13],c6:[323.15,459.21],c7:[229.61,323.15],c8:[161.57,229.61],c9:[113.39,161.57],c10:[79.37,113.39],dl:[311.81,623.62],letter:[612,792],"government-letter":[576,756],legal:[612,1008],"junior-legal":[576,360],ledger:[1224,792],tabloid:[792,1224],"credit-card":[153,
|
||||||
|
243]},B=this,ha=null,r=[],w=[],n=0,t="",S=[],G=[],Ea,K=[],U=!1;d.extend(!0,a,k);"xlsx"===a.type&&(a.mso.fileFormat=a.type,a.type="excel");"undefined"!==typeof a.excelFileFormat&&"undefined"===a.mso.fileFormat&&(a.mso.fileFormat=a.excelFileFormat);"undefined"!==typeof a.excelPageFormat&&"undefined"===a.mso.pageFormat&&(a.mso.pageFormat=a.excelPageFormat);"undefined"!==typeof a.excelPageOrientation&&"undefined"===a.mso.pageOrientation&&(a.mso.pageOrientation=a.excelPageOrientation);"undefined"!==typeof a.excelRTL&&
|
||||||
|
"undefined"===a.mso.rtl&&(a.mso.rtl=a.excelRTL);"undefined"!==typeof a.excelstyles&&"undefined"===a.mso.styles&&(a.mso.styles=a.excelstyles);"undefined"!==typeof a.onMsoNumberFormat&&"undefined"===a.mso.onMsoNumberFormat&&(a.mso.onMsoNumberFormat=a.onMsoNumberFormat);"undefined"!==typeof a.worksheetName&&"undefined"===a.mso.worksheetName&&(a.mso.worksheetName=a.worksheetName);a.mso.pageOrientation="l"===a.mso.pageOrientation.substr(0,1)?"landscape":"portrait";a.date.html=a.date.html||"";if(a.date.html.length){k=
|
||||||
|
[];k.dd="(3[01]|[12][0-9]|0?[1-9])";k.mm="(1[012]|0?[1-9])";k.yyyy="((?:1[6-9]|2[0-2])\\d{2})";k.yy="(\\d{2})";var z=a.date.html.match(/[^a-zA-Z0-9]/)[0];z=a.date.html.toLowerCase().split(z);a.date.regex="^\\s*";a.date.regex+=k[z[0]];a.date.regex+="(.)";a.date.regex+=k[z[1]];a.date.regex+="\\2";a.date.regex+=k[z[2]];a.date.regex+="\\s*$";a.date.pattern=new RegExp(a.date.regex,"g");k=z.indexOf("dd")+1;a.date.match_d=k+(1<k?1:0);k=z.indexOf("mm")+1;a.date.match_m=k+(1<k?1:0);k=(0<=z.indexOf("yyyy")?
|
||||||
|
z.indexOf("yyyy"):z.indexOf("yy"))+1;a.date.match_y=k+(1<k?1:0)}S=R(B);if("function"===typeof a.onTableExportBegin)a.onTableExportBegin();if("csv"===a.type||"tsv"===a.type||"txt"===a.type){var P="",Y=0;G=[];n=0;var qa=function(b,c,e){b.each(function(){t="";E(this,c,n,e+b.length,function(b,c,d){var e=t,f="";if(null!==b)if(b=D(b,c,d),c=null===b||""===b?"":b.toString(),"tsv"===a.type)b instanceof Date&&b.toLocaleString(),f=V(c,"\t"," ");else if(b instanceof Date)f=a.csvEnclosure+b.toLocaleString()+a.csvEnclosure;
|
||||||
|
else if(f=Ba(c),f=V(f,a.csvEnclosure,a.csvEnclosure+a.csvEnclosure),0<=f.indexOf(a.csvSeparator)||/[\r\n ]/g.test(f))f=a.csvEnclosure+f+a.csvEnclosure;t=e+(f+("tsv"===a.type?"\t":a.csvSeparator))});t=d.trim(t).substring(0,t.length-1);0<t.length&&(0<P.length&&(P+="\n"),P+=t);n++});return b.length};Y+=qa(d(B).find("thead").first().find(a.theadSelector),"th,td",Y);v(d(B),"tbody").each(function(){Y+=qa(v(d(this),a.tbodySelector),"td,th",Y)});a.tfootSelector.length&&qa(d(B).find("tfoot").first().find(a.tfootSelector),
|
||||||
|
"td,th",Y);P+="\n";if("string"===a.outputMode)return P;if("base64"===a.outputMode)return L(P);if("window"===a.outputMode){ka(!1,"data:text/"+("csv"===a.type?"csv":"plain")+";charset=utf-8,",P);return}N(P,a.fileName+"."+a.type,"text/"+("csv"===a.type?"csv":"plain"),"utf-8","","csv"===a.type&&a.csvUseBOM)}else if("sql"===a.type){n=0;G=[];var A="INSERT INTO "+a.sql.tableEnclosure+a.tableName+a.sql.tableEnclosure+" (";r=y(d(B));d(r).each(function(){E(this,"th,td",n,r.length,function(b,c,d){b=D(b,c,d)||
|
||||||
|
"";-1<b.indexOf(a.sql.columnEnclosure)&&(b=V(b.toString(),a.sql.columnEnclosure,a.sql.columnEnclosure+a.sql.columnEnclosure));A+=a.sql.columnEnclosure+b+a.sql.columnEnclosure+","});n++;A=d.trim(A).substring(0,A.length-1)});A+=") VALUES ";w=C(d(B));d(w).each(function(){t="";E(this,"td,th",n,r.length+w.length,function(a,c,d){a=D(a,c,d)||"";-1<a.indexOf("'")&&(a=V(a.toString(),"'","''"));t+="'"+a+"',"});3<t.length&&(A+="("+t,A=d.trim(A).substring(0,A.length-1),A+="),");n++});A=d.trim(A).substring(0,
|
||||||
|
A.length-1);A+=";";if("string"===a.outputMode)return A;if("base64"===a.outputMode)return L(A);N(A,a.fileName+".sql","application/sql","utf-8","",!1)}else if("json"===a.type){var W=[];G=[];r=y(d(B));d(r).each(function(){var a=[];E(this,"th,td",n,r.length,function(b,d,g){a.push(D(b,d,g))});W.push(a)});var ra=[];w=C(d(B));d(w).each(function(){var a={},c=0;E(this,"td,th",n,r.length+w.length,function(b,d,f){W.length?a[W[W.length-1][c]]=D(b,d,f):a[c]=D(b,d,f);c++});!1===d.isEmptyObject(a)&&ra.push(a);n++});
|
||||||
|
k="head"===a.jsonScope?JSON.stringify(W):"data"===a.jsonScope?JSON.stringify(ra):JSON.stringify({header:W,data:ra});if("string"===a.outputMode)return k;if("base64"===a.outputMode)return L(k);N(k,a.fileName+".json","application/json","utf-8","base64",!1)}else if("xml"===a.type){n=0;G=[];var Q='<?xml version="1.0" encoding="utf-8"?>';Q+="<tabledata><fields>";r=y(d(B));d(r).each(function(){E(this,"th,td",n,r.length,function(a,d,e){Q+="<field>"+D(a,d,e)+"</field>"});n++});Q+="</fields><data>";var Fa=
|
||||||
|
1;w=C(d(B));d(w).each(function(){var a=1;t="";E(this,"td,th",n,r.length+w.length,function(b,d,g){t+="<column-"+a+">"+D(b,d,g)+"</column-"+a+">";a++});0<t.length&&"<column-1></column-1>"!==t&&(Q+='<row id="'+Fa+'">'+t+"</row>",Fa++);n++});Q+="</data></tabledata>";if("string"===a.outputMode)return Q;if("base64"===a.outputMode)return L(Q);N(Q,a.fileName+".xml","application/xml","utf-8","base64",!1)}else if("excel"===a.type&&"xmlss"===a.mso.fileFormat){var sa=[],F=[];d(B).filter(function(){return I(d(this))}).each(function(){function b(a,
|
||||||
|
b,c){var e=[];d(a).each(function(){var b=0,f=0;t="";E(this,"td,th",n,c+a.length,function(a,c,l){if(null!==a){var h="";c=D(a,c,l);l="String";if(!1!==jQuery.isNumeric(c))l="Number";else{var g=Ma(c);!1!==g&&(c=g,l="Number",h+=' ss:StyleID="pct1"')}"Number"!==l&&(c=c.replace(/\n/g,"<br>"));g=J(a);a=T(a);d.each(e,function(){if(n>=this.s.r&&n<=this.e.r&&f>=this.s.c&&f<=this.e.c)for(var a=0;a<=this.e.c-this.s.c;++a)f++,b++});if(a||g)a=a||1,g=g||1,e.push({s:{r:n,c:f},e:{r:n+a-1,c:f+g-1}});1<g&&(h+=' ss:MergeAcross="'+
|
||||||
|
(g-1)+'"',f+=g-1);1<a&&(h+=' ss:MergeDown="'+(a-1)+'" ss:StyleID="rsp1"');0<b&&(h+=' ss:Index="'+(f+1)+'"',b=0);t+="<Cell"+h+'><Data ss:Type="'+l+'">'+d("<div />").text(c).html()+"</Data></Cell>\r";f++}});0<t.length&&(H+='<Row ss:AutoFitHeight="0">\r'+t+"</Row>\r");n++});return a.length}var c=d(this),e="";"string"===typeof a.mso.worksheetName&&a.mso.worksheetName.length?e=a.mso.worksheetName+" "+(F.length+1):"undefined"!==typeof a.mso.worksheetName[F.length]&&(e=a.mso.worksheetName[F.length]);e.length||
|
||||||
|
(e=c.find("caption").text()||"");e.length||(e="Table "+(F.length+1));e=d.trim(e.replace(/[\\\/[\]*:?'"]/g,"").substring(0,31));F.push(d("<div />").text(e).html());!1===a.exportHiddenCells&&(K=c.find("tr, th, td").filter(":hidden"),U=0<K.length);n=0;S=R(this);H="<Table>\r";e=b(y(c),"th,td",0);b(C(c),"td,th",e);H+="</Table>\r";sa.push(H)});k={};z={};for(var m,Z,X=0,da=F.length;X<da;X++)m=F[X],Z=k[m],Z=k[m]=null==Z?1:Z+1,2===Z&&(F[z[m]]=F[z[m]].substring(0,29)+"-1"),1<k[m]?F[X]=F[X].substring(0,29)+
|
||||||
|
"-"+k[m]:z[m]=X;k='<?xml version="1.0" encoding="UTF-8"?>\r<?mso-application progid="Excel.Sheet"?>\r<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"\r xmlns:o="urn:schemas-microsoft-com:office:office"\r xmlns:x="urn:schemas-microsoft-com:office:excel"\r xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"\r xmlns:html="http://www.w3.org/TR/REC-html40">\r<DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">\r <Created>'+(new Date).toISOString()+'</Created>\r</DocumentProperties>\r<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">\r <AllowPNG/>\r</OfficeDocumentSettings>\r<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">\r <WindowHeight>9000</WindowHeight>\r <WindowWidth>13860</WindowWidth>\r <WindowTopX>0</WindowTopX>\r <WindowTopY>0</WindowTopY>\r <ProtectStructure>False</ProtectStructure>\r <ProtectWindows>False</ProtectWindows>\r</ExcelWorkbook>\r<Styles>\r <Style ss:ID="Default" ss:Name="Normal">\r <Alignment ss:Vertical="Bottom"/>\r <Borders/>\r <Font/>\r <Interior/>\r <NumberFormat/>\r <Protection/>\r </Style>\r <Style ss:ID="rsp1">\r <Alignment ss:Vertical="Center"/>\r </Style>\r <Style ss:ID="pct1">\r <NumberFormat ss:Format="Percent"/>\r </Style>\r</Styles>\r';
|
||||||
|
for(z=0;z<sa.length;z++)k+='<Worksheet ss:Name="'+F[z]+'" ss:RightToLeft="'+(a.mso.rtl?"1":"0")+'">\r'+sa[z],k=a.mso.rtl?k+'<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">\r<DisplayRightToLeft/>\r</WorksheetOptions>\r':k+'<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel"/>\r',k+="</Worksheet>\r";k+="</Workbook>\r";if("string"===a.outputMode)return k;if("base64"===a.outputMode)return L(k);N(k,a.fileName+".xml","application/xml","utf-8","base64",!1)}else if("excel"===
|
||||||
|
a.type&&"xlsx"===a.mso.fileFormat){var aa=[],Ga=XLSX.utils.book_new();d(B).filter(function(){return I(d(this))}).each(function(){for(var b=d(this),c={},e=this.getElementsByTagName("tr"),g={s:{r:0,c:0},e:{r:0,c:0}},f=[],l,q=[],h=0,u=0,k,m,n,t,r,w=XLSX.SSF.get_table();h<e.length&&1E7>u;++h)if(k=e[h],m=!1,"function"===typeof a.onIgnoreRow&&(m=a.onIgnoreRow(d(k),h)),!0!==m&&(0===a.ignoreRow.length||-1===d.inArray(h,a.ignoreRow)&&-1===d.inArray(h-e.length,a.ignoreRow))&&!1!==I(d(k))){var y=k.children,
|
||||||
|
B=0;for(k=0;k<y.length;++k)r=y[k],t=+J(r)||1,B+=t;var z=0;for(k=m=0;k<y.length;++k)if(r=y[k],t=+J(r)||1,l=k+z,!ta(d(r),B,l+(l<m?m-l:0))){z+=t-1;for(l=0;l<f.length;++l){var v=f[l];v.s.c==m&&v.s.r<=u&&u<=v.e.r&&(m=v.e.c+1,l=-1)}(0<(n=+T(r))||1<t)&&f.push({s:{r:u,c:m},e:{r:u+(n||1)-1,c:m+t-1}});var C={type:""};l=D(r,h,k+z,C);v={t:"s",v:l};var A="";if(""!==d(r).attr("data-tableexport-cellformat")){var x=parseInt(d(r).attr("data-tableexport-xlsxformatid")||0);0===x&&"function"===typeof a.mso.xslx.formatId.numbers&&
|
||||||
|
(x=a.mso.xslx.formatId.numbers(d(r),h,k+z));0===x&&"function"===typeof a.mso.xslx.formatId.date&&(x=a.mso.xslx.formatId.date(d(r),h,k+z));if(49===x||"@"===x)A="s";else if("number"===C.type||0<x&&14>x||36<x&&41>x||48===x)A="n";else if("date"===C.type||13<x&&37>x||44<x&&48>x||56===x)A="d"}else A="s";if(null!=l)if(0===l.length)v.t="z";else if(0!==l.trim().length&&"s"!==A)if("function"===C.type)v={f:l};else if("TRUE"===l)v={t:"b",v:!0};else if("FALSE"===l)v={t:"b",v:!1};else if(""===A&&d(r).find("a").length)l=
|
||||||
|
"href"!==a.htmlHyperlink?l:"",v={f:'=HYPERLINK("'+d(r).find("a").attr("href")+(l.length?'","'+l:"")+'")'};else if("n"===A||isFinite(Da(l,a.numbers.output))){if(r=Da(l,a.numbers.output),0===x&&"function"!==typeof a.mso.xslx.formatId.numbers&&(x=a.mso.xslx.formatId.numbers),isFinite(r)||isFinite(l))v={t:"n",v:isFinite(r)?r:l,z:"string"===typeof x?x:x in w?w[x]:"0.00"}}else if(!1!==(r=La(l))||"d"===A)0===x&&"function"!==typeof a.mso.xslx.formatId.date&&(x=a.mso.xslx.formatId.date),v={t:"d",v:!1!==r?
|
||||||
|
r:l,z:"string"===typeof x?x:x in w?w[x]:"m/d/yy"};c[oa({c:m,r:u})]=v;g.e.c<m&&(g.e.c=m);m+=t}++u}f.length&&(c["!merges"]=f);q.length&&(c["!rows"]=q);g.e.r=u-1;c["!ref"]=pa(g);1E7<=u&&(c["!fullref"]=pa((g.e.r=e.length-h+u-1,g)));e="";"string"===typeof a.mso.worksheetName&&a.mso.worksheetName.length?e=a.mso.worksheetName+" "+(aa.length+1):"undefined"!==typeof a.mso.worksheetName[aa.length]&&(e=a.mso.worksheetName[aa.length]);e.length||(e=b.find("caption").text()||"");e.length||(e="Table "+(aa.length+
|
||||||
|
1));e=d.trim(e.replace(/[\\\/[\]*:?'"]/g,"").substring(0,31));aa.push(e);XLSX.utils.book_append_sheet(Ga,c,e)});k=XLSX.write(Ga,{type:"binary",bookType:a.mso.fileFormat,bookSST:!1});N(Oa(k),a.fileName+"."+a.mso.fileFormat,"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet","UTF-8","",!1)}else if("excel"===a.type||"xls"===a.type||"word"===a.type||"doc"===a.type){k="excel"===a.type||"xls"===a.type?"excel":"word";z="excel"===k?"xls":"doc";m='xmlns:x="urn:schemas-microsoft-com:office:'+
|
||||||
|
k+'"';var H="",ba="";d(B).filter(function(){return I(d(this))}).each(function(){var b=d(this);""===ba&&(ba=a.mso.worksheetName||b.find("caption").text()||"Table",ba=d.trim(ba.replace(/[\\\/[\]*:?'"]/g,"").substring(0,31)));!1===a.exportHiddenCells&&(K=b.find("tr, th, td").filter(":hidden"),U=0<K.length);n=0;G=[];S=R(this);H+="<table><thead>";r=y(b);d(r).each(function(){var b=d(this);t="";E(this,"th,td",n,r.length,function(d,c,f){if(null!==d){var e="";t+="<th";if(a.mso.styles.length){var g=document.defaultView.getComputedStyle(d,
|
||||||
|
null),h=document.defaultView.getComputedStyle(b[0],null),k;for(k in a.mso.styles){var m=g[a.mso.styles[k]];""===m&&(m=h[a.mso.styles[k]]);""!==m&&"0px none rgb(0, 0, 0)"!==m&&"rgba(0, 0, 0, 0)"!==m&&(e+=""===e?'style="':";",e+=a.mso.styles[k]+":"+m)}}""!==e&&(t+=" "+e+'"');e=J(d);0<e&&(t+=' colspan="'+e+'"');e=T(d);0<e&&(t+=' rowspan="'+e+'"');t+=">"+D(d,c,f)+"</th>"}});0<t.length&&(H+="<tr>"+t+"</tr>");n++});H+="</thead><tbody>";w=C(b);d(w).each(function(){var b=d(this);t="";E(this,"td,th",n,r.length+
|
||||||
|
w.length,function(c,g,f){if(null!==c){var e=D(c,g,f),q="",h=d(c).attr("data-tableexport-msonumberformat");"undefined"===typeof h&&"function"===typeof a.mso.onMsoNumberFormat&&(h=a.mso.onMsoNumberFormat(c,g,f));"undefined"!==typeof h&&""!==h&&(q="style=\"mso-number-format:'"+h+"'");if(a.mso.styles.length){g=document.defaultView.getComputedStyle(c,null);f=document.defaultView.getComputedStyle(b[0],null);for(var k in a.mso.styles)h=g[a.mso.styles[k]],""===h&&(h=f[a.mso.styles[k]]),""!==h&&"0px none rgb(0, 0, 0)"!==
|
||||||
|
h&&"rgba(0, 0, 0, 0)"!==h&&(q+=""===q?'style="':";",q+=a.mso.styles[k]+":"+h)}t+="<td";""!==q&&(t+=" "+q+'"');q=J(c);0<q&&(t+=' colspan="'+q+'"');c=T(c);0<c&&(t+=' rowspan="'+c+'"');"string"===typeof e&&""!==e&&(e=Ba(e),e=e.replace(/\n/g,"<br>"));t+=">"+e+"</td>"}});0<t.length&&(H+="<tr>"+t+"</tr>");n++});a.displayTableName&&(H+="<tr><td></td></tr><tr><td></td></tr><tr><td>"+D(d("<p>"+a.tableName+"</p>"))+"</td></tr>");H+="</tbody></table>"});m='<html xmlns:o="urn:schemas-microsoft-com:office:office" '+
|
||||||
|
m+' xmlns="http://www.w3.org/TR/REC-html40">'+('<meta http-equiv="content-type" content="application/vnd.ms-'+k+'; charset=UTF-8">')+"<head>";"excel"===k&&(m+="\x3c!--[if gte mso 9]>",m+="<xml>",m+="<x:ExcelWorkbook>",m+="<x:ExcelWorksheets>",m+="<x:ExcelWorksheet>",m+="<x:Name>",m+=ba,m+="</x:Name>",m+="<x:WorksheetOptions>",m+="<x:DisplayGridlines/>",a.mso.rtl&&(m+="<x:DisplayRightToLeft/>"),m+="</x:WorksheetOptions>",m+="</x:ExcelWorksheet>",m+="</x:ExcelWorksheets>",m+="</x:ExcelWorkbook>",m+=
|
||||||
|
"</xml>",m+="<![endif]--\x3e");m+="<style>";m+="@page { size:"+a.mso.pageOrientation+"; mso-page-orientation:"+a.mso.pageOrientation+"; }";m+="@page Section1 {size:"+O[a.mso.pageFormat][0]+"pt "+O[a.mso.pageFormat][1]+"pt";m+="; margin:1.0in 1.25in 1.0in 1.25in;mso-header-margin:.5in;mso-footer-margin:.5in;mso-paper-source:0;}";m+="div.Section1 {page:Section1;}";m+="@page Section2 {size:"+O[a.mso.pageFormat][1]+"pt "+O[a.mso.pageFormat][0]+"pt";m+=";mso-page-orientation:"+a.mso.pageOrientation+";margin:1.25in 1.0in 1.25in 1.0in;mso-header-margin:.5in;mso-footer-margin:.5in;mso-paper-source:0;}";
|
||||||
|
m+="div.Section2 {page:Section2;}";m+="br {mso-data-placement:same-cell;}";m+="</style>";m+="</head>";m+="<body>";m+='<div class="Section'+("landscape"===a.mso.pageOrientation?"2":"1")+'">';m+=H;m+="</div>";m+="</body>";m+="</html>";if("string"===a.outputMode)return m;if("base64"===a.outputMode)return L(m);N(m,a.fileName+"."+z,"application/vnd.ms-"+k,"","base64",!1)}else if("png"===a.type)html2canvas(d(B)[0]).then(function(b){b=b.toDataURL();for(var c=atob(b.substring(22)),d=new ArrayBuffer(c.length),
|
||||||
|
g=new Uint8Array(d),f=0;f<c.length;f++)g[f]=c.charCodeAt(f);if("string"===a.outputMode)return c;if("base64"===a.outputMode)return L(b);"window"===a.outputMode?window.open(b):N(d,a.fileName+".png","image/png","","",!1)});else if("pdf"===a.type)if(!0===a.pdfmake.enabled){var ia={content:[]};d.extend(!0,ia,a.pdfmake.docDefinition);G=[];d(B).filter(function(){return I(d(this))}).each(function(){var a=d(this),c=[],e=[];n=0;var g=function(a,b,c){var f=0;d(a).each(function(){var a=[];E(this,b,n,c,function(b,
|
||||||
|
d,c){if("undefined"!==typeof b&&null!==b){var f=J(b),e=T(b);b=D(b,d,c)||" ";1<f||1<e?a.push({colSpan:f||1,rowSpan:e||1,text:b}):a.push(b)}else a.push(" ")});a.length&&e.push(a);f<a.length&&(f=a.length);n++});return f};r=y(a);for(var f=g(r,"th,td",r.length),l=c.length;l<f;l++)c.push("*");w=C(a);g(w,"th,td",r.length+w.length);ia.content.push({table:{headerRows:r.length,widths:c,body:e},pageBreak:ia.content.length?"before":void 0})});"undefined"!==typeof pdfMake&&"undefined"!==typeof pdfMake.createPdf&&
|
||||||
|
(pdfMake.fonts={Roboto:{normal:"Roboto-Regular.ttf",bold:"Roboto-Medium.ttf",italics:"Roboto-Italic.ttf",bolditalics:"Roboto-MediumItalic.ttf"}},pdfMake.vfs.hasOwnProperty("Mirza-Regular.ttf")?(a.pdfmake.docDefinition.defaultStyle.font="Mirza",d.extend(!0,pdfMake.fonts,{Mirza:{normal:"Mirza-Regular.ttf",bold:"Mirza-Bold.ttf",italics:"Mirza-Medium.ttf",bolditalics:"Mirza-SemiBold.ttf"}})):pdfMake.vfs.hasOwnProperty("gbsn00lp.ttf")?(a.pdfmake.docDefinition.defaultStyle.font="gbsn00lp",d.extend(!0,pdfMake.fonts,
|
||||||
|
{gbsn00lp:{normal:"gbsn00lp.ttf",bold:"gbsn00lp.ttf",italics:"gbsn00lp.ttf",bolditalics:"gbsn00lp.ttf"}})):pdfMake.vfs.hasOwnProperty("ZCOOLXiaoWei-Regular.ttf")&&(a.pdfmake.docDefinition.defaultStyle.font="ZCOOLXiaoWei",d.extend(!0,pdfMake.fonts,{ZCOOLXiaoWei:{normal:"ZCOOLXiaoWei-Regular.ttf",bold:"ZCOOLXiaoWei-Regular.ttf",italics:"ZCOOLXiaoWei-Regular.ttf",bolditalics:"ZCOOLXiaoWei-Regular.ttf"}})),d.extend(!0,pdfMake.fonts,a.pdfmake.fonts),pdfMake.createPdf(ia).getBuffer(function(b){N(b,a.fileName+
|
||||||
|
".pdf","application/pdf","","",!1)}))}else if(!1===a.jspdf.autotable){k={dim:{w:fa(d(B).first().get(0),"width","mm"),h:fa(d(B).first().get(0),"height","mm")},pagesplit:!1};var Ha=new jsPDF(a.jspdf.orientation,a.jspdf.unit,a.jspdf.format);Ha.addHTML(d(B).first(),a.jspdf.margins.left,a.jspdf.margins.top,k,function(){va(Ha,!1)})}else{var g=a.jspdf.autotable.tableExport;if("string"===typeof a.jspdf.format&&"bestfit"===a.jspdf.format.toLowerCase()){var ja="",ca="",Ia=0;d(B).each(function(){if(I(d(this))){var a=
|
||||||
|
fa(d(this).get(0),"width","pt");if(a>Ia){a>O.a0[0]&&(ja="a0",ca="l");for(var c in O)O.hasOwnProperty(c)&&O[c][1]>a&&(ja=c,ca="l",O[c][0]>a&&(ca="p"));Ia=a}}});a.jspdf.format=""===ja?"a4":ja;a.jspdf.orientation=""===ca?"w":ca}if(null==g.doc&&(g.doc=new jsPDF(a.jspdf.orientation,a.jspdf.unit,a.jspdf.format),g.wScaleFactor=1,g.hScaleFactor=1,"function"===typeof a.jspdf.onDocCreated))a.jspdf.onDocCreated(g.doc);!0===g.outputImages&&(g.images={});"undefined"!==typeof g.images&&(d(B).filter(function(){return I(d(this))}).each(function(){var b=
|
||||||
|
0;G=[];!1===a.exportHiddenCells&&(K=d(this).find("tr, th, td").filter(":hidden"),U=0<K.length);r=y(d(this));w=C(d(this));d(w).each(function(){E(this,"td,th",r.length+b,r.length+w.length,function(a){xa(a,d(a).children(),g)});b++})}),r=[],w=[]);Ka(g,function(){d(B).filter(function(){return I(d(this))}).each(function(){var b;n=0;G=[];!1===a.exportHiddenCells&&(K=d(this).find("tr, th, td").filter(":hidden"),U=0<K.length);S=R(this);g.columns=[];g.rows=[];g.teCells={};if("function"===typeof g.onTable&&
|
||||||
|
!1===g.onTable(d(this),a))return!0;a.jspdf.autotable.tableExport=null;var c=d.extend(!0,{},a.jspdf.autotable);a.jspdf.autotable.tableExport=g;c.margin={};d.extend(!0,c.margin,a.jspdf.margins);c.tableExport=g;"function"!==typeof c.beforePageContent&&(c.beforePageContent=function(a){if(1===a.pageCount){var b=a.table.rows.concat(a.table.headerRow);d.each(b,function(){0<this.height&&(this.height+=(2-1.15)/2*this.styles.fontSize,a.table.height+=(2-1.15)/2*this.styles.fontSize)})}});"function"!==typeof c.createdHeaderCell&&
|
||||||
|
(c.createdHeaderCell=function(a,b){a.styles=d.extend({},b.row.styles);if("undefined"!==typeof g.columns[b.column.dataKey]){var e=g.columns[b.column.dataKey];if("undefined"!==typeof e.rect){a.contentWidth=e.rect.width;if("undefined"===typeof g.heightRatio||0===g.heightRatio){var f=b.row.raw[b.column.dataKey].rowspan?b.row.raw[b.column.dataKey].rect.height/b.row.raw[b.column.dataKey].rowspan:b.row.raw[b.column.dataKey].rect.height;g.heightRatio=a.styles.rowHeight/f}f=b.row.raw[b.column.dataKey].rect.height*
|
||||||
|
g.heightRatio;f>a.styles.rowHeight&&(a.styles.rowHeight=f)}a.styles.halign="inherit"===c.headerStyles.halign?"center":c.headerStyles.halign;a.styles.valign=c.headerStyles.valign;"undefined"!==typeof e.style&&!0!==e.style.hidden&&("inherit"===c.headerStyles.halign&&(a.styles.halign=e.style.align),"inherit"===c.styles.fillColor&&(a.styles.fillColor=e.style.bcolor),"inherit"===c.styles.textColor&&(a.styles.textColor=e.style.color),"inherit"===c.styles.fontStyle&&(a.styles.fontStyle=e.style.fstyle))}});
|
||||||
|
"function"!==typeof c.createdCell&&(c.createdCell=function(a,b){b=g.teCells[b.row.index+":"+b.column.dataKey];a.styles.halign="inherit"===c.styles.halign?"center":c.styles.halign;a.styles.valign=c.styles.valign;"undefined"!==typeof b&&"undefined"!==typeof b.style&&!0!==b.style.hidden&&("inherit"===c.styles.halign&&(a.styles.halign=b.style.align),"inherit"===c.styles.fillColor&&(a.styles.fillColor=b.style.bcolor),"inherit"===c.styles.textColor&&(a.styles.textColor=b.style.color),"inherit"===c.styles.fontStyle&&
|
||||||
|
(a.styles.fontStyle=b.style.fstyle))});"function"!==typeof c.drawHeaderCell&&(c.drawHeaderCell=function(a,b){var d=g.columns[b.column.dataKey];return(!0!==d.style.hasOwnProperty("hidden")||!0!==d.style.hidden)&&0<=d.rowIndex?wa(a,b,d):!1});"function"!==typeof c.drawCell&&(c.drawCell=function(a,b){var c=g.teCells[b.row.index+":"+b.column.dataKey];if(!0!==("undefined"!==typeof c&&c.isCanvas))wa(a,b,c)&&(g.doc.rect(a.x,a.y,a.width,a.height,a.styles.fillStyle),"undefined"===typeof c||"undefined"!==typeof c.hasUserDefText&&
|
||||||
|
!0===c.hasUserDefText||"undefined"===typeof c.elements||!c.elements.length?Aa(a,{},g):(b=a.height/c.rect.height,b>g.hScaleFactor&&(g.hScaleFactor=b),g.wScaleFactor=a.width/c.rect.width,b=a.textPos.y,za(a,c.elements,g),a.textPos.y=b,Aa(a,c.elements,g)));else{c=c.elements[0];var e=d(c).attr("data-tableexport-canvas"),f=c.getBoundingClientRect();a.width=f.width*g.wScaleFactor;a.height=f.height*g.hScaleFactor;b.row.height=a.height;ua(a,c,e,g)}return!1});g.headerrows=[];r=y(d(this));d(r).each(function(){b=
|
||||||
|
0;g.headerrows[n]=[];E(this,"th,td",n,r.length,function(a,c,d){var e=Ca(a);e.title=D(a,c,d);e.key=b++;e.rowIndex=n;g.headerrows[n].push(e)});n++});if(0<n)for(var e=n-1;0<=e;)d.each(g.headerrows[e],function(){var a=this;0<e&&null===this.rect&&(a=g.headerrows[e-1][this.key]);null!==a&&0<=a.rowIndex&&(!0!==a.style.hasOwnProperty("hidden")||!0!==a.style.hidden)&&g.columns.push(a)}),e=0<g.columns.length?-1:e-1;var k=0;w=[];w=C(d(this));d(w).each(function(){var a=[];b=0;E(this,"td,th",n,r.length+w.length,
|
||||||
|
function(c,e,f){if("undefined"===typeof g.columns[b]){var h={title:"",key:b,style:{hidden:!0}};g.columns.push(h)}a.push(D(c,e,f));"undefined"!==typeof c&&null!==c?(h=Ca(c),h.isCanvas=c.hasAttribute("data-tableexport-canvas"),h.elements=h.isCanvas?d(c):d(c).children(),"undefined"!==typeof d(c).data("teUserDefText")&&(h.hasUserDefText=!0)):(h=d.extend(!0,{},g.teCells[k+":"+(b-1)]),h.colspan=-1);g.teCells[k+":"+b++]=h});a.length&&(g.rows.push(a),k++);n++});if("function"===typeof g.onBeforeAutotable)g.onBeforeAutotable(d(this),
|
||||||
|
g.columns,g.rows,c);g.doc.autoTable(g.columns,g.rows,c);if("function"===typeof g.onAfterAutotable)g.onAfterAutotable(d(this),c);a.jspdf.autotable.startY=g.doc.autoTableEndPosY()+c.margin.top});va(g.doc,"undefined"!==typeof g.images&&!1===jQuery.isEmptyObject(g.images));"undefined"!==typeof g.headerrows&&(g.headerrows.length=0);"undefined"!==typeof g.columns&&(g.columns.length=0);"undefined"!==typeof g.rows&&(g.rows.length=0);delete g.doc;g.doc=null})}if("function"===typeof a.onTableExportEnd)a.onTableExportEnd();
|
||||||
|
return this}})(jQuery);
|
|
@ -45,7 +45,10 @@ function ajaxRequest(params) {
|
||||||
// rearrange the result into what bootstrap-table expects
|
// rearrange the result into what bootstrap-table expects
|
||||||
params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows});
|
params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows});
|
||||||
})
|
})
|
||||||
.fail(logAjaxFail);
|
.fail(function(jqXHR) {
|
||||||
|
logAjaxFail(jqXHR);
|
||||||
|
$j('#eventTable').bootstrapTable('refresh');
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function processRows(rows) {
|
function processRows(rows) {
|
||||||
|
@ -58,7 +61,7 @@ function processRows(rows) {
|
||||||
row.Id = '<a href="?view=event&eid=' + eid + filterQuery + sortQuery + '&page=1">' + eid + '</a>';
|
row.Id = '<a href="?view=event&eid=' + eid + filterQuery + sortQuery + '&page=1">' + eid + '</a>';
|
||||||
row.Name = '<a href="?view=event&eid=' + eid + filterQuery + sortQuery + '&page=1">' + row.Name + '</a>'
|
row.Name = '<a href="?view=event&eid=' + eid + filterQuery + sortQuery + '&page=1">' + row.Name + '</a>'
|
||||||
+ '<br/><div class="small text-nowrap text-muted">' + archived + emailed + '</div>';
|
+ '<br/><div class="small text-nowrap text-muted">' + archived + emailed + '</div>';
|
||||||
if ( canEdit.Monitors ) row.Monitor = '<a href="?view=monitor&mid=' + mid + '">' + row.Monitor + '</a>';
|
if ( canEdit.Monitors ) row.Monitor = '<a href="?view=event&eid=' + eid + '">' + row.Monitor + '</a>';
|
||||||
if ( canEdit.Events ) row.Cause = '<a href="#" title="' + row.Notes + '" class="eDetailLink" data-eid="' + eid + '">' + row.Cause + '</a>';
|
if ( canEdit.Events ) row.Cause = '<a href="#" title="' + row.Notes + '" class="eDetailLink" data-eid="' + eid + '">' + row.Cause + '</a>';
|
||||||
if ( row.Notes.indexOf('detected:') >= 0 ) {
|
if ( row.Notes.indexOf('detected:') >= 0 ) {
|
||||||
row.Cause = row.Cause + '<a href="#" class="objDetectLink" data-eid=' +eid+ '><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></div></a>';
|
row.Cause = row.Cause + '<a href="#" class="objDetectLink" data-eid=' +eid+ '><div class="small text-nowrap text-muted"><u>' + row.Notes + '</u></div></div></a>';
|
||||||
|
@ -118,7 +121,11 @@ function manageDelConfirmModalBtns() {
|
||||||
$j('#eventTable').bootstrapTable('refresh');
|
$j('#eventTable').bootstrapTable('refresh');
|
||||||
$j('#deleteConfirm').modal('hide');
|
$j('#deleteConfirm').modal('hide');
|
||||||
})
|
})
|
||||||
.fail(logAjaxFail);
|
.fail( function(jqxhr) {
|
||||||
|
logAjaxFail(jqxhr);
|
||||||
|
$j('#eventTable').bootstrapTable('refresh');
|
||||||
|
$j('#deleteConfirm').modal('hide');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Manage the CANCEL modal button
|
// Manage the CANCEL modal button
|
||||||
|
|
|
@ -871,6 +871,8 @@ include('_monitor_source_nvsocket.php');
|
||||||
'2048x1536'=>'2048x1536 3MP',
|
'2048x1536'=>'2048x1536 3MP',
|
||||||
'2560x1440'=>'2560x1440 1440p QHD WQHD',
|
'2560x1440'=>'2560x1440 1440p QHD WQHD',
|
||||||
'2592x1944'=>'2592x1944 5MP',
|
'2592x1944'=>'2592x1944 5MP',
|
||||||
|
'2688x1520'=>'2688x1520 4MP',
|
||||||
|
'3072x2048'=>'3072x2048 6MP',
|
||||||
'3840x2160'=>'3840x2160 4K UHD',
|
'3840x2160'=>'3840x2160 4K UHD',
|
||||||
);
|
);
|
||||||
$selected = '';
|
$selected = '';
|
||||||
|
@ -993,7 +995,7 @@ $videowriter_encoders = array(
|
||||||
'mpeg1' => 'mpeg1',
|
'mpeg1' => 'mpeg1',
|
||||||
'mpeg2' => 'mpeg2',
|
'mpeg2' => 'mpeg2',
|
||||||
);
|
);
|
||||||
echo htmlSelect( 'newMonitor[Encoder]', $videowriter_encoders, $monitor->Encoder() );?></td></tr>
|
echo htmlSelect('newMonitor[Encoder]', $videowriter_encoders, $monitor->Encoder());?></td></tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><?php echo translate('OutputContainer') ?></td>
|
<td><?php echo translate('OutputContainer') ?></td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -1017,7 +1019,7 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor
|
||||||
<?php if ( $monitor->Type() == 'Ffmpeg' ) { ?>
|
<?php if ( $monitor->Type() == 'Ffmpeg' ) { ?>
|
||||||
<input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ( $monitor->RecordAudio() ) { ?> checked="checked"<?php } ?>/>
|
<input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ( $monitor->RecordAudio() ) { ?> checked="checked"<?php } ?>/>
|
||||||
<?php } else { ?>
|
<?php } else { ?>
|
||||||
Audio recording only available with FFMPEG using H264 Passthrough
|
Audio recording only available with FFMPEG
|
||||||
<input type="hidden" name="newMonitor[RecordAudio]" value="<?php echo $monitor->RecordAudio() ? 1 : 0 ?>"/>
|
<input type="hidden" name="newMonitor[RecordAudio]" value="<?php echo $monitor->RecordAudio() ? 1 : 0 ?>"/>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
|
|
Loading…
Reference in New Issue