Merge branch 'master' into update_monitor_saving
commit
458268d866
|
@ -37,8 +37,16 @@ env:
|
||||||
- SMPFLAGS=-j4 OS=fedora DIST=29 DOCKER_REPO=knnniggett/packpack
|
- SMPFLAGS=-j4 OS=fedora DIST=29 DOCKER_REPO=knnniggett/packpack
|
||||||
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty
|
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty
|
||||||
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial
|
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial
|
||||||
|
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic
|
||||||
|
- SMPFLAGS=-j4 OS=ubuntu DIST=disco
|
||||||
|
- SMPFLAGS=-j4 OS=debian DIST=buster
|
||||||
|
- SMPFLAGS=-j4 OS=debian DIST=stretch
|
||||||
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty ARCH=i386
|
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty ARCH=i386
|
||||||
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial ARCH=i386
|
- SMPFLAGS=-j4 OS=ubuntu DIST=xenial ARCH=i386
|
||||||
|
- SMPFLAGS=-j4 OS=ubuntu DIST=bionic ARCH=i386
|
||||||
|
- SMPFLAGS=-j4 OS=ubuntu DIST=disco ARCH=i386
|
||||||
|
- SMPFLAGS=-j4 OS=debian DIST=buster ARCH=i386
|
||||||
|
- SMPFLAGS=-j4 OS=debian DIST=stretch ARCH=i386
|
||||||
- SMPFLAGS=-j4 OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack
|
- SMPFLAGS=-j4 OS=raspbian DIST=stretch ARCH=armhf DOCKER_REPO=knnniggett/packpack
|
||||||
|
|
||||||
compiler:
|
compiler:
|
||||||
|
|
|
@ -7,6 +7,7 @@ Build-Depends: debhelper (>= 9), python-sphinx | python3-sphinx, apache2-dev, dh
|
||||||
,cmake
|
,cmake
|
||||||
,libx264-dev, libmp4v2-dev
|
,libx264-dev, libmp4v2-dev
|
||||||
,libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libavdevice-dev
|
,libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libavdevice-dev
|
||||||
|
,libavresample-dev
|
||||||
,libbz2-dev
|
,libbz2-dev
|
||||||
,libgcrypt-dev
|
,libgcrypt-dev
|
||||||
,libcurl4-gnutls-dev
|
,libcurl4-gnutls-dev
|
||||||
|
|
|
@ -134,7 +134,7 @@ sub Path {
|
||||||
|
|
||||||
if ( ! $$event{Path} ) {
|
if ( ! $$event{Path} ) {
|
||||||
my $Storage = $event->Storage();
|
my $Storage = $event->Storage();
|
||||||
if ( defined $Storage->Id() ) {
|
if ( (!$$event{StorageId}) or defined $Storage->Id() ) {
|
||||||
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
|
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
|
||||||
} else {
|
} else {
|
||||||
Error("Storage area for $$event{StorageId} no longer exists in db.");
|
Error("Storage area for $$event{StorageId} no longer exists in db.");
|
||||||
|
|
|
@ -282,6 +282,7 @@ MAIN: while( $loop ) {
|
||||||
}
|
}
|
||||||
#Event path is hour/minute/sec
|
#Event path is hour/minute/sec
|
||||||
my $event_path = readlink($event_link);
|
my $event_path = readlink($event_link);
|
||||||
|
$event_path = '' if ! defined($event_path);
|
||||||
Debug("Checking link $event_link points to: $event_path");
|
Debug("Checking link $event_link points to: $event_path");
|
||||||
|
|
||||||
if ( !($event_path and -e $event_path) ) {
|
if ( !($event_path and -e $event_path) ) {
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
|
|
||||||
#include "zm_utils.h"
|
#include "zm_utils.h"
|
||||||
|
|
||||||
|
// Note that Error and Debug calls won't actually go anywhere unless you
|
||||||
|
// set the relevant ENV vars because the logger gets it's setting from the
|
||||||
|
// config.
|
||||||
|
|
||||||
void zmLoadConfig() {
|
void zmLoadConfig() {
|
||||||
|
|
||||||
// Process name, value pairs from the main config file first
|
// Process name, value pairs from the main config file first
|
||||||
|
@ -40,22 +44,22 @@ void zmLoadConfig() {
|
||||||
DIR* configSubFolder = opendir(ZM_CONFIG_SUBDIR);
|
DIR* configSubFolder = opendir(ZM_CONFIG_SUBDIR);
|
||||||
if ( configSubFolder ) { // subfolder exists and is readable
|
if ( configSubFolder ) { // subfolder exists and is readable
|
||||||
char glob_pattern[PATH_MAX] = "";
|
char glob_pattern[PATH_MAX] = "";
|
||||||
snprintf( glob_pattern, sizeof(glob_pattern), "%s/*.conf", ZM_CONFIG_SUBDIR );
|
snprintf(glob_pattern, sizeof(glob_pattern), "%s/*.conf", ZM_CONFIG_SUBDIR);
|
||||||
|
|
||||||
glob_t pglob;
|
glob_t pglob;
|
||||||
int glob_status = glob( glob_pattern, 0, 0, &pglob );
|
int glob_status = glob(glob_pattern, 0, 0, &pglob);
|
||||||
if ( glob_status != 0 ) {
|
if ( glob_status != 0 ) {
|
||||||
if ( glob_status < 0 ) {
|
if ( glob_status < 0 ) {
|
||||||
Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) );
|
Error("Can't glob '%s': %s", glob_pattern, strerror(errno));
|
||||||
} else {
|
} else {
|
||||||
Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status );
|
Debug(1, "Can't glob '%s': %d", glob_pattern, glob_status);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) {
|
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) {
|
||||||
process_configfile(pglob.gl_pathv[i]);
|
process_configfile(pglob.gl_pathv[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
globfree( &pglob );
|
globfree(&pglob);
|
||||||
closedir(configSubFolder);
|
closedir(configSubFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,59 +68,60 @@ void zmLoadConfig() {
|
||||||
config.Assign();
|
config.Assign();
|
||||||
|
|
||||||
// Populate the server config entries
|
// Populate the server config entries
|
||||||
if ( ! staticConfig.SERVER_ID ) {
|
if ( !staticConfig.SERVER_ID ) {
|
||||||
if ( ! staticConfig.SERVER_NAME.empty() ) {
|
if ( !staticConfig.SERVER_NAME.empty() ) {
|
||||||
|
|
||||||
Debug( 1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str() );
|
Debug(1, "Fetching ZM_SERVER_ID For Name = %s", staticConfig.SERVER_NAME.c_str());
|
||||||
std::string sql = stringtf("SELECT `Id` FROM `Servers` WHERE `Name`='%s'", staticConfig.SERVER_NAME.c_str() );
|
std::string sql = stringtf("SELECT `Id` FROM `Servers` WHERE `Name`='%s'",
|
||||||
|
staticConfig.SERVER_NAME.c_str());
|
||||||
zmDbRow dbrow;
|
zmDbRow dbrow;
|
||||||
if ( dbrow.fetch( sql.c_str() ) ) {
|
if ( dbrow.fetch(sql.c_str()) ) {
|
||||||
staticConfig.SERVER_ID = atoi(dbrow[0]);
|
staticConfig.SERVER_ID = atoi(dbrow[0]);
|
||||||
} else {
|
} else {
|
||||||
Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str() );
|
Fatal("Can't get ServerId for Server %s", staticConfig.SERVER_NAME.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
} // end if has SERVER_NAME
|
} // end if has SERVER_NAME
|
||||||
} else if ( staticConfig.SERVER_NAME.empty() ) {
|
} else if ( staticConfig.SERVER_NAME.empty() ) {
|
||||||
Debug( 1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID );
|
Debug(1, "Fetching ZM_SERVER_NAME For Id = %d", staticConfig.SERVER_ID);
|
||||||
std::string sql = stringtf("SELECT `Name` FROM `Servers` WHERE `Id`='%d'", staticConfig.SERVER_ID );
|
std::string sql = stringtf("SELECT `Name` FROM `Servers` WHERE `Id`='%d'", staticConfig.SERVER_ID);
|
||||||
|
|
||||||
zmDbRow dbrow;
|
zmDbRow dbrow;
|
||||||
if ( dbrow.fetch( sql.c_str() ) ) {
|
if ( dbrow.fetch(sql.c_str()) ) {
|
||||||
staticConfig.SERVER_NAME = std::string(dbrow[0]);
|
staticConfig.SERVER_NAME = std::string(dbrow[0]);
|
||||||
} else {
|
} else {
|
||||||
Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID );
|
Fatal("Can't get ServerName for Server ID %d", staticConfig.SERVER_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( staticConfig.SERVER_ID ) {
|
if ( staticConfig.SERVER_ID ) {
|
||||||
Debug( 3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID );
|
Debug(3, "Multi-server configuration detected. Server is %d.", staticConfig.SERVER_ID);
|
||||||
} else {
|
} else {
|
||||||
Debug( 3, "Single server configuration assumed because no Server ID or Name was specified." );
|
Debug(3, "Single server configuration assumed because no Server ID or Name was specified.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf( staticConfig.capture_file_format, sizeof(staticConfig.capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits );
|
snprintf(staticConfig.capture_file_format, sizeof(staticConfig.capture_file_format), "%%s/%%0%dd-capture.jpg", config.event_image_digits);
|
||||||
snprintf( staticConfig.analyse_file_format, sizeof(staticConfig.analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits );
|
snprintf(staticConfig.analyse_file_format, sizeof(staticConfig.analyse_file_format), "%%s/%%0%dd-analyse.jpg", config.event_image_digits);
|
||||||
snprintf( staticConfig.general_file_format, sizeof(staticConfig.general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits );
|
snprintf(staticConfig.general_file_format, sizeof(staticConfig.general_file_format), "%%s/%%0%dd-%%s", config.event_image_digits);
|
||||||
snprintf( staticConfig.video_file_format, sizeof(staticConfig.video_file_format), "%%s/%%s");
|
snprintf(staticConfig.video_file_format, sizeof(staticConfig.video_file_format), "%%s/%%s");
|
||||||
}
|
}
|
||||||
|
|
||||||
void process_configfile( char* configFile) {
|
void process_configfile(char* configFile) {
|
||||||
FILE *cfg;
|
FILE *cfg;
|
||||||
char line[512];
|
char line[512];
|
||||||
if ( (cfg = fopen( configFile, "r")) == NULL ) {
|
if ( (cfg = fopen(configFile, "r")) == NULL ) {
|
||||||
Fatal( "Can't open %s: %s", configFile, strerror(errno) );
|
Fatal("Can't open %s: %s", configFile, strerror(errno));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while ( fgets( line, sizeof(line), cfg ) != NULL ) {
|
while ( fgets(line, sizeof(line), cfg) != NULL ) {
|
||||||
char *line_ptr = line;
|
char *line_ptr = line;
|
||||||
|
|
||||||
// Trim off any cr/lf line endings
|
// Trim off any cr/lf line endings
|
||||||
int chomp_len = strcspn( line_ptr, "\r\n" );
|
int chomp_len = strcspn(line_ptr, "\r\n");
|
||||||
line_ptr[chomp_len] = '\0';
|
line_ptr[chomp_len] = '\0';
|
||||||
|
|
||||||
// Remove leading white space
|
// Remove leading white space
|
||||||
int white_len = strspn( line_ptr, " \t" );
|
int white_len = strspn(line_ptr, " \t");
|
||||||
line_ptr += white_len;
|
line_ptr += white_len;
|
||||||
|
|
||||||
// Check for comment or empty line
|
// Check for comment or empty line
|
||||||
|
@ -131,9 +136,9 @@ void process_configfile( char* configFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now look for the '=' in the middle of the line
|
// Now look for the '=' in the middle of the line
|
||||||
temp_ptr = strchr( line_ptr, '=' );
|
temp_ptr = strchr(line_ptr, '=');
|
||||||
if ( !temp_ptr ) {
|
if ( !temp_ptr ) {
|
||||||
Warning( "Invalid data in %s: '%s'", configFile, line );
|
Warning("Invalid data in %s: '%s'", configFile, line);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,49 +153,49 @@ void process_configfile( char* configFile) {
|
||||||
} while ( *temp_ptr == ' ' || *temp_ptr == '\t' );
|
} while ( *temp_ptr == ' ' || *temp_ptr == '\t' );
|
||||||
|
|
||||||
// Remove leading white space and leading quotes from the value part
|
// Remove leading white space and leading quotes from the value part
|
||||||
white_len = strspn( val_ptr, " \t" );
|
white_len = strspn(val_ptr, " \t");
|
||||||
white_len += strspn( val_ptr, "\'\"" );
|
white_len += strspn(val_ptr, "\'\"");
|
||||||
val_ptr += white_len;
|
val_ptr += white_len;
|
||||||
|
|
||||||
if ( strcasecmp( name_ptr, "ZM_DB_HOST" ) == 0 )
|
if ( strcasecmp(name_ptr, "ZM_DB_HOST") == 0 )
|
||||||
staticConfig.DB_HOST = std::string(val_ptr);
|
staticConfig.DB_HOST = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DB_NAME" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DB_NAME") == 0 )
|
||||||
staticConfig.DB_NAME = std::string(val_ptr);
|
staticConfig.DB_NAME = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DB_USER" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DB_USER") == 0 )
|
||||||
staticConfig.DB_USER = std::string(val_ptr);
|
staticConfig.DB_USER = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DB_PASS" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DB_PASS") == 0 )
|
||||||
staticConfig.DB_PASS = std::string(val_ptr);
|
staticConfig.DB_PASS = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CA_CERT" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DB_SSL_CA_CERT") == 0 )
|
||||||
staticConfig.DB_SSL_CA_CERT = std::string(val_ptr);
|
staticConfig.DB_SSL_CA_CERT = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CLIENT_KEY" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DB_SSL_CLIENT_KEY") == 0 )
|
||||||
staticConfig.DB_SSL_CLIENT_KEY = std::string(val_ptr);
|
staticConfig.DB_SSL_CLIENT_KEY = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DB_SSL_CLIENT_CERT" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DB_SSL_CLIENT_CERT") == 0 )
|
||||||
staticConfig.DB_SSL_CLIENT_CERT = std::string(val_ptr);
|
staticConfig.DB_SSL_CLIENT_CERT = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_PATH_WEB" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_PATH_WEB") == 0 )
|
||||||
staticConfig.PATH_WEB = std::string(val_ptr);
|
staticConfig.PATH_WEB = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_SERVER_HOST" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_SERVER_HOST") == 0 )
|
||||||
staticConfig.SERVER_NAME = std::string(val_ptr);
|
staticConfig.SERVER_NAME = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_SERVER_NAME" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_SERVER_NAME") == 0 )
|
||||||
staticConfig.SERVER_NAME = std::string(val_ptr);
|
staticConfig.SERVER_NAME = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_SERVER_ID" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_SERVER_ID") == 0 )
|
||||||
staticConfig.SERVER_ID = atoi(val_ptr);
|
staticConfig.SERVER_ID = atoi(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DIR_EVENTS" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DIR_EVENTS") == 0 )
|
||||||
staticConfig.DIR_EVENTS = std::string(val_ptr);
|
staticConfig.DIR_EVENTS = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DIR_SOUNDS" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DIR_SOUNDS") == 0 )
|
||||||
staticConfig.DIR_SOUNDS = std::string(val_ptr);
|
staticConfig.DIR_SOUNDS = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_DIR_EXPORTS" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_DIR_EXPORTS") == 0 )
|
||||||
staticConfig.DIR_EXPORTS = std::string(val_ptr);
|
staticConfig.DIR_EXPORTS = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_PATH_ZMS" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_PATH_ZMS") == 0 )
|
||||||
staticConfig.PATH_ZMS = std::string(val_ptr);
|
staticConfig.PATH_ZMS = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_PATH_MAP" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_PATH_MAP") == 0 )
|
||||||
staticConfig.PATH_MAP = std::string(val_ptr);
|
staticConfig.PATH_MAP = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_PATH_SOCKS" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_PATH_SOCKS") == 0 )
|
||||||
staticConfig.PATH_SOCKS = std::string(val_ptr);
|
staticConfig.PATH_SOCKS = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_PATH_LOGS" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_PATH_LOGS") == 0 )
|
||||||
staticConfig.PATH_LOGS = std::string(val_ptr);
|
staticConfig.PATH_LOGS = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_PATH_SWAP" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_PATH_SWAP") == 0 )
|
||||||
staticConfig.PATH_SWAP = std::string(val_ptr);
|
staticConfig.PATH_SWAP = std::string(val_ptr);
|
||||||
else if ( strcasecmp( name_ptr, "ZM_PATH_ARP" ) == 0 )
|
else if ( strcasecmp(name_ptr, "ZM_PATH_ARP") == 0 )
|
||||||
staticConfig.PATH_ARP = std::string(val_ptr);
|
staticConfig.PATH_ARP = std::string(val_ptr);
|
||||||
else {
|
else {
|
||||||
// We ignore this now as there may be more parameters than the
|
// We ignore this now as there may be more parameters than the
|
||||||
|
@ -198,18 +203,18 @@ void process_configfile( char* configFile) {
|
||||||
// Warning( "Invalid parameter '%s' in %s", name_ptr, ZM_CONFIG );
|
// Warning( "Invalid parameter '%s' in %s", name_ptr, ZM_CONFIG );
|
||||||
}
|
}
|
||||||
} // end foreach line of the config
|
} // end foreach line of the config
|
||||||
fclose( cfg );
|
fclose(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
StaticConfig staticConfig;
|
StaticConfig staticConfig;
|
||||||
|
|
||||||
ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *const p_type ) {
|
ConfigItem::ConfigItem(const char *p_name, const char *p_value, const char *const p_type) {
|
||||||
name = new char[strlen(p_name)+1];
|
name = new char[strlen(p_name)+1];
|
||||||
strcpy( name, p_name );
|
strcpy(name, p_name);
|
||||||
value = new char[strlen(p_value)+1];
|
value = new char[strlen(p_value)+1];
|
||||||
strcpy( value, p_value );
|
strcpy(value, p_value);
|
||||||
type = new char[strlen(p_type)+1];
|
type = new char[strlen(p_type)+1];
|
||||||
strcpy( type, p_type );
|
strcpy(type, p_type);
|
||||||
|
|
||||||
//Info( "Created new config item %s = %s (%s)\n", name, value, type );
|
//Info( "Created new config item %s = %s (%s)\n", name, value, type );
|
||||||
|
|
||||||
|
@ -217,28 +222,28 @@ ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *con
|
||||||
accessed = false;
|
accessed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigItem::ConfigItem( const ConfigItem &item ) {
|
ConfigItem::ConfigItem(const ConfigItem &item) {
|
||||||
name = new char[strlen(item.name)+1];
|
name = new char[strlen(item.name)+1];
|
||||||
strcpy( name, item.name );
|
strcpy(name, item.name);
|
||||||
value = new char[strlen(item.value)+1];
|
value = new char[strlen(item.value)+1];
|
||||||
strcpy( value, item.value );
|
strcpy(value, item.value);
|
||||||
type = new char[strlen(item.type)+1];
|
type = new char[strlen(item.type)+1];
|
||||||
strcpy( type, item.type );
|
strcpy(type, item.type);
|
||||||
|
|
||||||
//Info( "Created new config item %s = %s (%s)\n", name, value, type );
|
//Info( "Created new config item %s = %s (%s)\n", name, value, type );
|
||||||
|
|
||||||
accessed = false;
|
accessed = false;
|
||||||
}
|
}
|
||||||
void ConfigItem::Copy( const ConfigItem &item ) {
|
void ConfigItem::Copy(const ConfigItem &item) {
|
||||||
if (name) delete name;
|
if (name) delete name;
|
||||||
name = new char[strlen(item.name)+1];
|
name = new char[strlen(item.name)+1];
|
||||||
strcpy( name, item.name );
|
strcpy(name, item.name);
|
||||||
if (value) delete value;
|
if (value) delete value;
|
||||||
value = new char[strlen(item.value)+1];
|
value = new char[strlen(item.value)+1];
|
||||||
strcpy( value, item.value );
|
strcpy(value, item.value);
|
||||||
if (type) delete type;
|
if (type) delete type;
|
||||||
type = new char[strlen(item.type)+1];
|
type = new char[strlen(item.type)+1];
|
||||||
strcpy( type, item.type );
|
strcpy(type, item.type);
|
||||||
|
|
||||||
//Info( "Created new config item %s = %s (%s)\n", name, value, type );
|
//Info( "Created new config item %s = %s (%s)\n", name, value, type );
|
||||||
accessed = false;
|
accessed = false;
|
||||||
|
@ -253,16 +258,16 @@ ConfigItem::~ConfigItem() {
|
||||||
void ConfigItem::ConvertValue() const {
|
void ConfigItem::ConvertValue() const {
|
||||||
if ( !strcmp( type, "boolean" ) ) {
|
if ( !strcmp( type, "boolean" ) ) {
|
||||||
cfg_type = CFG_BOOLEAN;
|
cfg_type = CFG_BOOLEAN;
|
||||||
cfg_value.boolean_value = (bool)strtol( value, 0, 0 );
|
cfg_value.boolean_value = (bool)strtol(value, 0, 0);
|
||||||
} else if ( !strcmp( type, "integer" ) ) {
|
} else if ( !strcmp(type, "integer") ) {
|
||||||
cfg_type = CFG_INTEGER;
|
cfg_type = CFG_INTEGER;
|
||||||
cfg_value.integer_value = strtol( value, 0, 10 );
|
cfg_value.integer_value = strtol(value, 0, 10);
|
||||||
} else if ( !strcmp( type, "hexadecimal" ) ) {
|
} else if ( !strcmp(type, "hexadecimal") ) {
|
||||||
cfg_type = CFG_INTEGER;
|
cfg_type = CFG_INTEGER;
|
||||||
cfg_value.integer_value = strtol( value, 0, 16 );
|
cfg_value.integer_value = strtol(value, 0, 16);
|
||||||
} else if ( !strcmp( type, "decimal" ) ) {
|
} else if ( !strcmp(type, "decimal") ) {
|
||||||
cfg_type = CFG_DECIMAL;
|
cfg_type = CFG_DECIMAL;
|
||||||
cfg_value.decimal_value = strtod( value, 0 );
|
cfg_value.decimal_value = strtod(value, 0);
|
||||||
} else {
|
} else {
|
||||||
cfg_type = CFG_STRING;
|
cfg_type = CFG_STRING;
|
||||||
cfg_value.string_value = value;
|
cfg_value.string_value = value;
|
||||||
|
@ -275,11 +280,11 @@ bool ConfigItem::BooleanValue() const {
|
||||||
ConvertValue();
|
ConvertValue();
|
||||||
|
|
||||||
if ( cfg_type != CFG_BOOLEAN ) {
|
if ( cfg_type != CFG_BOOLEAN ) {
|
||||||
Error( "Attempt to fetch boolean value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
Error("Attempt to fetch boolean value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return( cfg_value.boolean_value );
|
return cfg_value.boolean_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ConfigItem::IntegerValue() const {
|
int ConfigItem::IntegerValue() const {
|
||||||
|
@ -287,11 +292,11 @@ int ConfigItem::IntegerValue() const {
|
||||||
ConvertValue();
|
ConvertValue();
|
||||||
|
|
||||||
if ( cfg_type != CFG_INTEGER ) {
|
if ( cfg_type != CFG_INTEGER ) {
|
||||||
Error( "Attempt to fetch integer value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
Error("Attempt to fetch integer value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return( cfg_value.integer_value );
|
return cfg_value.integer_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ConfigItem::DecimalValue() const {
|
double ConfigItem::DecimalValue() const {
|
||||||
|
@ -299,11 +304,11 @@ double ConfigItem::DecimalValue() const {
|
||||||
ConvertValue();
|
ConvertValue();
|
||||||
|
|
||||||
if ( cfg_type != CFG_DECIMAL ) {
|
if ( cfg_type != CFG_DECIMAL ) {
|
||||||
Error( "Attempt to fetch decimal value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
Error("Attempt to fetch decimal value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return( cfg_value.decimal_value );
|
return cfg_value.decimal_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *ConfigItem::StringValue() const {
|
const char *ConfigItem::StringValue() const {
|
||||||
|
@ -311,11 +316,11 @@ const char *ConfigItem::StringValue() const {
|
||||||
ConvertValue();
|
ConvertValue();
|
||||||
|
|
||||||
if ( cfg_type != CFG_STRING ) {
|
if ( cfg_type != CFG_STRING ) {
|
||||||
Error( "Attempt to fetch string value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type );
|
Error("Attempt to fetch string value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return( cfg_value.string_value );
|
return cfg_value.string_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::Config() {
|
Config::Config() {
|
||||||
|
@ -337,54 +342,54 @@ Config::~Config() {
|
||||||
void Config::Load() {
|
void Config::Load() {
|
||||||
static char sql[ZM_SQL_SML_BUFSIZ];
|
static char sql[ZM_SQL_SML_BUFSIZ];
|
||||||
|
|
||||||
strncpy( sql, "select Name, Value, Type from Config order by Id", sizeof(sql) );
|
strncpy(sql, "SELECT `Name`, `Value`, `Type` FROM `Config` ORDER BY `Id`", sizeof(sql) );
|
||||||
if ( mysql_query( &dbconn, sql ) ) {
|
if ( mysql_query(&dbconn, sql) ) {
|
||||||
Error( "Can't run query: %s", mysql_error( &dbconn ) );
|
Error("Can't run query: %s", mysql_error(&dbconn));
|
||||||
exit( mysql_errno( &dbconn ) );
|
exit(mysql_errno(&dbconn));
|
||||||
}
|
}
|
||||||
|
|
||||||
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", mysql_error( &dbconn ) );
|
Error("Can't use query result: %s", mysql_error(&dbconn));
|
||||||
exit( mysql_errno( &dbconn ) );
|
exit(mysql_errno(&dbconn));
|
||||||
}
|
}
|
||||||
n_items = mysql_num_rows( result );
|
n_items = mysql_num_rows(result);
|
||||||
|
|
||||||
if ( n_items <= ZM_MAX_CFG_ID ) {
|
if ( n_items <= ZM_MAX_CFG_ID ) {
|
||||||
Error( "Config mismatch, expected %d items, read %d. Try running 'zmupdate.pl -f' to reload config.", ZM_MAX_CFG_ID+1, n_items );
|
Error("Config mismatch, expected %d items, read %d. Try running 'zmupdate.pl -f' to reload config.", ZM_MAX_CFG_ID+1, n_items);
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
items = new ConfigItem *[n_items];
|
items = new ConfigItem *[n_items];
|
||||||
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
|
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
|
||||||
items[i] = new ConfigItem( dbrow[0], dbrow[1], dbrow[2] );
|
items[i] = new ConfigItem(dbrow[0], dbrow[1], dbrow[2]);
|
||||||
}
|
}
|
||||||
mysql_free_result( result );
|
mysql_free_result(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::Assign() {
|
void Config::Assign() {
|
||||||
ZM_CFG_ASSIGN_LIST
|
ZM_CFG_ASSIGN_LIST
|
||||||
}
|
}
|
||||||
|
|
||||||
const ConfigItem &Config::Item( int id ) {
|
const ConfigItem &Config::Item(int id) {
|
||||||
if ( !n_items ) {
|
if ( !n_items ) {
|
||||||
Load();
|
Load();
|
||||||
Assign();
|
Assign();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( id < 0 || id > ZM_MAX_CFG_ID ) {
|
if ( id < 0 || id > ZM_MAX_CFG_ID ) {
|
||||||
Error( "Attempt to access invalid config, id = %d. Try running 'zmupdate.pl -f' to reload config.", id );
|
Error("Attempt to access invalid config, id = %d. Try running 'zmupdate.pl -f' to reload config.", id);
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigItem *item = items[id];
|
ConfigItem *item = items[id];
|
||||||
|
|
||||||
if ( !item ) {
|
if ( !item ) {
|
||||||
Error( "Can't find config item %d", id );
|
Error("Can't find config item %d", id);
|
||||||
exit( -1 );
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return( *item );
|
return *item;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config config;
|
Config config;
|
||||||
|
|
|
@ -32,7 +32,7 @@ bool zmDbConnect() {
|
||||||
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
|
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
|
||||||
// But they really need to be here in order to prevent a double open of mysql
|
// But they really need to be here in order to prevent a double open of mysql
|
||||||
if ( zmDbConnected ) {
|
if ( zmDbConnected ) {
|
||||||
Warning("Calling zmDbConnect when already connected");
|
//Warning("Calling zmDbConnect when already connected");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -294,7 +294,6 @@ bool Event::WriteFrameImage(Image *image, struct timeval timestamp, const char *
|
||||||
|
|
||||||
int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default
|
int thisquality = ( alarm_frame && (config.jpeg_alarm_file_quality > config.jpeg_file_quality) ) ? config.jpeg_alarm_file_quality : 0 ; // quality to use, zero is default
|
||||||
bool rc;
|
bool rc;
|
||||||
Debug(3, "Writing image to %s", event_file);
|
|
||||||
|
|
||||||
if ( !config.timestamp_on_capture ) {
|
if ( !config.timestamp_on_capture ) {
|
||||||
// stash the image we plan to use in another pointer regardless if timestamped.
|
// stash the image we plan to use in another pointer regardless if timestamped.
|
||||||
|
@ -550,7 +549,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a
|
||||||
static char event_file[PATH_MAX];
|
static char event_file[PATH_MAX];
|
||||||
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
|
||||||
Debug(1, "Writing capture frame %d to %s", frames, event_file);
|
Debug(1, "Writing capture frame %d to %s", frames, event_file);
|
||||||
if ( ! WriteFrameImage(image, timestamp, event_file) ) {
|
if ( !WriteFrameImage(image, timestamp, event_file) ) {
|
||||||
Error("Failed to write frame image");
|
Error("Failed to write frame image");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -289,9 +289,10 @@ static void zm_log_fps(double d, const char *postfix) {
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
void zm_dump_codecpar ( const AVCodecParameters *par ) {
|
void zm_dump_codecpar ( const AVCodecParameters *par ) {
|
||||||
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d) codec_tag(%d) width(%d) height(%d) bit_rate(%d) format(%d = %s)",
|
Debug(1, "Dumping codecpar codec_type(%d) codec_id(%d %s) codec_tag(%d) width(%d) height(%d) bit_rate(%d) format(%d = %s)",
|
||||||
par->codec_type,
|
par->codec_type,
|
||||||
par->codec_id,
|
par->codec_id,
|
||||||
|
avcodec_get_name(par->codec_id),
|
||||||
par->codec_tag,
|
par->codec_tag,
|
||||||
par->width,
|
par->width,
|
||||||
par->height,
|
par->height,
|
||||||
|
@ -303,10 +304,11 @@ void zm_dump_codecpar ( const AVCodecParameters *par ) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void zm_dump_codec(const AVCodecContext *codec) {
|
void zm_dump_codec(const AVCodecContext *codec) {
|
||||||
Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d) format(%s)\n"
|
Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d %s) width(%d) height(%d) timebase(%d/%d) format(%s) "
|
||||||
"gop_size %d max_b_frames %d me_cmp %d me_range %d qmin %d qmax %d",
|
"gop_size %d max_b_frames %d me_cmp %d me_range %d qmin %d qmax %d",
|
||||||
codec->codec_type,
|
codec->codec_type,
|
||||||
codec->codec_id,
|
codec->codec_id,
|
||||||
|
avcodec_get_name(codec->codec_id),
|
||||||
codec->width,
|
codec->width,
|
||||||
codec->height,
|
codec->height,
|
||||||
codec->time_base.num,
|
codec->time_base.num,
|
||||||
|
@ -327,7 +329,6 @@ void zm_dump_codec(const AVCodecContext *codec) {
|
||||||
|
|
||||||
/* "user interface" functions */
|
/* "user interface" functions */
|
||||||
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
|
void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) {
|
||||||
char buf[256];
|
|
||||||
Debug(1, "Dumping stream index i(%d) index(%d)", i, index );
|
Debug(1, "Dumping stream index i(%d) index(%d)", i, index );
|
||||||
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
|
||||||
AVStream *st = ic->streams[i];
|
AVStream *st = ic->streams[i];
|
||||||
|
@ -350,8 +351,14 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output)
|
||||||
st->codec_info_nb_frames, codec->frame_size,
|
st->codec_info_nb_frames, codec->frame_size,
|
||||||
st->time_base.num, st->time_base.den
|
st->time_base.num, st->time_base.den
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
Debug(1, "codec: %s", avcodec_get_name(st->codecpar->codec_id));
|
||||||
|
#else
|
||||||
|
char buf[256];
|
||||||
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
avcodec_string(buf, sizeof(buf), st->codec, is_output);
|
||||||
Debug(1, "codec: %s", buf);
|
Debug(1, "codec: %s", buf);
|
||||||
|
#endif
|
||||||
|
|
||||||
if ( st->sample_aspect_ratio.num && // default
|
if ( st->sample_aspect_ratio.num && // default
|
||||||
av_cmp_q(st->sample_aspect_ratio, codec->sample_aspect_ratio)
|
av_cmp_q(st->sample_aspect_ratio, codec->sample_aspect_ratio)
|
||||||
|
@ -427,6 +434,35 @@ unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src ) {
|
||||||
dst->stream_index = src->stream_index;
|
dst->stream_index = src->stream_index;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
const char *avcodec_get_name(enum AVCodecID id) {
|
||||||
|
const AVCodecDescriptor *cd;
|
||||||
|
if ( id == AV_CODEC_ID_NONE)
|
||||||
|
return "none";
|
||||||
|
cd = avcodec_descriptor_get(id);
|
||||||
|
if (cd)
|
||||||
|
return cd->name;
|
||||||
|
AVCodec *codec;
|
||||||
|
codec = avcodec_find_decoder(id);
|
||||||
|
if (codec)
|
||||||
|
return codec->name;
|
||||||
|
codec = avcodec_find_encoder(id);
|
||||||
|
if (codec)
|
||||||
|
return codec->name;
|
||||||
|
return "unknown codec";
|
||||||
|
}
|
||||||
|
|
||||||
|
void av_packet_rescale_ts(
|
||||||
|
AVPacket *pkt,
|
||||||
|
AVRational src_tb,
|
||||||
|
AVRational dst_tb
|
||||||
|
) {
|
||||||
|
if ( pkt->pts != AV_NOPTS_VALUE)
|
||||||
|
pkt->pts = av_rescale_q(pkt->pts, src_tb, dst_tb);
|
||||||
|
if ( pkt->dts != AV_NOPTS_VALUE)
|
||||||
|
pkt->dts = av_rescale_q(pkt->dts, src_tb, dst_tb);
|
||||||
|
if ( pkt->duration != AV_NOPTS_VALUE)
|
||||||
|
pkt->duration = av_rescale_q(pkt->duration, src_tb, dst_tb);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
bool is_video_stream( AVStream * stream ) {
|
bool is_video_stream( AVStream * stream ) {
|
||||||
|
@ -477,7 +513,31 @@ bool is_audio_context( AVCodecContext *codec_context ) {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet) {
|
int zm_receive_packet(AVCodecContext *context, AVPacket &packet) {
|
||||||
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
int ret = avcodec_receive_packet(context, &packet);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
if ( AVERROR_EOF != ret ) {
|
||||||
|
Error("Error encoding (%d) (%s)", ret,
|
||||||
|
av_err2str(ret));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
#else
|
||||||
|
int got_packet = 0;
|
||||||
|
int ret = avcodec_encode_audio2(context, &packet, NULL, &got_packet);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Error("Error encoding (%d) (%s)", ret, av_err2str(ret));
|
||||||
|
}
|
||||||
|
return got_packet;
|
||||||
|
#endif
|
||||||
|
} // end int zm_receive_packet(AVCodecContext *context, AVPacket &packet)
|
||||||
|
|
||||||
|
int zm_send_packet_receive_frame(
|
||||||
|
AVCodecContext *context,
|
||||||
|
AVFrame *frame,
|
||||||
|
AVPacket &packet) {
|
||||||
int ret;
|
int ret;
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
if ( (ret = avcodec_send_packet(context, &packet)) < 0 ) {
|
if ( (ret = avcodec_send_packet(context, &packet)) < 0 ) {
|
||||||
|
@ -487,8 +547,14 @@ int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (ret = avcodec_receive_frame(context, frame)) < 0 ) {
|
if ( (ret = avcodec_receive_frame(context, frame)) < 0 ) {
|
||||||
Error("Unable to send packet %s, continuing",
|
if ( AVERROR(EAGAIN) == ret ) {
|
||||||
av_make_error_string(ret).c_str());
|
// The codec may need more samples than it has, perfectly valid
|
||||||
|
Debug(2, "Codec not ready to give us a frame");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
Error("Could not recieve frame (error %d = '%s')", ret,
|
||||||
|
av_make_error_string(ret).c_str());
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
|
@ -505,29 +571,31 @@ int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
||||||
}
|
}
|
||||||
} // end while !frameComplete
|
} // end while !frameComplete
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 1;
|
||||||
} // end int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
} // end int zm_send_packet_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
||||||
|
|
||||||
int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
/* Returns < 0 on error, 0 if codec not ready, 1 on success
|
||||||
|
*/
|
||||||
|
int zm_send_frame_receive_packet(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
||||||
int ret;
|
int ret;
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
if ( (ret = avcodec_send_frame(ctx, frame)) < 0 ) {
|
if ( (ret = avcodec_send_frame(ctx, frame)) < 0 ) {
|
||||||
Error("Could not send frame (error '%s')",
|
Error("Could not send frame (error '%s')",
|
||||||
av_make_error_string(ret).c_str());
|
av_make_error_string(ret).c_str());
|
||||||
zm_av_packet_unref(&packet);
|
return ret;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( (ret = avcodec_receive_packet(ctx, &packet)) < 0 ) {
|
if ( (ret = avcodec_receive_packet(ctx, &packet)) < 0 ) {
|
||||||
if ( AVERROR(EAGAIN) == ret ) {
|
if ( AVERROR(EAGAIN) == ret ) {
|
||||||
// The codec may need more samples than it has, perfectly valid
|
// The codec may need more samples than it has, perfectly valid
|
||||||
Debug(2, "Codec not ready to give us a packet");
|
Debug(2, "Codec not ready to give us a packet");
|
||||||
|
return 0;
|
||||||
} else {
|
} else {
|
||||||
Error("Could not recieve packet (error %d = '%s')", ret,
|
Error("Could not recieve packet (error %d = '%s')", ret,
|
||||||
av_make_error_string(ret).c_str());
|
av_make_error_string(ret).c_str());
|
||||||
}
|
}
|
||||||
zm_av_packet_unref(&packet);
|
zm_av_packet_unref(&packet);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
int data_present;
|
int data_present;
|
||||||
|
@ -536,7 +604,7 @@ int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
||||||
Error("Could not encode frame (error '%s')",
|
Error("Could not encode frame (error '%s')",
|
||||||
av_make_error_string(ret).c_str());
|
av_make_error_string(ret).c_str());
|
||||||
zm_av_packet_unref(&packet);
|
zm_av_packet_unref(&packet);
|
||||||
return 0;
|
return ret;
|
||||||
}
|
}
|
||||||
if ( !data_present ) {
|
if ( !data_present ) {
|
||||||
Debug(2, "Not ready to out a frame yet.");
|
Debug(2, "Not ready to out a frame yet.");
|
||||||
|
@ -545,7 +613,7 @@ int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return 1;
|
return 1;
|
||||||
} // wend zm_send_frame
|
} // end int zm_send_frame_receive_packet
|
||||||
|
|
||||||
void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) {
|
void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) {
|
||||||
char b[10240];
|
char b[10240];
|
||||||
|
@ -600,3 +668,117 @@ void dumpPacket(AVPacket *pkt, const char *text) {
|
||||||
pkt->duration);
|
pkt->duration);
|
||||||
Debug(2, "%s:%d:%s: %s", __FILE__, __LINE__, text, b);
|
Debug(2, "%s:%d:%s: %s", __FILE__, __LINE__, text, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void zm_packet_copy_rescale_ts(const AVPacket *ipkt, AVPacket *opkt, const AVRational src_tb, const AVRational dst_tb) {
|
||||||
|
opkt->pts = ipkt->pts;
|
||||||
|
opkt->dts = ipkt->dts;
|
||||||
|
opkt->duration = ipkt->duration;
|
||||||
|
av_packet_rescale_ts(opkt, src_tb, dst_tb);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
int zm_resample_audio(
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
|
SwrContext *resample_ctx,
|
||||||
|
#else
|
||||||
|
#if defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
AVAudioResampleContext *resample_ctx,
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
AVFrame *in_frame,
|
||||||
|
AVFrame *out_frame
|
||||||
|
) {
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
|
// Resample the in_frame into the audioSampleBuffer until we process the whole
|
||||||
|
// decoded data. Note: pts does not survive resampling or converting
|
||||||
|
Debug(2, "Converting %d to %d samples using swresample",
|
||||||
|
in_frame->nb_samples, out_frame->nb_samples);
|
||||||
|
int ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Error("Could not resample frame (error '%s')",
|
||||||
|
av_make_error_string(ret).c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
Debug(3,"swr_get_delay %d",
|
||||||
|
swr_get_delay(resample_ctx, out_frame->sample_rate));
|
||||||
|
#else
|
||||||
|
#if defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
int ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
|
||||||
|
0, in_frame->nb_samples);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Error("Could not resample frame (error '%s')",
|
||||||
|
av_make_error_string(ret).c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int samples_available = avresample_available(resample_ctx);
|
||||||
|
if ( samples_available < out_frame->nb_samples ) {
|
||||||
|
Debug(1, "Not enough samples yet (%d)", samples_available);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a frame audio data from the resample fifo
|
||||||
|
if ( avresample_read(resample_ctx, out_frame->data, out_frame->nb_samples) !=
|
||||||
|
out_frame->nb_samples) {
|
||||||
|
Warning("Error reading resampled audio.");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
zm_dump_frame(out_frame, "Out frame after resample");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zm_resample_get_delay(
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
|
SwrContext *resample_ctx,
|
||||||
|
#else
|
||||||
|
#if defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
AVAudioResampleContext *resample_ctx,
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
int time_base
|
||||||
|
) {
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
|
return swr_get_delay(resample_ctx, time_base);
|
||||||
|
#else
|
||||||
|
#if defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
return avresample_available(resample_ctx);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int zm_add_samples_to_fifo(AVAudioFifo *fifo, AVFrame *frame) {
|
||||||
|
int ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + frame->nb_samples);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Error("Could not reallocate FIFO to %d samples",
|
||||||
|
av_audio_fifo_size(fifo) + frame->nb_samples);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/** Store the new samples in the FIFO buffer. */
|
||||||
|
ret = av_audio_fifo_write(fifo, (void **)frame->data, frame->nb_samples);
|
||||||
|
if ( ret < frame->nb_samples ) {
|
||||||
|
Error("Could not write data to FIFO. %d written, expecting %d. Reason %s",
|
||||||
|
ret, frame->nb_samples, av_make_error_string(ret).c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int zm_get_samples_from_fifo(AVAudioFifo *fifo, AVFrame *frame) {
|
||||||
|
// AAC requires 1024 samples per encode. Our input tends to be something else, so need to buffer them.
|
||||||
|
if ( frame->nb_samples > av_audio_fifo_size(fifo) ) {
|
||||||
|
Debug(1, "Not enough samples in fifo for AAC codec frame_size %d > fifo size %d",
|
||||||
|
frame->nb_samples, av_audio_fifo_size(fifo));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( av_audio_fifo_read(fifo, (void **)frame->data, frame->nb_samples) < frame->nb_samples ) {
|
||||||
|
Error("Could not read data from FIFO");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//out_frame->nb_samples = frame_size;
|
||||||
|
zm_dump_frame(frame, "Out frame after fifo read");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,14 @@
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSWRESAMPLE
|
||||||
|
#include "libswresample/swresample.h"
|
||||||
|
#else
|
||||||
|
#ifdef HAVE_LIBAVRESAMPLE
|
||||||
|
#include "libavresample/avresample.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
// AVUTIL
|
// AVUTIL
|
||||||
#if HAVE_LIBAVUTIL_AVUTIL_H
|
#if HAVE_LIBAVUTIL_AVUTIL_H
|
||||||
#include "libavutil/avassert.h"
|
#include "libavutil/avassert.h"
|
||||||
|
@ -31,6 +39,7 @@ extern "C" {
|
||||||
#include <libavutil/base64.h>
|
#include <libavutil/base64.h>
|
||||||
#include <libavutil/mathematics.h>
|
#include <libavutil/mathematics.h>
|
||||||
#include <libavutil/avstring.h>
|
#include <libavutil/avstring.h>
|
||||||
|
#include "libavutil/audio_fifo.h"
|
||||||
|
|
||||||
/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
|
/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
|
||||||
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
* The original source is vlc (in modules/codec/avcodec/avcommon_compat.h)
|
||||||
|
@ -299,23 +308,6 @@ void zm_dump_codec(const AVCodecContext *codec);
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
void zm_dump_codecpar(const AVCodecParameters *par);
|
void zm_dump_codecpar(const AVCodecParameters *par);
|
||||||
#endif
|
#endif
|
||||||
#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100)
|
|
||||||
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \
|
|
||||||
" duration %" PRId64 \
|
|
||||||
" layout %d pts %" PRId64 " pkt_pts %" PRId64 " pkt_dts %" PRId64, \
|
|
||||||
text, \
|
|
||||||
frame->format, \
|
|
||||||
av_get_sample_fmt_name((AVSampleFormat)frame->format), \
|
|
||||||
frame->sample_rate, \
|
|
||||||
frame->nb_samples, \
|
|
||||||
frame->channels, \
|
|
||||||
frame->pkt_duration, \
|
|
||||||
frame->channel_layout, \
|
|
||||||
frame->pts, \
|
|
||||||
frame->pkt_pts, \
|
|
||||||
frame->pkt_dts \
|
|
||||||
);
|
|
||||||
#else
|
|
||||||
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \
|
#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \
|
||||||
" duration %" PRId64 \
|
" duration %" PRId64 \
|
||||||
" layout %d pts %" PRId64, \
|
" layout %d pts %" PRId64, \
|
||||||
|
@ -329,8 +321,6 @@ void zm_dump_codecpar(const AVCodecParameters *par);
|
||||||
frame->pts \
|
frame->pts \
|
||||||
);
|
);
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
|
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
|
||||||
text, \
|
text, \
|
||||||
frame->format, \
|
frame->format, \
|
||||||
|
@ -347,6 +337,9 @@ void zm_dump_codecpar(const AVCodecParameters *par);
|
||||||
#else
|
#else
|
||||||
unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src );
|
unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src );
|
||||||
#define zm_av_packet_unref( packet ) av_free_packet( packet )
|
#define zm_av_packet_unref( packet ) av_free_packet( packet )
|
||||||
|
const char *avcodec_get_name(AVCodecID id);
|
||||||
|
|
||||||
|
void av_packet_rescale_ts(AVPacket *pkt, AVRational src_tb, AVRational dst_tb);
|
||||||
#endif
|
#endif
|
||||||
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
#if LIBAVCODEC_VERSION_CHECK(52, 23, 0, 23, 0)
|
||||||
#define zm_avcodec_decode_video( context, rawFrame, frameComplete, packet ) avcodec_decode_video2( context, rawFrame, frameComplete, packet )
|
#define zm_avcodec_decode_video( context, rawFrame, frameComplete, packet ) avcodec_decode_video2( context, rawFrame, frameComplete, packet )
|
||||||
|
@ -371,9 +364,42 @@ bool is_audio_stream(AVStream *);
|
||||||
bool is_video_context(AVCodec *);
|
bool is_video_context(AVCodec *);
|
||||||
bool is_audio_context(AVCodec *);
|
bool is_audio_context(AVCodec *);
|
||||||
|
|
||||||
int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
int zm_receive_packet(AVCodecContext *context, AVPacket &packet);
|
||||||
int zm_send_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
|
||||||
|
int zm_send_packet_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
||||||
|
int zm_send_frame_receive_packet(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
|
||||||
|
|
||||||
void dumpPacket(AVStream *, AVPacket *,const char *text="");
|
void dumpPacket(AVStream *, AVPacket *,const char *text="");
|
||||||
void dumpPacket(AVPacket *,const char *text="");
|
void dumpPacket(AVPacket *,const char *text="");
|
||||||
|
void zm_packet_copy_rescale_ts(const AVPacket *ipkt, AVPacket *opkt, const AVRational src_tb, const AVRational dst_tb);
|
||||||
|
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
int zm_resample_audio(
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
|
SwrContext *resample_ctx,
|
||||||
|
#else
|
||||||
|
#if defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
AVAudioResampleContext *resample_ctx,
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
AVFrame *in_frame,
|
||||||
|
AVFrame *out_frame
|
||||||
|
);
|
||||||
|
int zm_resample_get_delay(
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
|
SwrContext *resample_ctx,
|
||||||
|
#else
|
||||||
|
#if defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
AVAudioResampleContext *resample_ctx,
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
int time_base
|
||||||
|
);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int zm_add_samples_to_fifo(AVAudioFifo *fifo, AVFrame *frame);
|
||||||
|
int zm_get_samples_from_fifo(AVAudioFifo *fifo, AVFrame *frame);
|
||||||
|
|
||||||
|
|
||||||
#endif // ZM_FFMPEG_H
|
#endif // ZM_FFMPEG_H
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_signal.h"
|
#include "zm_signal.h"
|
||||||
|
#include "zm_utils.h"
|
||||||
|
|
||||||
#if HAVE_LIBAVFORMAT
|
#if HAVE_LIBAVFORMAT
|
||||||
|
|
||||||
|
@ -35,11 +36,6 @@ extern "C" {
|
||||||
#define AV_ERROR_MAX_STRING_SIZE 64
|
#define AV_ERROR_MAX_STRING_SIZE 64
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SOLARIS
|
|
||||||
#include <sys/errno.h> // for ESRCH
|
|
||||||
#include <signal.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
|
||||||
|
@ -260,8 +256,8 @@ int FfmpegCamera::Capture(Image &image) {
|
||||||
&&
|
&&
|
||||||
(keyframe || have_video_keyframe)
|
(keyframe || have_video_keyframe)
|
||||||
) {
|
) {
|
||||||
ret = zm_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
ret = zm_send_packet_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
||||||
if ( ret < 0 ) {
|
if ( ret <= 0 ) {
|
||||||
Error("Unable to get frame at frame %d: %s, continuing",
|
Error("Unable to get frame at frame %d: %s, continuing",
|
||||||
frameCount, av_make_error_string(ret).c_str());
|
frameCount, av_make_error_string(ret).c_str());
|
||||||
zm_av_packet_unref(&packet);
|
zm_av_packet_unref(&packet);
|
||||||
|
@ -337,24 +333,27 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set transport method as specified by method field, rtpUni is default
|
// Set transport method as specified by method field, rtpUni is default
|
||||||
const std::string method = Method();
|
std::string protocol = mPath.substr(0, 4);
|
||||||
if ( method == "rtpMulti" ) {
|
string_toupper(protocol);
|
||||||
ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0);
|
if ( protocol == "RTSP" ) {
|
||||||
} else if ( method == "rtpRtsp" ) {
|
const std::string method = Method();
|
||||||
ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0);
|
if ( method == "rtpMulti" ) {
|
||||||
} else if ( method == "rtpRtspHttp" ) {
|
ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0);
|
||||||
ret = av_dict_set(&opts, "rtsp_transport", "http", 0);
|
} else if ( method == "rtpRtsp" ) {
|
||||||
} else if ( method == "rtpUni" ) {
|
ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0);
|
||||||
ret = av_dict_set(&opts, "rtsp_transport", "udp", 0);
|
} else if ( method == "rtpRtspHttp" ) {
|
||||||
} else {
|
ret = av_dict_set(&opts, "rtsp_transport", "http", 0);
|
||||||
Warning("Unknown method (%s)", method.c_str());
|
} else if ( method == "rtpUni" ) {
|
||||||
}
|
ret = av_dict_set(&opts, "rtsp_transport", "udp", 0);
|
||||||
|
} else {
|
||||||
|
Warning("Unknown method (%s)", method.c_str());
|
||||||
|
}
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Warning("Could not set rtsp_transport method '%s'", method.c_str());
|
||||||
|
}
|
||||||
|
} // end if RTSP
|
||||||
// #av_dict_set(&opts, "timeout", "10000000", 0); // in microseconds.
|
// #av_dict_set(&opts, "timeout", "10000000", 0); // in microseconds.
|
||||||
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
Warning("Could not set rtsp_transport method '%s'", method.c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug(1, "Calling avformat_open_input for %s", mPath.c_str());
|
Debug(1, "Calling avformat_open_input for %s", mPath.c_str());
|
||||||
|
|
||||||
mFormatContext = avformat_alloc_context();
|
mFormatContext = avformat_alloc_context();
|
||||||
|
@ -650,6 +649,9 @@ int FfmpegCamera::OpenFfmpeg() {
|
||||||
) {
|
) {
|
||||||
Warning("Monitor dimensions are %dx%d but camera is sending %dx%d",
|
Warning("Monitor dimensions are %dx%d but camera is sending %dx%d",
|
||||||
width, height, mVideoCodecContext->width, mVideoCodecContext->height);
|
width, height, mVideoCodecContext->width, mVideoCodecContext->height);
|
||||||
|
} else {
|
||||||
|
Warning("Monitor dimensions are %dx%d and camera is sending %dx%d",
|
||||||
|
width, height, mVideoCodecContext->width, mVideoCodecContext->height);
|
||||||
}
|
}
|
||||||
|
|
||||||
mCanCapture = true;
|
mCanCapture = true;
|
||||||
|
@ -952,8 +954,8 @@ int FfmpegCamera::CaptureAndRecord(
|
||||||
}
|
}
|
||||||
} // end if keyframe or have_video_keyframe
|
} // end if keyframe or have_video_keyframe
|
||||||
|
|
||||||
ret = zm_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
ret = zm_send_packet_receive_frame(mVideoCodecContext, mRawFrame, packet);
|
||||||
if ( ret < 0 ) {
|
if ( ret <= 0 ) {
|
||||||
Warning("Unable to receive frame %d: %s. error count is %d",
|
Warning("Unable to receive frame %d: %s. error count is %d",
|
||||||
frameCount, av_make_error_string(ret).c_str(), error_count);
|
frameCount, av_make_error_string(ret).c_str(), error_count);
|
||||||
error_count += 1;
|
error_count += 1;
|
||||||
|
|
|
@ -137,8 +137,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
|
||||||
} else {
|
} else {
|
||||||
frame = zm_av_frame_alloc();
|
frame = zm_av_frame_alloc();
|
||||||
}
|
}
|
||||||
ret = zm_receive_frame(context, frame, packet);
|
ret = zm_send_packet_receive_frame(context, frame, packet);
|
||||||
if ( ret < 0 ) {
|
if ( ret <= 0 ) {
|
||||||
Error("Unable to decode frame at frame %d: %s, continuing",
|
Error("Unable to decode frame at frame %d: %s, continuing",
|
||||||
streams[packet.stream_index].frame_count, av_make_error_string(ret).c_str());
|
streams[packet.stream_index].frame_count, av_make_error_string(ret).c_str());
|
||||||
zm_av_packet_unref(&packet);
|
zm_av_packet_unref(&packet);
|
||||||
|
|
|
@ -1,31 +1,27 @@
|
||||||
//
|
//
|
||||||
// ZoneMinder File Camera Class Implementation, $Date$, $Revision$
|
// ZoneMinder File Camera Class Implementation, $Date$, $Revision$
|
||||||
// Copyright (C) 2001-2008 Philip Coombes
|
// Copyright (C) 2001-2008 Philip Coombes
|
||||||
//
|
//
|
||||||
// This program is free software; you can redistribute it and/or
|
// This program is free software; you can redistribute it and/or
|
||||||
// modify it under the terms of the GNU General Public License
|
// modify it under the terms of the GNU General Public License
|
||||||
// as published by the Free Software Foundation; either version 2
|
// as published by the Free Software Foundation; either version 2
|
||||||
// of the License, or (at your option) any later version.
|
// of the License, or (at your option) any later version.
|
||||||
//
|
//
|
||||||
// This program is distributed in the hope that it will be useful,
|
// This program is distributed in the hope that it will be useful,
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
// GNU General Public License for more details.
|
// GNU General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program; if not, write to the Free Software
|
// along with this program; if not, write to the Free Software
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
@ -45,8 +41,20 @@ FileCamera::FileCamera(
|
||||||
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)
|
||||||
) : Camera( p_id, FILE_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio )
|
: Camera(
|
||||||
|
p_id,
|
||||||
|
FILE_SRC,
|
||||||
|
p_width,
|
||||||
|
p_height,
|
||||||
|
p_colours,
|
||||||
|
ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours),
|
||||||
|
p_brightness,
|
||||||
|
p_contrast,
|
||||||
|
p_hue,
|
||||||
|
p_colour,
|
||||||
|
p_capture,
|
||||||
|
p_record_audio)
|
||||||
{
|
{
|
||||||
strncpy( path, p_path, sizeof(path)-1 );
|
strncpy( path, p_path, sizeof(path)-1 );
|
||||||
if ( capture ) {
|
if ( capture ) {
|
||||||
|
@ -62,8 +70,7 @@ FileCamera::~FileCamera() {
|
||||||
|
|
||||||
void FileCamera::Initialise() {
|
void FileCamera::Initialise() {
|
||||||
if ( !path[0] ) {
|
if ( !path[0] ) {
|
||||||
Error( "No path specified for file image" );
|
Fatal("No path specified for file image");
|
||||||
exit( -1 );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,21 +79,25 @@ void FileCamera::Terminate() {
|
||||||
|
|
||||||
int FileCamera::PreCapture() {
|
int FileCamera::PreCapture() {
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
if ( stat( path, &statbuf ) < 0 ) {
|
if ( stat(path, &statbuf) < 0 ) {
|
||||||
Error( "Can't stat %s: %s", path, strerror(errno) );
|
Error("Can't stat %s: %s", path, strerror(errno));
|
||||||
return( -1 );
|
return -1;
|
||||||
}
|
}
|
||||||
|
bytes += statbuf.st_size;
|
||||||
|
|
||||||
|
// This waits until 1 second has passed since it was modified. Effectively limiting fps to 60.
|
||||||
|
// Which is kinda bogus. If we were writing to this jpg constantly faster than we are monitoring it here
|
||||||
|
// we would never break out of this loop
|
||||||
while ( (time(0) - statbuf.st_mtime) < 1 ) {
|
while ( (time(0) - statbuf.st_mtime) < 1 ) {
|
||||||
usleep( 100000 );
|
usleep(100000);
|
||||||
}
|
}
|
||||||
return( 0 );
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileCamera::Capture( Image &image ) {
|
int FileCamera::Capture(Image &image) {
|
||||||
return( image.ReadJpeg( path, colours, subpixelorder )?1:-1 );
|
return image.ReadJpeg(path, colours, subpixelorder)?1:-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int FileCamera::PostCapture() {
|
int FileCamera::PostCapture() {
|
||||||
return( 0 );
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
398
src/zm_image.cpp
398
src/zm_image.cpp
File diff suppressed because it is too large
Load Diff
|
@ -55,7 +55,7 @@ static void subtractTime( struct timeval * const tp1, struct timeval * const tp2
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void Logger::usrHandler( int sig ) {
|
void Logger::usrHandler(int sig) {
|
||||||
Logger *logger = fetch();
|
Logger *logger = fetch();
|
||||||
if ( sig == SIGUSR1 )
|
if ( sig == SIGUSR1 )
|
||||||
logger->level(logger->level()+1);
|
logger->level(logger->level()+1);
|
||||||
|
@ -71,9 +71,9 @@ Logger::Logger() :
|
||||||
mFileLevel(NOLOG),
|
mFileLevel(NOLOG),
|
||||||
mSyslogLevel(NOLOG),
|
mSyslogLevel(NOLOG),
|
||||||
mEffectiveLevel(NOLOG),
|
mEffectiveLevel(NOLOG),
|
||||||
//mLogPath( staticConfig.PATH_LOGS.c_str() ),
|
|
||||||
//mLogFile( mLogPath+"/"+mId+".log" ),
|
|
||||||
mDbConnected(false),
|
mDbConnected(false),
|
||||||
|
mLogPath(staticConfig.PATH_LOGS.c_str()),
|
||||||
|
//mLogFile( mLogPath+"/"+mId+".log" ),
|
||||||
mLogFileFP(NULL),
|
mLogFileFP(NULL),
|
||||||
mHasTerminal(false),
|
mHasTerminal(false),
|
||||||
mFlush(false) {
|
mFlush(false) {
|
||||||
|
@ -106,9 +106,11 @@ Logger::Logger() :
|
||||||
smInitialised = true;
|
smInitialised = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( fileno(stderr) && isatty(fileno(stderr)) )
|
if ( fileno(stderr) && isatty(fileno(stderr)) ) {
|
||||||
mHasTerminal = true;
|
mHasTerminal = true;
|
||||||
}
|
mTerminalLevel = WARNING;
|
||||||
|
}
|
||||||
|
} // End Logger::Logger
|
||||||
|
|
||||||
Logger::~Logger() {
|
Logger::~Logger() {
|
||||||
terminate();
|
terminate();
|
||||||
|
@ -138,7 +140,8 @@ void Logger::initialise(const std::string &id, const Options &options) {
|
||||||
} else if ( options.mLogFile.size() ) {
|
} else if ( options.mLogFile.size() ) {
|
||||||
tempLogFile = options.mLogFile;
|
tempLogFile = options.mLogFile;
|
||||||
} else {
|
} else {
|
||||||
if ( options.mLogPath.size() ) {
|
// options.mLogPath defaults to '.' so only use it if we don't already have a path
|
||||||
|
if ( (!mLogPath.size()) || options.mLogPath != "." ) {
|
||||||
mLogPath = options.mLogPath;
|
mLogPath = options.mLogPath;
|
||||||
}
|
}
|
||||||
tempLogFile = mLogPath+"/"+mId+".log";
|
tempLogFile = mLogPath+"/"+mId+".log";
|
||||||
|
@ -240,7 +243,7 @@ void Logger::initialise(const std::string &id, const Options &options) {
|
||||||
|
|
||||||
mInitialised = true;
|
mInitialised = true;
|
||||||
|
|
||||||
Debug(1, "LogOpts: level=%s/%s, screen=%s, database=%s, logfile=%s->%s, syslog=%s",
|
Debug(1, "LogOpts: level=%s effective=%s, screen=%s, database=%s, logfile=%s->%s, syslog=%s",
|
||||||
smCodes[mLevel].c_str(),
|
smCodes[mLevel].c_str(),
|
||||||
smCodes[mEffectiveLevel].c_str(),
|
smCodes[mEffectiveLevel].c_str(),
|
||||||
smCodes[mTerminalLevel].c_str(),
|
smCodes[mTerminalLevel].c_str(),
|
||||||
|
@ -297,7 +300,7 @@ const std::string &Logger::id(const std::string &id) {
|
||||||
|
|
||||||
size_t pos;
|
size_t pos;
|
||||||
// Remove whitespace
|
// Remove whitespace
|
||||||
while ( (pos = tempId.find_first_of( " \t" )) != std::string::npos ) {
|
while ( (pos = tempId.find_first_of(" \t")) != std::string::npos ) {
|
||||||
tempId.replace(pos, 1, "");
|
tempId.replace(pos, 1, "");
|
||||||
}
|
}
|
||||||
// Replace non-alphanum with underscore
|
// Replace non-alphanum with underscore
|
||||||
|
@ -341,7 +344,7 @@ Logger::Level Logger::level(Logger::Level level) {
|
||||||
return mLevel;
|
return mLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Level Logger::terminalLevel( Logger::Level terminalLevel ) {
|
Logger::Level Logger::terminalLevel(Logger::Level terminalLevel) {
|
||||||
if ( terminalLevel > NOOPT ) {
|
if ( terminalLevel > NOOPT ) {
|
||||||
if ( !mHasTerminal )
|
if ( !mHasTerminal )
|
||||||
terminalLevel = NOLOG;
|
terminalLevel = NOLOG;
|
||||||
|
@ -352,34 +355,35 @@ Logger::Level Logger::terminalLevel( Logger::Level terminalLevel ) {
|
||||||
return mTerminalLevel;
|
return mTerminalLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) {
|
Logger::Level Logger::databaseLevel(Logger::Level databaseLevel) {
|
||||||
if ( databaseLevel > NOOPT ) {
|
if ( databaseLevel > NOOPT ) {
|
||||||
databaseLevel = limit(databaseLevel);
|
databaseLevel = limit(databaseLevel);
|
||||||
if ( mDatabaseLevel != databaseLevel ) {
|
if ( mDatabaseLevel != databaseLevel ) {
|
||||||
if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG ) {
|
if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG ) {
|
||||||
zmDbConnect();
|
if ( !zmDbConnect() ) {
|
||||||
} // end if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG )
|
databaseLevel = NOLOG;
|
||||||
|
}
|
||||||
|
} // end if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG )
|
||||||
mDatabaseLevel = databaseLevel;
|
mDatabaseLevel = databaseLevel;
|
||||||
} // end if ( mDatabaseLevel != databaseLevel )
|
} // end if ( mDatabaseLevel != databaseLevel )
|
||||||
} // end if ( databaseLevel > NOOPT )
|
} // end if ( databaseLevel > NOOPT )
|
||||||
|
|
||||||
return mDatabaseLevel;
|
return mDatabaseLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
if ( mFileLevel > NOLOG )
|
// Don't try to open it here because it will create the log file even if we never write to it.
|
||||||
openFile();
|
|
||||||
}
|
}
|
||||||
return mFileLevel;
|
return mFileLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 ) {
|
||||||
|
@ -393,7 +397,7 @@ Logger::Level Logger::syslogLevel( Logger::Level syslogLevel ) {
|
||||||
return mSyslogLevel;
|
return mSyslogLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
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] == '+' ) {
|
||||||
|
@ -401,16 +405,16 @@ void Logger::logFile( const std::string &logFile ) {
|
||||||
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")) == (FILE *)NULL ) {
|
if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == (FILE *)NULL ) {
|
||||||
mFileLevel = NOLOG;
|
mFileLevel = NOLOG;
|
||||||
Fatal( "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");
|
||||||
|
@ -419,29 +423,33 @@ void Logger::openFile() {
|
||||||
|
|
||||||
void Logger::closeFile() {
|
void Logger::closeFile() {
|
||||||
if ( mLogFileFP ) {
|
if ( mLogFileFP ) {
|
||||||
fflush( mLogFileFP );
|
fflush(mLogFileFP);
|
||||||
if ( fclose( mLogFileFP ) < 0 ) {
|
if ( fclose(mLogFileFP) < 0 ) {
|
||||||
Fatal( "fclose(), error = %s",strerror(errno) );
|
mLogFileFP = (FILE *)NULL;
|
||||||
|
Error("fclose(), error = %s", strerror(errno));
|
||||||
}
|
}
|
||||||
mLogFileFP = (FILE *)NULL;
|
mLogFileFP = (FILE *)NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::closeDatabase() {
|
void Logger::closeDatabase() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::openSyslog() {
|
void Logger::openSyslog() {
|
||||||
(void) openlog( mId.c_str(), LOG_PID|LOG_NDELAY, LOG_LOCAL1 );
|
(void) openlog(mId.c_str(), LOG_PID|LOG_NDELAY, LOG_LOCAL1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::closeSyslog() {
|
void Logger::closeSyslog() {
|
||||||
(void) closelog();
|
(void) closelog();
|
||||||
}
|
}
|
||||||
|
|
||||||
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 )
|
|
||||||
|
if ( level > mEffectiveLevel ) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
log_mutex.lock();
|
log_mutex.lock();
|
||||||
char timeString[64];
|
char timeString[64];
|
||||||
char logString[8192];
|
char logString[8192];
|
||||||
|
@ -479,24 +487,24 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
|
||||||
thr_self(&lwpid);
|
thr_self(&lwpid);
|
||||||
tid = lwpid;
|
tid = lwpid;
|
||||||
|
|
||||||
if (tid < 0 ) // Thread/Process id
|
if ( tid < 0 ) // Thread/Process id
|
||||||
#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 // HAVE_SYSCALL
|
||||||
#endif
|
#endif
|
||||||
#endif // HAVE_SYSCALL
|
tid = getpid(); // Process id
|
||||||
#endif
|
|
||||||
tid = getpid(); // Process id
|
|
||||||
|
|
||||||
char *logPtr = logString;
|
char *logPtr = logString;
|
||||||
logPtr += snprintf( logPtr, sizeof(logString), "%s %s[%d].%s-%s/%d [",
|
logPtr += snprintf(logPtr, sizeof(logString), "%s %s[%d].%s-%s/%d [",
|
||||||
timeString,
|
timeString,
|
||||||
mId.c_str(),
|
mId.c_str(),
|
||||||
tid,
|
tid,
|
||||||
|
@ -520,32 +528,39 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
|
||||||
}
|
}
|
||||||
va_end(argPtr);
|
va_end(argPtr);
|
||||||
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 )
|
||||||
|
openFile();
|
||||||
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 file not open\n");
|
puts("Logging to file, but failed to open it\n");
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
|
} else {
|
||||||
|
printf("Not writing to log file because level %d %s <= mFileLevel %d %s\nstring: %s\n",
|
||||||
|
level, smCodes[level].c_str(), mFileLevel, smCodes[mFileLevel].c_str(), logString);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
*syslogEnd = '\0';
|
*syslogEnd = '\0';
|
||||||
if ( level <= mDatabaseLevel ) {
|
if ( level <= mDatabaseLevel ) {
|
||||||
char sql[ZM_SQL_MED_BUFSIZ];
|
char sql[ZM_SQL_MED_BUFSIZ];
|
||||||
char escapedString[(strlen(syslogStart)*2)+1];
|
char escapedString[(strlen(syslogStart)*2)+1];
|
||||||
|
|
||||||
if ( ! db_mutex.trylock() ) {
|
if ( !db_mutex.trylock() ) {
|
||||||
mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) );
|
mysql_real_escape_string(&dbconn, escapedString, syslogStart, strlen(syslogStart));
|
||||||
|
|
||||||
snprintf(sql, sizeof(sql),
|
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
|
||||||
|
@ -567,7 +582,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
|
||||||
if ( level <= mSyslogLevel ) {
|
if ( level <= mSyslogLevel ) {
|
||||||
int priority = smSyslogPriorities[level];
|
int priority = smSyslogPriorities[level];
|
||||||
//priority |= LOG_DAEMON;
|
//priority |= LOG_DAEMON;
|
||||||
syslog( priority, "%s [%s] [%s]", classString, mId.c_str(), syslogStart );
|
syslog(priority, "%s [%s] [%s]", classString, mId.c_str(), syslogStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(filecopy);
|
free(filecopy);
|
||||||
|
@ -580,15 +595,16 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
log_mutex.unlock();
|
log_mutex.unlock();
|
||||||
}
|
} // 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 ) {
|
||||||
Logger::smInstance = new Logger();
|
delete Logger::smInstance;
|
||||||
Logger::Options tempOptions = options;
|
Logger::smInstance = NULL;
|
||||||
tempOptions.mLogPath = staticConfig.PATH_LOGS;
|
}
|
||||||
Logger::smInstance->initialise(name, tempOptions);
|
|
||||||
|
Logger::smInstance = new Logger();
|
||||||
|
Logger::smInstance->initialise(name, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
void logTerm() {
|
void logTerm() {
|
||||||
|
|
|
@ -36,12 +36,12 @@ class Logger {
|
||||||
public:
|
public:
|
||||||
enum {
|
enum {
|
||||||
NOOPT=-6,
|
NOOPT=-6,
|
||||||
NOLOG,
|
NOLOG, // -5
|
||||||
PANIC,
|
PANIC, // -4
|
||||||
FATAL,
|
FATAL, // -3
|
||||||
ERROR,
|
ERROR, // -2
|
||||||
WARNING,
|
WARNING, // -1
|
||||||
INFO,
|
INFO, // 0
|
||||||
DEBUG1,
|
DEBUG1,
|
||||||
DEBUG2,
|
DEBUG2,
|
||||||
DEBUG3,
|
DEBUG3,
|
||||||
|
@ -68,14 +68,20 @@ public:
|
||||||
std::string mLogPath;
|
std::string mLogPath;
|
||||||
std::string mLogFile;
|
std::string mLogFile;
|
||||||
|
|
||||||
public:
|
Options(
|
||||||
Options( Level terminalLevel=NOOPT, Level databaseLevel=NOOPT, Level fileLevel=NOOPT, Level syslogLevel=NOOPT, const std::string &logPath=".", const std::string &logFile="" ) :
|
Level terminalLevel=NOOPT,
|
||||||
mTerminalLevel( terminalLevel ),
|
Level databaseLevel=NOOPT,
|
||||||
mDatabaseLevel( databaseLevel ),
|
Level fileLevel=NOOPT,
|
||||||
mFileLevel( fileLevel ),
|
Level syslogLevel=NOOPT,
|
||||||
mSyslogLevel( syslogLevel ),
|
const std::string &logPath=".",
|
||||||
mLogPath( logPath ),
|
const std::string &logFile=""
|
||||||
mLogFile( logFile )
|
) :
|
||||||
|
mTerminalLevel(terminalLevel),
|
||||||
|
mDatabaseLevel(databaseLevel),
|
||||||
|
mFileLevel(fileLevel),
|
||||||
|
mSyslogLevel(syslogLevel),
|
||||||
|
mLogPath(logPath),
|
||||||
|
mLogFile(logFile)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -89,21 +95,21 @@ private:
|
||||||
static StringMap smCodes;
|
static StringMap smCodes;
|
||||||
static IntMap smSyslogPriorities;
|
static IntMap smSyslogPriorities;
|
||||||
|
|
||||||
private:
|
|
||||||
bool mInitialised;
|
bool mInitialised;
|
||||||
|
|
||||||
std::string mId;
|
std::string mId;
|
||||||
std::string mIdRoot;
|
std::string mIdRoot;
|
||||||
std::string mIdArgs;
|
std::string mIdArgs;
|
||||||
|
|
||||||
Level mLevel; // Level that is currently in operation
|
Level mLevel; // Level that is currently in operation
|
||||||
Level mTerminalLevel; // Maximum level output via terminal
|
Level mTerminalLevel; // Maximum level output via terminal
|
||||||
Level mDatabaseLevel; // Maximum level output via database
|
Level mDatabaseLevel; // Maximum level output via database
|
||||||
Level mFileLevel; // Maximum level output via file
|
Level mFileLevel; // Maximum level output via file
|
||||||
Level mSyslogLevel; // Maximum level output via syslog
|
Level mSyslogLevel; // Maximum level output via syslog
|
||||||
Level mEffectiveLevel; // Level optimised to take account of maxima
|
Level mEffectiveLevel; // Level optimised to take account of maxima
|
||||||
|
|
||||||
bool mDbConnected;
|
bool mDbConnected;
|
||||||
|
|
||||||
std::string mLogPath;
|
std::string mLogPath;
|
||||||
std::string mLogFile;
|
std::string mLogFile;
|
||||||
FILE *mLogFileFP;
|
FILE *mLogFileFP;
|
||||||
|
@ -111,31 +117,10 @@ private:
|
||||||
bool mHasTerminal;
|
bool mHasTerminal;
|
||||||
bool mFlush;
|
bool mFlush;
|
||||||
|
|
||||||
private:
|
|
||||||
static void usrHandler(int sig);
|
|
||||||
|
|
||||||
public:
|
|
||||||
friend void logInit(const char *name, const Options &options);
|
|
||||||
friend void logTerm();
|
|
||||||
|
|
||||||
static Logger *fetch() {
|
|
||||||
if ( !smInstance ) {
|
|
||||||
smInstance = new Logger();
|
|
||||||
Options options;
|
|
||||||
smInstance->initialise( "undef", options );
|
|
||||||
}
|
|
||||||
return smInstance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Logger();
|
Logger();
|
||||||
~Logger();
|
~Logger();
|
||||||
|
|
||||||
public:
|
|
||||||
void initialise(const std::string &id, const Options &options);
|
|
||||||
void terminate();
|
|
||||||
|
|
||||||
private:
|
|
||||||
int limit(int level) {
|
int limit(int level) {
|
||||||
if ( level > DEBUG9 )
|
if ( level > DEBUG9 )
|
||||||
return DEBUG9;
|
return DEBUG9;
|
||||||
|
@ -150,14 +135,29 @@ private:
|
||||||
char *getTargettedEnv(const std::string &name);
|
char *getTargettedEnv(const std::string &name);
|
||||||
|
|
||||||
void loadEnv();
|
void loadEnv();
|
||||||
|
static void usrHandler(int sig);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
friend void logInit(const char *name, const Options &options);
|
||||||
|
friend void logTerm();
|
||||||
|
|
||||||
|
static Logger *fetch() {
|
||||||
|
if ( !smInstance ) {
|
||||||
|
smInstance = new Logger();
|
||||||
|
Options options;
|
||||||
|
smInstance->initialise("undef", options);
|
||||||
|
}
|
||||||
|
return smInstance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialise(const std::string &id, const Options &options);
|
||||||
|
void terminate();
|
||||||
|
|
||||||
|
const std::string &id(const std::string &id);
|
||||||
const std::string &id() const {
|
const std::string &id() const {
|
||||||
return mId;
|
return mId;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &id(const std::string &id);
|
|
||||||
|
|
||||||
Level level() const {
|
Level level() const {
|
||||||
return mLevel;
|
return mLevel;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "zm_utils.h"
|
#include "zm_utils.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <algorithm>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <fcntl.h> /* Definition of AT_* constants */
|
#include <fcntl.h> /* Definition of AT_* constants */
|
||||||
|
@ -416,6 +417,10 @@ Warning("ZM Compiled without LIBCURL. UriDecoding not implemented.");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void string_toupper( std::string& str) {
|
||||||
|
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
|
||||||
|
}
|
||||||
|
|
||||||
void touch(const char *pathname) {
|
void touch(const char *pathname) {
|
||||||
int fd = open(pathname,
|
int fd = open(pathname,
|
||||||
O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK,
|
O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK,
|
||||||
|
|
|
@ -40,6 +40,7 @@ StringVector split( const std::string &string, const std::string &chars, int lim
|
||||||
const std::string join( const StringVector &, const char * );
|
const std::string join( const StringVector &, const char * );
|
||||||
|
|
||||||
const std::string base64Encode( const std::string &inString );
|
const std::string base64Encode( const std::string &inString );
|
||||||
|
void string_toupper(std::string& str);
|
||||||
|
|
||||||
int split(const char* string, const char delim, std::vector<std::string>& items);
|
int split(const char* string, const char delim, std::vector<std::string>& items);
|
||||||
int pairsplit(const char* string, const char delim, std::string& name, std::string& value);
|
int pairsplit(const char* string, const char delim, std::string& name, std::string& value);
|
||||||
|
|
|
@ -20,13 +20,14 @@
|
||||||
|
|
||||||
#define __STDC_FORMAT_MACROS 1
|
#define __STDC_FORMAT_MACROS 1
|
||||||
|
|
||||||
#include <cinttypes>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "zm.h"
|
#include "zm.h"
|
||||||
#include "zm_videostore.h"
|
#include "zm_videostore.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <cinttypes>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "libavutil/time.h"
|
#include "libavutil/time.h"
|
||||||
}
|
}
|
||||||
|
@ -60,7 +61,7 @@ VideoStore::VideoStore(
|
||||||
|
|
||||||
Info("Opening video storage stream %s format: %s", filename, format);
|
Info("Opening video storage stream %s format: %s", filename, format);
|
||||||
|
|
||||||
ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
int ret = avformat_alloc_output_context2(&oc, NULL, NULL, filename);
|
||||||
if ( ret < 0 ) {
|
if ( ret < 0 ) {
|
||||||
Warning(
|
Warning(
|
||||||
"Could not create video storage stream %s as no out ctx"
|
"Could not create video storage stream %s as no out ctx"
|
||||||
|
@ -91,7 +92,7 @@ VideoStore::VideoStore(
|
||||||
|
|
||||||
oc->metadata = pmetadata;
|
oc->metadata = pmetadata;
|
||||||
out_format = oc->oformat;
|
out_format = oc->oformat;
|
||||||
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
|
out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts
|
||||||
|
|
||||||
video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
|
video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id);
|
||||||
if ( !video_out_codec ) {
|
if ( !video_out_codec ) {
|
||||||
|
@ -136,7 +137,7 @@ VideoStore::VideoStore(
|
||||||
video_out_ctx->time_base = video_in_ctx->time_base;
|
video_out_ctx->time_base = video_in_ctx->time_base;
|
||||||
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
|
if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) {
|
||||||
Debug(2,"No timebase found in video in context, defaulting to Q");
|
Debug(2,"No timebase found in video in context, defaulting to Q");
|
||||||
video_out_ctx->time_base = AV_TIME_BASE_Q;
|
video_out_ctx->time_base = AV_TIME_BASE_Q;
|
||||||
}
|
}
|
||||||
|
|
||||||
zm_dump_codec(video_out_ctx);
|
zm_dump_codec(video_out_ctx);
|
||||||
|
@ -162,7 +163,7 @@ VideoStore::VideoStore(
|
||||||
|
|
||||||
if ( !video_out_ctx->codec_tag ) {
|
if ( !video_out_ctx->codec_tag ) {
|
||||||
Debug(2, "No codec_tag");
|
Debug(2, "No codec_tag");
|
||||||
if (
|
if (
|
||||||
!oc->oformat->codec_tag
|
!oc->oformat->codec_tag
|
||||||
||
|
||
|
||||||
av_codec_get_id(oc->oformat->codec_tag, video_in_ctx->codec_tag) == video_out_ctx->codec_id
|
av_codec_get_id(oc->oformat->codec_tag, video_in_ctx->codec_tag) == video_out_ctx->codec_id
|
||||||
|
@ -178,32 +179,20 @@ VideoStore::VideoStore(
|
||||||
video_out_stream->time_base = video_in_stream->time_base;
|
video_out_stream->time_base = video_in_stream->time_base;
|
||||||
if ( video_in_stream->avg_frame_rate.num ) {
|
if ( video_in_stream->avg_frame_rate.num ) {
|
||||||
Debug(3,"Copying avg_frame_rate (%d/%d)",
|
Debug(3,"Copying avg_frame_rate (%d/%d)",
|
||||||
video_in_stream->avg_frame_rate.num,
|
video_in_stream->avg_frame_rate.num,
|
||||||
video_in_stream->avg_frame_rate.den
|
video_in_stream->avg_frame_rate.den
|
||||||
);
|
);
|
||||||
video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate;
|
video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate;
|
||||||
}
|
}
|
||||||
if ( video_in_stream->r_frame_rate.num ) {
|
if ( video_in_stream->r_frame_rate.num ) {
|
||||||
Debug(3,"Copying r_frame_rate (%d/%d) to out (%d/%d)",
|
Debug(3,"Copying r_frame_rate (%d/%d) to out (%d/%d)",
|
||||||
video_in_stream->r_frame_rate.num,
|
video_in_stream->r_frame_rate.num,
|
||||||
video_in_stream->r_frame_rate.den ,
|
video_in_stream->r_frame_rate.den ,
|
||||||
video_out_stream->r_frame_rate.num,
|
video_out_stream->r_frame_rate.num,
|
||||||
video_out_stream->r_frame_rate.den
|
video_out_stream->r_frame_rate.den
|
||||||
);
|
);
|
||||||
video_out_stream->r_frame_rate = video_in_stream->r_frame_rate;
|
video_out_stream->r_frame_rate = video_in_stream->r_frame_rate;
|
||||||
}
|
}
|
||||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
|
||||||
ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx);
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
Error("Could not initialize video_out_ctx parameters");
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
zm_dump_codec(video_out_ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
zm_dump_codecpar(video_in_stream->codecpar);
|
|
||||||
zm_dump_codecpar(video_out_stream->codecpar);
|
|
||||||
#endif
|
|
||||||
Debug(3,
|
Debug(3,
|
||||||
"Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out "
|
"Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out "
|
||||||
"stream: (%d/%d) out codec (%d/%d)",
|
"stream: (%d/%d) out codec (%d/%d)",
|
||||||
|
@ -221,6 +210,10 @@ VideoStore::VideoStore(
|
||||||
}
|
}
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
|
||||||
|
/* I'm not entirely sure that this is a good idea. We may have to do it someday but really only when transcoding
|
||||||
|
* * think what I was trying to achieve here was to have zm_dump_codecpar output nice info
|
||||||
|
* */
|
||||||
|
#if 0
|
||||||
AVDictionary *opts = 0;
|
AVDictionary *opts = 0;
|
||||||
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",
|
Warning("Can't open video codec (%s) %s",
|
||||||
|
@ -234,6 +227,24 @@ VideoStore::VideoStore(
|
||||||
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
|
||||||
Warning("Encoder Option %s not recognized by ffmpeg codec", e->key);
|
Warning("Encoder Option %s not recognized by ffmpeg codec", e->key);
|
||||||
}
|
}
|
||||||
|
ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Error("Could not initialize video_out_ctx parameters");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
zm_dump_codec(video_out_ctx);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_in_ctx);
|
||||||
|
if ( ret < 0 ) {
|
||||||
|
Error("Could not initialize video_out_ctx parameters");
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
zm_dump_codec(video_out_ctx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
zm_dump_codecpar(video_in_stream->codecpar);
|
||||||
|
zm_dump_codecpar(video_out_stream->codecpar);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Monitor::Orientation orientation = monitor->getOrientation();
|
Monitor::Orientation orientation = monitor->getOrientation();
|
||||||
|
@ -262,9 +273,7 @@ VideoStore::VideoStore(
|
||||||
out_frame = NULL;
|
out_frame = NULL;
|
||||||
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
|
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
|
||||||
resample_ctx = NULL;
|
resample_ctx = NULL;
|
||||||
#if defined(HAVE_LIBSWRESAMPLE)
|
|
||||||
fifo = NULL;
|
fifo = NULL;
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
video_first_pts = 0;
|
video_first_pts = 0;
|
||||||
video_first_dts = 0;
|
video_first_dts = 0;
|
||||||
|
@ -273,6 +282,7 @@ VideoStore::VideoStore(
|
||||||
|
|
||||||
audio_first_pts = 0;
|
audio_first_pts = 0;
|
||||||
audio_first_dts = 0;
|
audio_first_dts = 0;
|
||||||
|
/* When encoding audio, these are used to tell us what the correct pts is, because it gets lost during resampling. */
|
||||||
audio_next_pts = 0;
|
audio_next_pts = 0;
|
||||||
audio_next_dts = 0;
|
audio_next_dts = 0;
|
||||||
|
|
||||||
|
@ -301,7 +311,7 @@ VideoStore::VideoStore(
|
||||||
audio_out_stream = NULL;
|
audio_out_stream = NULL;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
audio_out_stream = avformat_new_stream(oc, audio_out_codec);
|
audio_out_stream = avformat_new_stream(oc, audio_out_codec);
|
||||||
audio_out_ctx = audio_out_stream->codec;
|
audio_out_ctx = audio_out_stream->codec;
|
||||||
#endif
|
#endif
|
||||||
|
@ -375,6 +385,7 @@ VideoStore::VideoStore(
|
||||||
} // VideoStore::VideoStore
|
} // VideoStore::VideoStore
|
||||||
|
|
||||||
bool VideoStore::open() {
|
bool VideoStore::open() {
|
||||||
|
int ret;
|
||||||
/* open the out file, if needed */
|
/* open the out file, if needed */
|
||||||
if ( !(out_format->flags & AVFMT_NOFILE) ) {
|
if ( !(out_format->flags & AVFMT_NOFILE) ) {
|
||||||
ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL);
|
ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL);
|
||||||
|
@ -419,6 +430,7 @@ VideoStore::~VideoStore() {
|
||||||
if ( oc->pb ) {
|
if ( oc->pb ) {
|
||||||
|
|
||||||
if ( audio_out_codec ) {
|
if ( audio_out_codec ) {
|
||||||
|
|
||||||
// The codec queues data. We need to send a flush command and out
|
// The codec queues data. We need to send a flush command and out
|
||||||
// whatever we get. Failures are not fatal.
|
// whatever we get. Failures are not fatal.
|
||||||
AVPacket pkt;
|
AVPacket pkt;
|
||||||
|
@ -426,105 +438,75 @@ VideoStore::~VideoStore() {
|
||||||
pkt.data = NULL;
|
pkt.data = NULL;
|
||||||
pkt.size = 0;
|
pkt.size = 0;
|
||||||
av_init_packet(&pkt);
|
av_init_packet(&pkt);
|
||||||
|
|
||||||
|
int frame_size = audio_out_ctx->frame_size;
|
||||||
|
/*
|
||||||
|
* At the end of the file, we pass the remaining samples to
|
||||||
|
* the encoder. */
|
||||||
|
while ( zm_resample_get_delay(resample_ctx, audio_out_ctx->sample_rate) ) {
|
||||||
|
zm_resample_audio(resample_ctx, out_frame, NULL);
|
||||||
|
|
||||||
|
if ( zm_add_samples_to_fifo(fifo, out_frame) ) {
|
||||||
|
// Should probably set the frame size to what is reported FIXME
|
||||||
|
if ( zm_get_samples_from_fifo(fifo, out_frame) ) {
|
||||||
|
if ( zm_send_frame_receive_packet(audio_out_ctx, out_frame, pkt) ) {
|
||||||
|
pkt.stream_index = audio_out_stream->index;
|
||||||
|
|
||||||
|
av_packet_rescale_ts(&pkt,
|
||||||
|
audio_out_ctx->time_base,
|
||||||
|
audio_out_stream->time_base);
|
||||||
|
write_packet(&pkt, audio_out_stream);
|
||||||
|
}
|
||||||
|
} // end if data returned from fifo
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end if have buffered samples in the resampler
|
||||||
|
|
||||||
|
Debug(2, "av_audio_fifo_size = %d", av_audio_fifo_size(fifo));
|
||||||
|
while ( av_audio_fifo_size(fifo) > 0 ) {
|
||||||
|
/* Take one frame worth of audio samples from the FIFO buffer,
|
||||||
|
* encode it and write it to the output file. */
|
||||||
|
|
||||||
|
Debug(1, "Remaining samples in fifo for AAC codec frame_size %d > fifo size %d",
|
||||||
|
frame_size, av_audio_fifo_size(fifo));
|
||||||
|
|
||||||
|
// SHould probably set the frame size to what is reported FIXME
|
||||||
|
if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) ) {
|
||||||
|
if ( zm_send_frame_receive_packet(audio_out_ctx, out_frame, pkt) ) {
|
||||||
|
pkt.stream_index = audio_out_stream->index;
|
||||||
|
|
||||||
|
av_packet_rescale_ts(&pkt,
|
||||||
|
audio_out_ctx->time_base,
|
||||||
|
audio_out_stream->time_base);
|
||||||
|
write_packet(&pkt, audio_out_stream);
|
||||||
|
}
|
||||||
|
} // end if data returned from fifo
|
||||||
|
} // end while still data in the fifo
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
// Put encoder into flushing mode
|
// Put encoder into flushing mode
|
||||||
avcodec_send_frame(audio_out_ctx, NULL);
|
avcodec_send_frame(audio_out_ctx, NULL);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
if ( ! zm_receive_packet(audio_out_ctx, pkt) ) {
|
||||||
ret = avcodec_receive_packet(audio_out_ctx, &pkt);
|
Debug(1, "No more packets");
|
||||||
if ( ret < 0 ) {
|
|
||||||
if ( AVERROR_EOF != ret ) {
|
|
||||||
Error("Error encoding audio while flushing (%d) (%s)", ret,
|
|
||||||
av_err2str(ret));
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
int got_packet = 0;
|
|
||||||
ret = avcodec_encode_audio2(audio_out_ctx, &pkt, NULL, &got_packet);
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
Error("Error encoding audio while flushing (%d) (%s)", ret,
|
|
||||||
av_err2str(ret));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
Debug(1, "Have audio encoder, need to flush it's out");
|
|
||||||
if ( !got_packet ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
dumpPacket(&pkt, "raw from encoder");
|
dumpPacket(&pkt, "raw from encoder");
|
||||||
// Need to adjust pts and dts and duration
|
av_packet_rescale_ts(&pkt, audio_out_ctx->time_base, audio_out_stream->time_base);
|
||||||
|
|
||||||
pkt.stream_index = audio_out_stream->index;
|
|
||||||
|
|
||||||
pkt.duration = av_rescale_q(
|
|
||||||
pkt.duration,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
// Scale the PTS of the outgoing packet to be the correct time base
|
|
||||||
if ( pkt.pts != AV_NOPTS_VALUE ) {
|
|
||||||
#if 0
|
|
||||||
pkt.pts = av_rescale_q(
|
|
||||||
pkt.pts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_in_stream->time_base);
|
|
||||||
// audio_first_pts is in audio_in_stream time base
|
|
||||||
pkt.pts -= audio_first_pts;
|
|
||||||
pkt.pts = av_rescale_q(
|
|
||||||
pkt.pts,
|
|
||||||
audio_in_stream->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
#else
|
|
||||||
pkt.pts = av_rescale_q(
|
|
||||||
pkt.pts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Debug(2, "audio pkt.pts = %" PRId64 " from first_pts(%" PRId64 ")",
|
|
||||||
pkt.pts, audio_first_pts);
|
|
||||||
} else {
|
|
||||||
Debug(2, "pkt.pts = undef");
|
|
||||||
pkt.pts = AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( pkt.dts != AV_NOPTS_VALUE ) {
|
|
||||||
#if 0
|
|
||||||
pkt.dts = av_rescale_q(
|
|
||||||
pkt.dts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_in_stream->time_base);
|
|
||||||
pkt.dts -= audio_first_dts;
|
|
||||||
pkt.dts = av_rescale_q(
|
|
||||||
pkt.dts,
|
|
||||||
audio_in_stream->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
#else
|
|
||||||
pkt.dts = av_rescale_q(
|
|
||||||
pkt.dts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
#endif
|
|
||||||
Debug(2, "pkt.dts = %" PRId64 " - first_dts(%" PRId64 ")",
|
|
||||||
pkt.dts, audio_first_dts);
|
|
||||||
} else {
|
|
||||||
pkt.dts = AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpPacket(audio_out_stream, &pkt, "writing flushed packet");
|
dumpPacket(audio_out_stream, &pkt, "writing flushed packet");
|
||||||
av_interleaved_write_frame(oc, &pkt);
|
write_packet(&pkt, audio_out_stream);
|
||||||
zm_av_packet_unref(&pkt);
|
zm_av_packet_unref(&pkt);
|
||||||
} // while have buffered frames
|
} // while have buffered frames
|
||||||
} // end if audio_out_codec
|
} // end if audio_out_codec
|
||||||
|
|
||||||
// Flush Queues
|
// Flush Queues
|
||||||
Debug(1,"Flushing interleaved queues");
|
Debug(1, "Flushing interleaved queues");
|
||||||
av_interleaved_write_frame(oc, NULL);
|
av_interleaved_write_frame(oc, NULL);
|
||||||
|
|
||||||
Debug(1,"Writing trailer");
|
Debug(1, "Writing trailer");
|
||||||
/* Write the trailer before close */
|
/* Write the trailer before close */
|
||||||
if ( int rc = av_write_trailer(oc) ) {
|
if ( int rc = av_write_trailer(oc) ) {
|
||||||
Error("Error writing trailer %s", av_err2str(rc));
|
Error("Error writing trailer %s", av_err2str(rc));
|
||||||
|
@ -593,11 +575,11 @@ VideoStore::~VideoStore() {
|
||||||
|
|
||||||
#if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE)
|
#if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE)
|
||||||
if ( resample_ctx ) {
|
if ( resample_ctx ) {
|
||||||
#if defined(HAVE_LIBSWRESAMPLE)
|
|
||||||
if ( fifo ) {
|
if ( fifo ) {
|
||||||
av_audio_fifo_free(fifo);
|
av_audio_fifo_free(fifo);
|
||||||
fifo = NULL;
|
fifo = NULL;
|
||||||
}
|
}
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
swr_free(&resample_ctx);
|
swr_free(&resample_ctx);
|
||||||
#else
|
#else
|
||||||
#if defined(HAVE_LIBAVRESAMPLE)
|
#if defined(HAVE_LIBAVRESAMPLE)
|
||||||
|
@ -632,6 +614,7 @@ bool VideoStore::setup_resampler() {
|
||||||
"Cannot do audio conversion to AAC");
|
"Cannot do audio conversion to AAC");
|
||||||
return false;
|
return false;
|
||||||
#else
|
#else
|
||||||
|
int ret;
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
// Newer ffmpeg wants to keep everything separate... so have to lookup our own
|
// Newer ffmpeg wants to keep everything separate... so have to lookup our own
|
||||||
|
@ -650,8 +633,13 @@ bool VideoStore::setup_resampler() {
|
||||||
#else
|
#else
|
||||||
// codec is already open in ffmpeg_camera
|
// codec is already open in ffmpeg_camera
|
||||||
audio_in_ctx = audio_in_stream->codec;
|
audio_in_ctx = audio_in_stream->codec;
|
||||||
audio_in_codec = (AVCodec *)audio_in_ctx->codec;
|
audio_in_codec = reinterpret_cast<const AVCodec *>(audio_in_ctx->codec);
|
||||||
//audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id);
|
if ( !audio_in_codec ) {
|
||||||
|
audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id);
|
||||||
|
}
|
||||||
|
if ( !audio_in_codec ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
|
@ -707,7 +695,7 @@ bool VideoStore::setup_resampler() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ( found ) {
|
if ( found ) {
|
||||||
Debug(3, "Sample rate is good");
|
Debug(3, "Sample rate is good %d", audio_out_ctx->sample_rate);
|
||||||
} else {
|
} else {
|
||||||
audio_out_ctx->sample_rate =
|
audio_out_ctx->sample_rate =
|
||||||
audio_out_codec->supported_samplerates[0];
|
audio_out_codec->supported_samplerates[0];
|
||||||
|
@ -739,6 +727,7 @@ bool VideoStore::setup_resampler() {
|
||||||
audio_out_stream = NULL;
|
audio_out_stream = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
zm_dump_codec(audio_out_ctx);
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
||||||
ret = avcodec_parameters_from_context(
|
ret = avcodec_parameters_from_context(
|
||||||
|
@ -747,6 +736,7 @@ bool VideoStore::setup_resampler() {
|
||||||
Error("Could not initialize stream parameteres");
|
Error("Could not initialize stream parameteres");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
zm_dump_codecpar(audio_out_stream->codecpar);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Debug(3,
|
Debug(3,
|
||||||
|
@ -783,13 +773,13 @@ bool VideoStore::setup_resampler() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(HAVE_LIBSWRESAMPLE)
|
|
||||||
if ( !(fifo = av_audio_fifo_alloc(
|
if ( !(fifo = av_audio_fifo_alloc(
|
||||||
audio_out_ctx->sample_fmt,
|
audio_out_ctx->sample_fmt,
|
||||||
audio_out_ctx->channels, 1)) ) {
|
audio_out_ctx->channels, 1)) ) {
|
||||||
Error("Could not allocate FIFO");
|
Error("Could not allocate FIFO");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#if defined(HAVE_LIBSWRESAMPLE)
|
||||||
resample_ctx = swr_alloc_set_opts(NULL,
|
resample_ctx = swr_alloc_set_opts(NULL,
|
||||||
audio_out_ctx->channel_layout,
|
audio_out_ctx->channel_layout,
|
||||||
audio_out_ctx->sample_fmt,
|
audio_out_ctx->sample_fmt,
|
||||||
|
@ -864,7 +854,7 @@ bool VideoStore::setup_resampler() {
|
||||||
NULL, audio_out_ctx->channels,
|
NULL, audio_out_ctx->channels,
|
||||||
audio_out_ctx->frame_size,
|
audio_out_ctx->frame_size,
|
||||||
audio_out_ctx->sample_fmt, 0);
|
audio_out_ctx->sample_fmt, 0);
|
||||||
converted_in_samples = (uint8_t *)av_malloc(audioSampleBuffer_size);
|
converted_in_samples = reinterpret_cast<uint8_t *>(av_malloc(audioSampleBuffer_size));
|
||||||
|
|
||||||
if ( !converted_in_samples ) {
|
if ( !converted_in_samples ) {
|
||||||
Error("Could not allocate converted in sample pointers");
|
Error("Could not allocate converted in sample pointers");
|
||||||
|
@ -890,131 +880,31 @@ bool VideoStore::setup_resampler() {
|
||||||
int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
||||||
av_init_packet(&opkt);
|
av_init_packet(&opkt);
|
||||||
|
|
||||||
dumpPacket(video_in_stream, ipkt, "input packet");
|
dumpPacket(video_in_stream, ipkt, "video input packet");
|
||||||
|
|
||||||
int64_t duration;
|
opkt.flags = ipkt->flags;
|
||||||
if ( ipkt->duration != AV_NOPTS_VALUE ) {
|
opkt.data = ipkt->data;
|
||||||
duration = av_rescale_q(
|
opkt.size = ipkt->size;
|
||||||
ipkt->duration,
|
opkt.duration = ipkt->duration;
|
||||||
video_in_stream->time_base,
|
|
||||||
video_out_stream->time_base);
|
|
||||||
Debug(1, "duration from ipkt: %" PRId64 ") => (%" PRId64 ") (%d/%d) (%d/%d)",
|
|
||||||
ipkt->duration,
|
|
||||||
duration,
|
|
||||||
video_in_stream->time_base.num,
|
|
||||||
video_in_stream->time_base.den,
|
|
||||||
video_out_stream->time_base.num,
|
|
||||||
video_out_stream->time_base.den
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
duration = av_rescale_q(
|
|
||||||
ipkt->pts - video_last_pts,
|
|
||||||
video_in_stream->time_base,
|
|
||||||
video_out_stream->time_base);
|
|
||||||
Debug(1, "duration calc: pts(%" PRId64 ") - last_pts(%" PRId64 ") = (%" PRId64 ") => (%" PRId64 ")",
|
|
||||||
ipkt->pts,
|
|
||||||
video_last_pts,
|
|
||||||
ipkt->pts - video_last_pts,
|
|
||||||
duration
|
|
||||||
);
|
|
||||||
if ( duration <= 0 ) {
|
|
||||||
// Why are we setting the duration to 1?
|
|
||||||
duration = ipkt->duration ? ipkt->duration : av_rescale_q(1,video_in_stream->time_base, video_out_stream->time_base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
opkt.duration = duration;
|
|
||||||
|
|
||||||
// Scale the PTS of the outgoing packet to be the correct time base
|
|
||||||
if ( ipkt->pts != AV_NOPTS_VALUE ) {
|
|
||||||
|
|
||||||
if ( (!video_first_pts) && (ipkt->pts >= 0) ) {
|
|
||||||
// This is the first packet.
|
|
||||||
opkt.pts = 0;
|
|
||||||
Debug(2, "Starting video first_pts will become %" PRId64, ipkt->pts);
|
|
||||||
video_first_pts = ipkt->pts;
|
|
||||||
#if 1
|
|
||||||
if ( audio_in_stream ) {
|
|
||||||
// Since audio starts after the start of the video, need to set this here.
|
|
||||||
audio_first_pts = av_rescale_q(
|
|
||||||
ipkt->pts,
|
|
||||||
video_in_stream->time_base,
|
|
||||||
audio_in_stream->time_base
|
|
||||||
);
|
|
||||||
Debug(2, "Starting audio first_pts will become %" PRId64, audio_first_pts);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
opkt.pts = av_rescale_q(
|
|
||||||
ipkt->pts - video_first_pts,
|
|
||||||
video_in_stream->time_base,
|
|
||||||
video_out_stream->time_base
|
|
||||||
);
|
|
||||||
}
|
|
||||||
Debug(3, "opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")",
|
|
||||||
opkt.pts, ipkt->pts, video_first_pts);
|
|
||||||
video_last_pts = ipkt->pts;
|
|
||||||
} else {
|
|
||||||
Debug(3, "opkt.pts = undef");
|
|
||||||
opkt.pts = AV_NOPTS_VALUE;
|
|
||||||
// can't set 0, it will get rejected
|
|
||||||
//AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
// Just because the in stream wraps, doesn't mean the out needs to.
|
// Just because the in stream wraps, doesn't mean the out needs to.
|
||||||
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
|
// Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out.
|
||||||
// So need to handle in wrap, without causing out wrap.
|
// So need to handle in wrap, without causing out wrap.
|
||||||
|
// The cameras that Icon has seem to do EOF instead of wrapping
|
||||||
|
|
||||||
if ( ipkt->dts != AV_NOPTS_VALUE ) {
|
if ( ipkt->dts != AV_NOPTS_VALUE ) {
|
||||||
if ( !video_first_dts ) {
|
if ( !video_first_dts ) {
|
||||||
// && ( ipkt->dts >= 0 ) ) {
|
Debug(2, "Starting video first_dts will become %" PRId64, ipkt->dts);
|
||||||
// This is the first packet.
|
|
||||||
opkt.dts = 0;
|
|
||||||
Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
|
|
||||||
video_first_dts = ipkt->dts;
|
video_first_dts = ipkt->dts;
|
||||||
#if 1
|
|
||||||
if ( audio_in_stream ) {
|
|
||||||
// Since audio starts after the start of the video, need to set this here.
|
|
||||||
audio_first_dts = av_rescale_q(
|
|
||||||
ipkt->dts,
|
|
||||||
video_in_stream->time_base,
|
|
||||||
audio_in_stream->time_base
|
|
||||||
);
|
|
||||||
Debug(2, "Starting audio first dts will become %" PRId64, audio_first_dts);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
opkt.dts = av_rescale_q(
|
|
||||||
ipkt->dts - video_first_dts,
|
|
||||||
video_in_stream->time_base,
|
|
||||||
video_out_stream->time_base
|
|
||||||
);
|
|
||||||
Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")",
|
|
||||||
opkt.dts, ipkt->dts, video_first_dts);
|
|
||||||
}
|
}
|
||||||
if ( (opkt.pts != AV_NOPTS_VALUE) && (opkt.dts > opkt.pts) ) {
|
opkt.dts = ipkt->dts - video_first_dts;
|
||||||
Debug(1,
|
|
||||||
"opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen "
|
|
||||||
"before presentation.",
|
|
||||||
opkt.dts, opkt.pts);
|
|
||||||
opkt.dts = opkt.pts;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Debug(3, "opkt.dts = undef");
|
|
||||||
opkt.dts = video_out_stream->cur_dts;
|
|
||||||
}
|
}
|
||||||
|
if ( ipkt->pts != AV_NOPTS_VALUE ) {
|
||||||
|
opkt.pts = ipkt->pts - video_first_dts;
|
||||||
|
}
|
||||||
|
av_packet_rescale_ts(&opkt, video_in_stream->time_base, video_out_stream->time_base);
|
||||||
|
|
||||||
if ( opkt.dts < video_out_stream->cur_dts ) {
|
dumpPacket(video_out_stream, &opkt, "after pts adjustment");
|
||||||
Debug(1, "Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64,
|
|
||||||
opkt.dts, opkt.pts, video_out_stream->cur_dts);
|
|
||||||
opkt.dts = video_out_stream->cur_dts;
|
|
||||||
if ( opkt.dts > opkt.pts ) {
|
|
||||||
opkt.pts = opkt.dts;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
opkt.flags = ipkt->flags;
|
|
||||||
opkt.pos = -1;
|
|
||||||
opkt.data = ipkt->data;
|
|
||||||
opkt.size = ipkt->size;
|
|
||||||
write_packet(&opkt, video_out_stream);
|
write_packet(&opkt, video_out_stream);
|
||||||
zm_av_packet_unref(&opkt);
|
zm_av_packet_unref(&opkt);
|
||||||
|
|
||||||
|
@ -1022,6 +912,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
|
||||||
} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
|
} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
|
||||||
|
|
||||||
int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
if ( !audio_out_stream ) {
|
if ( !audio_out_stream ) {
|
||||||
Debug(1, "Called writeAudioFramePacket when no audio_out_stream");
|
Debug(1, "Called writeAudioFramePacket when no audio_out_stream");
|
||||||
|
@ -1030,151 +921,57 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
||||||
}
|
}
|
||||||
dumpPacket(audio_in_stream, ipkt, "input packet");
|
dumpPacket(audio_in_stream, ipkt, "input packet");
|
||||||
|
|
||||||
|
if ( !audio_first_dts ) {
|
||||||
|
audio_first_dts = ipkt->dts;
|
||||||
|
audio_next_pts = audio_out_ctx->frame_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
dumpPacket(audio_in_stream, ipkt, "after pts adjustment");
|
||||||
|
|
||||||
if ( audio_out_codec ) {
|
if ( audio_out_codec ) {
|
||||||
if ( ( ret = zm_receive_frame(audio_in_ctx, in_frame, *ipkt) ) < 0 ) {
|
// I wonder if we can get multiple frames per packet? Probably
|
||||||
|
ret = zm_send_packet_receive_frame(audio_in_ctx, in_frame, *ipkt);
|
||||||
|
if ( ret <= 0 ) {
|
||||||
Debug(3, "Not ready to receive frame");
|
Debug(3, "Not ready to receive frame");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
zm_dump_frame(in_frame, "In frame from decode");
|
zm_dump_frame(in_frame, "In frame from decode");
|
||||||
if ( in_frame->pts != AV_NOPTS_VALUE ) {
|
|
||||||
if ( !audio_first_pts ) {
|
|
||||||
audio_first_pts = in_frame->pts;
|
|
||||||
Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts);
|
|
||||||
in_frame->pts = 0;
|
|
||||||
} else {
|
|
||||||
// out_frame_pts is in codec->timebase, audio_first_pts is in packet timebase.
|
|
||||||
in_frame->pts = in_frame->pts - audio_first_pts;
|
|
||||||
zm_dump_frame(in_frame, "in frame after pts adjustment");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// sending AV_NOPTS_VALUE doesn't really work but we seem to get it in ffmpeg 2.8
|
|
||||||
in_frame->pts = audio_next_pts;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !resample_audio() ) {
|
AVFrame *input_frame = in_frame;
|
||||||
//av_frame_unref(in_frame);
|
|
||||||
return 0;
|
while ( zm_resample_audio(resample_ctx, input_frame, out_frame) ) {
|
||||||
}
|
//out_frame->pkt_duration = in_frame->pkt_duration; // resampling doesn't alter duration
|
||||||
|
if ( zm_add_samples_to_fifo(fifo, out_frame) <= 0 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
if ( zm_get_samples_from_fifo(fifo, out_frame) <= 0 )
|
||||||
|
break;
|
||||||
|
|
||||||
zm_dump_frame(out_frame, "Out frame after resample");
|
|
||||||
#if 0
|
|
||||||
// out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder
|
|
||||||
if ( out_frame->pts != AV_NOPTS_VALUE ) {
|
|
||||||
if ( !audio_first_pts ) {
|
|
||||||
audio_first_pts = out_frame->pts;
|
|
||||||
Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts);
|
|
||||||
out_frame->pts = 0;
|
|
||||||
} else {
|
|
||||||
// out_frame_pts is in codec->timebase, audio_first_pts is in packet timebase.
|
|
||||||
out_frame->pts = out_frame->pts - audio_first_pts;
|
|
||||||
zm_dump_frame(out_frame, "Out frame after pts adjustment");
|
|
||||||
}
|
|
||||||
//
|
|
||||||
} else {
|
|
||||||
// sending AV_NOPTS_VALUE doesn't really work but we seem to get it in ffmpeg 2.8
|
|
||||||
out_frame->pts = audio_next_pts;
|
out_frame->pts = audio_next_pts;
|
||||||
}
|
audio_next_pts += out_frame->nb_samples;
|
||||||
audio_next_pts = out_frame->pts + out_frame->nb_samples;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
av_init_packet(&opkt);
|
zm_dump_frame(out_frame, "Out frame after resample");
|
||||||
if ( !zm_send_frame(audio_out_ctx, out_frame, opkt) ) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
dumpPacket(audio_out_stream, &opkt, "raw opkt");
|
av_init_packet(&opkt);
|
||||||
Debug(1, "Duration before %d in %d/%d", opkt.duration,
|
if ( zm_send_frame_receive_packet(audio_out_ctx, out_frame, opkt) <= 0 )
|
||||||
audio_out_ctx->time_base.num,
|
break;
|
||||||
audio_out_ctx->time_base.den);
|
|
||||||
|
|
||||||
opkt.duration = av_rescale_q(
|
// Scale the PTS of the outgoing packet to be the correct time base
|
||||||
opkt.duration,
|
av_packet_rescale_ts(&opkt,
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
Debug(1, "Duration after %d in %d/%d", opkt.duration,
|
|
||||||
audio_out_stream->time_base.num,
|
|
||||||
audio_out_stream->time_base.den);
|
|
||||||
// Scale the PTS of the outgoing packet to be the correct time base
|
|
||||||
#if 0
|
|
||||||
if ( ipkt->pts != AV_NOPTS_VALUE ) {
|
|
||||||
if ( !audio_first_pts ) {
|
|
||||||
opkt.pts = 0;
|
|
||||||
audio_first_pts = ipkt->pts;
|
|
||||||
Debug(1, "No audio_first_pts");
|
|
||||||
} else {
|
|
||||||
opkt.pts = av_rescale_q(
|
|
||||||
opkt.pts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
opkt.pts -= audio_first_pts;
|
|
||||||
Debug(2, "audio opkt.pts = %" PRId64 " from first_pts %" PRId64,
|
|
||||||
opkt.pts, audio_first_pts);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Debug(2, "opkt.pts = undef");
|
|
||||||
opkt.pts = AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( opkt.dts != AV_NOPTS_VALUE ) {
|
|
||||||
if ( !audio_first_dts ) {
|
|
||||||
opkt.dts = 0;
|
|
||||||
audio_first_dts = opkt.dts;
|
|
||||||
} else {
|
|
||||||
opkt.dts = av_rescale_q(
|
|
||||||
opkt.dts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
opkt.dts -= audio_first_dts;
|
|
||||||
Debug(2, "audio opkt.dts = %" PRId64 " from first_dts %" PRId64,
|
|
||||||
opkt.dts, audio_first_dts);
|
|
||||||
}
|
|
||||||
audio_last_dts = opkt.dts;
|
|
||||||
} else {
|
|
||||||
opkt.dts = AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
opkt.pts = av_rescale_q(
|
|
||||||
opkt.pts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
opkt.dts = av_rescale_q(
|
|
||||||
opkt.dts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
write_packet(&opkt, audio_out_stream);
|
|
||||||
zm_av_packet_unref(&opkt);
|
|
||||||
|
|
||||||
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
|
|
||||||
// While the encoder still has packets for us
|
|
||||||
while ( !avcodec_receive_packet(audio_out_ctx, &opkt) ) {
|
|
||||||
opkt.pts = av_rescale_q(
|
|
||||||
opkt.pts,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
opkt.dts = av_rescale_q(
|
|
||||||
opkt.dts,
|
|
||||||
audio_out_ctx->time_base,
|
audio_out_ctx->time_base,
|
||||||
audio_out_stream->time_base);
|
audio_out_stream->time_base);
|
||||||
|
|
||||||
dumpPacket(audio_out_stream, &opkt, "raw opkt");
|
|
||||||
Debug(1, "Duration before %d in %d/%d", opkt.duration,
|
|
||||||
audio_out_ctx->time_base.num,
|
|
||||||
audio_out_ctx->time_base.den);
|
|
||||||
|
|
||||||
opkt.duration = av_rescale_q(
|
|
||||||
opkt.duration,
|
|
||||||
audio_out_ctx->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
Debug(1, "Duration after %d in %d/%d", opkt.duration,
|
|
||||||
audio_out_stream->time_base.num,
|
|
||||||
audio_out_stream->time_base.den);
|
|
||||||
write_packet(&opkt, audio_out_stream);
|
write_packet(&opkt, audio_out_stream);
|
||||||
}
|
zm_av_packet_unref(&opkt);
|
||||||
#endif
|
|
||||||
zm_av_packet_unref(&opkt);
|
if ( zm_resample_get_delay(resample_ctx, out_frame->sample_rate) < out_frame->nb_samples)
|
||||||
|
break;
|
||||||
|
// This will send a null frame, emptying out the resample buffer
|
||||||
|
input_frame = NULL;
|
||||||
|
} // end while there is data in the resampler
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Debug(2,"copying");
|
Debug(2,"copying");
|
||||||
|
@ -1183,171 +980,50 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
|
||||||
opkt.size = ipkt->size;
|
opkt.size = ipkt->size;
|
||||||
opkt.flags = ipkt->flags;
|
opkt.flags = ipkt->flags;
|
||||||
|
|
||||||
if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) {
|
opkt.duration = ipkt->duration;
|
||||||
opkt.duration = av_rescale_q(
|
opkt.pts = ipkt->pts;
|
||||||
ipkt->duration,
|
opkt.dts = ipkt->dts;
|
||||||
audio_in_stream->time_base,
|
av_packet_rescale_ts(&opkt, audio_in_stream->time_base, audio_out_stream->time_base);
|
||||||
audio_out_stream->time_base);
|
|
||||||
}
|
|
||||||
// Scale the PTS of the outgoing packet to be the correct time base
|
|
||||||
if ( ipkt->pts != AV_NOPTS_VALUE ) {
|
|
||||||
if ( !audio_first_pts ) {
|
|
||||||
opkt.pts = 0;
|
|
||||||
audio_first_pts = ipkt->pts;
|
|
||||||
Debug(1, "No audio_first_pts");
|
|
||||||
} else {
|
|
||||||
opkt.pts = av_rescale_q(
|
|
||||||
ipkt->pts - audio_first_pts,
|
|
||||||
audio_in_stream->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")",
|
|
||||||
opkt.pts, ipkt->pts, audio_first_pts);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Debug(2, "opkt.pts = undef");
|
|
||||||
opkt.pts = AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ipkt->dts != AV_NOPTS_VALUE ) {
|
|
||||||
if ( !audio_first_dts ) {
|
|
||||||
opkt.dts = 0;
|
|
||||||
audio_first_dts = ipkt->dts;
|
|
||||||
} else {
|
|
||||||
opkt.dts = av_rescale_q(
|
|
||||||
ipkt->dts - audio_first_dts,
|
|
||||||
audio_in_stream->time_base,
|
|
||||||
audio_out_stream->time_base);
|
|
||||||
Debug(2, "opkt.dts = %" PRId64 " from ipkt.dts(%" PRId64 ") - first_dts(%" PRId64 ")",
|
|
||||||
opkt.dts, ipkt->dts, audio_first_dts);
|
|
||||||
}
|
|
||||||
audio_last_dts = ipkt->dts;
|
|
||||||
} else {
|
|
||||||
opkt.dts = AV_NOPTS_VALUE;
|
|
||||||
}
|
|
||||||
write_packet(&opkt, audio_out_stream);
|
write_packet(&opkt, audio_out_stream);
|
||||||
|
|
||||||
zm_av_packet_unref(&opkt);
|
zm_av_packet_unref(&opkt);
|
||||||
} // end if encoding or copying
|
} // end if encoding or copying
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
|
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
|
||||||
|
|
||||||
int VideoStore::write_packet(AVPacket *pkt, AVStream *stream) {
|
int VideoStore::write_packet(AVPacket *pkt, AVStream *stream) {
|
||||||
pkt->pos = -1;
|
pkt->pos = -1;
|
||||||
pkt->stream_index = stream->index;
|
pkt->stream_index = stream->index;
|
||||||
|
|
||||||
if ( pkt->dts < stream->cur_dts ) {
|
if ( pkt->dts < stream->cur_dts ) {
|
||||||
Warning("non increasing dts, fixing");
|
Debug(1, "non increasing dts, fixing. our dts %" PRId64 " stream cur_dts %" PRId64, pkt->dts, stream->cur_dts);
|
||||||
pkt->dts = stream->cur_dts;
|
pkt->dts = stream->cur_dts;
|
||||||
if ( pkt->dts > pkt->pts ) {
|
if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
|
||||||
Debug(1,
|
Debug(1,
|
||||||
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
|
"pkt.dts %" PRId64 " must be <= pkt.pts %" PRId64 "."
|
||||||
"Decompression must happen before presentation.",
|
"Decompression must happen before presentation.",
|
||||||
pkt->dts, pkt->pts);
|
pkt->dts, pkt->pts);
|
||||||
pkt->pts = pkt->dts;
|
pkt->pts = pkt->dts;
|
||||||
}
|
}
|
||||||
} else if ( pkt->dts > pkt->pts ) {
|
} else if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
|
||||||
Debug(1,
|
Debug(1,
|
||||||
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
|
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
|
||||||
"Decompression must happen before presentation.",
|
"Decompression must happen before presentation.",
|
||||||
pkt->dts, pkt->pts);
|
pkt->dts, pkt->pts);
|
||||||
pkt->dts = pkt->pts;
|
pkt->dts = pkt->pts;
|
||||||
|
} else {
|
||||||
|
Debug(1, "Acceptable pts and dts. cur_dts = %" PRId64, stream->cur_dts);
|
||||||
}
|
}
|
||||||
|
|
||||||
dumpPacket(stream, pkt, "finished pkt");
|
dumpPacket(stream, pkt, "finished pkt");
|
||||||
|
|
||||||
ret = av_interleaved_write_frame(oc, pkt);
|
int ret = av_interleaved_write_frame(oc, pkt);
|
||||||
if ( ret != 0 ) {
|
if ( ret != 0 ) {
|
||||||
Error("Error writing packet: %s",
|
Error("Error writing packet: %s",
|
||||||
av_make_error_string(ret).c_str());
|
av_make_error_string(ret).c_str());
|
||||||
} else {
|
} else {
|
||||||
Debug(2, "Success writing packet");
|
Debug(2, "Success writing packet");
|
||||||
}
|
}
|
||||||
} // end int VideoStore::write_packet(AVPacket *pkt, AVStream *stream)
|
return ret;
|
||||||
|
} // end int VideoStore::write_packet(AVPacket *pkt, AVStream *stream)
|
||||||
int VideoStore::resample_audio() {
|
|
||||||
// Resample the in_frame into the audioSampleBuffer until we process the whole
|
|
||||||
// decoded data. Note: pts does not survive resampling or converting
|
|
||||||
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
|
|
||||||
#if defined(HAVE_LIBSWRESAMPLE)
|
|
||||||
Debug(2, "Converting %d to %d samples using swresample",
|
|
||||||
in_frame->nb_samples, out_frame->nb_samples);
|
|
||||||
ret = swr_convert_frame(resample_ctx, out_frame, in_frame);
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
Error("Could not resample frame (error '%s')",
|
|
||||||
av_make_error_string(ret).c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
zm_dump_frame(out_frame, "Out frame after resample");
|
|
||||||
out_frame->pkt_duration = in_frame->pkt_duration; // resampling doesn't alter duration
|
|
||||||
|
|
||||||
ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples);
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
Error("Could not reallocate FIFO");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/** Store the new samples in the FIFO buffer. */
|
|
||||||
ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples);
|
|
||||||
if ( ret < out_frame->nb_samples ) {
|
|
||||||
Error("Could not write data to FIFO. %d written, expecting %d. Reason %s",
|
|
||||||
ret, out_frame->nb_samples, av_make_error_string(ret).c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset frame_size to output_frame_size
|
|
||||||
int frame_size = audio_out_ctx->frame_size;
|
|
||||||
|
|
||||||
// AAC requires 1024 samples per encode. Our input tends to be something else, so need to buffer them.
|
|
||||||
if ( frame_size > av_audio_fifo_size(fifo) ) {
|
|
||||||
Debug(1, "Not enough samples in fifo for AAC codec frame_size %d > fifo size %d",
|
|
||||||
frame_size, av_audio_fifo_size(fifo));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) < frame_size ) {
|
|
||||||
Error("Could not read data from FIFO");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
out_frame->nb_samples = frame_size;
|
|
||||||
zm_dump_frame(out_frame, "Out frame after fifo read");
|
|
||||||
// resampling changes the duration because the timebase is 1/samples
|
|
||||||
// I think we should be dealing in codec timebases not stream
|
|
||||||
if ( in_frame->pts != AV_NOPTS_VALUE ) {
|
|
||||||
out_frame->pts = av_rescale_q(
|
|
||||||
in_frame->pts,
|
|
||||||
audio_in_ctx->time_base,
|
|
||||||
audio_out_ctx->time_base);
|
|
||||||
}
|
|
||||||
zm_dump_frame(out_frame, "Out frame after timestamp conversion");
|
|
||||||
#else
|
|
||||||
#if defined(HAVE_LIBAVRESAMPLE)
|
|
||||||
ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data,
|
|
||||||
0, in_frame->nb_samples);
|
|
||||||
if ( ret < 0 ) {
|
|
||||||
Error("Could not resample frame (error '%s')",
|
|
||||||
av_make_error_string(ret).c_str());
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int frame_size = audio_out_ctx->frame_size;
|
|
||||||
|
|
||||||
int samples_available = avresample_available(resample_ctx);
|
|
||||||
if ( samples_available < frame_size ) {
|
|
||||||
Debug(1, "Not enough samples yet (%d)", samples_available);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read a frame audio data from the resample fifo
|
|
||||||
if ( avresample_read(resample_ctx, out_frame->data, frame_size) !=
|
|
||||||
frame_size) {
|
|
||||||
Warning("Error reading resampled audio.");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#else
|
|
||||||
Error("Have audio codec but no resampler?!");
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
return 1;
|
|
||||||
} // end int VideoStore::resample_audio
|
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#ifdef HAVE_LIBSWRESAMPLE
|
#ifdef HAVE_LIBSWRESAMPLE
|
||||||
#include "libswresample/swresample.h"
|
#include "libswresample/swresample.h"
|
||||||
#include "libavutil/audio_fifo.h"
|
|
||||||
#else
|
#else
|
||||||
#ifdef HAVE_LIBAVRESAMPLE
|
#ifdef HAVE_LIBAVRESAMPLE
|
||||||
#include "libavresample/avresample.h"
|
#include "libavresample/avresample.h"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
#include "libavutil/audio_fifo.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#if HAVE_LIBAVCODEC
|
#if HAVE_LIBAVCODEC
|
||||||
|
@ -38,9 +38,8 @@ private:
|
||||||
AVFrame *out_frame;
|
AVFrame *out_frame;
|
||||||
|
|
||||||
AVCodecContext *video_in_ctx;
|
AVCodecContext *video_in_ctx;
|
||||||
AVCodec *audio_in_codec;
|
const AVCodec *audio_in_codec;
|
||||||
AVCodecContext *audio_in_ctx;
|
AVCodecContext *audio_in_ctx;
|
||||||
int ret;
|
|
||||||
|
|
||||||
// The following are used when encoding the audio stream to AAC
|
// The following are used when encoding the audio stream to AAC
|
||||||
AVStream *audio_out_stream;
|
AVStream *audio_out_stream;
|
||||||
|
@ -48,12 +47,12 @@ private:
|
||||||
AVCodecContext *audio_out_ctx;
|
AVCodecContext *audio_out_ctx;
|
||||||
#ifdef HAVE_LIBSWRESAMPLE
|
#ifdef HAVE_LIBSWRESAMPLE
|
||||||
SwrContext *resample_ctx;
|
SwrContext *resample_ctx;
|
||||||
AVAudioFifo *fifo;
|
|
||||||
#else
|
#else
|
||||||
#ifdef HAVE_LIBAVRESAMPLE
|
#ifdef HAVE_LIBAVRESAMPLE
|
||||||
AVAudioResampleContext* resample_ctx;
|
AVAudioResampleContext* resample_ctx;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
AVAudioFifo *fifo;
|
||||||
uint8_t *converted_in_samples;
|
uint8_t *converted_in_samples;
|
||||||
|
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
@ -77,8 +76,6 @@ private:
|
||||||
int64_t audio_next_dts;
|
int64_t audio_next_dts;
|
||||||
|
|
||||||
bool setup_resampler();
|
bool setup_resampler();
|
||||||
int resample_audio();
|
|
||||||
|
|
||||||
int write_packet(AVPacket *pkt, AVStream *stream);
|
int write_packet(AVPacket *pkt, AVStream *stream);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -187,8 +187,8 @@ int main(int argc, char *argv[]) {
|
||||||
snprintf(log_id_string, sizeof(log_id_string), "zmc_m%d", monitor_id);
|
snprintf(log_id_string, sizeof(log_id_string), "zmc_m%d", monitor_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logInit(log_id_string);
|
||||||
zmLoadConfig();
|
zmLoadConfig();
|
||||||
|
|
||||||
logInit(log_id_string);
|
logInit(log_id_string);
|
||||||
|
|
||||||
hwcaps_detect();
|
hwcaps_detect();
|
||||||
|
|
|
@ -138,7 +138,7 @@ movecrud () {
|
||||||
|
|
||||||
# previsouly part of installzm.sh
|
# previsouly part of installzm.sh
|
||||||
# install the trusty deb and test zoneminder
|
# install the trusty deb and test zoneminder
|
||||||
installtrusty () {
|
install_deb () {
|
||||||
|
|
||||||
# Check we've got gdebi installed
|
# Check we've got gdebi installed
|
||||||
type gdebi 2>&1 > /dev/null
|
type gdebi 2>&1 > /dev/null
|
||||||
|
@ -347,8 +347,8 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
|
||||||
echo "Starting packpack..."
|
echo "Starting packpack..."
|
||||||
execpackpack
|
execpackpack
|
||||||
|
|
||||||
if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then
|
if [ "${TRAVIS}" == "true" ]; then
|
||||||
installtrusty
|
install_deb
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ elif [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86
|
||||||
|
|
||||||
# If we are running inside Travis then attempt to install the deb we just built
|
# If we are running inside Travis then attempt to install the deb we just built
|
||||||
if [ "${TRAVIS}" == "true" ]; then
|
if [ "${TRAVIS}" == "true" ]; then
|
||||||
installtrusty
|
install_deb
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
|
|
@ -142,16 +142,14 @@ class Event extends ZM_Object {
|
||||||
# Assumption: All events have a start time
|
# Assumption: All events have a start time
|
||||||
$start_date = date_parse($this->{'StartTime'});
|
$start_date = date_parse($this->{'StartTime'});
|
||||||
if ( ! $start_date ) {
|
if ( ! $start_date ) {
|
||||||
Error('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
|
throw new Exception('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
$start_date['year'] = $start_date['year'] % 100;
|
$start_date['year'] = $start_date['year'] % 100;
|
||||||
|
|
||||||
# So this is because ZM creates a link under the day pointing to the time that the event happened.
|
# So this is because ZM creates a link under the day pointing to the time that the event happened.
|
||||||
$link_path = $this->Link_Path();
|
$link_path = $this->Link_Path();
|
||||||
if ( ! $link_path ) {
|
if ( ! $link_path ) {
|
||||||
Error('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
|
throw new Exception('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$Storage = $this->Storage();
|
$Storage = $this->Storage();
|
||||||
|
@ -159,8 +157,7 @@ class Event extends ZM_Object {
|
||||||
|
|
||||||
if ( $id_files = glob($eventlink_path) ) {
|
if ( $id_files = glob($eventlink_path) ) {
|
||||||
if ( ! $eventPath = readlink($id_files[0]) ) {
|
if ( ! $eventPath = readlink($id_files[0]) ) {
|
||||||
Error("Unable to read link at $id_files[0]");
|
throw new Exception("Unable to read link at $id_files[0]");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
# I know we are using arrays here, but really there can only ever be 1 in the array
|
# I know we are using arrays here, but really there can only ever be 1 in the array
|
||||||
$eventPath = preg_replace('/\.'.$this->{'Id'}.'$/', $eventPath, $id_files[0]);
|
$eventPath = preg_replace('/\.'.$this->{'Id'}.'$/', $eventPath, $id_files[0]);
|
||||||
|
@ -179,8 +176,7 @@ class Event extends ZM_Object {
|
||||||
} else {
|
} else {
|
||||||
$eventPath = $this->Path();
|
$eventPath = $this->Path();
|
||||||
if ( ! $eventPath ) {
|
if ( ! $eventPath ) {
|
||||||
Error('No event Path in Event delete. Not deleting');
|
throw new Exception('No event Path in Event delete. Not deleting');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
deletePath($eventPath);
|
deletePath($eventPath);
|
||||||
if ( $this->SecondaryStorageId() ) {
|
if ( $this->SecondaryStorageId() ) {
|
||||||
|
@ -199,6 +195,9 @@ class Event extends ZM_Object {
|
||||||
$dbConn->commit();
|
$dbConn->commit();
|
||||||
} catch (PDOException $e) {
|
} catch (PDOException $e) {
|
||||||
$dbConn->rollback();
|
$dbConn->rollback();
|
||||||
|
} catch (Exception $e) {
|
||||||
|
Error($e->getMessage());
|
||||||
|
$dbConn->rollback();
|
||||||
}
|
}
|
||||||
} # end Event->delete
|
} # end Event->delete
|
||||||
|
|
||||||
|
@ -254,7 +253,7 @@ class Event extends ZM_Object {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$streamSrc .= '?'.http_build_query($args,'', $querySep);
|
$streamSrc .= '?'.http_build_query($args, '', $querySep);
|
||||||
|
|
||||||
return $streamSrc;
|
return $streamSrc;
|
||||||
} // end function getStreamSrc
|
} // end function getStreamSrc
|
||||||
|
|
|
@ -103,6 +103,11 @@ class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function Url( $port = null ) {
|
public function Url( $port = null ) {
|
||||||
|
if ( !$this->Id() ) {
|
||||||
|
# Trying to guess and make up values tends to break proxies. So just return nothing
|
||||||
|
# so that the resulting url will be something like "?view="
|
||||||
|
return '';
|
||||||
|
}
|
||||||
$url = $this->Protocol().'://';
|
$url = $this->Protocol().'://';
|
||||||
$url .= $this->Hostname();
|
$url .= $this->Hostname();
|
||||||
if ( $port ) {
|
if ( $port ) {
|
||||||
|
|
|
@ -44,11 +44,9 @@ if ( $action == 'archive' ) {
|
||||||
$dbConn->commit();
|
$dbConn->commit();
|
||||||
$refreshParent = true;
|
$refreshParent = true;
|
||||||
} else if ( $action == 'delete' ) {
|
} else if ( $action == 'delete' ) {
|
||||||
$dbConn->beginTransaction();
|
|
||||||
foreach ( getAffectedIds('eids') as $markEid ) {
|
foreach ( getAffectedIds('eids') as $markEid ) {
|
||||||
deleteEvent($markEid);
|
deleteEvent($markEid);
|
||||||
}
|
}
|
||||||
$dbConn->commit();
|
|
||||||
$refreshParent = true;
|
$refreshParent = true;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
|
@ -37,7 +37,6 @@ if ( $action == 'user' ) {
|
||||||
|
|
||||||
if ( $_REQUEST['newUser']['Password'] ) {
|
if ( $_REQUEST['newUser']['Password'] ) {
|
||||||
$changes['Password'] = 'Password = '.$pass_hash;
|
$changes['Password'] = 'Password = '.$pass_hash;
|
||||||
ZM\Info('PASS CMD='.$changes['Password']);
|
|
||||||
} else {
|
} else {
|
||||||
unset($changes['Password']);
|
unset($changes['Password']);
|
||||||
}
|
}
|
||||||
|
@ -47,7 +46,7 @@ if ( $action == 'user' ) {
|
||||||
dbQuery('UPDATE Users SET '.implode(', ', $changes).' WHERE Id = ?', array($_REQUEST['uid']));
|
dbQuery('UPDATE Users SET '.implode(', ', $changes).' WHERE Id = ?', array($_REQUEST['uid']));
|
||||||
# If we are updating the logged in user, then update our session user data.
|
# If we are updating the logged in user, then update our session user data.
|
||||||
if ( $user and ( $dbUser['Username'] == $user['Username'] ) )
|
if ( $user and ( $dbUser['Username'] == $user['Username'] ) )
|
||||||
userLogin($dbUser['Username'], $dbUser['Password']);
|
generateAuthHash(ZM_AUTH_HASH_IPS);
|
||||||
} else {
|
} else {
|
||||||
dbQuery('INSERT INTO Users SET '.implode(', ', $changes));
|
dbQuery('INSERT INTO Users SET '.implode(', ', $changes));
|
||||||
}
|
}
|
||||||
|
@ -71,13 +70,13 @@ if ( $action == 'user' ) {
|
||||||
|
|
||||||
if ( !empty($_REQUEST['newUser']['Password']) ) {
|
if ( !empty($_REQUEST['newUser']['Password']) ) {
|
||||||
$changes['Password'] = 'Password = '.$pass_hash;
|
$changes['Password'] = 'Password = '.$pass_hash;
|
||||||
}
|
} else {
|
||||||
|
|
||||||
else
|
|
||||||
unset($changes['Password']);
|
unset($changes['Password']);
|
||||||
|
}
|
||||||
if ( count($changes) ) {
|
if ( count($changes) ) {
|
||||||
dbQuery('UPDATE Users SET '.implode(', ', $changes).' WHERE Id=?', array($uid));
|
dbQuery('UPDATE Users SET '.implode(', ', $changes).' WHERE Id=?', array($uid));
|
||||||
$refreshParent = true;
|
$refreshParent = true;
|
||||||
|
generateAuthHash(ZM_AUTH_HASH_IPS);
|
||||||
}
|
}
|
||||||
$view = 'none';
|
$view = 'none';
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ function dbConnect() {
|
||||||
|
|
||||||
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
|
||||||
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||||
} catch(PDOException $ex ) {
|
} catch(PDOException $ex) {
|
||||||
echo 'Unable to connect to ZM db.' . $ex->getMessage();
|
echo 'Unable to connect to ZM db.' . $ex->getMessage();
|
||||||
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
|
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
|
||||||
$dbConn = null;
|
$dbConn = null;
|
||||||
|
|
|
@ -120,33 +120,6 @@ function CORSHeaders() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getStreamSrc( $args, $querySep='&' ) {
|
|
||||||
$streamSrc = ZM_BASE_URL.ZM_PATH_ZMS;
|
|
||||||
|
|
||||||
if ( ZM_OPT_USE_AUTH ) {
|
|
||||||
if ( ZM_AUTH_RELAY == 'hashed' ) {
|
|
||||||
$args[] = 'auth='.generateAuthHash( ZM_AUTH_HASH_IPS );
|
|
||||||
} elseif ( ZM_AUTH_RELAY == 'plain' ) {
|
|
||||||
$args[] = 'user='.$_SESSION['username'];
|
|
||||||
$args[] = 'pass='.$_SESSION['password'];
|
|
||||||
} elseif ( ZM_AUTH_RELAY == 'none' ) {
|
|
||||||
$args[] = 'user='.$_SESSION['username'];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ( !in_array( 'mode=single', $args ) && !empty($GLOBALS['connkey']) ) {
|
|
||||||
$args[] = 'connkey='.$GLOBALS['connkey'];
|
|
||||||
}
|
|
||||||
if ( ZM_RAND_STREAM ) {
|
|
||||||
$args[] = 'rand='.time();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( count($args) ) {
|
|
||||||
$streamSrc .= '?'.join( $querySep, $args );
|
|
||||||
}
|
|
||||||
|
|
||||||
return( $streamSrc );
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMimeType( $file ) {
|
function getMimeType( $file ) {
|
||||||
if ( function_exists('mime_content_type') ) {
|
if ( function_exists('mime_content_type') ) {
|
||||||
return( mime_content_type( $file ) );
|
return( mime_content_type( $file ) );
|
||||||
|
@ -156,7 +129,7 @@ function getMimeType( $file ) {
|
||||||
finfo_close($finfo);
|
finfo_close($finfo);
|
||||||
return( $mimeType );
|
return( $mimeType );
|
||||||
}
|
}
|
||||||
return( trim( exec( 'file -bi '.escapeshellarg( $file ).' 2>/dev/null' ) ) );
|
return trim(exec('file -bi '.escapeshellarg($file).' 2>/dev/null'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function outputVideoStream( $id, $src, $width, $height, $format, $title='' ) {
|
function outputVideoStream( $id, $src, $width, $height, $format, $title='' ) {
|
||||||
|
@ -169,8 +142,8 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
|
||||||
$height = validInt($height);
|
$height = validInt($height);
|
||||||
$title = validHtmlStr($title);
|
$title = validHtmlStr($title);
|
||||||
|
|
||||||
if ( file_exists( $src ) ) {
|
if ( file_exists($src) ) {
|
||||||
$mimeType = getMimeType( $src );
|
$mimeType = getMimeType($src);
|
||||||
} else {
|
} else {
|
||||||
switch( $format ) {
|
switch( $format ) {
|
||||||
case 'asf' :
|
case 'asf' :
|
||||||
|
@ -205,7 +178,6 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
|
||||||
case 'video/x-ms-asf' :
|
case 'video/x-ms-asf' :
|
||||||
case 'video/x-msvideo' :
|
case 'video/x-msvideo' :
|
||||||
case 'video/mp4' :
|
case 'video/mp4' :
|
||||||
{
|
|
||||||
if ( isWindows() ) {
|
if ( isWindows() ) {
|
||||||
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'
|
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'
|
||||||
classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
|
classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
|
||||||
|
@ -226,9 +198,7 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
|
||||||
</embed>
|
</embed>
|
||||||
</object>';
|
</object>';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
case 'video/quicktime' :
|
case 'video/quicktime' :
|
||||||
{
|
|
||||||
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
|
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
|
||||||
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
|
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
|
||||||
codebase="'.ZM_BASE_PROTOCOL.'://www.apple.com/qtactivex/qtplugin.cab"
|
codebase="'.ZM_BASE_PROTOCOL.'://www.apple.com/qtactivex/qtplugin.cab"
|
||||||
|
@ -244,9 +214,7 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
|
||||||
controller="true">
|
controller="true">
|
||||||
</embed>
|
</embed>
|
||||||
</object>';
|
</object>';
|
||||||
}
|
|
||||||
case 'application/x-shockwave-flash' :
|
case 'application/x-shockwave-flash' :
|
||||||
{
|
|
||||||
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
|
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
|
||||||
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
|
||||||
codebase="'.ZM_BASE_PROTOCOL.'://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
|
codebase="'.ZM_BASE_PROTOCOL.'://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0"
|
||||||
|
@ -264,7 +232,6 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
|
||||||
bgcolor="#ffffff">
|
bgcolor="#ffffff">
|
||||||
</embed>
|
</embed>
|
||||||
</object>';
|
</object>';
|
||||||
}
|
|
||||||
} # end switch
|
} # end switch
|
||||||
} # end if use object tags
|
} # end if use object tags
|
||||||
return '<embed'. ( isset($mimeType)?(' type="'.$mimeType.'"'):'' ). '
|
return '<embed'. ( isset($mimeType)?(' type="'.$mimeType.'"'):'' ). '
|
||||||
|
@ -295,25 +262,25 @@ function getImageStreamHTML( $id, $src, $width, $height, $title='' ) {
|
||||||
function outputControlStream( $src, $width, $height, $monitor, $scale, $target ) {
|
function outputControlStream( $src, $width, $height, $monitor, $scale, $target ) {
|
||||||
?>
|
?>
|
||||||
<form name="ctrlForm" method="post" action="?" target="<?php echo $target ?>">
|
<form name="ctrlForm" method="post" action="?" target="<?php echo $target ?>">
|
||||||
<input type="hidden" name="view" value="blank">
|
<input type="hidden" name="view" value="blank"/>
|
||||||
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>">
|
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>"/>
|
||||||
<input type="hidden" name="action" value="control">
|
<input type="hidden" name="action" value="control"/>
|
||||||
<?php
|
<?php
|
||||||
if ( $monitor['CanMoveMap'] ) {
|
if ( $monitor['CanMoveMap'] ) {
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="control" value="moveMap">
|
<input type="hidden" name="control" value="moveMap"/>
|
||||||
<?php
|
<?php
|
||||||
} elseif ( $monitor['CanMoveRel'] ) {
|
} else if ( $monitor['CanMoveRel'] ) {
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="control" value="movePseudoMap">
|
<input type="hidden" name="control" value="movePseudoMap"/>
|
||||||
<?php
|
<?php
|
||||||
} elseif ( $monitor['CanMoveCon'] ) {
|
} else if ( $monitor['CanMoveCon'] ) {
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="control" value="moveConMap">
|
<input type="hidden" name="control" value="moveConMap"/>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="scale" value="<?php echo $scale ?>">
|
<input type="hidden" name="scale" value="<?php echo $scale ?>"/>
|
||||||
<input type="image" src="<?php echo $src ?>" width="<?php echo $width ?>" height="<?php echo $height ?>">
|
<input type="image" src="<?php echo $src ?>" width="<?php echo $width ?>" height="<?php echo $height ?>">
|
||||||
</form>
|
</form>
|
||||||
<?php
|
<?php
|
||||||
|
@ -365,26 +332,26 @@ function getWebSiteUrl( $id, $src, $width, $height, $title='' ) {
|
||||||
function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) {
|
function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) {
|
||||||
?>
|
?>
|
||||||
<form name="ctrlForm" method="post" action="?" target="<?php echo $target ?>">
|
<form name="ctrlForm" method="post" action="?" target="<?php echo $target ?>">
|
||||||
<input type="hidden" name="view" value="blank">
|
<input type="hidden" name="view" value="blank"/>
|
||||||
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>">
|
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>"/>
|
||||||
<input type="hidden" name="action" value="control">
|
<input type="hidden" name="action" value="control"/>
|
||||||
<?php
|
<?php
|
||||||
if ( $monitor['CanMoveMap'] ) {
|
if ( $monitor['CanMoveMap'] ) {
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="control" value="moveMap">
|
<input type="hidden" name="control" value="moveMap"/>
|
||||||
<?php
|
<?php
|
||||||
} elseif ( $monitor['CanMoveRel'] ) {
|
} else if ( $monitor['CanMoveRel'] ) {
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="control" value="movePseudoMap">
|
<input type="hidden" name="control" value="movePseudoMap"/>
|
||||||
<?php
|
<?php
|
||||||
} elseif ( $monitor['CanMoveCon'] ) {
|
} else if ( $monitor['CanMoveCon'] ) {
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="control" value="moveConMap">
|
<input type="hidden" name="control" value="moveConMap"/>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<input type="hidden" name="scale" value="<?php echo $scale ?>">
|
<input type="hidden" name="scale" value="<?php echo $scale ?>"/>
|
||||||
<input type="image" src="<?php echo $src ?>" width="<?php echo $width ?>" height="<?php echo $height ?>">
|
<input type="image" src="<?php echo $src ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"/>
|
||||||
</form>
|
</form>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
@ -405,12 +372,12 @@ function getZmuCommand( $args ) {
|
||||||
|
|
||||||
$zmuCommand .= $args;
|
$zmuCommand .= $args;
|
||||||
|
|
||||||
return( $zmuCommand );
|
return $zmuCommand;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getEventDefaultVideoPath( $event ) {
|
function getEventDefaultVideoPath($event) {
|
||||||
$Event = new ZM\Event( $event );
|
$Event = new ZM\Event($event);
|
||||||
return $Event->getStreamSrc( array( 'mode'=>'mpeg', 'format'=>'h264' ) );
|
return $Event->getStreamSrc(array('mode'=>'mpeg', 'format'=>'h264'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function deletePath( $path ) {
|
function deletePath( $path ) {
|
||||||
|
|
|
@ -28,7 +28,6 @@ function zm_session_start() {
|
||||||
session_destroy();
|
session_destroy();
|
||||||
session_start();
|
session_start();
|
||||||
} else if ( !empty($_SESSION['generated_at']) ) {
|
} else if ( !empty($_SESSION['generated_at']) ) {
|
||||||
ZM\Logger::Debug("Have generated_at: " . $_SESSION['generated_at']);
|
|
||||||
if ( $_SESSION['generated_at']<($now-(ZM_COOKIE_LIFETIME/2)) ) {
|
if ( $_SESSION['generated_at']<($now-(ZM_COOKIE_LIFETIME/2)) ) {
|
||||||
ZM\Logger::Debug("Regenerating session because generated_at " . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
|
ZM\Logger::Debug("Regenerating session because generated_at " . $_SESSION['generated_at'] . ' < ' . $now . '-'.ZM_COOKIE_LIFETIME.'/2 = '.($now-ZM_COOKIE_LIFETIME/2));
|
||||||
zm_session_regenerate_id();
|
zm_session_regenerate_id();
|
||||||
|
|
|
@ -87,27 +87,38 @@ if ( isset($_GET['skin']) ) {
|
||||||
$skin = 'classic';
|
$skin = 'classic';
|
||||||
}
|
}
|
||||||
|
|
||||||
$skins = array_map('basename', glob('skins/*', GLOB_ONLYDIR));
|
if ( ! is_dir("skins/$skin") ) {
|
||||||
|
$skins = array_map('basename', glob('skins/*', GLOB_ONLYDIR));
|
||||||
|
|
||||||
if ( ! in_array($skin, $skins) ) {
|
if ( !in_array($skin, $skins) ) {
|
||||||
ZM\Error("Invalid skin '$skin' setting to " . $skins[0]);
|
ZM\Error("Invalid skin '$skin' setting to ".$skins[0]);
|
||||||
$skin = $skins[0];
|
$skin = $skins[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( isset($_GET['css']) ) {
|
if ( isset($_GET['css']) ) {
|
||||||
$css = $_GET['css'];
|
$css = $_GET['css'];
|
||||||
} elseif ( isset($_COOKIE['zmCSS']) ) {
|
} else if ( isset($_COOKIE['zmCSS']) ) {
|
||||||
$css = $_COOKIE['zmCSS'];
|
$css = $_COOKIE['zmCSS'];
|
||||||
} elseif ( defined('ZM_CSS_DEFAULT') ) {
|
} else if ( defined('ZM_CSS_DEFAULT') ) {
|
||||||
$css = ZM_CSS_DEFAULT;
|
$css = ZM_CSS_DEFAULT;
|
||||||
} else {
|
} else {
|
||||||
$css = 'classic';
|
$css = 'classic';
|
||||||
}
|
}
|
||||||
|
|
||||||
$css_skins = array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR));
|
if ( !is_dir("skins/$skin/css/$css") ) {
|
||||||
if ( !in_array($css, $css_skins) ) {
|
$css_skins = array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR));
|
||||||
ZM\Error("Invalid skin css '$css' setting to " . $css_skins[0]);
|
if ( count($css_skins) ) {
|
||||||
$css = $css_skins[0];
|
if ( !in_array($css, $css_skins) ) {
|
||||||
|
ZM\Error("Invalid skin css '$css' setting to " . $css_skins[0]);
|
||||||
|
$css = $css_skins[0];
|
||||||
|
} else {
|
||||||
|
$css = '';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ZM\Error("No css options found at skins/$skin/css");
|
||||||
|
$css = '';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
define('ZM_BASE_PATH', dirname($_SERVER['REQUEST_URI']));
|
define('ZM_BASE_PATH', dirname($_SERVER['REQUEST_URI']));
|
||||||
|
@ -116,7 +127,7 @@ define('ZM_SKIN_NAME', $skin);
|
||||||
|
|
||||||
$skinBase = array(); // To allow for inheritance of skins
|
$skinBase = array(); // To allow for inheritance of skins
|
||||||
if ( !file_exists(ZM_SKIN_PATH) )
|
if ( !file_exists(ZM_SKIN_PATH) )
|
||||||
Fatal("Invalid skin '$skin'");
|
ZM\Fatal("Invalid skin '$skin'");
|
||||||
$skinBase[] = $skin;
|
$skinBase[] = $skin;
|
||||||
|
|
||||||
zm_session_start();
|
zm_session_start();
|
||||||
|
@ -125,7 +136,7 @@ if (
|
||||||
!isset($_SESSION['skin']) ||
|
!isset($_SESSION['skin']) ||
|
||||||
isset($_REQUEST['skin']) ||
|
isset($_REQUEST['skin']) ||
|
||||||
!isset($_COOKIE['zmSkin']) ||
|
!isset($_COOKIE['zmSkin']) ||
|
||||||
$_COOKIE['zmSkin'] != $skin
|
($_COOKIE['zmSkin'] != $skin)
|
||||||
) {
|
) {
|
||||||
$_SESSION['skin'] = $skin;
|
$_SESSION['skin'] = $skin;
|
||||||
setcookie('zmSkin', $skin, time()+3600*24*30*12*10);
|
setcookie('zmSkin', $skin, time()+3600*24*30*12*10);
|
||||||
|
@ -135,7 +146,7 @@ if (
|
||||||
!isset($_SESSION['css']) ||
|
!isset($_SESSION['css']) ||
|
||||||
isset($_REQUEST['css']) ||
|
isset($_REQUEST['css']) ||
|
||||||
!isset($_COOKIE['zmCSS']) ||
|
!isset($_COOKIE['zmCSS']) ||
|
||||||
$_COOKIE['zmCSS'] != $css
|
($_COOKIE['zmCSS'] != $css)
|
||||||
) {
|
) {
|
||||||
$_SESSION['css'] = $css;
|
$_SESSION['css'] = $css;
|
||||||
setcookie('zmCSS', $css, time()+3600*24*30*12*10);
|
setcookie('zmCSS', $css, time()+3600*24*30*12*10);
|
||||||
|
|
|
@ -1,76 +0,0 @@
|
||||||
<?php
|
|
||||||
//
|
|
||||||
// ZoneMinder web frame view file, $Date$, $Revision$
|
|
||||||
// Copyright (C) 2001-2008 Philip Coombes
|
|
||||||
//
|
|
||||||
// This program is free software; you can redistribute it and/or
|
|
||||||
// modify it under the terms of the GNU General Public License
|
|
||||||
// as published by the Free Software Foundation; either version 2
|
|
||||||
// of the License, or (at your option) any later version.
|
|
||||||
//
|
|
||||||
// This program is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with this program; if not, write to the Free Software
|
|
||||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
//
|
|
||||||
|
|
||||||
if ( !canView( 'Events' ) )
|
|
||||||
{
|
|
||||||
$view = "error";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$eid = validInt($_REQUEST['eid']);
|
|
||||||
if ( !empty($_REQUEST['fid']) )
|
|
||||||
$fid = validInt($_REQUEST['fid']);
|
|
||||||
|
|
||||||
$sql = 'SELECT E.*,M.Name AS MonitorName,M.DefaultScale,M.VideoWriter,M.Orientation FROM Events AS E INNER JOIN Monitors AS M ON E.MonitorId = M.Id WHERE E.Id = ?';
|
|
||||||
$event = dbFetchOne( $sql, NULL, array($eid) );
|
|
||||||
|
|
||||||
if ( !empty($fid) ) {
|
|
||||||
$sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?';
|
|
||||||
if ( !($frame = dbFetchOne( $sql, NULL, array($eid, $fid) )) )
|
|
||||||
$frame = array( 'FrameId'=>$fid, 'Type'=>'Normal', 'Score'=>0 );
|
|
||||||
} else {
|
|
||||||
$frame = dbFetchOne( 'SELECT * FROM Frames WHERE EventId = ? AND Score = ?', NULL, array( $eid, $event['MaxScore'] ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
$maxFid = $event['Frames'];
|
|
||||||
|
|
||||||
$firstFid = 1;
|
|
||||||
$prevFid = $frame['FrameId']-1;
|
|
||||||
$nextFid = $frame['FrameId']+1;
|
|
||||||
$lastFid = $maxFid;
|
|
||||||
|
|
||||||
$alarmFrame = $frame['Type']=='Alarm';
|
|
||||||
|
|
||||||
if ( isset( $_REQUEST['scale'] ) )
|
|
||||||
$scale = validInt($_REQUEST['scale']);
|
|
||||||
else
|
|
||||||
$scale = max( reScale( SCALE_BASE, $event['DefaultScale'], ZM_WEB_DEFAULT_SCALE ), SCALE_BASE );
|
|
||||||
|
|
||||||
$Transpose = '';
|
|
||||||
if ( $event['VideoWriter'] == "2" ) { // PASSTHROUGH
|
|
||||||
$Rotation = $event['Orientation'];
|
|
||||||
// rotate right
|
|
||||||
if ( in_array($event['Orientation'],array("90")))
|
|
||||||
$Transpose = 'transpose=1,';
|
|
||||||
// rotate 180 // upside down cam
|
|
||||||
if ( in_array($event['Orientation'],array("180")))
|
|
||||||
$Transpose = 'transpose=2,transpose=2,';
|
|
||||||
// rotate left
|
|
||||||
if ( in_array($event['Orientation'],array("270")))
|
|
||||||
$Transpose = 'transpose=2,';
|
|
||||||
}
|
|
||||||
$focusWindow = true;
|
|
||||||
$Scale = 100/$scale;
|
|
||||||
$fid = $fid - 1;
|
|
||||||
#$command = 'ffmpeg -v 0 -i '.getEventDefaultVideoPath($event).' -vf "select=gte(selected_n\,'.$fid.'),setpts=PTS-STARTPTS" '.$Transpose.',scale=iw/'.$Scale.':-1" -frames:v 1 -f mjpeg -';
|
|
||||||
$command = 'ffmpeg -v 0 -i '.getEventDefaultVideoPath($event).' -vf "select=gte(n\\,'.$fid.'),setpts=PTS-STARTPTS,'.$Transpose.'scale=iw/'.$Scale.':-1" -f image2 -';
|
|
||||||
header('Content-Type: image/jpeg');
|
|
||||||
system($command);
|
|
||||||
?>
|
|
|
@ -215,7 +215,6 @@ function selectLayout(element) {
|
||||||
|
|
||||||
if ( layout_id = parseInt(layout) ) {
|
if ( layout_id = parseInt(layout) ) {
|
||||||
layout = layouts[layout];
|
layout = layouts[layout];
|
||||||
console.log(layout);
|
|
||||||
|
|
||||||
for ( var i = 0, length = monitors.length; i < length; i++ ) {
|
for ( var i = 0, length = monitors.length; i < length; i++ ) {
|
||||||
monitor = monitors[i];
|
monitor = monitors[i];
|
||||||
|
@ -396,6 +395,16 @@ function edit_layout(button) {
|
||||||
|
|
||||||
function save_layout(button) {
|
function save_layout(button) {
|
||||||
var form = button.form;
|
var form = button.form;
|
||||||
|
var name = form.elements['Name'].value;
|
||||||
|
|
||||||
|
if ( !name )
|
||||||
|
name = form.elements['zmMontageLayout'].options[form.elements['zmMontageLayout'].selectedIndex].text;
|
||||||
|
|
||||||
|
if ( name=='Freeform' || name=='2 Wide' || name=='3 Wide' || name=='4 Wide' || name=='5 Wide' ) {
|
||||||
|
alert('You cannot edit the built in layouts. Please give the layout a new name.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// In fixed positioning, order doesn't matter. In floating positioning, it does.
|
// In fixed positioning, order doesn't matter. In floating positioning, it does.
|
||||||
var Positions = {};
|
var Positions = {};
|
||||||
for ( var i = 0, length = monitors.length; i < length; i++ ) {
|
for ( var i = 0, length = monitors.length; i < length; i++ ) {
|
||||||
|
|
|
@ -22,14 +22,14 @@ function gotoStep2( element ) {
|
||||||
form.submit();
|
form.submit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function configureButtons( element ) {
|
function configureButtons(element) {
|
||||||
var form = element.form;
|
var form = element.form;
|
||||||
if (form.elements.namedItem("nextBtn")) {
|
if (form.elements.namedItem('nextBtn')) {
|
||||||
form.nextBtn.disabled = (form.probe.selectedIndex==0) ||
|
form.nextBtn.disabled = (form.probe.selectedIndex==0) ||
|
||||||
(form.username == "") || (form.username == null) ||
|
(form.Username == '') || (form.Username == null) ||
|
||||||
(form.password == "") || (form.password == null);
|
(form.Password == '') || (form.Password == null);
|
||||||
}
|
}
|
||||||
if (form.elements.namedItem("saveBtn")) {
|
if (form.elements.namedItem('saveBtn')) {
|
||||||
form.saveBtn.disabled = (form.probe.selectedIndex==0);
|
form.saveBtn.disabled = (form.probe.selectedIndex==0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,11 +180,11 @@ if ( $showZones ) {
|
||||||
<?php echo htmlSelect('zmMontageLayout', $layoutsById, $layout_id, array('onchange'=>'selectLayout(this);')); ?>
|
<?php echo htmlSelect('zmMontageLayout', $layoutsById, $layout_id, array('onchange'=>'selectLayout(this);')); ?>
|
||||||
</span>
|
</span>
|
||||||
<input type="hidden" name="Positions"/>
|
<input type="hidden" name="Positions"/>
|
||||||
<input type="button" id="EditLayout" value="<?php echo translate('EditLayout') ?>" data-on-click-this="edit_layout"/>
|
<button type="button" id="EditLayout" data-on-click-this="edit_layout"><?php echo translate('EditLayout') ?></button>
|
||||||
<span id="SaveLayout" style="display:none;">
|
<span id="SaveLayout" style="display:none;">
|
||||||
<input type="text" name="Name" placeholder="Enter new name for layout if desired" />
|
<input type="text" name="Name" placeholder="Enter new name for layout if desired" />
|
||||||
<input type="button" value="<?php echo translate('Save') ?>" data-on-click-this="save_layout"/>
|
<button type="button" value="Save" data-on-click-this="save_layout"><?php echo translate('Save') ?></button>
|
||||||
<input type="button" value="Cancel" data-on-click-this="cancel_layout"/>
|
<button type="button" value="Cancel" data-on-click-this="cancel_layout"><?php echo translate('Cancel') ?></button>
|
||||||
</span>
|
</span>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -41,18 +41,18 @@ function execONVIF( $cmd ) {
|
||||||
Please the following command from a command line for more information:<br/><br/>$shell_command"
|
Please the following command from a command line for more information:<br/><br/>$shell_command"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
ZM\Logger::Debug( "Results from probe: " . implode( '<br/>', $output ) );
|
ZM\Logger::Debug('Results from probe: '.implode('<br/>', $output));
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
function probeCameras( $localIp ) {
|
function probeCameras($localIp) {
|
||||||
$cameras = array();
|
$cameras = array();
|
||||||
if ( $lines = @execONVIF( 'probe' ) ) {
|
if ( $lines = @execONVIF('probe') ) {
|
||||||
foreach ( $lines as $line ) {
|
foreach ( $lines as $line ) {
|
||||||
$line = rtrim( $line );
|
$line = rtrim($line);
|
||||||
if ( preg_match( '|^(.+),(.+),\s\((.*)\)$|', $line, $matches ) ) {
|
if ( preg_match('|^(.+),(.+),\s\((.*)\)$|', $line, $matches) ) {
|
||||||
$device_ep = $matches[1];
|
$device_ep = $matches[1];
|
||||||
$soapversion = $matches[2];
|
$soapversion = $matches[2];
|
||||||
$camera = array(
|
$camera = array(
|
||||||
|
@ -65,7 +65,7 @@ function probeCameras( $localIp ) {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
foreach ( preg_split('|,\s*|', $matches[3]) as $attr_val ) {
|
foreach ( preg_split('|,\s*|', $matches[3]) as $attr_val ) {
|
||||||
if ( preg_match( '|(.+)=\'(.*)\'|', $attr_val, $tokens ) ) {
|
if ( preg_match('|(.+)=\'(.*)\'|', $attr_val, $tokens) ) {
|
||||||
if ( $tokens[1] == 'hardware' ) {
|
if ( $tokens[1] == 'hardware' ) {
|
||||||
$camera['model'] = $tokens[2];
|
$camera['model'] = $tokens[2];
|
||||||
} elseif ( $tokens[1] == 'name' ) {
|
} elseif ( $tokens[1] == 'name' ) {
|
||||||
|
@ -84,7 +84,7 @@ function probeCameras( $localIp ) {
|
||||||
return $cameras;
|
return $cameras;
|
||||||
} // end function probeCameras
|
} // end function probeCameras
|
||||||
|
|
||||||
function probeProfiles( $device_ep, $soapversion, $username, $password ) {
|
function probeProfiles($device_ep, $soapversion, $username, $password) {
|
||||||
$profiles = array();
|
$profiles = array();
|
||||||
if ( $lines = @execONVIF("profiles $device_ep $soapversion $username $password") ) {
|
if ( $lines = @execONVIF("profiles $device_ep $soapversion $username $password") ) {
|
||||||
foreach ( $lines as $line ) {
|
foreach ( $lines as $line ) {
|
||||||
|
@ -94,7 +94,7 @@ function probeProfiles( $device_ep, $soapversion, $username, $password ) {
|
||||||
// add user@pass to URI
|
// add user@pass to URI
|
||||||
if ( preg_match('|^(\S+://)(.+)$|', $stream_uri, $tokens) ) {
|
if ( preg_match('|^(\S+://)(.+)$|', $stream_uri, $tokens) ) {
|
||||||
$stream_uri = $tokens[1].$username.':'.$password.'@'.$tokens[2];
|
$stream_uri = $tokens[1].$username.':'.$password.'@'.$tokens[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
$profile = array( # 'monitor' part of camera
|
$profile = array( # 'monitor' part of camera
|
||||||
'Type' => 'Ffmpeg',
|
'Type' => 'Ffmpeg',
|
||||||
|
@ -125,8 +125,8 @@ xhtmlHeaders(__FILE__, translate('MonitorProbe') );
|
||||||
if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
|
if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
|
||||||
|
|
||||||
$monitors = array();
|
$monitors = array();
|
||||||
foreach ( dbFetchAll("SELECT Id, Name, Host FROM Monitors WHERE Type = 'Remote' ORDER BY Host") as $monitor ) {
|
foreach ( dbFetchAll("SELECT Id, Name, Host FROM Monitors WHERE Type='Remote' ORDER BY Host") as $monitor ) {
|
||||||
if ( preg_match( '/^(.+)@(.+)$/', $monitor['Host'], $matches ) ) {
|
if ( preg_match('/^(.+)@(.+)$/', $monitor['Host'], $matches) ) {
|
||||||
//echo "1: ".$matches[2]." = ".gethostbyname($matches[2])."<br/>";
|
//echo "1: ".$matches[2]." = ".gethostbyname($matches[2])."<br/>";
|
||||||
$monitors[gethostbyname($matches[2])] = $monitor;
|
$monitors[gethostbyname($matches[2])] = $monitor;
|
||||||
} else {
|
} else {
|
||||||
|
@ -137,26 +137,12 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
|
||||||
|
|
||||||
$detcameras = probeCameras('');
|
$detcameras = probeCameras('');
|
||||||
foreach ( $detcameras as $camera ) {
|
foreach ( $detcameras as $camera ) {
|
||||||
if ( preg_match( '|([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|', $camera['monitor']['Host'], $matches ) ) {
|
if ( preg_match('|([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)|', $camera['monitor']['Host'], $matches) ) {
|
||||||
$ip = $matches[1];
|
$ip = $matches[1];
|
||||||
}
|
}
|
||||||
$host = $ip;
|
$host = $ip;
|
||||||
/*
|
|
||||||
if ( isset($monitors[$ip]) )
|
|
||||||
{
|
|
||||||
$monitor = $monitors[$ip];
|
|
||||||
$sourceString .= " (".$monitor['Name'].")";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$sourceString .= " - ".translate('Available');
|
|
||||||
}
|
|
||||||
$cameras[$sourceDesc] = $sourceString;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
// $sourceDesc = htmlspecialchars(serialize($camera['monitor']));
|
|
||||||
$sourceDesc = base64_encode(json_encode($camera['monitor']));
|
$sourceDesc = base64_encode(json_encode($camera['monitor']));
|
||||||
$sourceString = $camera['model'].' @ '.$host . ' using version ' . $camera['monitor']['SOAP'] ;
|
$sourceString = $camera['model'].' @ '.$host.' using version '.$camera['monitor']['SOAP'];
|
||||||
$cameras[$sourceDesc] = $sourceString;
|
$cameras[$sourceDesc] = $sourceString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,39 +165,38 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="probe"><?php echo translate('DetectedCameras') ?></label>
|
<label for="probe"><?php echo translate('DetectedCameras') ?></label>
|
||||||
<?php echo htmlSelect('probe', $cameras, null, array('onchange'=>'configureButtons(this)')); ?>
|
<?php echo htmlSelect('probe', $cameras, null, array('data-on-change-this'=>'configureButtons')); ?>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<?php echo translate('OnvifCredentialsIntro') ?>
|
<?php echo translate('OnvifCredentialsIntro') ?>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="username"><?php echo translate('Username') ?></label>
|
<label for="Username"><?php echo translate('Username') ?></label>
|
||||||
<input type="text" name="username" value="" onChange="configureButtons(this)"/>
|
<input type="text" name="Username" data-on-change-this="configureButtons"/>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="password"><?php echo translate('Password') ?></label>
|
<label for="Password"><?php echo translate('Password') ?></label>
|
||||||
<input type="password" name="password" value="" onChange="configureButtons(this)"/>
|
<input type="password" name="Password" data-on-change-this="configureButtons"/>
|
||||||
</p>
|
</p>
|
||||||
<div id="contentButtons">
|
<div id="contentButtons">
|
||||||
<input type="button" value="<?php echo translate('Cancel') ?>" data-on-click="closeWindow"/>
|
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
|
||||||
<input type="submit" name="nextBtn" value="<?php echo translate('Next') ?>" data-on-click-this="gotoStep2" disabled="disabled"/>
|
<button type="button" name="nextBtn" data-on-click-this="gotoStep2" disabled="disabled"><?php echo translate('Next') ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
//==== STEP 2 ============================================================
|
//==== STEP 2 ============================================================
|
||||||
} else if($_REQUEST['step'] == '2') {
|
} else if ( $_REQUEST['step'] == '2' ) {
|
||||||
if ( empty($_REQUEST['probe']) )
|
if ( empty($_REQUEST['probe']) )
|
||||||
ZM\Fatal('No probe passed in request. Please go back and try again.');
|
ZM\Fatal('No probe passed in request. Please go back and try again.');
|
||||||
#|| empty($_REQUEST['username']) ||
|
#|| empty($_REQUEST['username']) ||
|
||||||
#empty($_REQUEST['password']) )
|
#empty($_REQUEST['password']) )
|
||||||
|
|
||||||
$probe = json_decode(base64_decode($_REQUEST['probe']));
|
$probe = json_decode(base64_decode($_REQUEST['probe']));
|
||||||
ZM\Logger::Debug(print_r($probe,true));
|
ZM\Logger::Debug(print_r($probe, true));
|
||||||
foreach ( $probe as $name=>$value ) {
|
foreach ( $probe as $name=>$value ) {
|
||||||
if ( isset($value) ) {
|
if ( isset($value) ) {
|
||||||
$monitor[$name] = $value;
|
$monitor[$name] = $value;
|
||||||
|
@ -221,7 +206,7 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
|
||||||
|
|
||||||
//print $monitor['Host'].", ".$_REQUEST['username'].", ".$_REQUEST['password']."<br/>";
|
//print $monitor['Host'].", ".$_REQUEST['username'].", ".$_REQUEST['password']."<br/>";
|
||||||
|
|
||||||
$detprofiles = probeProfiles($monitor['Host'], $monitor['SOAP'], $_REQUEST['username'], $_REQUEST['password']);
|
$detprofiles = probeProfiles($monitor['Host'], $monitor['SOAP'], $_REQUEST['Username'], $_REQUEST['Password']);
|
||||||
foreach ( $detprofiles as $profile ) {
|
foreach ( $detprofiles as $profile ) {
|
||||||
$monitor = $camera['monitor'];
|
$monitor = $camera['monitor'];
|
||||||
|
|
||||||
|
@ -258,18 +243,18 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="probe"><?php echo translate('DetectedProfiles') ?></label>
|
<label for="probe"><?php echo translate('DetectedProfiles') ?></label>
|
||||||
<?php echo htmlSelect('probe', $profiles, null, array('onchange'=>'configureButtons(this)')); ?>
|
<?php echo htmlSelect('probe', $profiles, null, array('data-on-change-this'=>'configureButtons')); ?>
|
||||||
</p>
|
</p>
|
||||||
<div id="contentButtons">
|
<div id="contentButtons">
|
||||||
<input type="button" name="prevBtn" value="<?php echo translate('Prev') ?>" data-on-click-this="gotoStep1"/>
|
<button type="button" name="prevBtn" data-on-click-this="gotoStep1"><?php echo translate('Prev') ?></button>
|
||||||
<input type="button" value="<?php echo translate('Cancel') ?>" data-on-click="closeWindow"/>
|
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
|
||||||
<input type="submit" name="saveBtn" value="<?php echo translate('Save') ?>" data-on-click-this="submitCamera" disabled="disabled"/>
|
<button type="button" name="saveBtn" data-on-click-this="submitCamera" disabled="disabled"><?php echo translate('Save') ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
|
||||||
<?php
|
<?php
|
||||||
} // end if step 1 or 2
|
} // end if step 1 or 2
|
||||||
?>
|
?>
|
||||||
|
</html>
|
||||||
|
|
|
@ -53,31 +53,6 @@ $focusWindow = true;
|
||||||
|
|
||||||
xhtmlHeaders(__FILE__, translate('Options'));
|
xhtmlHeaders(__FILE__, translate('Options'));
|
||||||
|
|
||||||
# Have to do this stuff up here before including header.php because fof the cookie setting
|
|
||||||
$skin_options = array_map('basename', glob('skins/*',GLOB_ONLYDIR));
|
|
||||||
if ( $tab == 'skins' ) {
|
|
||||||
$current_skin = $_COOKIE['zmSkin'];
|
|
||||||
$reload = false;
|
|
||||||
if ( isset($_GET['skin-choice']) && ( $_GET['skin-choice'] != $current_skin ) ) {
|
|
||||||
setcookie('zmSkin',$_GET['skin-choice'], time()+3600*24*30*12*10 );
|
|
||||||
//header("Location: index.php?view=options&tab=skins&reset_parent=1");
|
|
||||||
$reload = true;
|
|
||||||
}
|
|
||||||
$current_css = $_COOKIE['zmCSS'];
|
|
||||||
if ( isset($_GET['css-choice']) and ( $_GET['css-choice'] != $current_css ) ) {
|
|
||||||
setcookie('zmCSS',$_GET['css-choice'], time()+3600*24*30*12*10 );
|
|
||||||
array_map('unlink', glob(ZM_PATH_WEB.'/cache/*')); //cleanup symlinks from cache_bust
|
|
||||||
//header("Location: index.php?view=options&tab=skins&reset_parent=1");
|
|
||||||
$reload = true;
|
|
||||||
}
|
|
||||||
if ( $reload )
|
|
||||||
echo "<script nonce=\"$cspNonce\">if (window.opener) {
|
|
||||||
window.opener.location.reload();
|
|
||||||
}
|
|
||||||
window.location.href=\"?view={$view}&tab={$tab}\";
|
|
||||||
</script>";
|
|
||||||
} # end if tab == skins
|
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<body>
|
<body>
|
||||||
<?php echo getNavBarHTML(); ?>
|
<?php echo getNavBarHTML(); ?>
|
||||||
|
@ -104,12 +79,14 @@ if ( $tab == 'skins' ) {
|
||||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||||
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
|
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="skin-choice" class="col-sm-3 control-label">SKIN</label>
|
<label for="skin" class="col-sm-3 control-label">SKIN</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<select name="skin-choice" class="form-control chosen">
|
<select name="skin" class="form-control chosen">
|
||||||
<?php
|
<?php
|
||||||
|
# Have to do this stuff up here before including header.php because fof the cookie setting
|
||||||
|
$skin_options = array_map('basename', glob('skins/*',GLOB_ONLYDIR));
|
||||||
foreach ( $skin_options as $dir ) {
|
foreach ( $skin_options as $dir ) {
|
||||||
echo '<option value="'.$dir.'" '.($current_skin==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
|
echo '<option value="'.$dir.'" '.($skin==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
|
@ -117,12 +94,12 @@ foreach ( $skin_options as $dir ) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="css-choice" class="col-sm-3 control-label">CSS</label>
|
<label for="css" class="col-sm-3 control-label">CSS</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<select name="css-choice" class="form-control chosen">
|
<select name="css" class="form-control chosen">
|
||||||
<?php
|
<?php
|
||||||
foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDIR)) as $dir ) {
|
foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $dir ) {
|
||||||
echo '<option value="'.$dir.'" '.($current_css==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
|
echo '<option value="'.$dir.'" '.($css==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
</select>
|
</select>
|
||||||
|
@ -325,40 +302,37 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<form name="userForm" method="post" action="?">
|
<form name="userForm" method="post" action="?">
|
||||||
<button class="pull-left" type="submit" name="updateSelected" id="updateSelected"><?php echo translate("Update")?> </button><button class="btn-danger pull-right" type="submit" name="revokeAllTokens" id="revokeAllTokens"> <?php echo translate("RevokeAllTokens")?></button><br/>
|
<button class="pull-left" type="submit" name="updateSelected" id="updateSelected"><?php echo translate('Update')?></button>
|
||||||
|
<button class="btn-danger pull-right" type="submit" name="revokeAllTokens" id="revokeAllTokens"><?php echo translate('RevokeAllTokens')?></button>
|
||||||
|
<br/>
|
||||||
<?php
|
<?php
|
||||||
function revokeAllTokens()
|
function revokeAllTokens() {
|
||||||
{
|
|
||||||
$minTokenTime = time();
|
$minTokenTime = time();
|
||||||
dbQuery ('UPDATE Users SET TokenMinExpiry=?', array ($minTokenTime));
|
dbQuery('UPDATE `Users` SET `TokenMinExpiry`=?', array($minTokenTime));
|
||||||
echo "<span class='timedSuccessBox'>".translate('AllTokensRevoked')."</span>";
|
echo '<span class="timedSuccessBox">'.translate('AllTokensRevoked').'</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSelected()
|
function updateSelected() {
|
||||||
{
|
dbQuery('UPDATE `Users` SET `APIEnabled`=0');
|
||||||
dbQuery("UPDATE Users SET APIEnabled=0");
|
foreach ( $_REQUEST["tokenUids"] as $markUid ) {
|
||||||
foreach( $_REQUEST["tokenUids"] as $markUid ) {
|
|
||||||
$minTime = time();
|
$minTime = time();
|
||||||
dbQuery('UPDATE Users SET TokenMinExpiry=? WHERE Id=?', array($minTime, $markUid));
|
dbQuery('UPDATE `Users` SET `TokenMinExpiry`=? WHERE `Id`=?', array($minTime, $markUid));
|
||||||
}
|
}
|
||||||
foreach( $_REQUEST["apiUids"] as $markUid ) {
|
foreach ( $_REQUEST["apiUids"] as $markUid ) {
|
||||||
dbQuery('UPDATE Users SET APIEnabled=1 WHERE Id=?', array($markUid));
|
dbQuery('UPDATE `Users` SET `APIEnabled`=1 WHERE `Id`=?', array($markUid));
|
||||||
|
|
||||||
}
|
}
|
||||||
echo "<span class='timedSuccessBox'>".translate('Updated')."</span>";
|
echo '<span class="timedSuccessBox">'.translate('Updated').'</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(array_key_exists('revokeAllTokens',$_POST)){
|
if ( array_key_exists('revokeAllTokens',$_POST) ) {
|
||||||
revokeAllTokens();
|
revokeAllTokens();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(array_key_exists('updateSelected',$_POST)){
|
if ( array_key_exists('updateSelected',$_POST) ) {
|
||||||
updateSelected();
|
updateSelected();
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
|
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
<input type="hidden" name="view" value="<?php echo $view ?>"/>
|
||||||
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
|
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
|
||||||
|
@ -375,7 +349,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
$sql = 'SELECT * FROM Users ORDER BY Username';
|
$sql = 'SELECT * FROM Users ORDER BY Username';
|
||||||
foreach( dbFetchAll($sql) as $row ) {
|
foreach ( dbFetchAll($sql) as $row ) {
|
||||||
?>
|
?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="colUsername"><?php echo validHtmlStr($row['Username']) ?></td>
|
<td class="colUsername"><?php echo validHtmlStr($row['Username']) ?></td>
|
||||||
|
@ -398,7 +372,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
||||||
$configCat = array();
|
$configCat = array();
|
||||||
$configCats = array();
|
$configCats = array();
|
||||||
|
|
||||||
$result = $dbConn->query('SELECT * FROM Config ORDER BY Id ASC');
|
$result = $dbConn->query('SELECT * FROM `Config` ORDER BY `Id` ASC');
|
||||||
if ( !$result )
|
if ( !$result )
|
||||||
echo mysql_error();
|
echo mysql_error();
|
||||||
while( $row = dbFetchNext($result) ) {
|
while( $row = dbFetchNext($result) ) {
|
||||||
|
@ -411,9 +385,9 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $tab == 'system' ) {
|
if ( $tab == 'system' ) {
|
||||||
$configCats[$tab]['ZM_LANG_DEFAULT']['Hint'] = join( '|', getLanguages() );
|
$configCats[$tab]['ZM_LANG_DEFAULT']['Hint'] = join('|', getLanguages());
|
||||||
$configCats[$tab]['ZM_SKIN_DEFAULT']['Hint'] = join( '|', $skin_options );
|
$configCats[$tab]['ZM_SKIN_DEFAULT']['Hint'] = join('|', array_map('basename', glob('skins/*',GLOB_ONLYDIR)));
|
||||||
$configCats[$tab]['ZM_CSS_DEFAULT']['Hint'] = join( '|', array_map ( 'basename', glob('skins/'.ZM_SKIN_DEFAULT.'/css/*',GLOB_ONLYDIR) ) );
|
$configCats[$tab]['ZM_CSS_DEFAULT']['Hint'] = join('|', array_map ( 'basename', glob('skins/'.ZM_SKIN_DEFAULT.'/css/*',GLOB_ONLYDIR) ));
|
||||||
$configCats[$tab]['ZM_BANDWIDTH_DEFAULT']['Hint'] = $bandwidth_options;
|
$configCats[$tab]['ZM_BANDWIDTH_DEFAULT']['Hint'] = $bandwidth_options;
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -508,7 +482,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<div id="contentButtons">
|
<div id="contentButtons">
|
||||||
<button type="submit" value="Save"<?php echo $canEdit?'':' disabled="disabled"' ?>><?php echo translate('Save') ?></button>
|
<button type="submit" <?php echo $canEdit?'':' disabled="disabled"' ?>><?php echo translate('Save') ?></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<?php
|
<?php
|
||||||
|
|
|
@ -132,7 +132,7 @@ $chart = array(
|
||||||
$monitors = array();
|
$monitors = array();
|
||||||
$monitorsSql = 'SELECT * FROM Monitors ORDER BY Sequence ASC';
|
$monitorsSql = 'SELECT * FROM Monitors ORDER BY Sequence ASC';
|
||||||
//srand( 97981 );
|
//srand( 97981 );
|
||||||
foreach( dbFetchAll( $monitorsSql ) as $row ) {
|
foreach( dbFetchAll($monitorsSql) as $row ) {
|
||||||
//if ( empty($row['WebColour']) )
|
//if ( empty($row['WebColour']) )
|
||||||
//{
|
//{
|
||||||
//$row['WebColour'] = sprintf( "#%02x%02x%02x", rand( 0, 255 ), rand( 0, 255), rand( 0, 255 ) );
|
//$row['WebColour'] = sprintf( "#%02x%02x%02x", rand( 0, 255 ), rand( 0, 255), rand( 0, 255 ) );
|
||||||
|
@ -312,9 +312,9 @@ $chart['data']['x']['density'] = $chart['data']['x']['range']/$chart['graph']['w
|
||||||
$monEventSlots = array();
|
$monEventSlots = array();
|
||||||
$monFrameSlots = array();
|
$monFrameSlots = array();
|
||||||
$monitorIds = array();
|
$monitorIds = array();
|
||||||
$events_result = dbQuery( $eventsSql );
|
$events_result = dbQuery($eventsSql);
|
||||||
if ( ! $events_result ) {
|
if ( !$events_result ) {
|
||||||
Fatal( "SQL-ERR");
|
Fatal("SQL-ERR");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue