Merge branch 'master' into update_monitor_saving

pull/2725/head
Isaac Connor 2019-09-18 11:40:09 -04:00
commit 458268d866
36 changed files with 1065 additions and 1281 deletions

View File

@ -37,8 +37,16 @@ env:
- SMPFLAGS=-j4 OS=fedora DIST=29 DOCKER_REPO=knnniggett/packpack
- SMPFLAGS=-j4 OS=ubuntu DIST=trusty
- 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=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
compiler:

View File

@ -7,6 +7,7 @@ Build-Depends: debhelper (>= 9), python-sphinx | python3-sphinx, apache2-dev, dh
,cmake
,libx264-dev, libmp4v2-dev
,libavcodec-dev, libavformat-dev (>= 3:0.svn20090204), libswscale-dev (>= 3:0.svn20090204), libavutil-dev, libavdevice-dev
,libavresample-dev
,libbz2-dev
,libgcrypt-dev
,libcurl4-gnutls-dev

View File

@ -134,7 +134,7 @@ sub Path {
if ( ! $$event{Path} ) {
my $Storage = $event->Storage();
if ( defined $Storage->Id() ) {
if ( (!$$event{StorageId}) or defined $Storage->Id() ) {
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath());
} else {
Error("Storage area for $$event{StorageId} no longer exists in db.");

View File

@ -282,6 +282,7 @@ MAIN: while( $loop ) {
}
#Event path is hour/minute/sec
my $event_path = readlink($event_link);
$event_path = '' if ! defined($event_path);
Debug("Checking link $event_link points to: $event_path");
if ( !($event_path and -e $event_path) ) {

View File

@ -29,6 +29,10 @@
#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() {
// Process name, value pairs from the main config file first
@ -40,22 +44,22 @@ void zmLoadConfig() {
DIR* configSubFolder = opendir(ZM_CONFIG_SUBDIR);
if ( configSubFolder ) { // subfolder exists and is readable
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;
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 ) {
Error( "Can't glob '%s': %s", glob_pattern, strerror(errno) );
Error("Can't glob '%s': %s", glob_pattern, strerror(errno));
} else {
Debug( 1, "Can't glob '%s': %d", glob_pattern, glob_status );
Debug(1, "Can't glob '%s': %d", glob_pattern, glob_status);
}
} else {
for ( unsigned int i = 0; i < pglob.gl_pathc; i++ ) {
process_configfile(pglob.gl_pathv[i]);
}
}
globfree( &pglob );
globfree(&pglob);
closedir(configSubFolder);
}
@ -64,59 +68,60 @@ void zmLoadConfig() {
config.Assign();
// Populate the server config entries
if ( ! staticConfig.SERVER_ID ) {
if ( ! staticConfig.SERVER_NAME.empty() ) {
if ( !staticConfig.SERVER_ID ) {
if ( !staticConfig.SERVER_NAME.empty() ) {
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() );
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());
zmDbRow dbrow;
if ( dbrow.fetch( sql.c_str() ) ) {
if ( dbrow.fetch(sql.c_str()) ) {
staticConfig.SERVER_ID = atoi(dbrow[0]);
} 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
} else if ( staticConfig.SERVER_NAME.empty() ) {
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 );
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);
zmDbRow dbrow;
if ( dbrow.fetch( sql.c_str() ) ) {
if ( dbrow.fetch(sql.c_str()) ) {
staticConfig.SERVER_NAME = std::string(dbrow[0]);
} 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 ) {
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 {
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.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.video_file_format, sizeof(staticConfig.video_file_format), "%%s/%%s");
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.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");
}
void process_configfile( char* configFile) {
void process_configfile(char* configFile) {
FILE *cfg;
char line[512];
if ( (cfg = fopen( configFile, "r")) == NULL ) {
Fatal( "Can't open %s: %s", configFile, strerror(errno) );
if ( (cfg = fopen(configFile, "r")) == NULL ) {
Fatal("Can't open %s: %s", configFile, strerror(errno));
return;
}
while ( fgets( line, sizeof(line), cfg ) != NULL ) {
while ( fgets(line, sizeof(line), cfg) != NULL ) {
char *line_ptr = line;
// 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';
// Remove leading white space
int white_len = strspn( line_ptr, " \t" );
int white_len = strspn(line_ptr, " \t");
line_ptr += white_len;
// 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
temp_ptr = strchr( line_ptr, '=' );
temp_ptr = strchr(line_ptr, '=');
if ( !temp_ptr ) {
Warning( "Invalid data in %s: '%s'", configFile, line );
Warning("Invalid data in %s: '%s'", configFile, line);
continue;
}
@ -148,49 +153,49 @@ void process_configfile( char* configFile) {
} while ( *temp_ptr == ' ' || *temp_ptr == '\t' );
// Remove leading white space and leading quotes from the value part
white_len = strspn( val_ptr, " \t" );
white_len += strspn( val_ptr, "\'\"" );
white_len = strspn(val_ptr, " \t");
white_len += strspn(val_ptr, "\'\"");
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
else if ( strcasecmp( name_ptr, "ZM_SERVER_ID" ) == 0 )
else if ( strcasecmp(name_ptr, "ZM_SERVER_ID") == 0 )
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);
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);
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);
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);
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);
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);
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);
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);
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);
else {
// 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 );
}
} // end foreach line of the config
fclose( cfg );
fclose(cfg);
}
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];
strcpy( name, p_name );
strcpy(name, p_name);
value = new char[strlen(p_value)+1];
strcpy( value, p_value );
strcpy(value, p_value);
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 );
@ -217,28 +222,28 @@ ConfigItem::ConfigItem( const char *p_name, const char *p_value, const char *con
accessed = false;
}
ConfigItem::ConfigItem( const ConfigItem &item ) {
ConfigItem::ConfigItem(const ConfigItem &item) {
name = new char[strlen(item.name)+1];
strcpy( name, item.name );
strcpy(name, item.name);
value = new char[strlen(item.value)+1];
strcpy( value, item.value );
strcpy(value, item.value);
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 );
accessed = false;
}
void ConfigItem::Copy( const ConfigItem &item ) {
void ConfigItem::Copy(const ConfigItem &item) {
if (name) delete name;
name = new char[strlen(item.name)+1];
strcpy( name, item.name );
strcpy(name, item.name);
if (value) delete value;
value = new char[strlen(item.value)+1];
strcpy( value, item.value );
strcpy(value, item.value);
if (type) delete type;
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 );
accessed = false;
@ -253,16 +258,16 @@ ConfigItem::~ConfigItem() {
void ConfigItem::ConvertValue() const {
if ( !strcmp( type, "boolean" ) ) {
cfg_type = CFG_BOOLEAN;
cfg_value.boolean_value = (bool)strtol( value, 0, 0 );
} else if ( !strcmp( type, "integer" ) ) {
cfg_value.boolean_value = (bool)strtol(value, 0, 0);
} else if ( !strcmp(type, "integer") ) {
cfg_type = CFG_INTEGER;
cfg_value.integer_value = strtol( value, 0, 10 );
} else if ( !strcmp( type, "hexadecimal" ) ) {
cfg_value.integer_value = strtol(value, 0, 10);
} else if ( !strcmp(type, "hexadecimal") ) {
cfg_type = CFG_INTEGER;
cfg_value.integer_value = strtol( value, 0, 16 );
} else if ( !strcmp( type, "decimal" ) ) {
cfg_value.integer_value = strtol(value, 0, 16);
} else if ( !strcmp(type, "decimal") ) {
cfg_type = CFG_DECIMAL;
cfg_value.decimal_value = strtod( value, 0 );
cfg_value.decimal_value = strtod(value, 0);
} else {
cfg_type = CFG_STRING;
cfg_value.string_value = value;
@ -275,11 +280,11 @@ bool ConfigItem::BooleanValue() const {
ConvertValue();
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 );
exit( -1 );
Error("Attempt to fetch boolean value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
exit(-1);
}
return( cfg_value.boolean_value );
return cfg_value.boolean_value;
}
int ConfigItem::IntegerValue() const {
@ -287,11 +292,11 @@ int ConfigItem::IntegerValue() const {
ConvertValue();
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 );
exit( -1 );
Error("Attempt to fetch integer value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
exit(-1);
}
return( cfg_value.integer_value );
return cfg_value.integer_value;
}
double ConfigItem::DecimalValue() const {
@ -299,11 +304,11 @@ double ConfigItem::DecimalValue() const {
ConvertValue();
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 );
exit( -1 );
Error("Attempt to fetch decimal value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
exit(-1);
}
return( cfg_value.decimal_value );
return cfg_value.decimal_value;
}
const char *ConfigItem::StringValue() const {
@ -311,11 +316,11 @@ const char *ConfigItem::StringValue() const {
ConvertValue();
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 );
exit( -1 );
Error("Attempt to fetch string value for %s, actual type is %s. Try running 'zmupdate.pl -f' to reload config.", name, type);
exit(-1);
}
return( cfg_value.string_value );
return cfg_value.string_value;
}
Config::Config() {
@ -337,54 +342,54 @@ Config::~Config() {
void Config::Load() {
static char sql[ZM_SQL_SML_BUFSIZ];
strncpy( sql, "select Name, Value, Type from Config order by Id", sizeof(sql) );
if ( mysql_query( &dbconn, sql ) ) {
Error( "Can't run query: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );
strncpy(sql, "SELECT `Name`, `Value`, `Type` FROM `Config` ORDER BY `Id`", sizeof(sql) );
if ( mysql_query(&dbconn, sql) ) {
Error("Can't run query: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
MYSQL_RES *result = mysql_store_result( &dbconn );
MYSQL_RES *result = mysql_store_result(&dbconn);
if ( !result ) {
Error( "Can't use query result: %s", mysql_error( &dbconn ) );
exit( mysql_errno( &dbconn ) );
Error("Can't use query result: %s", mysql_error(&dbconn));
exit(mysql_errno(&dbconn));
}
n_items = mysql_num_rows( result );
n_items = mysql_num_rows(result);
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 );
exit( -1 );
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);
}
items = new ConfigItem *[n_items];
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) {
items[i] = new ConfigItem( dbrow[0], dbrow[1], dbrow[2] );
for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) {
items[i] = new ConfigItem(dbrow[0], dbrow[1], dbrow[2]);
}
mysql_free_result( result );
mysql_free_result(result);
}
void Config::Assign() {
ZM_CFG_ASSIGN_LIST
}
const ConfigItem &Config::Item( int id ) {
const ConfigItem &Config::Item(int id) {
if ( !n_items ) {
Load();
Assign();
}
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 );
exit( -1 );
Error("Attempt to access invalid config, id = %d. Try running 'zmupdate.pl -f' to reload config.", id);
exit(-1);
}
ConfigItem *item = items[id];
if ( !item ) {
Error( "Can't find config item %d", id );
exit( -1 );
Error("Can't find config item %d", id);
exit(-1);
}
return( *item );
return *item;
}
Config config;

View File

@ -32,7 +32,7 @@ bool zmDbConnect() {
// 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
if ( zmDbConnected ) {
Warning("Calling zmDbConnect when already connected");
//Warning("Calling zmDbConnect when already connected");
return true;
}

View File

@ -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
bool rc;
Debug(3, "Writing image to %s", event_file);
if ( !config.timestamp_on_capture ) {
// 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];
snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames);
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");
}
} else {

View File

@ -289,9 +289,10 @@ static void zm_log_fps(double d, const char *postfix) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
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_id,
avcodec_get_name(par->codec_id),
par->codec_tag,
par->width,
par->height,
@ -303,10 +304,11 @@ void zm_dump_codecpar ( const AVCodecParameters *par ) {
#endif
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",
codec->codec_type,
codec->codec_id,
avcodec_get_name(codec->codec_id),
codec->width,
codec->height,
codec->time_base.num,
@ -327,7 +329,6 @@ void zm_dump_codec(const AVCodecContext *codec) {
/* "user interface" functions */
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 );
int flags = (is_output ? ic->oformat->flags : ic->iformat->flags);
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->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);
Debug(1, "codec: %s", buf);
#endif
if ( st->sample_aspect_ratio.num && // default
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;
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
bool is_video_stream( AVStream * stream ) {
@ -477,7 +513,31 @@ bool is_audio_context( AVCodecContext *codec_context ) {
#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;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 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 ) {
Error("Unable to send packet %s, continuing",
av_make_error_string(ret).c_str());
if ( AVERROR(EAGAIN) == ret ) {
// 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;
}
# else
@ -505,29 +571,31 @@ int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
}
} // end while !frameComplete
#endif
return 0;
} // end int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
return 1;
} // 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;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
if ( (ret = avcodec_send_frame(ctx, frame)) < 0 ) {
Error("Could not send frame (error '%s')",
av_make_error_string(ret).c_str());
zm_av_packet_unref(&packet);
return 0;
return ret;
}
if ( (ret = avcodec_receive_packet(ctx, &packet)) < 0 ) {
if ( AVERROR(EAGAIN) == ret ) {
// The codec may need more samples than it has, perfectly valid
Debug(2, "Codec not ready to give us a packet");
return 0;
} else {
Error("Could not recieve packet (error %d = '%s')", ret,
av_make_error_string(ret).c_str());
}
zm_av_packet_unref(&packet);
return 0;
return ret;
}
#else
int data_present;
@ -536,7 +604,7 @@ int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
Error("Could not encode frame (error '%s')",
av_make_error_string(ret).c_str());
zm_av_packet_unref(&packet);
return 0;
return ret;
}
if ( !data_present ) {
Debug(2, "Not ready to out a frame yet.");
@ -545,7 +613,7 @@ int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
}
#endif
return 1;
} // wend zm_send_frame
} // end int zm_send_frame_receive_packet
void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) {
char b[10240];
@ -600,3 +668,117 @@ void dumpPacket(AVPacket *pkt, const char *text) {
pkt->duration);
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;
}

View File

@ -24,6 +24,14 @@
extern "C" {
#ifdef HAVE_LIBSWRESAMPLE
#include "libswresample/swresample.h"
#else
#ifdef HAVE_LIBAVRESAMPLE
#include "libavresample/avresample.h"
#endif
#endif
// AVUTIL
#if HAVE_LIBAVUTIL_AVUTIL_H
#include "libavutil/avassert.h"
@ -31,6 +39,7 @@ extern "C" {
#include <libavutil/base64.h>
#include <libavutil/mathematics.h>
#include <libavutil/avstring.h>
#include "libavutil/audio_fifo.h"
/* LIBAVUTIL_VERSION_CHECK checks for the right version of libav and FFmpeg
* 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)
void zm_dump_codecpar(const AVCodecParameters *par);
#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" \
" duration %" PRId64 \
" layout %d pts %" PRId64, \
@ -329,8 +321,6 @@ void zm_dump_codecpar(const AVCodecParameters *par);
frame->pts \
);
#endif
#define zm_dump_video_frame(frame,text) Debug(1, "%s: format %d %s %dx%d linesize:%dx%d pts: %" PRId64, \
text, \
frame->format, \
@ -347,6 +337,9 @@ void zm_dump_codecpar(const AVCodecParameters *par);
#else
unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src );
#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
#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 )
@ -371,9 +364,42 @@ bool is_audio_stream(AVStream *);
bool is_video_context(AVCodec *);
bool is_audio_context(AVCodec *);
int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
int zm_send_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet);
int zm_receive_packet(AVCodecContext *context, 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(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

View File

@ -19,6 +19,7 @@
#include "zm.h"
#include "zm_signal.h"
#include "zm_utils.h"
#if HAVE_LIBAVFORMAT
@ -35,11 +36,6 @@ extern "C" {
#define AV_ERROR_MAX_STRING_SIZE 64
#endif
#ifdef SOLARIS
#include <sys/errno.h> // for ESRCH
#include <signal.h>
#include <pthread.h>
#endif
#include <string>
@ -260,8 +256,8 @@ int FfmpegCamera::Capture(Image &image) {
&&
(keyframe || have_video_keyframe)
) {
ret = zm_receive_frame(mVideoCodecContext, mRawFrame, packet);
if ( ret < 0 ) {
ret = zm_send_packet_receive_frame(mVideoCodecContext, mRawFrame, packet);
if ( ret <= 0 ) {
Error("Unable to get frame at frame %d: %s, continuing",
frameCount, av_make_error_string(ret).c_str());
zm_av_packet_unref(&packet);
@ -337,24 +333,27 @@ int FfmpegCamera::OpenFfmpeg() {
}
// Set transport method as specified by method field, rtpUni is default
const std::string method = Method();
if ( method == "rtpMulti" ) {
ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0);
} else if ( method == "rtpRtsp" ) {
ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0);
} else if ( method == "rtpRtspHttp" ) {
ret = av_dict_set(&opts, "rtsp_transport", "http", 0);
} else if ( method == "rtpUni" ) {
ret = av_dict_set(&opts, "rtsp_transport", "udp", 0);
} else {
Warning("Unknown method (%s)", method.c_str());
}
std::string protocol = mPath.substr(0, 4);
string_toupper(protocol);
if ( protocol == "RTSP" ) {
const std::string method = Method();
if ( method == "rtpMulti" ) {
ret = av_dict_set(&opts, "rtsp_transport", "udp_multicast", 0);
} else if ( method == "rtpRtsp" ) {
ret = av_dict_set(&opts, "rtsp_transport", "tcp", 0);
} else if ( method == "rtpRtspHttp" ) {
ret = av_dict_set(&opts, "rtsp_transport", "http", 0);
} 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.
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());
mFormatContext = avformat_alloc_context();
@ -650,6 +649,9 @@ int FfmpegCamera::OpenFfmpeg() {
) {
Warning("Monitor dimensions are %dx%d but camera is sending %dx%d",
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;
@ -952,8 +954,8 @@ int FfmpegCamera::CaptureAndRecord(
}
} // end if keyframe or have_video_keyframe
ret = zm_receive_frame(mVideoCodecContext, mRawFrame, packet);
if ( ret < 0 ) {
ret = zm_send_packet_receive_frame(mVideoCodecContext, mRawFrame, packet);
if ( ret <= 0 ) {
Warning("Unable to receive frame %d: %s. error count is %d",
frameCount, av_make_error_string(ret).c_str(), error_count);
error_count += 1;

View File

@ -137,8 +137,8 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) {
} else {
frame = zm_av_frame_alloc();
}
ret = zm_receive_frame(context, frame, packet);
if ( ret < 0 ) {
ret = zm_send_packet_receive_frame(context, frame, packet);
if ( ret <= 0 ) {
Error("Unable to decode frame at frame %d: %s, continuing",
streams[packet.stream_index].frame_count, av_make_error_string(ret).c_str());
zm_av_packet_unref(&packet);

View File

@ -1,31 +1,27 @@
//
// ZoneMinder File Camera Class Implementation, $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.
//
//
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <syslog.h>
#include <signal.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h>
@ -45,8 +41,20 @@ FileCamera::FileCamera(
int p_hue,
int p_colour,
bool p_capture,
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 )
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)
{
strncpy( path, p_path, sizeof(path)-1 );
if ( capture ) {
@ -62,8 +70,7 @@ FileCamera::~FileCamera() {
void FileCamera::Initialise() {
if ( !path[0] ) {
Error( "No path specified for file image" );
exit( -1 );
Fatal("No path specified for file image");
}
}
@ -72,21 +79,25 @@ void FileCamera::Terminate() {
int FileCamera::PreCapture() {
struct stat statbuf;
if ( stat( path, &statbuf ) < 0 ) {
Error( "Can't stat %s: %s", path, strerror(errno) );
return( -1 );
if ( stat(path, &statbuf) < 0 ) {
Error("Can't stat %s: %s", path, strerror(errno));
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 ) {
usleep( 100000 );
usleep(100000);
}
return( 0 );
return 0;
}
int FileCamera::Capture( Image &image ) {
return( image.ReadJpeg( path, colours, subpixelorder )?1:-1 );
int FileCamera::Capture(Image &image) {
return image.ReadJpeg(path, colours, subpixelorder)?1:-1;
}
int FileCamera::PostCapture() {
return( 0 );
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,7 @@ static void subtractTime( struct timeval * const tp1, struct timeval * const tp2
}
#endif
void Logger::usrHandler( int sig ) {
void Logger::usrHandler(int sig) {
Logger *logger = fetch();
if ( sig == SIGUSR1 )
logger->level(logger->level()+1);
@ -71,9 +71,9 @@ Logger::Logger() :
mFileLevel(NOLOG),
mSyslogLevel(NOLOG),
mEffectiveLevel(NOLOG),
//mLogPath( staticConfig.PATH_LOGS.c_str() ),
//mLogFile( mLogPath+"/"+mId+".log" ),
mDbConnected(false),
mLogPath(staticConfig.PATH_LOGS.c_str()),
//mLogFile( mLogPath+"/"+mId+".log" ),
mLogFileFP(NULL),
mHasTerminal(false),
mFlush(false) {
@ -106,9 +106,11 @@ Logger::Logger() :
smInitialised = true;
}
if ( fileno(stderr) && isatty(fileno(stderr)) )
if ( fileno(stderr) && isatty(fileno(stderr)) ) {
mHasTerminal = true;
}
mTerminalLevel = WARNING;
}
} // End Logger::Logger
Logger::~Logger() {
terminate();
@ -138,7 +140,8 @@ void Logger::initialise(const std::string &id, const Options &options) {
} else if ( options.mLogFile.size() ) {
tempLogFile = options.mLogFile;
} 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;
}
tempLogFile = mLogPath+"/"+mId+".log";
@ -240,7 +243,7 @@ void Logger::initialise(const std::string &id, const Options &options) {
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[mEffectiveLevel].c_str(),
smCodes[mTerminalLevel].c_str(),
@ -297,7 +300,7 @@ const std::string &Logger::id(const std::string &id) {
size_t pos;
// 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, "");
}
// Replace non-alphanum with underscore
@ -341,7 +344,7 @@ Logger::Level Logger::level(Logger::Level level) {
return mLevel;
}
Logger::Level Logger::terminalLevel( Logger::Level terminalLevel ) {
Logger::Level Logger::terminalLevel(Logger::Level terminalLevel) {
if ( terminalLevel > NOOPT ) {
if ( !mHasTerminal )
terminalLevel = NOLOG;
@ -352,34 +355,35 @@ Logger::Level Logger::terminalLevel( Logger::Level terminalLevel ) {
return mTerminalLevel;
}
Logger::Level Logger::databaseLevel( Logger::Level databaseLevel ) {
Logger::Level Logger::databaseLevel(Logger::Level databaseLevel) {
if ( databaseLevel > NOOPT ) {
databaseLevel = limit(databaseLevel);
if ( mDatabaseLevel != databaseLevel ) {
if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG ) {
zmDbConnect();
} // end if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG )
if ( !zmDbConnect() ) {
databaseLevel = NOLOG;
}
} // end if ( databaseLevel > NOLOG && mDatabaseLevel <= NOLOG )
mDatabaseLevel = databaseLevel;
} // end if ( mDatabaseLevel != databaseLevel )
} // end if ( databaseLevel > NOOPT )
} // end if ( mDatabaseLevel != databaseLevel )
} // end if ( databaseLevel > NOOPT )
return mDatabaseLevel;
}
Logger::Level Logger::fileLevel( Logger::Level fileLevel ) {
Logger::Level Logger::fileLevel(Logger::Level fileLevel) {
if ( fileLevel > NOOPT ) {
fileLevel = limit(fileLevel);
// Always close, because we may have changed file names
if ( mFileLevel > NOLOG )
closeFile();
mFileLevel = fileLevel;
if ( mFileLevel > NOLOG )
openFile();
// Don't try to open it here because it will create the log file even if we never write to it.
}
return mFileLevel;
}
Logger::Level Logger::syslogLevel( Logger::Level syslogLevel ) {
Logger::Level Logger::syslogLevel(Logger::Level syslogLevel) {
if ( syslogLevel > NOOPT ) {
syslogLevel = limit(syslogLevel);
if ( mSyslogLevel != syslogLevel ) {
@ -393,7 +397,7 @@ Logger::Level Logger::syslogLevel( Logger::Level syslogLevel ) {
return mSyslogLevel;
}
void Logger::logFile( const std::string &logFile ) {
void Logger::logFile(const std::string &logFile) {
bool addLogPid = false;
std::string tempLogFile = logFile;
if ( tempLogFile[tempLogFile.length()-1] == '+' ) {
@ -401,16 +405,16 @@ void Logger::logFile( const std::string &logFile ) {
addLogPid = true;
}
if ( addLogPid )
mLogFile = stringtf( "%s.%05d", tempLogFile.c_str(), getpid() );
mLogFile = stringtf("%s.%05d", tempLogFile.c_str(), getpid());
else
mLogFile = tempLogFile;
}
void Logger::openFile() {
if ( mLogFile.size() ) {
if ( (mLogFileFP = fopen(mLogFile.c_str() ,"a")) == (FILE *)NULL ) {
if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == (FILE *)NULL ) {
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 {
puts("Called Logger::openFile() without a filename");
@ -419,29 +423,33 @@ void Logger::openFile() {
void Logger::closeFile() {
if ( mLogFileFP ) {
fflush( mLogFileFP );
if ( fclose( mLogFileFP ) < 0 ) {
Fatal( "fclose(), error = %s",strerror(errno) );
fflush(mLogFileFP);
if ( fclose(mLogFileFP) < 0 ) {
mLogFileFP = (FILE *)NULL;
Error("fclose(), error = %s", strerror(errno));
}
mLogFileFP = (FILE *)NULL;
}
}
void Logger::closeDatabase() {
}
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) closelog();
}
void Logger::logPrint( bool hex, const char * const filepath, const int line, const int level, const char *fstring, ... ) {
if ( level > mEffectiveLevel )
void Logger::logPrint(bool hex, const char * const filepath, const int line, const int level, const char *fstring, ...) {
if ( level > mEffectiveLevel ) {
return;
}
log_mutex.lock();
char timeString[64];
char logString[8192];
@ -479,24 +487,24 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
thr_self(&lwpid);
tid = lwpid;
if (tid < 0 ) // Thread/Process id
if ( tid < 0 ) // Thread/Process id
#else
#ifdef HAVE_SYSCALL
#ifdef __FreeBSD_kernel__
#ifdef HAVE_SYSCALL
#ifdef __FreeBSD_kernel__
if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id
# else
# else
// SOLARIS doesn't have SYS_gettid; don't assume
#ifdef SYS_gettid
if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id
#endif // SYS_gettid
#ifdef SYS_gettid
if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id
#endif // SYS_gettid
#endif
#endif // HAVE_SYSCALL
#endif
#endif // HAVE_SYSCALL
#endif
tid = getpid(); // Process id
tid = getpid(); // Process id
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,
mId.c_str(),
tid,
@ -520,32 +528,39 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
}
va_end(argPtr);
char *syslogEnd = logPtr;
strncpy( logPtr, "]\n", sizeof(logString)-(logPtr-logString) );
strncpy(logPtr, "]\n", sizeof(logString)-(logPtr-logString));
if ( level <= mTerminalLevel ) {
puts( logString );
fflush( stdout );
puts(logString);
fflush(stdout);
}
if ( level <= mFileLevel ) {
if ( !mLogFileFP )
openFile();
if ( mLogFileFP ) {
fputs( logString, mLogFileFP );
fputs(logString, mLogFileFP);
if ( mFlush )
fflush( mLogFileFP );
fflush(mLogFileFP);
} 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';
if ( level <= mDatabaseLevel ) {
char sql[ZM_SQL_MED_BUFSIZ];
char escapedString[(strlen(syslogStart)*2)+1];
if ( ! db_mutex.trylock() ) {
mysql_real_escape_string( &dbconn, escapedString, syslogStart, strlen(syslogStart) );
if ( !db_mutex.trylock() ) {
mysql_real_escape_string(&dbconn, escapedString, syslogStart, strlen(syslogStart));
snprintf(sql, sizeof(sql),
"INSERT INTO Logs "
"( TimeKey, Component, ServerId, Pid, Level, Code, Message, File, Line )"
"INSERT INTO `Logs` "
"( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )"
" VALUES "
"( %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
@ -567,7 +582,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
if ( level <= mSyslogLevel ) {
int priority = smSyslogPriorities[level];
//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);
@ -580,15 +595,16 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co
exit(-1);
}
log_mutex.unlock();
}
} // end logPrint
void logInit(const char *name, const Logger::Options &options) {
if ( !Logger::smInstance )
Logger::smInstance = new Logger();
Logger::Options tempOptions = options;
tempOptions.mLogPath = staticConfig.PATH_LOGS;
Logger::smInstance->initialise(name, tempOptions);
if ( Logger::smInstance ) {
delete Logger::smInstance;
Logger::smInstance = NULL;
}
Logger::smInstance = new Logger();
Logger::smInstance->initialise(name, options);
}
void logTerm() {

View File

@ -36,12 +36,12 @@ class Logger {
public:
enum {
NOOPT=-6,
NOLOG,
PANIC,
FATAL,
ERROR,
WARNING,
INFO,
NOLOG, // -5
PANIC, // -4
FATAL, // -3
ERROR, // -2
WARNING, // -1
INFO, // 0
DEBUG1,
DEBUG2,
DEBUG3,
@ -68,14 +68,20 @@ public:
std::string mLogPath;
std::string mLogFile;
public:
Options( Level terminalLevel=NOOPT, Level databaseLevel=NOOPT, Level fileLevel=NOOPT, Level syslogLevel=NOOPT, const std::string &logPath=".", const std::string &logFile="" ) :
mTerminalLevel( terminalLevel ),
mDatabaseLevel( databaseLevel ),
mFileLevel( fileLevel ),
mSyslogLevel( syslogLevel ),
mLogPath( logPath ),
mLogFile( logFile )
Options(
Level terminalLevel=NOOPT,
Level databaseLevel=NOOPT,
Level fileLevel=NOOPT,
Level syslogLevel=NOOPT,
const std::string &logPath=".",
const std::string &logFile=""
) :
mTerminalLevel(terminalLevel),
mDatabaseLevel(databaseLevel),
mFileLevel(fileLevel),
mSyslogLevel(syslogLevel),
mLogPath(logPath),
mLogFile(logFile)
{
}
};
@ -89,21 +95,21 @@ private:
static StringMap smCodes;
static IntMap smSyslogPriorities;
private:
bool mInitialised;
std::string mId;
std::string mIdRoot;
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 mDatabaseLevel; // Maximum level output via database
Level mFileLevel; // Maximum level output via file
Level mSyslogLevel; // Maximum level output via syslog
Level mEffectiveLevel; // Level optimised to take account of maxima
Level mDatabaseLevel; // Maximum level output via database
Level mFileLevel; // Maximum level output via file
Level mSyslogLevel; // Maximum level output via syslog
Level mEffectiveLevel; // Level optimised to take account of maxima
bool mDbConnected;
std::string mLogPath;
std::string mLogFile;
FILE *mLogFileFP;
@ -111,31 +117,10 @@ private:
bool mHasTerminal;
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:
Logger();
~Logger();
public:
void initialise(const std::string &id, const Options &options);
void terminate();
private:
int limit(int level) {
if ( level > DEBUG9 )
return DEBUG9;
@ -150,14 +135,29 @@ private:
char *getTargettedEnv(const std::string &name);
void loadEnv();
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;
}
void initialise(const std::string &id, const Options &options);
void terminate();
const std::string &id(const std::string &id);
const std::string &id() const {
return mId;
}
const std::string &id(const std::string &id);
Level level() const {
return mLevel;
}

View File

@ -22,6 +22,7 @@
#include "zm_utils.h"
#include <string.h>
#include <algorithm>
#include <stdio.h>
#include <stdarg.h>
#include <fcntl.h> /* Definition of AT_* constants */
@ -416,6 +417,10 @@ Warning("ZM Compiled without LIBCURL. UriDecoding not implemented.");
#endif
}
void string_toupper( std::string& str) {
std::transform(str.begin(), str.end(), str.begin(), ::toupper);
}
void touch(const char *pathname) {
int fd = open(pathname,
O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK,

View File

@ -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 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 pairsplit(const char* string, const char delim, std::string& name, std::string& value);

View File

@ -20,13 +20,14 @@
#define __STDC_FORMAT_MACROS 1
#include <cinttypes>
#include <stdlib.h>
#include <string.h>
#include "zm.h"
#include "zm_videostore.h"
#include <stdlib.h>
#include <string.h>
#include <cinttypes>
extern "C" {
#include "libavutil/time.h"
}
@ -60,7 +61,7 @@ VideoStore::VideoStore(
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 ) {
Warning(
"Could not create video storage stream %s as no out ctx"
@ -91,7 +92,7 @@ VideoStore::VideoStore(
oc->metadata = pmetadata;
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);
if ( !video_out_codec ) {
@ -136,7 +137,7 @@ VideoStore::VideoStore(
video_out_ctx->time_base = video_in_ctx->time_base;
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");
video_out_ctx->time_base = AV_TIME_BASE_Q;
video_out_ctx->time_base = AV_TIME_BASE_Q;
}
zm_dump_codec(video_out_ctx);
@ -162,7 +163,7 @@ VideoStore::VideoStore(
if ( !video_out_ctx->codec_tag ) {
Debug(2, "No codec_tag");
if (
if (
!oc->oformat->codec_tag
||
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;
if ( video_in_stream->avg_frame_rate.num ) {
Debug(3,"Copying avg_frame_rate (%d/%d)",
video_in_stream->avg_frame_rate.num,
video_in_stream->avg_frame_rate.den
video_in_stream->avg_frame_rate.num,
video_in_stream->avg_frame_rate.den
);
video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate;
}
if ( video_in_stream->r_frame_rate.num ) {
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_out_stream->r_frame_rate.num,
video_out_stream->r_frame_rate.den
video_out_stream->r_frame_rate.num,
video_out_stream->r_frame_rate.den
);
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,
"Time bases: VIDEO in stream (%d/%d) in codec: (%d/%d) out "
"stream: (%d/%d) out codec (%d/%d)",
@ -221,6 +210,10 @@ VideoStore::VideoStore(
}
#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;
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
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 ) {
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
Monitor::Orientation orientation = monitor->getOrientation();
@ -262,9 +273,7 @@ VideoStore::VideoStore(
out_frame = NULL;
#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE)
resample_ctx = NULL;
#if defined(HAVE_LIBSWRESAMPLE)
fifo = NULL;
#endif
#endif
video_first_pts = 0;
video_first_dts = 0;
@ -273,6 +282,7 @@ VideoStore::VideoStore(
audio_first_pts = 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_dts = 0;
@ -301,7 +311,7 @@ VideoStore::VideoStore(
audio_out_stream = NULL;
return;
}
#else
#else
audio_out_stream = avformat_new_stream(oc, audio_out_codec);
audio_out_ctx = audio_out_stream->codec;
#endif
@ -375,6 +385,7 @@ VideoStore::VideoStore(
} // VideoStore::VideoStore
bool VideoStore::open() {
int ret;
/* open the out file, if needed */
if ( !(out_format->flags & AVFMT_NOFILE) ) {
ret = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, NULL, NULL);
@ -419,6 +430,7 @@ VideoStore::~VideoStore() {
if ( oc->pb ) {
if ( audio_out_codec ) {
// The codec queues data. We need to send a flush command and out
// whatever we get. Failures are not fatal.
AVPacket pkt;
@ -426,105 +438,75 @@ VideoStore::~VideoStore() {
pkt.data = NULL;
pkt.size = 0;
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)
// Put encoder into flushing mode
avcodec_send_frame(audio_out_ctx, NULL);
#endif
while (1) {
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_receive_packet(audio_out_ctx, &pkt);
if ( ret < 0 ) {
if ( AVERROR_EOF != ret ) {
Error("Error encoding audio while flushing (%d) (%s)", ret,
av_err2str(ret));
}
if ( ! zm_receive_packet(audio_out_ctx, pkt) ) {
Debug(1, "No more packets");
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");
// Need to adjust pts and dts and duration
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;
}
av_packet_rescale_ts(&pkt, audio_out_ctx->time_base, audio_out_stream->time_base);
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);
} // while have buffered frames
} // end if audio_out_codec
} // while have buffered frames
} // end if audio_out_codec
// Flush Queues
Debug(1,"Flushing interleaved queues");
Debug(1, "Flushing interleaved queues");
av_interleaved_write_frame(oc, NULL);
Debug(1,"Writing trailer");
Debug(1, "Writing trailer");
/* Write the trailer before close */
if ( int rc = av_write_trailer(oc) ) {
Error("Error writing trailer %s", av_err2str(rc));
@ -593,11 +575,11 @@ VideoStore::~VideoStore() {
#if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE)
if ( resample_ctx ) {
#if defined(HAVE_LIBSWRESAMPLE)
if ( fifo ) {
av_audio_fifo_free(fifo);
fifo = NULL;
}
#if defined(HAVE_LIBSWRESAMPLE)
swr_free(&resample_ctx);
#else
#if defined(HAVE_LIBAVRESAMPLE)
@ -632,6 +614,7 @@ bool VideoStore::setup_resampler() {
"Cannot do audio conversion to AAC");
return false;
#else
int ret;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
// Newer ffmpeg wants to keep everything separate... so have to lookup our own
@ -650,8 +633,13 @@ bool VideoStore::setup_resampler() {
#else
// codec is already open in ffmpeg_camera
audio_in_ctx = audio_in_stream->codec;
audio_in_codec = (AVCodec *)audio_in_ctx->codec;
//audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id);
audio_in_codec = reinterpret_cast<const AVCodec *>(audio_in_ctx->codec);
if ( !audio_in_codec ) {
audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id);
}
if ( !audio_in_codec ) {
return false;
}
#endif
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
@ -707,7 +695,7 @@ bool VideoStore::setup_resampler() {
}
}
if ( found ) {
Debug(3, "Sample rate is good");
Debug(3, "Sample rate is good %d", audio_out_ctx->sample_rate);
} else {
audio_out_ctx->sample_rate =
audio_out_codec->supported_samplerates[0];
@ -739,6 +727,7 @@ bool VideoStore::setup_resampler() {
audio_out_stream = NULL;
return false;
}
zm_dump_codec(audio_out_ctx);
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
ret = avcodec_parameters_from_context(
@ -747,6 +736,7 @@ bool VideoStore::setup_resampler() {
Error("Could not initialize stream parameteres");
return false;
}
zm_dump_codecpar(audio_out_stream->codecpar);
#endif
Debug(3,
@ -783,13 +773,13 @@ bool VideoStore::setup_resampler() {
return false;
}
#if defined(HAVE_LIBSWRESAMPLE)
if ( !(fifo = av_audio_fifo_alloc(
audio_out_ctx->sample_fmt,
audio_out_ctx->channels, 1)) ) {
Error("Could not allocate FIFO");
return false;
}
#if defined(HAVE_LIBSWRESAMPLE)
resample_ctx = swr_alloc_set_opts(NULL,
audio_out_ctx->channel_layout,
audio_out_ctx->sample_fmt,
@ -864,7 +854,7 @@ bool VideoStore::setup_resampler() {
NULL, audio_out_ctx->channels,
audio_out_ctx->frame_size,
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 ) {
Error("Could not allocate converted in sample pointers");
@ -890,131 +880,31 @@ bool VideoStore::setup_resampler() {
int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
av_init_packet(&opkt);
dumpPacket(video_in_stream, ipkt, "input packet");
dumpPacket(video_in_stream, ipkt, "video input packet");
int64_t duration;
if ( ipkt->duration != AV_NOPTS_VALUE ) {
duration = av_rescale_q(
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;
opkt.flags = ipkt->flags;
opkt.data = ipkt->data;
opkt.size = ipkt->size;
opkt.duration = ipkt->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.
// 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.
// 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.
// The cameras that Icon has seem to do EOF instead of wrapping
if ( ipkt->dts != AV_NOPTS_VALUE ) {
if ( !video_first_dts ) {
// && ( ipkt->dts >= 0 ) ) {
// This is the first packet.
opkt.dts = 0;
Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts);
Debug(2, "Starting video first_dts will become %" PRId64, 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) ) {
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;
opkt.dts = ipkt->dts - video_first_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 ) {
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;
dumpPacket(video_out_stream, &opkt, "after pts adjustment");
write_packet(&opkt, video_out_stream);
zm_av_packet_unref(&opkt);
@ -1022,6 +912,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) {
} // end int VideoStore::writeVideoFramePacket( AVPacket *ipkt )
int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
int ret;
if ( !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");
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 ( ( 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");
return 0;
}
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() ) {
//av_frame_unref(in_frame);
return 0;
}
AVFrame *input_frame = in_frame;
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;
}
audio_next_pts = out_frame->pts + out_frame->nb_samples;
#endif
audio_next_pts += out_frame->nb_samples;
av_init_packet(&opkt);
if ( !zm_send_frame(audio_out_ctx, out_frame, opkt) ) {
return 0;
}
zm_dump_frame(out_frame, "Out frame after resample");
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);
av_init_packet(&opkt);
if ( zm_send_frame_receive_packet(audio_out_ctx, out_frame, opkt) <= 0 )
break;
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);
// 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,
// Scale the PTS of the outgoing packet to be the correct time base
av_packet_rescale_ts(&opkt,
audio_out_ctx->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);
}
#endif
zm_av_packet_unref(&opkt);
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 {
Debug(2,"copying");
@ -1183,171 +980,50 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) {
opkt.size = ipkt->size;
opkt.flags = ipkt->flags;
if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) {
opkt.duration = av_rescale_q(
ipkt->duration,
audio_in_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;
}
opkt.duration = ipkt->duration;
opkt.pts = ipkt->pts;
opkt.dts = ipkt->dts;
av_packet_rescale_ts(&opkt, audio_in_stream->time_base, audio_out_stream->time_base);
write_packet(&opkt, audio_out_stream);
zm_av_packet_unref(&opkt);
} // end if encoding or copying
} // end if encoding or copying
return 0;
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
} // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt)
int VideoStore::write_packet(AVPacket *pkt, AVStream *stream) {
pkt->pos = -1;
pkt->stream_index = stream->index;
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;
if ( pkt->dts > pkt->pts ) {
if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
Debug(1,
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
"pkt.dts %" PRId64 " must be <= pkt.pts %" PRId64 "."
"Decompression must happen before presentation.",
pkt->dts, pkt->pts);
pkt->pts = pkt->dts;
}
} else if ( pkt->dts > pkt->pts ) {
} else if ( (pkt->pts != AV_NOPTS_VALUE) && (pkt->dts > pkt->pts) ) {
Debug(1,
"pkt.dts(%" PRId64 ") must be <= pkt.pts(%" PRId64 ")."
"Decompression must happen before presentation.",
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");
ret = av_interleaved_write_frame(oc, pkt);
int ret = av_interleaved_write_frame(oc, pkt);
if ( ret != 0 ) {
Error("Error writing packet: %s",
av_make_error_string(ret).c_str());
} else {
Debug(2, "Success writing packet");
}
} // 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
return ret;
} // end int VideoStore::write_packet(AVPacket *pkt, AVStream *stream)

View File

@ -5,12 +5,12 @@
extern "C" {
#ifdef HAVE_LIBSWRESAMPLE
#include "libswresample/swresample.h"
#include "libavutil/audio_fifo.h"
#else
#ifdef HAVE_LIBAVRESAMPLE
#include "libavresample/avresample.h"
#endif
#endif
#include "libavutil/audio_fifo.h"
}
#if HAVE_LIBAVCODEC
@ -38,9 +38,8 @@ private:
AVFrame *out_frame;
AVCodecContext *video_in_ctx;
AVCodec *audio_in_codec;
const AVCodec *audio_in_codec;
AVCodecContext *audio_in_ctx;
int ret;
// The following are used when encoding the audio stream to AAC
AVStream *audio_out_stream;
@ -48,12 +47,12 @@ private:
AVCodecContext *audio_out_ctx;
#ifdef HAVE_LIBSWRESAMPLE
SwrContext *resample_ctx;
AVAudioFifo *fifo;
#else
#ifdef HAVE_LIBAVRESAMPLE
AVAudioResampleContext* resample_ctx;
#endif
#endif
AVAudioFifo *fifo;
uint8_t *converted_in_samples;
const char *filename;
@ -77,8 +76,6 @@ private:
int64_t audio_next_dts;
bool setup_resampler();
int resample_audio();
int write_packet(AVPacket *pkt, AVStream *stream);
public:

View File

@ -187,8 +187,8 @@ int main(int argc, char *argv[]) {
snprintf(log_id_string, sizeof(log_id_string), "zmc_m%d", monitor_id);
}
logInit(log_id_string);
zmLoadConfig();
logInit(log_id_string);
hwcaps_detect();

View File

@ -138,7 +138,7 @@ movecrud () {
# previsouly part of installzm.sh
# install the trusty deb and test zoneminder
installtrusty () {
install_deb () {
# Check we've got gdebi installed
type gdebi 2>&1 > /dev/null
@ -347,8 +347,8 @@ if [ "${TRAVIS_EVENT_TYPE}" == "cron" ] || [ "${TRAVIS}" != "true" ]; then
echo "Starting packpack..."
execpackpack
if [ "${OS}" == "ubuntu" ] && [ "${DIST}" == "trusty" ] && [ "${ARCH}" == "x86_64" ] && [ "${TRAVIS}" == "true" ]; then
installtrusty
if [ "${TRAVIS}" == "true" ]; then
install_deb
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 [ "${TRAVIS}" == "true" ]; then
installtrusty
install_deb
fi
fi

View File

@ -142,16 +142,14 @@ class Event extends ZM_Object {
# Assumption: All events have a start time
$start_date = date_parse($this->{'StartTime'});
if ( ! $start_date ) {
Error('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
return;
throw new Exception('Unable to parse start time for event ' . $this->{'Id'} . ' not deleting files.');
}
$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.
$link_path = $this->Link_Path();
if ( ! $link_path ) {
Error('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
return;
throw new Exception('Unable to determine link path for event '.$this->{'Id'}.' not deleting files.');
}
$Storage = $this->Storage();
@ -159,8 +157,7 @@ class Event extends ZM_Object {
if ( $id_files = glob($eventlink_path) ) {
if ( ! $eventPath = readlink($id_files[0]) ) {
Error("Unable to read link at $id_files[0]");
return;
throw new Exception("Unable to read link at $id_files[0]");
}
# 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]);
@ -179,8 +176,7 @@ class Event extends ZM_Object {
} else {
$eventPath = $this->Path();
if ( ! $eventPath ) {
Error('No event Path in Event delete. Not deleting');
return;
throw new Exception('No event Path in Event delete. Not deleting');
}
deletePath($eventPath);
if ( $this->SecondaryStorageId() ) {
@ -199,6 +195,9 @@ class Event extends ZM_Object {
$dbConn->commit();
} catch (PDOException $e) {
$dbConn->rollback();
} catch (Exception $e) {
Error($e->getMessage());
$dbConn->rollback();
}
} # 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;
} // end function getStreamSrc

View File

@ -103,6 +103,11 @@ class Server {
}
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->Hostname();
if ( $port ) {

View File

@ -44,11 +44,9 @@ if ( $action == 'archive' ) {
$dbConn->commit();
$refreshParent = true;
} else if ( $action == 'delete' ) {
$dbConn->beginTransaction();
foreach ( getAffectedIds('eids') as $markEid ) {
deleteEvent($markEid);
}
$dbConn->commit();
$refreshParent = true;
}
?>

View File

@ -37,7 +37,6 @@ if ( $action == 'user' ) {
if ( $_REQUEST['newUser']['Password'] ) {
$changes['Password'] = 'Password = '.$pass_hash;
ZM\Info('PASS CMD='.$changes['Password']);
} else {
unset($changes['Password']);
}
@ -47,7 +46,7 @@ if ( $action == 'user' ) {
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 ( $user and ( $dbUser['Username'] == $user['Username'] ) )
userLogin($dbUser['Username'], $dbUser['Password']);
generateAuthHash(ZM_AUTH_HASH_IPS);
} else {
dbQuery('INSERT INTO Users SET '.implode(', ', $changes));
}
@ -71,13 +70,13 @@ if ( $action == 'user' ) {
if ( !empty($_REQUEST['newUser']['Password']) ) {
$changes['Password'] = 'Password = '.$pass_hash;
}
else
} else {
unset($changes['Password']);
}
if ( count($changes) ) {
dbQuery('UPDATE Users SET '.implode(', ', $changes).' WHERE Id=?', array($uid));
$refreshParent = true;
generateAuthHash(ZM_AUTH_HASH_IPS);
}
$view = 'none';
}

View File

@ -56,7 +56,7 @@ function dbConnect() {
$dbConn->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbConn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $ex ) {
} catch(PDOException $ex) {
echo 'Unable to connect to ZM db.' . $ex->getMessage();
error_log('Unable to connect to ZM DB ' . $ex->getMessage());
$dbConn = null;

View File

@ -120,33 +120,6 @@ function CORSHeaders() {
}
}
function getStreamSrc( $args, $querySep='&amp;' ) {
$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 ) {
if ( function_exists('mime_content_type') ) {
return( mime_content_type( $file ) );
@ -156,7 +129,7 @@ function getMimeType( $file ) {
finfo_close($finfo);
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='' ) {
@ -169,8 +142,8 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
$height = validInt($height);
$title = validHtmlStr($title);
if ( file_exists( $src ) ) {
$mimeType = getMimeType( $src );
if ( file_exists($src) ) {
$mimeType = getMimeType($src);
} else {
switch( $format ) {
case 'asf' :
@ -205,7 +178,6 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
case 'video/x-ms-asf' :
case 'video/x-msvideo' :
case 'video/mp4' :
{
if ( isWindows() ) {
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'
classid="CLSID:22D6F312-B0F6-11D0-94AB-0080C74C7E95"
@ -226,9 +198,7 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
</embed>
</object>';
}
}
case 'video/quicktime' :
{
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B"
codebase="'.ZM_BASE_PROTOCOL.'://www.apple.com/qtactivex/qtplugin.cab"
@ -244,9 +214,7 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
controller="true">
</embed>
</object>';
}
case 'application/x-shockwave-flash' :
{
return '<object id="'.$id.'" width="'.$width.'" height="'.$height.'"
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"
@ -264,7 +232,6 @@ function getVideoStreamHTML( $id, $src, $width, $height, $format, $title='' ) {
bgcolor="#ffffff">
</embed>
</object>';
}
} # end switch
} # end if use object tags
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 ) {
?>
<form name="ctrlForm" method="post" action="?" target="<?php echo $target ?>">
<input type="hidden" name="view" value="blank">
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>">
<input type="hidden" name="action" value="control">
<input type="hidden" name="view" value="blank"/>
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>"/>
<input type="hidden" name="action" value="control"/>
<?php
if ( $monitor['CanMoveMap'] ) {
?>
<input type="hidden" name="control" value="moveMap">
<input type="hidden" name="control" value="moveMap"/>
<?php
} elseif ( $monitor['CanMoveRel'] ) {
} else if ( $monitor['CanMoveRel'] ) {
?>
<input type="hidden" name="control" value="movePseudoMap">
<input type="hidden" name="control" value="movePseudoMap"/>
<?php
} elseif ( $monitor['CanMoveCon'] ) {
} else if ( $monitor['CanMoveCon'] ) {
?>
<input type="hidden" name="control" value="moveConMap">
<input type="hidden" name="control" value="moveConMap"/>
<?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 ?>">
</form>
<?php
@ -365,26 +332,26 @@ function getWebSiteUrl( $id, $src, $width, $height, $title='' ) {
function outputControlStill( $src, $width, $height, $monitor, $scale, $target ) {
?>
<form name="ctrlForm" method="post" action="?" target="<?php echo $target ?>">
<input type="hidden" name="view" value="blank">
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>">
<input type="hidden" name="action" value="control">
<input type="hidden" name="view" value="blank"/>
<input type="hidden" name="mid" value="<?php echo $monitor['Id'] ?>"/>
<input type="hidden" name="action" value="control"/>
<?php
if ( $monitor['CanMoveMap'] ) {
?>
<input type="hidden" name="control" value="moveMap">
<input type="hidden" name="control" value="moveMap"/>
<?php
} elseif ( $monitor['CanMoveRel'] ) {
} else if ( $monitor['CanMoveRel'] ) {
?>
<input type="hidden" name="control" value="movePseudoMap">
<input type="hidden" name="control" value="movePseudoMap"/>
<?php
} elseif ( $monitor['CanMoveCon'] ) {
} else if ( $monitor['CanMoveCon'] ) {
?>
<input type="hidden" name="control" value="moveConMap">
<input type="hidden" name="control" value="moveConMap"/>
<?php
}
?>
<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="hidden" name="scale" value="<?php echo $scale ?>"/>
<input type="image" src="<?php echo $src ?>" width="<?php echo $width ?>" height="<?php echo $height ?>"/>
</form>
<?php
}
@ -405,12 +372,12 @@ function getZmuCommand( $args ) {
$zmuCommand .= $args;
return( $zmuCommand );
return $zmuCommand;
}
function getEventDefaultVideoPath( $event ) {
$Event = new ZM\Event( $event );
return $Event->getStreamSrc( array( 'mode'=>'mpeg', 'format'=>'h264' ) );
function getEventDefaultVideoPath($event) {
$Event = new ZM\Event($event);
return $Event->getStreamSrc(array('mode'=>'mpeg', 'format'=>'h264'));
}
function deletePath( $path ) {

View File

@ -28,7 +28,6 @@ function zm_session_start() {
session_destroy();
session_start();
} else if ( !empty($_SESSION['generated_at']) ) {
ZM\Logger::Debug("Have generated_at: " . $_SESSION['generated_at']);
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_session_regenerate_id();

View File

@ -87,27 +87,38 @@ if ( isset($_GET['skin']) ) {
$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) ) {
ZM\Error("Invalid skin '$skin' setting to " . $skins[0]);
$skin = $skins[0];
if ( !in_array($skin, $skins) ) {
ZM\Error("Invalid skin '$skin' setting to ".$skins[0]);
$skin = $skins[0];
}
}
if ( isset($_GET['css']) ) {
$css = $_GET['css'];
} elseif ( isset($_COOKIE['zmCSS']) ) {
} else if ( isset($_COOKIE['zmCSS']) ) {
$css = $_COOKIE['zmCSS'];
} elseif ( defined('ZM_CSS_DEFAULT') ) {
} else if ( defined('ZM_CSS_DEFAULT') ) {
$css = ZM_CSS_DEFAULT;
} else {
$css = 'classic';
}
$css_skins = array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR));
if ( !in_array($css, $css_skins) ) {
ZM\Error("Invalid skin css '$css' setting to " . $css_skins[0]);
$css = $css_skins[0];
if ( !is_dir("skins/$skin/css/$css") ) {
$css_skins = array_map('basename', glob('skins/'.$skin.'/css/*', GLOB_ONLYDIR));
if ( count($css_skins) ) {
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']));
@ -116,7 +127,7 @@ define('ZM_SKIN_NAME', $skin);
$skinBase = array(); // To allow for inheritance of skins
if ( !file_exists(ZM_SKIN_PATH) )
Fatal("Invalid skin '$skin'");
ZM\Fatal("Invalid skin '$skin'");
$skinBase[] = $skin;
zm_session_start();
@ -125,7 +136,7 @@ if (
!isset($_SESSION['skin']) ||
isset($_REQUEST['skin']) ||
!isset($_COOKIE['zmSkin']) ||
$_COOKIE['zmSkin'] != $skin
($_COOKIE['zmSkin'] != $skin)
) {
$_SESSION['skin'] = $skin;
setcookie('zmSkin', $skin, time()+3600*24*30*12*10);
@ -135,7 +146,7 @@ if (
!isset($_SESSION['css']) ||
isset($_REQUEST['css']) ||
!isset($_COOKIE['zmCSS']) ||
$_COOKIE['zmCSS'] != $css
($_COOKIE['zmCSS'] != $css)
) {
$_SESSION['css'] = $css;
setcookie('zmCSS', $css, time()+3600*24*30*12*10);

View File

@ -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);
?>

View File

@ -215,7 +215,6 @@ function selectLayout(element) {
if ( layout_id = parseInt(layout) ) {
layout = layouts[layout];
console.log(layout);
for ( var i = 0, length = monitors.length; i < length; i++ ) {
monitor = monitors[i];
@ -396,6 +395,16 @@ function edit_layout(button) {
function save_layout(button) {
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.
var Positions = {};
for ( var i = 0, length = monitors.length; i < length; i++ ) {

View File

@ -22,14 +22,14 @@ function gotoStep2( element ) {
form.submit();
}
function configureButtons( element ) {
function configureButtons(element) {
var form = element.form;
if (form.elements.namedItem("nextBtn")) {
if (form.elements.namedItem('nextBtn')) {
form.nextBtn.disabled = (form.probe.selectedIndex==0) ||
(form.username == "") || (form.username == null) ||
(form.password == "") || (form.password == null);
(form.Username == '') || (form.Username == null) ||
(form.Password == '') || (form.Password == null);
}
if (form.elements.namedItem("saveBtn")) {
if (form.elements.namedItem('saveBtn')) {
form.saveBtn.disabled = (form.probe.selectedIndex==0);
}
}

View File

@ -180,11 +180,11 @@ if ( $showZones ) {
<?php echo htmlSelect('zmMontageLayout', $layoutsById, $layout_id, array('onchange'=>'selectLayout(this);')); ?>
</span>
<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;">
<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"/>
<input type="button" value="Cancel" data-on-click-this="cancel_layout"/>
<button type="button" value="Save" data-on-click-this="save_layout"><?php echo translate('Save') ?></button>
<button type="button" value="Cancel" data-on-click-this="cancel_layout"><?php echo translate('Cancel') ?></button>
</span>
</form>
</div>

View File

@ -41,18 +41,18 @@ function execONVIF( $cmd ) {
Please the following command from a command line for more information:<br/><br/>$shell_command"
);
} else {
ZM\Logger::Debug( "Results from probe: " . implode( '<br/>', $output ) );
ZM\Logger::Debug('Results from probe: '.implode('<br/>', $output));
}
return $output;
}
function probeCameras( $localIp ) {
function probeCameras($localIp) {
$cameras = array();
if ( $lines = @execONVIF( 'probe' ) ) {
if ( $lines = @execONVIF('probe') ) {
foreach ( $lines as $line ) {
$line = rtrim( $line );
if ( preg_match( '|^(.+),(.+),\s\((.*)\)$|', $line, $matches ) ) {
$line = rtrim($line);
if ( preg_match('|^(.+),(.+),\s\((.*)\)$|', $line, $matches) ) {
$device_ep = $matches[1];
$soapversion = $matches[2];
$camera = array(
@ -65,7 +65,7 @@ function probeCameras( $localIp ) {
),
);
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' ) {
$camera['model'] = $tokens[2];
} elseif ( $tokens[1] == 'name' ) {
@ -84,7 +84,7 @@ function probeCameras( $localIp ) {
return $cameras;
} // end function probeCameras
function probeProfiles( $device_ep, $soapversion, $username, $password ) {
function probeProfiles($device_ep, $soapversion, $username, $password) {
$profiles = array();
if ( $lines = @execONVIF("profiles $device_ep $soapversion $username $password") ) {
foreach ( $lines as $line ) {
@ -94,7 +94,7 @@ function probeProfiles( $device_ep, $soapversion, $username, $password ) {
// add user@pass to URI
if ( preg_match('|^(\S+://)(.+)$|', $stream_uri, $tokens) ) {
$stream_uri = $tokens[1].$username.':'.$password.'@'.$tokens[2];
}
}
$profile = array( # 'monitor' part of camera
'Type' => 'Ffmpeg',
@ -125,8 +125,8 @@ xhtmlHeaders(__FILE__, translate('MonitorProbe') );
if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
$monitors = array();
foreach ( dbFetchAll("SELECT Id, Name, Host FROM Monitors WHERE Type = 'Remote' ORDER BY Host") as $monitor ) {
if ( preg_match( '/^(.+)@(.+)$/', $monitor['Host'], $matches ) ) {
foreach ( dbFetchAll("SELECT Id, Name, Host FROM Monitors WHERE Type='Remote' ORDER BY Host") as $monitor ) {
if ( preg_match('/^(.+)@(.+)$/', $monitor['Host'], $matches) ) {
//echo "1: ".$matches[2]." = ".gethostbyname($matches[2])."<br/>";
$monitors[gethostbyname($matches[2])] = $monitor;
} else {
@ -137,26 +137,12 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
$detcameras = probeCameras('');
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];
}
$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']));
$sourceString = $camera['model'].' @ '.$host . ' using version ' . $camera['monitor']['SOAP'] ;
$sourceString = $camera['model'].' @ '.$host.' using version '.$camera['monitor']['SOAP'];
$cameras[$sourceDesc] = $sourceString;
}
@ -179,39 +165,38 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
</p>
<p>
<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>
<?php echo translate('OnvifCredentialsIntro') ?>
</p>
<p>
<label for="username"><?php echo translate('Username') ?></label>
<input type="text" name="username" value="" onChange="configureButtons(this)"/>
<label for="Username"><?php echo translate('Username') ?></label>
<input type="text" name="Username" data-on-change-this="configureButtons"/>
</p>
<p>
<label for="password"><?php echo translate('Password') ?></label>
<input type="password" name="password" value="" onChange="configureButtons(this)"/>
<label for="Password"><?php echo translate('Password') ?></label>
<input type="password" name="Password" data-on-change-this="configureButtons"/>
</p>
<div id="contentButtons">
<input type="button" value="<?php echo translate('Cancel') ?>" data-on-click="closeWindow"/>
<input type="submit" name="nextBtn" value="<?php echo translate('Next') ?>" data-on-click-this="gotoStep2" disabled="disabled"/>
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
<button type="button" name="nextBtn" data-on-click-this="gotoStep2" disabled="disabled"><?php echo translate('Next') ?></button>
</div>
</form>
</div>
</div>
</body>
</html>
<?php
//==== STEP 2 ============================================================
} else if($_REQUEST['step'] == '2') {
} else if ( $_REQUEST['step'] == '2' ) {
if ( empty($_REQUEST['probe']) )
ZM\Fatal('No probe passed in request. Please go back and try again.');
#|| empty($_REQUEST['username']) ||
#empty($_REQUEST['password']) )
$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 ) {
if ( isset($value) ) {
$monitor[$name] = $value;
@ -221,7 +206,7 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
//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 ) {
$monitor = $camera['monitor'];
@ -258,18 +243,18 @@ if ( !isset($_REQUEST['step']) || ($_REQUEST['step'] == '1') ) {
</p>
<p>
<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>
<div id="contentButtons">
<input type="button" name="prevBtn" value="<?php echo translate('Prev') ?>" data-on-click-this="gotoStep1"/>
<input type="button" value="<?php echo translate('Cancel') ?>" data-on-click="closeWindow"/>
<input type="submit" name="saveBtn" value="<?php echo translate('Save') ?>" data-on-click-this="submitCamera" disabled="disabled"/>
<button type="button" name="prevBtn" data-on-click-this="gotoStep1"><?php echo translate('Prev') ?></button>
<button type="button" data-on-click="closeWindow"><?php echo translate('Cancel') ?></button>
<button type="button" name="saveBtn" data-on-click-this="submitCamera" disabled="disabled"><?php echo translate('Save') ?></button>
</div>
</form>
</div>
</div>
</body>
</html>
<?php
} // end if step 1 or 2
?>
</html>

View File

@ -53,31 +53,6 @@ $focusWindow = true;
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>
<?php echo getNavBarHTML(); ?>
@ -104,12 +79,14 @@ if ( $tab == 'skins' ) {
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
<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">
<select name="skin-choice" class="form-control chosen">
<select name="skin" class="form-control chosen">
<?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 ) {
echo '<option value="'.$dir.'" '.($current_skin==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
echo '<option value="'.$dir.'" '.($skin==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
}
?>
</select>
@ -117,12 +94,12 @@ foreach ( $skin_options as $dir ) {
</div>
</div>
<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">
<select name="css-choice" class="form-control chosen">
<select name="css" class="form-control chosen">
<?php
foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDIR)) as $dir ) {
echo '<option value="'.$dir.'" '.($current_css==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
foreach ( array_map('basename', glob('skins/'.$skin.'/css/*',GLOB_ONLYDIR)) as $dir ) {
echo '<option value="'.$dir.'" '.($css==$dir ? 'SELECTED="SELECTED"' : '').'>'.$dir.'</option>';
}
?>
</select>
@ -325,40 +302,37 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
?>
<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
function revokeAllTokens()
{
function revokeAllTokens() {
$minTokenTime = time();
dbQuery ('UPDATE Users SET TokenMinExpiry=?', array ($minTokenTime));
echo "<span class='timedSuccessBox'>".translate('AllTokensRevoked')."</span>";
dbQuery('UPDATE `Users` SET `TokenMinExpiry`=?', array($minTokenTime));
echo '<span class="timedSuccessBox">'.translate('AllTokensRevoked').'</span>';
}
function updateSelected()
{
dbQuery("UPDATE Users SET APIEnabled=0");
foreach( $_REQUEST["tokenUids"] as $markUid ) {
function updateSelected() {
dbQuery('UPDATE `Users` SET `APIEnabled`=0');
foreach ( $_REQUEST["tokenUids"] as $markUid ) {
$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 ) {
dbQuery('UPDATE Users SET APIEnabled=1 WHERE Id=?', array($markUid));
foreach ( $_REQUEST["apiUids"] as $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();
}
if(array_key_exists('updateSelected',$_POST)){
if ( array_key_exists('updateSelected',$_POST) ) {
updateSelected();
}
?>
<br/><br/>
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<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
$sql = 'SELECT * FROM Users ORDER BY Username';
foreach( dbFetchAll($sql) as $row ) {
foreach ( dbFetchAll($sql) as $row ) {
?>
<tr>
<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();
$configCats = array();
$result = $dbConn->query('SELECT * FROM Config ORDER BY Id ASC');
$result = $dbConn->query('SELECT * FROM `Config` ORDER BY `Id` ASC');
if ( !$result )
echo mysql_error();
while( $row = dbFetchNext($result) ) {
@ -411,9 +385,9 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
}
if ( $tab == 'system' ) {
$configCats[$tab]['ZM_LANG_DEFAULT']['Hint'] = join( '|', getLanguages() );
$configCats[$tab]['ZM_SKIN_DEFAULT']['Hint'] = join( '|', $skin_options );
$configCats[$tab]['ZM_CSS_DEFAULT']['Hint'] = join( '|', array_map ( 'basename', glob('skins/'.ZM_SKIN_DEFAULT.'/css/*',GLOB_ONLYDIR) ) );
$configCats[$tab]['ZM_LANG_DEFAULT']['Hint'] = join('|', getLanguages());
$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_BANDWIDTH_DEFAULT']['Hint'] = $bandwidth_options;
}
?>
@ -508,7 +482,7 @@ foreach ( array_map('basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
?>
<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>
</form>
<?php

View File

@ -132,7 +132,7 @@ $chart = array(
$monitors = array();
$monitorsSql = 'SELECT * FROM Monitors ORDER BY Sequence ASC';
//srand( 97981 );
foreach( dbFetchAll( $monitorsSql ) as $row ) {
foreach( dbFetchAll($monitorsSql) as $row ) {
//if ( empty($row['WebColour']) )
//{
//$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();
$monFrameSlots = array();
$monitorIds = array();
$events_result = dbQuery( $eventsSql );
if ( ! $events_result ) {
Fatal( "SQL-ERR");
$events_result = dbQuery($eventsSql);
if ( !$events_result ) {
Fatal("SQL-ERR");
return;
}