diff --git a/docs/installationguide/debian.rst b/docs/installationguide/debian.rst index 96907eee7..a6a27aa19 100644 --- a/docs/installationguide/debian.rst +++ b/docs/installationguide/debian.rst @@ -3,6 +3,147 @@ Debian .. contents:: +Easy Way: Debian Stretch +------------------------ + +This procedure will guide you through the installation of ZoneMinder on Debian 9 (Stretch). This section has been tested with ZoneMinder 1.32.3 on Debian 9.8. + +**Step 1:** Make sure your system is up to date + +Open a console and use ``su`` command to become Root. + +:: + + apt update + apt upgrade + + +**Step 2:** Setup Sudo (optional but recommended) + +By default Debian does not come with sudo, so you have to install it and configure it manually. This step is optional but recommended and the following instructions assume that you have setup sudo. If you prefer to setup ZoneMinder as root, do it at your own risk and adapt the following instructions accordingly. + +:: + + apt install sudo + usermod -a -G sudo + exit + +Now your terminal session is back under your normal user. You can check that you are now part of the sudo group with the command ``groups``, "sudo" should appear in the list. If not, run ``newgrp sudo`` and check again with ``groups``. + + +**Step 3:** Install Apache and MySQL + +These are not dependencies for the ZoneMinder package as they could be installed elsewhere. If they are not installed yet in your system, you have to trigger their installation manually. + +:: + + sudo apt install apache2 mysql-server + +**Step 4:** Add ZoneMinder's Package repository to your apt sources + +ZoneMinder's Debian packages are not included in Debian's official package repositories. To be able to install ZoneMinder with APT, you have to edit the list of apt sources and add ZoneMinder's repository. + +:: + + sudo nano /etc/apt/sources.list + +Add the following to the bottom of the file + +:: + + # ZoneMinder repository + deb https://zmrepo.zoneminder.com/debian/release stretch/ + +CTRL+o and to save +CTRL+x to exit + +Because ZoneMinder's package repository provides a secure connection through HTTPS, apt must be enabled for HTTPS. +:: + + sudo apt install apt-transport-https + +Finally, download the GPG key for ZoneMinder's repository: +:: + + wget -O - https://zmrepo.zoneminder.com/debian/archive-keyring.gpg | sudo apt-key add - + + +**Step 5:** Install ZoneMinder + +:: + + sudo apt update + sudo apt install zoneminder + +**Step 6:** Read the Readme + +The rest of the install process is covered in the README.Debian, so feel free to have +a read. + +:: + + gunzip /usr/share/doc/zoneminder/README.Debian.gz + cat /usr/share/doc/zoneminder/README.Debian + + +**Step 7:** Enable ZoneMinder service + +:: + + sudo systemctl enable zoneminder.service + +**Step 8:** Configure Apache + +The following commands will setup the default /zm virtual directory and configure +required apache modules. + +:: + + sudo a2enconf zoneminder + sudo a2enmod rewrite + sudo a2enmod cgi # this is done automatically when installing the package. Redo this command manually only for troubleshooting. + + +**Step 9:** Edit Timezone in PHP + +Automated way: +:: + + sudo sed -i "s/;date.timezone =/date.timezone = $(sed 's/\//\\\//' /etc/timezone)/g" /etc/php/7.0/apache2/php.ini + +Manual way +:: + + sudo nano /etc/php/7.0/apache2/php.ini + +Search for [Date] (Ctrl + w then type Date and press Enter) and change +date.timezone for your time zone. Don't forget to remove the ; from in front +of date.timezone. + +:: + + [Date] + ; Defines the default timezone used by the date functions + ; http://php.net/date.timezone + date.timezone = America/New_York + +CTRL+o then [Enter] to save + +CTRL+x to exit + + +**Step 10:** Start ZoneMinder + +Reload Apache to enable your changes and then start ZoneMinder. + +:: + + sudo systemctl reload apache2 + sudo systemctl start zoneminder + +You are now ready to go with ZoneMinder. Open a browser and type either ``localhost/zm`` one the local machine or ``{IP-OF-ZM-SERVER}/zm`` if you connect from a remote computer. + + Easy Way: Debian Jessie ----------------------- @@ -81,7 +222,7 @@ should you choose to change default database user and password. cat /usr/share/zoneminder/db/zm_create.sql | sudo mysql --defaults-file=/etc/mysql/debian.cnf echo 'grant lock tables,alter,create,select,insert,update,delete,index on zm.* to 'zmuser'@localhost identified by "zmpass";' | sudo mysql --defaults-file=/etc/mysql/debian.cnf mysql -** Step 8:** zm.conf Permissions +**Step 8:** zm.conf Permissions Adjust permissions to the zm.conf file to allow web account to access it. @@ -129,6 +270,7 @@ CTRL+x to exit **Step 12:** Please check the configuration + Zoneminder 1.32.x 1. Check path of ZM_PATH in '/etc/zm/conf.d/zmcustom.conf' is ZM_PATH_ZMS=/zm/cgi-bin/nph-zms :: diff --git a/docs/userguide/introduction.rst b/docs/userguide/introduction.rst index 2d9985eb1..a6573a24d 100644 --- a/docs/userguide/introduction.rst +++ b/docs/userguide/introduction.rst @@ -11,4 +11,4 @@ A fast video interface core, a user-friendly and comprehensive PHP based web int The core of ZoneMinder is the capture and analysis of images and a highly configurable set of parameters that eliminate false positives whilst ensuring minimum loss of footage. For example, you can define a set of 'zones' for each camera of varying sensitivity and functionality. This eliminates zones that you don't wish to track or define areas that will alarm if various thresholds are exceeded in conjunction with other zones. -ZoneMinder is free under GPL License, but if you do find it useful, then please feel free to visit http://www.zoneminder.com/donate.html and help us fund our future improvements. +ZoneMinder is free under GPL License, but if you do find it useful, then please feel free to visit https://zoneminder.com/donate/ and help us fund our future improvements. diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 90a2b9aac..2089fecc3 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -252,8 +252,6 @@ void Logger::initialise(const std::string &id, const Options &options) { } void Logger::terminate() { - Debug(1, "Terminating Logger"); - if ( mFileLevel > NOLOG ) closeFile(); @@ -574,6 +572,7 @@ void Logger::logPrint( bool hex, const char * const filepath, const int line, co free(filecopy); if ( level <= FATAL ) { + log_mutex.unlock(); logTerm(); zmDbClose(); if ( level <= PANIC ) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index c211dd7db..2987d08f2 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -360,17 +360,17 @@ Monitor::Monitor( { strncpy( name, p_name, sizeof(name)-1 ); - strncpy( event_prefix, p_event_prefix, sizeof(event_prefix)-1 ); - strncpy( label_format, p_label_format, sizeof(label_format)-1 ); + strncpy(event_prefix, p_event_prefix, sizeof(event_prefix)-1); + strncpy(label_format, p_label_format, sizeof(label_format)-1); // Change \n to actual line feeds char *token_ptr = label_format; const char *token_string = "\n"; - while( ( token_ptr = strstr( token_ptr, token_string ) ) ) { + while ( ( token_ptr = strstr(token_ptr, token_string) ) ) { if ( *(token_ptr+1) ) { *token_ptr = '\n'; token_ptr++; - strcpy( token_ptr, token_ptr+1 ); + strcpy(token_ptr, token_ptr+1); } else { *token_ptr = '\0'; break; @@ -434,7 +434,7 @@ Monitor::Monitor( exit(-1); } - memset( mem_ptr, 0, mem_size ); + memset(mem_ptr, 0, mem_size); shared_data->size = sizeof(SharedData); shared_data->active = enabled; shared_data->signal = false; @@ -510,10 +510,17 @@ Monitor::Monitor( shared_data->last_write_index, shared_data->last_write_time ); sleep(1); } - ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); + ref_image.Assign( width, height, camera->Colours(), camera->SubpixelOrder(), + image_buffer[shared_data->last_write_index].image->Buffer(), camera->ImageSize()); adaptive_skip = true; ReloadLinkedMonitors(p_linked_monitors); + + if ( config.record_diag_images ) { + diag_path_r = stringtf("%s/%d/diag-r.jpg", storage->Path(), id); + diag_path_d = stringtf("%s/%d/diag-d.jpg", storage->Path(), id); + } + } // end if purpose == ANALYSIS } // Monitor::Monitor @@ -889,12 +896,12 @@ double Monitor::GetFPS() const { useconds_t Monitor::GetAnalysisRate() { double capturing_fps = GetFPS(); if ( !analysis_fps ) { - return( 0 ); + return 0; } else if ( analysis_fps > capturing_fps ) { - Warning( "Analysis fps (%.2f) is greater than capturing fps (%.2f)", analysis_fps, capturing_fps ); - return( 0 ); + Warning("Analysis fps (%.2f) is greater than capturing fps (%.2f)", analysis_fps, capturing_fps); + return 0; } else { - return( ( 1000000 / analysis_fps ) - ( 1000000 / capturing_fps ) ); + return ( ( 1000000 / analysis_fps ) - ( 1000000 / capturing_fps ) ); } } @@ -902,10 +909,10 @@ void Monitor::UpdateAdaptiveSkip() { if ( config.opt_adaptive_skip ) { double capturing_fps = GetFPS(); if ( adaptive_skip && analysis_fps && ( analysis_fps < capturing_fps ) ) { - Info( "Analysis fps (%.2f) is lower than capturing fps (%.2f), disabling adaptive skip feature", analysis_fps, capturing_fps ); + Info("Analysis fps (%.2f) is lower than capturing fps (%.2f), disabling adaptive skip feature", analysis_fps, capturing_fps); adaptive_skip = false; } else if ( !adaptive_skip && ( !analysis_fps || ( analysis_fps >= capturing_fps ) ) ) { - Info( "Enabling adaptive skip feature" ); + Info("Enabling adaptive skip feature"); adaptive_skip = true; } } else { @@ -916,8 +923,8 @@ void Monitor::UpdateAdaptiveSkip() { void Monitor::ForceAlarmOn( int force_score, const char *force_cause, const char *force_text ) { trigger_data->trigger_state = TRIGGER_ON; trigger_data->trigger_score = force_score; - strncpy( trigger_data->trigger_cause, force_cause, sizeof(trigger_data->trigger_cause)-1 ); - strncpy( trigger_data->trigger_text, force_text, sizeof(trigger_data->trigger_text)-1 ); + strncpy(trigger_data->trigger_cause, force_cause, sizeof(trigger_data->trigger_cause)-1); + strncpy(trigger_data->trigger_text, force_text, sizeof(trigger_data->trigger_text)-1); } void Monitor::ForceAlarmOff() { @@ -964,7 +971,7 @@ void Monitor::actionResume() { shared_data->action |= RESUME; } -int Monitor::actionBrightness( int p_brightness ) { +int Monitor::actionBrightness(int p_brightness) { if ( purpose != CAPTURE ) { if ( p_brightness >= 0 ) { shared_data->brightness = p_brightness; @@ -972,10 +979,10 @@ int Monitor::actionBrightness( int p_brightness ) { int wait_loops = 10; while ( shared_data->action & SET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to set brightness" ); - return( -1 ); + Warning("Timed out waiting to set brightness"); + return -1; } } } else { @@ -983,19 +990,19 @@ int Monitor::actionBrightness( int p_brightness ) { int wait_loops = 10; while ( shared_data->action & GET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to get brightness" ); - return( -1 ); + Warning("Timed out waiting to get brightness"); + return -1; } } } - return( shared_data->brightness ); + return shared_data->brightness; } - return( camera->Brightness( p_brightness ) ); -} + return camera->Brightness(p_brightness); +} // end int Monitor::actionBrightness(int p_brightness) -int Monitor::actionContrast( int p_contrast ) { +int Monitor::actionContrast(int p_contrast) { if ( purpose != CAPTURE ) { if ( p_contrast >= 0 ) { shared_data->contrast = p_contrast; @@ -1003,10 +1010,10 @@ int Monitor::actionContrast( int p_contrast ) { int wait_loops = 10; while ( shared_data->action & SET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to set contrast" ); - return( -1 ); + Warning("Timed out waiting to set contrast"); + return -1; } } } else { @@ -1014,19 +1021,19 @@ int Monitor::actionContrast( int p_contrast ) { int wait_loops = 10; while ( shared_data->action & GET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to get contrast" ); - return( -1 ); + Warning("Timed out waiting to get contrast"); + return -1; } } } - return( shared_data->contrast ); + return shared_data->contrast; } - return( camera->Contrast( p_contrast ) ); -} + return camera->Contrast(p_contrast); +} // end int Monitor::actionContrast(int p_contrast) -int Monitor::actionHue( int p_hue ) { +int Monitor::actionHue(int p_hue) { if ( purpose != CAPTURE ) { if ( p_hue >= 0 ) { shared_data->hue = p_hue; @@ -1034,10 +1041,10 @@ int Monitor::actionHue( int p_hue ) { int wait_loops = 10; while ( shared_data->action & SET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to set hue" ); - return( -1 ); + Warning("Timed out waiting to set hue"); + return -1; } } } else { @@ -1045,19 +1052,19 @@ int Monitor::actionHue( int p_hue ) { int wait_loops = 10; while ( shared_data->action & GET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to get hue" ); - return( -1 ); + Warning("Timed out waiting to get hue"); + return -1; } } } - return( shared_data->hue ); + return shared_data->hue; } - return( camera->Hue( p_hue ) ); -} + return camera->Hue(p_hue); +} // end int Monitor::actionHue(int p_hue) -int Monitor::actionColour( int p_colour ) { +int Monitor::actionColour(int p_colour) { if ( purpose != CAPTURE ) { if ( p_colour >= 0 ) { shared_data->colour = p_colour; @@ -1065,10 +1072,10 @@ int Monitor::actionColour( int p_colour ) { int wait_loops = 10; while ( shared_data->action & SET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to set colour" ); - return( -1 ); + Warning("Timed out waiting to set colour"); + return -1; } } } else { @@ -1076,19 +1083,19 @@ int Monitor::actionColour( int p_colour ) { int wait_loops = 10; while ( shared_data->action & GET_SETTINGS ) { if ( wait_loops-- ) { - usleep( 100000 ); + usleep(100000); } else { - Warning( "Timed out waiting to get colour" ); - return( -1 ); + Warning("Timed out waiting to get colour"); + return -1; } } } - return( shared_data->colour ); + return shared_data->colour; } - return( camera->Colour( p_colour ) ); -} + return camera->Colour(p_colour); +} // end int Monitor::actionColour(int p_colour) -void Monitor::DumpZoneImage( const char *zone_string ) { +void Monitor::DumpZoneImage(const char *zone_string) { int exclude_id = 0; int extra_colour = 0; Polygon extra_zone; @@ -1129,7 +1136,7 @@ void Monitor::DumpZoneImage( const char *zone_string ) { zone_image->Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB); } - for( int i = 0; i < n_zones; i++ ) { + for ( int i = 0; i < n_zones; i++ ) { if ( exclude_id && (!extra_colour || extra_zone.getNumCoords()) && zones[i]->Id() == exclude_id ) continue; @@ -1149,33 +1156,33 @@ void Monitor::DumpZoneImage( const char *zone_string ) { colour = RGB_WHITE; } } - zone_image->Fill( colour, 2, zones[i]->GetPolygon() ); - zone_image->Outline( colour, zones[i]->GetPolygon() ); + zone_image->Fill(colour, 2, zones[i]->GetPolygon()); + zone_image->Outline(colour, zones[i]->GetPolygon()); } if ( extra_zone.getNumCoords() ) { - zone_image->Fill( extra_colour, 2, extra_zone ); - zone_image->Outline( extra_colour, extra_zone ); + zone_image->Fill(extra_colour, 2, extra_zone); + zone_image->Outline(extra_colour, extra_zone); } static char filename[PATH_MAX]; - snprintf( filename, sizeof(filename), "Zones%d.jpg", id ); - zone_image->WriteJpeg( filename ); + snprintf(filename, sizeof(filename), "Zones%d.jpg", id); + zone_image->WriteJpeg(filename); delete zone_image; -} +} // end void Monitor::DumpZoneImage(const char *zone_string) -void Monitor::DumpImage( Image *dump_image ) const { +void Monitor::DumpImage(Image *dump_image) const { if ( image_count && !(image_count%10) ) { static char filename[PATH_MAX]; static char new_filename[PATH_MAX]; - snprintf( filename, sizeof(filename), "Monitor%d.jpg", id ); - snprintf( new_filename, sizeof(new_filename), "Monitor%d-new.jpg", id ); - if ( dump_image->WriteJpeg( new_filename ) ) - rename( new_filename, filename ); + snprintf(filename, sizeof(filename), "Monitor%d.jpg", id); + snprintf(new_filename, sizeof(new_filename), "Monitor%d-new.jpg", id); + if ( dump_image->WriteJpeg(new_filename) ) + rename(new_filename, filename); } -} +} // end void Monitor::DumpImage(Image *dump_image) -bool Monitor::CheckSignal( const Image *image ) { +bool Monitor::CheckSignal(const Image *image) { static bool static_undef = true; /* RGB24 colors */ static uint8_t red_val; @@ -1241,11 +1248,11 @@ bool Monitor::CheckSignal( const Image *image ) { } } } // end for < signal_check_points - Debug(1,"SignalCheck: %d points, colour_val(%d)", signal_check_points, colour_val); + Debug(1, "SignalCheck: %d points, colour_val(%d)", signal_check_points, colour_val); return false; } // end if signal_check_points return true; -} +} // end bool Monitor::CheckSignal(const Image *image) bool Monitor::Analyse() { if ( shared_data->last_read_index == shared_data->last_write_index ) { @@ -1299,7 +1306,7 @@ bool Monitor::Analyse() { index = (shared_data->last_read_index+step)%image_buffer_count; } else { if ( pending_frames ) { - Warning( "Approaching buffer overrun, consider slowing capture, simplifying analysis or increasing ring buffer size" ); + Warning("Approaching buffer overrun, consider slowing capture, simplifying analysis or increasing ring buffer size"); } index = shared_data->last_write_index%image_buffer_count; } @@ -1382,9 +1389,9 @@ bool Monitor::Analyse() { signalText = "Reacquired"; score += 100; } - Warning( "%s: %s", SIGNAL_CAUSE, signalText ); + Warning("%s: %s", SIGNAL_CAUSE, signalText); if ( event && !signal ) { - Info( "%s: %03d - Closing event %" PRIu64 ", signal loss", name, image_count, event->Id() ); + Info("%s: %03d - Closing event %" PRIu64 ", signal loss", name, image_count, event->Id()); closeEvent(); } if ( !event ) { @@ -1456,8 +1463,11 @@ bool Monitor::Analyse() { if ( event ) { Debug(3, "Have signal and recording with open event at (%d.%d)", timestamp->tv_sec, timestamp->tv_usec); - if ( section_length && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length ) ) { - Info( "%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d", + if ( section_length + && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length ) + && ( ! ( timestamp->tv_sec % section_length ) ) + ) { + Info("%s: %03d - Closing event %" PRIu64 ", section end forced %d - %d = %d >= %d", name, image_count, event->Id(), timestamp->tv_sec, video_store_data->recording.tv_sec, timestamp->tv_sec - video_store_data->recording.tv_sec, @@ -1476,7 +1486,7 @@ bool Monitor::Analyse() { snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); video_store_data->recording = event->StartTime(); - Info( "%s: %03d - Opening new event %" PRIu64 ", section start", name, image_count, event->Id() ); + Info("%s: %03d - Opening new event %" PRIu64 ", section start", name, image_count, event->Id()); /* To prevent cancelling out an existing alert\prealarm\alarm state */ if ( state == IDLE ) { @@ -1537,17 +1547,27 @@ bool Monitor::Analyse() { if ( score ) { if ( state == IDLE || state == TAPE || state == PREALARM ) { if ( (!pre_event_count) || (Event::PreAlarmCount() >= alarm_frame_count) ) { - Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u", - name, image_count, Event::PreAlarmCount(), alarm_frame_count); shared_data->state = state = ALARM; + // lets construct alarm cause. It will contain cause + names of zones alarmed + std::string alarm_cause=""; + for ( int i=0; i < n_zones; i++) { + if (zones[i]->Alarmed()) { + alarm_cause = alarm_cause+ ","+ std::string(zones[i]->Label()); + } + } + if (!alarm_cause.empty()) alarm_cause[0]=' '; + alarm_cause = cause+alarm_cause; + strncpy(shared_data->alarm_cause,alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1); + Info("%s: %03d - Gone into alarm state PreAlarmCount: %u > AlarmFrameCount:%u Cause:%s", + name, image_count, Event::PreAlarmCount(), alarm_frame_count, shared_data->alarm_cause); if ( signal_change || (function != MOCORD && state != ALERT) ) { int pre_index; int pre_event_images = pre_event_count; -if ( event ) { -// SHouldn't be able to happen because -Error("Creating new event when one exists"); -} + if ( event ) { + // Shouldn't be able to happen because + Error("Creating new event when one exists"); + } if ( analysis_fps && pre_event_count ) { // If analysis fps is set, // compute the index for pre event images in the dedicated buffer @@ -1584,23 +1604,12 @@ Error("Creating new event when one exists"); event = new Event(this, *(image_buffer[pre_index].timestamp), cause, noteSetMap); } shared_data->last_event = event->Id(); - // lets construct alarm cause. It will contain cause + names of zones alarmed - std::string alarm_cause=""; - for ( int i=0; i < n_zones; i++) { - if (zones[i]->Alarmed()) { - alarm_cause += std::string(zones[i]->Label()); - if (i < n_zones-1) { - alarm_cause +=","; - } - } - } - alarm_cause = cause+" "+alarm_cause; - strncpy(shared_data->alarm_cause,alarm_cause.c_str(), sizeof(shared_data->alarm_cause)-1); + //set up video store data snprintf(video_store_data->event_file, sizeof(video_store_data->event_file), "%s", event->getEventFile()); video_store_data->recording = event->StartTime(); - Info( "%s: %03d - Opening new event %" PRIu64 ", alarm start", name, image_count, event->Id() ); + Info("%s: %03d - Opening new event %" PRIu64 ", alarm start", name, image_count, event->Id()); if ( pre_event_images ) { if ( analysis_fps ) { @@ -1623,31 +1632,34 @@ Error("Creating new event when one exists"); } } } else if ( state != PREALARM ) { - Info( "%s: %03d - Gone into prealarm state", name, image_count ); + Info("%s: %03d - Gone into prealarm state", name, image_count); shared_data->state = state = PREALARM; } } else if ( state == ALERT ) { - Info( "%s: %03d - Gone back into alarm state", name, image_count ); + Info("%s: %03d - Gone back into alarm state", name, image_count); shared_data->state = state = ALARM; } last_alarm_count = image_count; } else { if ( state == ALARM ) { - Info( "%s: %03d - Gone into alert state", name, image_count ); + Info("%s: %03d - Gone into alert state", name, image_count); shared_data->state = state = ALERT; } else if ( state == ALERT ) { if ( image_count-last_alarm_count > post_event_count ) { - Info( "%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", name, image_count, event->Id(), event->Frames(), event->AlarmFrames() ); + Info("%s: %03d - Left alarm state (%" PRIu64 ") - %d(%d) images", + name, image_count, event->Id(), event->Frames(), event->AlarmFrames()); //if ( function != MOCORD || event_close_mode == CLOSE_ALARM || event->Cause() == SIGNAL_CAUSE ) if ( function != MOCORD || event_close_mode == CLOSE_ALARM ) { shared_data->state = state = IDLE; - Info( "%s: %03d - Closing event %" PRIu64 ", alarm end%s", name, image_count, event->Id(), (function==MOCORD)?", section truncated":"" ); + Info("%s: %03d - Closing event %" PRIu64 ", alarm end%s", + name, image_count, event->Id(), (function==MOCORD)?", section truncated":""); closeEvent(); } else { shared_data->state = state = TAPE; } } - } + } // end if ALARM or ALERT + if ( state == PREALARM ) { if ( function != MOCORD ) { shared_data->state = state = IDLE; @@ -1666,57 +1678,60 @@ Error("Creating new event when one exists"); for( int i = 0; i < n_zones; i++ ) { if ( zones[i]->Alarmed() ) { if ( zones[i]->AlarmImage() ) { - alarm_image.Overlay( *(zones[i]->AlarmImage()) ); + alarm_image.Overlay(*(zones[i]->AlarmImage())); got_anal_image = true; } if ( config.record_event_stats && state == ALARM ) { - zones[i]->RecordStats( event ); + zones[i]->RecordStats(event); } } - } + } // end foreach zone + if ( got_anal_image ) { if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score, &alarm_image ); + Event::AddPreAlarmFrame(snap_image, *timestamp, score, &alarm_image); else - event->AddFrame( snap_image, *timestamp, score, &alarm_image ); + event->AddFrame(snap_image, *timestamp, score, &alarm_image); } else { if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score ); + Event::AddPreAlarmFrame(snap_image, *timestamp, score); else - event->AddFrame( snap_image, *timestamp, score ); + event->AddFrame(snap_image, *timestamp, score); } } else { - for( int i = 0; i < n_zones; i++ ) { + for ( int i = 0; i < n_zones; i++ ) { if ( zones[i]->Alarmed() ) { if ( config.record_event_stats && state == ALARM ) { - zones[i]->RecordStats( event ); + zones[i]->RecordStats(event); } } } if ( state == PREALARM ) - Event::AddPreAlarmFrame( snap_image, *timestamp, score ); + Event::AddPreAlarmFrame(snap_image, *timestamp, score); else - event->AddFrame( snap_image, *timestamp, score ); + event->AddFrame(snap_image, *timestamp, score); } - if ( event && noteSetMap.size() > 0 ) - event->updateNotes( noteSetMap ); + if ( event ) { + if ( noteSetMap.size() > 0 ) + event->updateNotes(noteSetMap); - if ( section_length - && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length ) - && ! (image_count % fps_report_interval) - ) { - Warning( "%s: %03d - event %" PRIu64 ", has exceeded desired section length. %d - %d = %d >= %d", - name, image_count, event->Id(), - timestamp->tv_sec, video_store_data->recording.tv_sec, - timestamp->tv_sec - video_store_data->recording.tv_sec, - section_length - ); - } + if ( section_length + && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length ) + && ! (image_count % fps_report_interval) + ) { + Warning("%s: %03d - event %" PRIu64 ", has exceeded desired section length. %d - %d = %d >= %d", + name, image_count, event->Id(), + timestamp->tv_sec, video_store_data->recording.tv_sec, + timestamp->tv_sec - video_store_data->recording.tv_sec, + section_length + ); + } + } // end if event } else if ( state == ALERT ) { - event->AddFrame( snap_image, *timestamp ); + event->AddFrame(snap_image, *timestamp); if ( noteSetMap.size() > 0 ) - event->updateNotes( noteSetMap ); + event->updateNotes(noteSetMap); } else if ( state == TAPE ) { //Video Storage: activate only for supported cameras. Event::AddFrame knows whether or not we are recording video and saves frames accordingly //if((GetOptVideoWriter() == 2) && camera->SupportsNativeVideo()) { @@ -1726,9 +1741,9 @@ Error("Creating new event when one exists"); //} if ( (!frame_skip) || !(image_count%(frame_skip+1)) ) { if ( config.bulk_frame_interval > 1 ) { - event->AddFrame( snap_image, *timestamp, (event->Frames()AddFrame(snap_image, *timestamp, (event->Frames()AddFrame( snap_image, *timestamp ); + event->AddFrame(snap_image, *timestamp); } } } @@ -1761,25 +1776,25 @@ Error("Creating new event when one exists"); // If analysis fps is set, add analysed image to dedicated pre event buffer int pre_index = image_count%pre_event_buffer_count; pre_event_buffer[pre_index].image->Assign(*snap->image); - memcpy( pre_event_buffer[pre_index].timestamp, snap->timestamp, sizeof(struct timeval) ); + memcpy(pre_event_buffer[pre_index].timestamp, snap->timestamp, sizeof(struct timeval)); } image_count++; return true; -} +} // end Monitor::Analyze void Monitor::Reload() { - Debug( 1, "Reloading monitor %s", name ); + Debug(1, "Reloading monitor %s", name); if ( event ) { - Info( "%s: %03d - Closing event %" PRIu64 ", reloading", name, image_count, event->Id() ); + Info("%s: %03d - Closing event %" PRIu64 ", reloading", name, image_count, event->Id()); closeEvent(); } static char sql[ZM_SQL_MED_BUFSIZ]; // This seems to have fallen out of date. - snprintf( sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id ); + snprintf(sql, sizeof(sql), "select Function+0, Enabled, LinkedMonitors, EventPrefix, LabelFormat, LabelX, LabelY, LabelSize, WarmupCount, PreEventCount, PostEventCount, AlarmFrameCount, SectionLength, FrameSkip, MotionFrameSkip, AnalysisFPSLimit, AnalysisUpdateDelay, MaxFPS, AlarmMaxFPS, FPSReportInterval, RefBlendPerc, AlarmRefBlendPerc, TrackMotion, SignalCheckColour from Monitors where Id = '%d'", id); zmDbRow *row = zmDbFetchOne(sql); if ( !row ) { @@ -1791,13 +1806,13 @@ void Monitor::Reload() { const char *p_linked_monitors = dbrow[index++]; if ( dbrow[index] ) { - strncpy( event_prefix, dbrow[index++], sizeof(event_prefix)-1 ); + strncpy(event_prefix, dbrow[index++], sizeof(event_prefix)-1); } else { event_prefix[0] = 0; index++; } if ( dbrow[index] ) { - strncpy( label_format, dbrow[index++], sizeof(label_format)-1 ); + strncpy(label_format, dbrow[index++], sizeof(label_format)-1); } else { label_format[0] = 0; index++; @@ -1840,23 +1855,23 @@ void Monitor::Reload() { } // end if row ReloadZones(); -} +} // end void Monitor::Reload() void Monitor::ReloadZones() { - Debug( 1, "Reloading zones for monitor %s", name ); - for( int i = 0; i < n_zones; i++ ) { + Debug(1, "Reloading zones for monitor %s", name); + for ( int i = 0; i < n_zones; i++ ) { delete zones[i]; } delete[] zones; zones = 0; - n_zones = Zone::Load( this, zones ); + n_zones = Zone::Load(this, zones); //DumpZoneImage(); -} +} // end void Monitor::ReloadZones() void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { Debug(1, "Reloading linked monitors for monitor %s, '%s'", name, p_linked_monitors); if ( n_linked_monitors ) { - for( int i = 0; i < n_linked_monitors; i++ ) { + for ( int i = 0; i < n_linked_monitors; i++ ) { delete linked_monitors[i]; } delete[] linked_monitors; @@ -1871,9 +1886,9 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { char link_id_str[8]; char *dest_ptr = link_id_str; const char *src_ptr = p_linked_monitors; - while( 1 ) { + while ( 1 ) { dest_ptr = link_id_str; - while( *src_ptr >= '0' && *src_ptr <= '9' ) { + while ( *src_ptr >= '0' && *src_ptr <= '9' ) { if ( (dest_ptr-link_id_str) < (unsigned int)(sizeof(link_id_str)-1) ) { *dest_ptr++ = *src_ptr++; } else { @@ -1952,10 +1967,10 @@ int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) return 0; } int n_monitors = mysql_num_rows(result); - Debug( 1, "Got %d monitors", n_monitors ); + Debug(1, "Got %d monitors", n_monitors); delete[] monitors; monitors = new Monitor *[n_monitors]; - for( int i=0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + for ( int i=0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { monitors[i] = Monitor::Load(dbrow, 1, purpose); } if ( mysql_errno(&dbconn) ) { @@ -1965,10 +1980,10 @@ int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) mysql_free_result(result); return n_monitors; -} +} // end int Monitor::LoadMonitors(std::string sql, Monitor **&monitors, Purpose purpose) #if ZM_HAS_V4L -int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose purpose ) { +int Monitor::LoadLocalMonitors(const char *device, Monitor **&monitors, Purpose purpose) { std::string sql = load_monitor_sql + " WHERE Function != 'None' AND Type = 'Local'"; @@ -1977,28 +1992,28 @@ int Monitor::LoadLocalMonitors( const char *device, Monitor **&monitors, Purpose if ( staticConfig.SERVER_ID ) sql += stringtf(" AND ServerId=%d", staticConfig.SERVER_ID); return LoadMonitors(sql, monitors, purpose); -} +} // end int Monitor::LoadLocalMonitors(const char *device, Monitor **&monitors, Purpose purpose) #endif // ZM_HAS_V4L -int Monitor::LoadRemoteMonitors( const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose ) { +int Monitor::LoadRemoteMonitors(const char *protocol, const char *host, const char *port, const char *path, Monitor **&monitors, Purpose purpose) { std::string sql = load_monitor_sql + " WHERE Function != 'None' AND Type = 'Remote'"; if ( staticConfig.SERVER_ID ) - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); + sql += stringtf(" AND ServerId=%d", staticConfig.SERVER_ID); if ( protocol ) - sql += stringtf(" AND Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path ); + sql += stringtf(" AND Protocol = '%s' and Host = '%s' and Port = '%s' and Path = '%s'", protocol, host, port, path); return LoadMonitors(sql, monitors, purpose); -} +} // end int Monitor::LoadRemoteMonitors -int Monitor::LoadFileMonitors( const char *file, Monitor **&monitors, Purpose purpose ) { +int Monitor::LoadFileMonitors(const char *file, Monitor **&monitors, Purpose purpose) { std::string sql = load_monitor_sql + " WHERE Function != 'None' AND Type = 'File'"; if ( file[0] ) sql += " AND Path='" + std::string(file) + "'"; if ( staticConfig.SERVER_ID ) { - sql += stringtf( " AND ServerId=%d", staticConfig.SERVER_ID ); + sql += stringtf(" AND ServerId=%d", staticConfig.SERVER_ID); } return LoadMonitors(sql, monitors, purpose); -} +} // end int Monitor::LoadFileMonitors #if HAVE_LIBAVFORMAT int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose purpose) { @@ -2010,7 +2025,7 @@ int Monitor::LoadFfmpegMonitors(const char *file, Monitor **&monitors, Purpose p sql += stringtf(" AND ServerId=%d", staticConfig.SERVER_ID); } return LoadMonitors(sql, monitors, purpose); -} +} // end int Monitor::LoadFfmpegMonitors #endif // HAVE_LIBAVFORMAT /* @@ -2065,7 +2080,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { } else { v4l_captures_per_frame = config.captures_per_frame; } - Debug( 1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame ); + Debug(1, "Got %d for v4l_captures_per_frame", v4l_captures_per_frame); col++; std::string protocol = dbrow[col] ? dbrow[col] : ""; col++; @@ -2186,7 +2201,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { } #endif // HAVE_LIBAVFORMAT else { - Fatal( "Unexpected remote camera protocol '%s'", protocol.c_str() ); + Fatal("Unexpected remote camera protocol '%s'", protocol.c_str()); } } else if ( type == "File" ) { camera = new FileCamera( @@ -2254,7 +2269,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { record_audio ); #else // HAVE_LIBVLC - Fatal( "You must have vlc libraries installed to use vlc cameras for monitor %d", id ); + Fatal("You must have vlc libraries installed to use vlc cameras for monitor %d", id); #endif // HAVE_LIBVLC } else if ( type == "cURL" ) { #if HAVE_LIBCURL @@ -2274,13 +2289,13 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { record_audio ); #else // HAVE_LIBCURL - Fatal( "You must have libcurl installed to use ffmpeg cameras for monitor %d", id ); + Fatal("You must have libcurl installed to use ffmpeg cameras for monitor %d", id); #endif // HAVE_LIBCURL } else { - Fatal( "Bogus monitor type '%s' for monitor %d", type.c_str(), id ); + Fatal("Bogus monitor type '%s' for monitor %d", type.c_str(), id); } // end if type - Monitor *monitor = new Monitor( + Monitor *monitor = new Monitor( id, name, server_id, @@ -2322,7 +2337,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { purpose, 0, 0 - ); + ); camera->setMonitor(monitor); Zone **zones = 0; int n_zones = Zone::Load(monitor, zones); @@ -2330,7 +2345,7 @@ Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) { monitor->AddPrivacyBitmask(zones); Debug(1, "Loaded monitor %d(%s), %d zones", id, name, n_zones); return monitor; -} +} // end Monitor *Monitor::Load(MYSQL_ROW dbrow, bool load_zones, Purpose purpose) Monitor *Monitor::Load(unsigned int p_id, bool load_zones, Purpose purpose) { std::string sql = load_monitor_sql + stringtf(" WHERE Id=%d", p_id); @@ -2394,7 +2409,7 @@ int Monitor::Capture() { /* Capture directly into image buffer, avoiding the need to memcpy() */ captureResult = camera->Capture(*capture_image); } - } + } // end if deinterlacing or not if ( captureResult < 0 ) { Info("Return from Capture (%d), signal loss", captureResult); @@ -2416,54 +2431,53 @@ int Monitor::Capture() { } else if ( deinterlacing_value == 3 ) { capture_image->Deinterlace_Blend(); } else if ( deinterlacing_value == 4 ) { - capture_image->Deinterlace_4Field( next_buffer.image, (deinterlacing>>8)&0xff ); + capture_image->Deinterlace_4Field(next_buffer.image, (deinterlacing>>8)&0xff); } else if ( deinterlacing_value == 5 ) { - capture_image->Deinterlace_Blend_CustomRatio( (deinterlacing>>8)&0xff ); + capture_image->Deinterlace_Blend_CustomRatio((deinterlacing>>8)&0xff); } if ( orientation != ROTATE_0 ) { switch ( orientation ) { - case ROTATE_0 : { + case ROTATE_0 : // No action required break; - } case ROTATE_90 : case ROTATE_180 : - case ROTATE_270 : { - capture_image->Rotate( (orientation-1)*90 ); + case ROTATE_270 : + capture_image->Rotate((orientation-1)*90); break; - } case FLIP_HORI : - case FLIP_VERT : { - capture_image->Flip( orientation==FLIP_HORI ); + case FLIP_VERT : + capture_image->Flip(orientation==FLIP_HORI); break; - } } } // end if have rotation if ( capture_image->Size() > camera->ImageSize() ) { - Error( "Captured image %d does not match expected size %d check width, height and colour depth",capture_image->Size(),camera->ImageSize() ); + Error("Captured image %d does not match expected size %d check width, height and colour depth", + capture_image->Size(),camera->ImageSize() ); return -1; } if ( (index == shared_data->last_read_index) && (function > MONITOR) ) { - Warning( "Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", index, image_count ); + Warning("Buffer overrun at index %d, image %d, slow down capture, speed up analysis or increase ring buffer size", + index, image_count ); time_t now = time(0); double approxFps = double(image_buffer_count)/double(now-image_buffer[index].timestamp->tv_sec); time_t last_read_delta = now - shared_data->last_read_time; if ( last_read_delta > (image_buffer_count/approxFps) ) { - Warning( "Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta ) + Warning("Last image read from shared memory %ld seconds ago, zma may have gone away", last_read_delta); shared_data->last_read_index = image_buffer_count; } - } + } // end if overrun if ( privacy_bitmask ) - capture_image->MaskPrivacy( privacy_bitmask ); + capture_image->MaskPrivacy(privacy_bitmask); // Might be able to remove this call, when we start passing around ZMPackets, which will already have a timestamp - gettimeofday( image_buffer[index].timestamp, NULL ); + gettimeofday(image_buffer[index].timestamp, NULL); if ( config.timestamp_on_capture ) { - TimestampImage( capture_image, image_buffer[index].timestamp ); + TimestampImage(capture_image, image_buffer[index].timestamp); } // Maybe we don't need to do this on all camera types shared_data->signal = signal_check_points ? CheckSignal(capture_image) : true; @@ -2483,7 +2497,8 @@ int Monitor::Capture() { last_camera_bytes = new_camera_bytes; //Info( "%d -> %d -> %d", fps_report_interval, now, last_fps_time ); //Info( "%d -> %d -> %lf -> %lf", now-last_fps_time, fps_report_interval/(now-last_fps_time), double(fps_report_interval)/(now-last_fps_time), fps ); - Info("%s: images:%d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec", name, image_count, new_fps, new_capture_bandwidth); + Info("%s: images:%d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec", + name, image_count, new_fps, new_capture_bandwidth); last_fps_time = now; fps = new_fps; db_mutex.lock(); @@ -2514,118 +2529,107 @@ int Monitor::Capture() { shared_data->action &= ~GET_SETTINGS; } if ( shared_data->action & SET_SETTINGS ) { - camera->Brightness( shared_data->brightness ); - camera->Hue( shared_data->hue ); - camera->Colour( shared_data->colour ); - camera->Contrast( shared_data->contrast ); + camera->Brightness(shared_data->brightness); + camera->Hue(shared_data->hue); + camera->Colour(shared_data->colour); + camera->Contrast(shared_data->contrast); shared_data->action &= ~SET_SETTINGS; } return captureResult; -} +} // end int Monitor::Capture -void Monitor::TimestampImage( Image *ts_image, const struct timeval *ts_time ) const { - if ( label_format[0] ) { - // Expand the strftime macros first - char label_time_text[256]; - strftime( label_time_text, sizeof(label_time_text), label_format, localtime( &ts_time->tv_sec ) ); +void Monitor::TimestampImage(Image *ts_image, const struct timeval *ts_time) const { + if ( !label_format[0] ) + return; - char label_text[1024]; - const char *s_ptr = label_time_text; - char *d_ptr = label_text; - while ( *s_ptr && ((d_ptr-label_text) < (unsigned int)sizeof(label_text)) ) { - if ( *s_ptr == config.timestamp_code_char[0] ) { - bool found_macro = false; - switch ( *(s_ptr+1) ) { - case 'N' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name ); - found_macro = true; - break; - case 'Q' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext ); - found_macro = true; - break; - case 'f' : - d_ptr += snprintf( d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000 ); - found_macro = true; - break; - } - if ( found_macro ) { - s_ptr += 2; - continue; - } + // Expand the strftime macros first + char label_time_text[256]; + strftime(label_time_text, sizeof(label_time_text), label_format, localtime(&ts_time->tv_sec)); + + char label_text[1024]; + const char *s_ptr = label_time_text; + char *d_ptr = label_text; + while ( *s_ptr && ((d_ptr-label_text) < (unsigned int)sizeof(label_text)) ) { + if ( *s_ptr == config.timestamp_code_char[0] ) { + bool found_macro = false; + switch ( *(s_ptr+1) ) { + case 'N' : + d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", name); + found_macro = true; + break; + case 'Q' : + d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%s", trigger_data->trigger_showtext); + found_macro = true; + break; + case 'f' : + d_ptr += snprintf(d_ptr, sizeof(label_text)-(d_ptr-label_text), "%02ld", ts_time->tv_usec/10000); + found_macro = true; + break; + } + if ( found_macro ) { + s_ptr += 2; + continue; } - *d_ptr++ = *s_ptr++; } - *d_ptr = '\0'; - ts_image->Annotate( label_text, label_coord, label_size ); - } -} + *d_ptr++ = *s_ptr++; + } // end while + *d_ptr = '\0'; + ts_image->Annotate( label_text, label_coord, label_size ); +} // end void Monitor::TimestampImage bool Monitor::closeEvent() { - if ( event ) { - if ( function == RECORD || function == MOCORD ) { - gettimeofday(&(event->EndTime()), NULL); - } - if ( event_delete_thread ) { - event_delete_thread->join(); - delete event_delete_thread; - event_delete_thread = NULL; - } + if ( !event ) + return false; + + if ( function == RECORD || function == MOCORD ) { + //FIXME Is this neccessary? ENdTime should be set in the destructor + gettimeofday(&(event->EndTime()), NULL); + } + if ( event_delete_thread ) { + event_delete_thread->join(); + delete event_delete_thread; + event_delete_thread = NULL; + } #if 0 - event_delete_thread = new std::thread([](Event *event) { + event_delete_thread = new std::thread([](Event *event) { Event * e = event; event = NULL; delete e; e = NULL; - }, event); + }, event); #else - delete event; - event = NULL; + delete event; + event = NULL; #endif - video_store_data->recording = (struct timeval){0}; - return true; - } - return false; -} + video_store_data->recording = (struct timeval){0}; + return true; +} // end bool Monitor::closeEvent() -unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &zoneSet ) { +unsigned int Monitor::DetectMotion(const Image &comp_image, Event::StringSet &zoneSet) { bool alarm = false; unsigned int score = 0; - if ( n_zones <= 0 ) return( alarm ); + if ( n_zones <= 0 ) return alarm; - Storage *storage = this->getStorage(); + ref_image.Delta(comp_image, &delta_image); if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-r.jpg", storage->Path(), id ); - } - ref_image.WriteJpeg( diag_path ); - } - - ref_image.Delta( comp_image, &delta_image ); - - if ( config.record_diag_images ) { - static char diag_path[PATH_MAX] = ""; - if ( !diag_path[0] ) { - snprintf( diag_path, sizeof(diag_path), "%s/%d/diag-d.jpg", storage->Path(), id ); - } - delta_image.WriteJpeg( diag_path ); + ref_image.WriteJpeg(diag_path_r.c_str()); + delta_image.WriteJpeg(diag_path_d.c_str()); } // Blank out all exclusion zones for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) { Zone *zone = zones[n_zone]; // need previous alarmed state for preclusive zone, so don't clear just yet - if (!zone->IsPreclusive()) + if ( !zone->IsPreclusive() ) zone->ClearAlarm(); if ( !zone->IsInactive() ) { continue; } - Debug( 3, "Blanking inactive zone %s", zone->Label() ); - delta_image.Fill( RGB_BLACK, zone->GetPolygon() ); - } + Debug(3, "Blanking inactive zone %s", zone->Label()); + delta_image.Fill(RGB_BLACK, zone->GetPolygon()); + } // end foreach zone // Check preclusive zones first for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) { @@ -2635,30 +2639,32 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z } int old_zone_score = zone->Score(); bool old_zone_alarmed = zone->Alarmed(); - Debug( 3, "Checking preclusive zone %s - old score: %d, state: %s", zone->Label(),old_zone_score, zone->Alarmed()?"alarmed":"quiet" ); - if ( zone->CheckAlarms( &delta_image ) ) { + Debug(3, "Checking preclusive zone %s - old score: %d, state: %s", + zone->Label(),old_zone_score, zone->Alarmed()?"alarmed":"quiet"); + if ( zone->CheckAlarms(&delta_image) ) { alarm = true; score += zone->Score(); zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); + Debug(3, "Zone is alarmed, zone score = %d", zone->Score()); + zoneSet.insert(zone->Label()); //zone->ResetStats(); } else { // check if end of alarm - if (old_zone_alarmed) { - Debug(3, "Preclusive Zone %s alarm Ends. Previous score: %d", zone->Label(), old_zone_score); - if (old_zone_score > 0) { + if ( old_zone_alarmed ) { + Debug(3, "Preclusive Zone %s alarm Ends. Previous score: %d", + zone->Label(), old_zone_score); + if ( old_zone_score > 0 ) { zone->SetExtendAlarmCount(zone->GetExtendAlarmFrames()); } - if (zone->CheckExtendAlarmCount()) { - alarm=true; + if ( zone->CheckExtendAlarmCount() ) { + alarm = true; zone->SetAlarm(); } else { zone->ClearAlarm(); } } - } - } + } // end if CheckAlarms + } // end foreach zone Coord alarm_centre; int top_score = -1; @@ -2673,13 +2679,13 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z if ( !zone->IsActive() || zone->IsPreclusive()) { continue; } - Debug( 3, "Checking active zone %s", zone->Label() ); - if ( zone->CheckAlarms( &delta_image ) ) { + Debug(3, "Checking active zone %s", zone->Label()); + if ( zone->CheckAlarms(&delta_image) ) { alarm = true; score += zone->Score(); zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); + Debug(3, "Zone is alarmed, zone score = %d", zone->Score()); + zoneSet.insert(zone->Label()); if ( config.opt_control && track_motion ) { if ( (int)zone->Score() > top_score ) { top_score = zone->Score(); @@ -2687,7 +2693,7 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z } } } - } + } // end foreach zone if ( alarm ) { for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) { @@ -2696,12 +2702,12 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z if ( !zone->IsInclusive() ) { continue; } - Debug( 3, "Checking inclusive zone %s", zone->Label() ); - if ( zone->CheckAlarms( &delta_image ) ) { + Debug(3, "Checking inclusive zone %s", zone->Label()); + if ( zone->CheckAlarms(&delta_image) ) { alarm = true; score += zone->Score(); zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); + Debug(3, "Zone is alarmed, zone score = %d", zone->Score()); zoneSet.insert( zone->Label() ); if ( config.opt_control && track_motion ) { if ( zone->Score() > (unsigned int)top_score ) { @@ -2709,8 +2715,8 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z alarm_centre = zone->GetAlarmCentre(); } } - } - } + } // end if CheckAlarm + } // end foreach zone } else { // Find all alarm pixels in exclusive zones for ( int n_zone = 0; n_zone < n_zones; n_zone++ ) { @@ -2718,32 +2724,33 @@ unsigned int Monitor::DetectMotion( const Image &comp_image, Event::StringSet &z if ( !zone->IsExclusive() ) { continue; } - Debug( 3, "Checking exclusive zone %s", zone->Label() ); - if ( zone->CheckAlarms( &delta_image ) ) { + Debug(3, "Checking exclusive zone %s", zone->Label()); + if ( zone->CheckAlarms(&delta_image) ) { alarm = true; score += zone->Score(); zone->SetAlarm(); - Debug( 3, "Zone is alarmed, zone score = %d", zone->Score() ); - zoneSet.insert( zone->Label() ); + Debug(3, "Zone is alarmed, zone score = %d", zone->Score()); + zoneSet.insert(zone->Label()); } - } + } // end foreach zone } // end if alarm or not - } + } // end if alarm if ( top_score > 0 ) { shared_data->alarm_x = alarm_centre.X(); shared_data->alarm_y = alarm_centre.Y(); - Info( "Got alarm centre at %d,%d, at count %d", shared_data->alarm_x, shared_data->alarm_y, image_count ); + Info("Got alarm centre at %d,%d, at count %d", + shared_data->alarm_x, shared_data->alarm_y, image_count); } else { shared_data->alarm_x = shared_data->alarm_y = -1; } // This is a small and innocent hack to prevent scores of 0 being returned in alarm state - return( score?score:alarm ); -} + return score ? score : alarm; +} // end MotionDetect -bool Monitor::DumpSettings( char *output, bool verbose ) { +bool Monitor::DumpSettings(char *output, bool verbose) { output[0] = 0; sprintf( output+strlen(output), "Id : %d\n", id ); @@ -2821,9 +2828,9 @@ Monitor::Snapshot *Monitor::getSnapshot() const { return &image_buffer[ shared_data->last_write_index%image_buffer_count ]; } -std::vector Monitor::Groups() { +std::vector Monitor::Groups() { // At the moment, only load groups once. - if ( ! groups.size() ) { + if ( !groups.size() ) { std::string sql = stringtf( "SELECT Id,ParentId,Name FROM Groups WHERE Groups.Id IN " "(SELECT GroupId FROM Groups_Monitors WHERE MonitorId=%d)",id); @@ -2843,14 +2850,13 @@ std::vector Monitor::Groups() { mysql_free_result(result); } return groups; -} +} // end Monitor::Groups() StringVector Monitor::GroupNames() { StringVector groupnames; - for(Group * g: Groups()) { + for ( Group * g: Groups() ) { groupnames.push_back(std::string(g->Name())); -Debug(1,"Groups: %s", g->Name()); + Debug(1,"Groups: %s", g->Name()); } return groupnames; -} - +} // end Monitor::GroupNames() diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 8856e4b26..f3927144c 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -291,40 +291,42 @@ protected: bool last_signal; - double fps; - unsigned int last_camera_bytes; + double fps; + unsigned int last_camera_bytes; - Image delta_image; - Image ref_image; - Image alarm_image; // Used in creating analysis images, will be initialized in Analysis - Image write_image; // Used when creating snapshot images + Image delta_image; + Image ref_image; + Image alarm_image; // Used in creating analysis images, will be initialized in Analysis + Image write_image; // Used when creating snapshot images + std::string diag_path_r; + std::string diag_path_d; Purpose purpose; // What this monitor has been created to do - int event_count; - int image_count; - int ready_count; - int first_alarm_count; - int last_alarm_count; - int buffer_count; - int prealarm_count; - State state; - time_t start_time; - time_t last_fps_time; - time_t auto_resume_time; + int event_count; + int image_count; + int ready_count; + int first_alarm_count; + int last_alarm_count; + int buffer_count; + int prealarm_count; + State state; + time_t start_time; + time_t last_fps_time; + time_t auto_resume_time; unsigned int last_motion_score; EventCloseMode event_close_mode; #if ZM_MEM_MAPPED - int map_fd; - char mem_file[PATH_MAX]; + int map_fd; + char mem_file[PATH_MAX]; #else // ZM_MEM_MAPPED - int shm_id; + int shm_id; #endif // ZM_MEM_MAPPED - off_t mem_size; - unsigned char *mem_ptr; - SharedData *shared_data; - TriggerData *trigger_data; + off_t mem_size; + unsigned char *mem_ptr; + SharedData *shared_data; + TriggerData *trigger_data; VideoStoreData *video_store_data; Snapshot *image_buffer; diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 7e2143203..1f94f4849 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -28,7 +28,22 @@ #include #include -RemoteCameraRtsp::RemoteCameraRtsp( unsigned int p_monitor_id, const std::string &p_method, const std::string &p_host, const std::string &p_port, const std::string &p_path, int p_width, int p_height, bool p_rtsp_describe, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : +RemoteCameraRtsp::RemoteCameraRtsp( + unsigned int p_monitor_id, + const std::string &p_method, + const std::string &p_host, + const std::string &p_port, + const std::string &p_path, + int p_width, + int p_height, + bool p_rtsp_describe, + int p_colours, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio ) : RemoteCamera( p_monitor_id, "rtsp", p_host, p_port, p_path, p_width, p_height, p_colours, p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), rtsp_describe( p_rtsp_describe ), rtspThread( 0 ) @@ -63,13 +78,13 @@ RemoteCameraRtsp::RemoteCameraRtsp( unsigned int p_monitor_id, const std::string mConvertContext = NULL; #endif /* Has to be located inside the constructor so other components such as zma will receive correct colours and subpixel order */ - if(colours == ZM_COLOUR_RGB32) { + if ( colours == ZM_COLOUR_RGB32 ) { subpixelorder = ZM_SUBPIX_ORDER_RGBA; imagePixFormat = AV_PIX_FMT_RGBA; - } else if(colours == ZM_COLOUR_RGB24) { + } else if ( colours == ZM_COLOUR_RGB24 ) { subpixelorder = ZM_SUBPIX_ORDER_RGB; imagePixFormat = AV_PIX_FMT_RGB24; - } else if(colours == ZM_COLOUR_GRAY8) { + } else if ( colours == ZM_COLOUR_GRAY8 ) { subpixelorder = ZM_SUBPIX_ORDER_NONE; imagePixFormat = AV_PIX_FMT_GRAY8; } else { @@ -169,7 +184,7 @@ int RemoteCameraRtsp::PrimeCapture() { } else { Debug(2, "Have another video stream." ); } - } + } else #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) if ( mFormatContext->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO ) #else @@ -181,6 +196,8 @@ int RemoteCameraRtsp::PrimeCapture() { } else { Debug(2, "Have another audio stream." ); } + } else { + Debug(1, "Have unknown codec type in stream %d : %d", i, mFormatContext->streams[i]->codec->codec_type); } } // end foreach stream diff --git a/src/zm_remote_camera_rtsp.h b/src/zm_remote_camera_rtsp.h index b3e392a77..5fa5a0778 100644 --- a/src/zm_remote_camera_rtsp.h +++ b/src/zm_remote_camera_rtsp.h @@ -34,8 +34,7 @@ // accessed over a network connection using rtsp protocol // (Real Time Streaming Protocol) // -class RemoteCameraRtsp : public RemoteCamera -{ +class RemoteCameraRtsp : public RemoteCamera { protected: struct sockaddr_in rtsp_sa; struct sockaddr_in rtcp_sa; diff --git a/src/zm_rtp_ctrl.cpp b/src/zm_rtp_ctrl.cpp index b586c979f..bc6725c5d 100644 --- a/src/zm_rtp_ctrl.cpp +++ b/src/zm_rtp_ctrl.cpp @@ -28,12 +28,12 @@ #include -RtpCtrlThread::RtpCtrlThread( RtspThread &rtspThread, RtpSource &rtpSource ) : mRtspThread( rtspThread ), mRtpSource( rtpSource ), mStop( false ) +RtpCtrlThread::RtpCtrlThread( RtspThread &rtspThread, RtpSource &rtpSource ) + : mRtspThread( rtspThread ), mRtpSource( rtpSource ), mStop( false ) { } -int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen ) -{ +int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen ) { const RtcpPacket *rtcpPacket; rtcpPacket = (RtcpPacket *)packet; @@ -48,33 +48,24 @@ int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen ) int pt = rtcpPacket->header.pt; int len = ntohs(rtcpPacket->header.lenN); - Debug( 5, "RTCP Ver: %d", ver ); - Debug( 5, "RTCP Count: %d", count ); - Debug( 5, "RTCP Pt: %d", pt ); - Debug( 5, "RTCP len: %d", len ); + Debug( 5, "RTCP Ver: %d Count: %d Pt: %d len: %d", ver, count, pt, len); - switch( pt ) - { + switch( pt ) { case RTCP_SR : { uint32_t ssrc = ntohl(rtcpPacket->body.sr.ssrcN); Debug( 5, "RTCP Got SR (%x)", ssrc ); - if ( mRtpSource.getSsrc() ) - { - if ( ssrc != mRtpSource.getSsrc() ) - { + if ( mRtpSource.getSsrc() ) { + if ( ssrc != mRtpSource.getSsrc() ) { Warning( "Discarding packet for unrecognised ssrc %x", ssrc ); return( -1 ); } - } - else if ( ssrc ) - { + } else if ( ssrc ) { mRtpSource.setSsrc( ssrc ); } - if ( len > 1 ) - { + if ( len > 1 ) { //printf( "NTPts:%d.%d, RTPts:%d\n", $ntptsmsb, $ntptslsb, $rtpts ); uint16_t ntptsmsb = ntohl(rtcpPacket->body.sr.ntpSecN); uint16_t ntptslsb = ntohl(rtcpPacket->body.sr.ntpFracN); @@ -89,25 +80,21 @@ int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen ) case RTCP_SDES : { ssize_t contentLen = packetLen - sizeof(rtcpPacket->header); - while ( contentLen ) - { + while ( contentLen ) { Debug( 5, "RTCP CL: %zd", contentLen ); uint32_t ssrc = ntohl(rtcpPacket->body.sdes.srcN); Debug( 5, "RTCP Got SDES (%x), %d items", ssrc, count ); - if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) - { + if ( mRtpSource.getSsrc() && (ssrc != mRtpSource.getSsrc()) ) { Warning( "Discarding packet for unrecognised ssrc %x", ssrc ); return( -1 ); } unsigned char *sdesPtr = (unsigned char *)&rtcpPacket->body.sdes.item; - for ( int i = 0; i < count; i++ ) - { + for ( int i = 0; i < count; i++ ) { RtcpSdesItem *item = (RtcpSdesItem *)sdesPtr; Debug( 5, "RTCP Item length %d", item->len ); - switch( item->type ) - { + switch( item->type ) { case RTCP_SDES_CNAME : { std::string cname( item->data, item->len ); @@ -123,50 +110,39 @@ int RtpCtrlThread::recvPacket( const unsigned char *packet, ssize_t packetLen ) case RTCP_SDES_NOTE : case RTCP_SDES_PRIV : default : - { Error( "Received unexpected SDES item type %d, ignoring", item->type ); - return( -1 ); - } + return -1; } int paddedLen = 4+2+item->len+1; // Add null byte paddedLen = (((paddedLen-1)/4)+1)*4; // Round to nearest multiple of 4 - Debug( 5, "RTCP PL:%d", paddedLen ); + Debug(5, "RTCP PL:%d", paddedLen); sdesPtr += paddedLen; contentLen = ( paddedLen <= contentLen ) ? ( contentLen - paddedLen ) : 0; } - } + } // end whiel contentLen break; } case RTCP_BYE : - { - Debug( 5, "RTCP Got BYE" ); + Debug(5, "RTCP Got BYE"); mStop = true; break; - } case RTCP_APP : - { // Ignoring as per RFC 3550 - Debug( 5, "Received RTCP_APP packet, ignoring."); + Debug(5, "Received RTCP_APP packet, ignoring."); break; - } case RTCP_RR : - { - Error( "Received RTCP_RR packet." ); - return( -1 ); - } + Error("Received RTCP_RR packet."); + return -1; default : - { // Ignore unknown packet types. Some cameras do this by design. - Debug( 5, "Received unexpected packet type %d, ignoring", pt ); + Debug(5, "Received unexpected packet type %d, ignoring", pt); break; - } } consumed = sizeof(uint32_t)*(len+1); - return( consumed ); + return consumed; } -int RtpCtrlThread::generateRr( const unsigned char *packet, ssize_t packetLen ) -{ +int RtpCtrlThread::generateRr( const unsigned char *packet, ssize_t packetLen ) { RtcpPacket *rtcpPacket = (RtcpPacket *)packet; int byteLen = sizeof(rtcpPacket->header)+sizeof(rtcpPacket->body.rr)+sizeof(rtcpPacket->body.rr.rr[0]); @@ -180,11 +156,13 @@ int RtpCtrlThread::generateRr( const unsigned char *packet, ssize_t packetLen ) mRtpSource.updateRtcpStats(); - Debug( 5, "Ssrc = %d", mRtspThread.getSsrc()+1 ); - Debug( 5, "Ssrc_1 = %d", mRtpSource.getSsrc() ); - Debug( 5, "Last Seq = %d", mRtpSource.getMaxSeq() ); - Debug( 5, "Jitter = %d", mRtpSource.getJitter() ); - Debug( 5, "Last SR = %d", mRtpSource.getLastSrTimestamp() ); + Debug(5, "Ssrc = %d Ssrc_1 = %d Last Seq = %d Jitter = %d Last SR = %d", + mRtspThread.getSsrc()+1, + mRtpSource.getSsrc(), + mRtpSource.getMaxSeq(), + mRtpSource.getJitter(), + mRtpSource.getLastSrTimestamp() + ); rtcpPacket->body.rr.ssrcN = htonl(mRtspThread.getSsrc()+1); rtcpPacket->body.rr.rr[0].ssrcN = htonl(mRtpSource.getSsrc()); @@ -195,11 +173,10 @@ int RtpCtrlThread::generateRr( const unsigned char *packet, ssize_t packetLen ) rtcpPacket->body.rr.rr[0].lsrN = htonl(mRtpSource.getLastSrTimestamp()); rtcpPacket->body.rr.rr[0].dlsrN = 0; - return( wordLen*sizeof(uint32_t) ); -} + return wordLen*sizeof(uint32_t); +} // end RtpCtrlThread::generateRr -int RtpCtrlThread::generateSdes( const unsigned char *packet, ssize_t packetLen ) -{ +int RtpCtrlThread::generateSdes( const unsigned char *packet, ssize_t packetLen ) { RtcpPacket *rtcpPacket = (RtcpPacket *)packet; const std::string &cname = mRtpSource.getCname(); @@ -218,11 +195,10 @@ int RtpCtrlThread::generateSdes( const unsigned char *packet, ssize_t packetLen rtcpPacket->body.sdes.item[0].len = cname.size(); memcpy( rtcpPacket->body.sdes.item[0].data, cname.data(), cname.size() ); - return( wordLen*sizeof(uint32_t) ); -} + return wordLen*sizeof(uint32_t); +} // end RtpCtrlThread::generateSdes -int RtpCtrlThread::generateBye( const unsigned char *packet, ssize_t packetLen ) -{ +int RtpCtrlThread::generateBye( const unsigned char *packet, ssize_t packetLen ) { RtcpPacket *rtcpPacket = (RtcpPacket *)packet; int byteLen = sizeof(rtcpPacket->header)+sizeof(rtcpPacket->body.bye)+sizeof(rtcpPacket->body.bye.srcN[0]); @@ -236,11 +212,10 @@ int RtpCtrlThread::generateBye( const unsigned char *packet, ssize_t packetLen ) rtcpPacket->body.bye.srcN[0] = htonl(mRtpSource.getSsrc()); - return( wordLen*sizeof(uint32_t) ); -} + return wordLen*sizeof(uint32_t); +} // end RtpCtrolThread::generateBye -int RtpCtrlThread::recvPackets( unsigned char *buffer, ssize_t nBytes ) -{ +int RtpCtrlThread::recvPackets( unsigned char *buffer, ssize_t nBytes ) { unsigned char *bufferPtr = buffer; // u_int32 len; /* length of compound RTCP packet in words */ @@ -259,33 +234,28 @@ int RtpCtrlThread::recvPackets( unsigned char *buffer, ssize_t nBytes ) // /* something wrong with packet format */ // } - while ( nBytes > 0 ) - { + while ( nBytes > 0 ) { int consumed = recvPacket( bufferPtr, nBytes ); if ( consumed <= 0 ) break; bufferPtr += consumed; nBytes -= consumed; } - return( nBytes ); + return nBytes; } -int RtpCtrlThread::run() -{ +int RtpCtrlThread::run() { Debug( 2, "Starting control thread %x on port %d", mRtpSource.getSsrc(), mRtpSource.getLocalCtrlPort() ); SockAddrInet localAddr, remoteAddr; bool sendReports; UdpInetSocket rtpCtrlServer; - if ( mRtpSource.getLocalHost() != "" ) - { + if ( mRtpSource.getLocalHost() != "" ) { if ( !rtpCtrlServer.bind( mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalCtrlPort() ) ) Fatal( "Failed to bind RTCP server" ); sendReports = false; Debug( 3, "Bound to %s:%d", mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalCtrlPort() ); - } - else - { + } else { if ( !rtpCtrlServer.bind( mRtspThread.getAddressFamily() == AF_INET6 ? "::" : "0.0.0.0", mRtpSource.getLocalCtrlPort() ) ) Fatal( "Failed to bind RTCP server" ); Debug( 3, "Bound to %s:%d", mRtpSource.getLocalHost().c_str(), mRtpSource.getLocalCtrlPort() ); @@ -309,17 +279,17 @@ int RtpCtrlThread::run() time_t now = time(NULL); Select::CommsList readable = select.getReadable(); - if ( readable.size() == 0 ) - { + if ( readable.size() == 0 ) { if ( ! timeout ) { // With this code here, we will send an SDES and RR packet every 10 seconds ssize_t nBytes; unsigned char *bufferPtr = buffer; bufferPtr += generateRr( bufferPtr, sizeof(buffer)-(bufferPtr-buffer) ); bufferPtr += generateSdes( bufferPtr, sizeof(buffer)-(bufferPtr-buffer) ); - Debug( 3, "Preventing timeout by sending %zd bytes on sd %d. Time since last receive: %d", bufferPtr-buffer, rtpCtrlServer.getWriteDesc(), ( now-last_receive) ); - if ( (nBytes = rtpCtrlServer.send( buffer, bufferPtr-buffer )) < 0 ) - Error( "Unable to send: %s", strerror( errno ) ); + Debug( 3, "Preventing timeout by sending %zd bytes on sd %d. Time since last receive: %d", + bufferPtr-buffer, rtpCtrlServer.getWriteDesc(), ( now-last_receive) ); + if ( (nBytes = rtpCtrlServer.send(buffer, bufferPtr-buffer)) < 0 ) + Error("Unable to send: %s", strerror(errno)); timeout = true; continue; } else { @@ -332,25 +302,21 @@ int RtpCtrlThread::run() timeout = false; last_receive = time(NULL); } - for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) - { - if ( UdpInetSocket *socket = dynamic_cast(*iter) ) - { + for ( Select::CommsList::iterator iter = readable.begin(); iter != readable.end(); ++iter ) { + if ( UdpInetSocket *socket = dynamic_cast(*iter) ) { ssize_t nBytes = socket->recv( buffer, sizeof(buffer) ); Debug( 4, "Read %zd bytes on sd %d", nBytes, socket->getReadDesc() ); - if ( nBytes ) - { + if ( nBytes ) { recvPackets( buffer, nBytes ); - if ( sendReports ) - { + if ( sendReports ) { unsigned char *bufferPtr = buffer; bufferPtr += generateRr( bufferPtr, sizeof(buffer)-(bufferPtr-buffer) ); bufferPtr += generateSdes( bufferPtr, sizeof(buffer)-(bufferPtr-buffer) ); - Debug( 3, "Sending %zd bytes on sd %d", bufferPtr-buffer, rtpCtrlServer.getWriteDesc() ); + Debug(3, "Sending %zd bytes on sd %d", bufferPtr-buffer, rtpCtrlServer.getWriteDesc()); if ( (nBytes = rtpCtrlServer.send( buffer, bufferPtr-buffer )) < 0 ) - Error( "Unable to send: %s", strerror( errno ) ); + Error("Unable to send: %s", strerror(errno)); //Debug( 4, "Sent %d bytes on sd %d", nBytes, rtpCtrlServer.getWriteDesc() ); } } else { @@ -358,16 +324,14 @@ int RtpCtrlThread::run() mStop = true; break; } - } - else - { - Panic( "Barfed" ); - } - } + } else { + Panic("Barfed"); + } // end if socket + } // end foeach comms iterator } rtpCtrlServer.close(); mRtspThread.stop(); - return( 0 ); + return 0; } #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_rtp_ctrl.h b/src/zm_rtp_ctrl.h index 6d8f3024c..9e5306f92 100644 --- a/src/zm_rtp_ctrl.h +++ b/src/zm_rtp_ctrl.h @@ -34,13 +34,11 @@ class RtspThread; class RtpSource; -class RtpCtrlThread : public Thread -{ +class RtpCtrlThread : public Thread { friend class RtspThread; private: - typedef enum - { + typedef enum { RTCP_SR = 200, RTCP_RR = 201, RTCP_SDES = 202, @@ -48,8 +46,7 @@ private: RTCP_APP = 204 } RtcpType; - typedef enum - { + typedef enum { RTCP_SDES_END = 0, RTCP_SDES_CNAME = 1, RTCP_SDES_NAME = 2, @@ -61,8 +58,7 @@ private: RTCP_SDES_PRIV = 8 } RtcpSdesType; - struct RtcpCommonHeader - { + struct RtcpCommonHeader { uint8_t count:5; // varies by packet type uint8_t p:1; // padding flag uint8_t version:2; // protocol version @@ -71,8 +67,7 @@ private: }; // Reception report block - struct RtcpRr - { + struct RtcpRr { uint32_t ssrcN; // data source being reported int32_t lost:24; // cumul. no. pkts lost (signed!) uint32_t fraction:8; // fraction lost since last SR/RR @@ -83,22 +78,18 @@ private: }; // SDES item - struct RtcpSdesItem - { + struct RtcpSdesItem { uint8_t type; // type of item (rtcp_sdes_type_t) uint8_t len; // length of item (in octets) char data[]; // text, not null-terminated }; // RTCP packet - struct RtcpPacket - { + struct RtcpPacket { RtcpCommonHeader header; // common header - union - { + union { // Sender Report (SR) - struct Sr - { + struct Sr { uint32_t ssrcN; // sender generating this report, network order uint32_t ntpSecN; // NTP timestamp, network order uint32_t ntpFracN; @@ -109,22 +100,19 @@ private: } sr; // Reception Report (RR) - struct Rr - { + struct Rr { uint32_t ssrcN; // receiver generating this report RtcpRr rr[]; // variable-length list } rr; // source description (SDES) - struct Sdes - { + struct Sdes { uint32_t srcN; // first SSRC/CSRC RtcpSdesItem item[]; // list of SDES items } sdes; // BYE - struct - { + struct { uint32_t srcN[]; // list of sources // can't express trailing text for reason (what does this mean? it's not even english!) } bye; @@ -148,8 +136,7 @@ private: public: RtpCtrlThread( RtspThread &rtspThread, RtpSource &rtpSource ); - void stop() - { + void stop() { mStop = true; } }; diff --git a/src/zm_rtp_source.cpp b/src/zm_rtp_source.cpp index 0cd838902..02e8ed0c5 100644 --- a/src/zm_rtp_source.cpp +++ b/src/zm_rtp_source.cpp @@ -26,7 +26,17 @@ #if HAVE_LIBAVCODEC -RtpSource::RtpSource( int id, const std::string &localHost, int localPortBase, const std::string &remoteHost, int remotePortBase, uint32_t ssrc, uint16_t seq, uint32_t rtpClock, uint32_t rtpTime, _AVCODECID codecId ) : +RtpSource::RtpSource( + int id, + const std::string &localHost, + int localPortBase, + const std::string &remoteHost, + int remotePortBase, + uint32_t ssrc, + uint16_t seq, + uint32_t rtpClock, + uint32_t rtpTime, + _AVCODECID codecId ) : mId( id ), mSsrc( ssrc ), mLocalHost( localHost ), @@ -65,13 +75,12 @@ RtpSource::RtpSource( int id, const std::string &localHost, int localPortBase, c mLastSrTimeNtp = tvZero(); mLastSrTimeRtp = 0; - if(mCodecId != AV_CODEC_ID_H264 && mCodecId != AV_CODEC_ID_MPEG4) - Warning( "The device is using a codec that may not be supported. Do not be surprised if things don't work." ); + if ( mCodecId != AV_CODEC_ID_H264 && mCodecId != AV_CODEC_ID_MPEG4 ) + Warning("The device is using a codec (%d) that may not be supported. Do not be surprised if things don't work.", mCodecId); } -void RtpSource::init( uint16_t seq ) -{ - Debug( 3, "Initialising sequence" ); +void RtpSource::init( uint16_t seq ) { + Debug(3, "Initialising sequence"); mBaseSeq = seq; mMaxSeq = seq; mBadSeq = RTP_SEQ_MOD + 1; // so seq == mBadSeq is false @@ -84,77 +93,58 @@ void RtpSource::init( uint16_t seq ) mTransit = 0; } -bool RtpSource::updateSeq( uint16_t seq ) -{ +bool RtpSource::updateSeq( uint16_t seq ) { uint16_t uDelta = seq - mMaxSeq; // Source is not valid until MIN_SEQUENTIAL packets with // sequential sequence numbers have been received. Debug( 5, "Seq: %d", seq ); - if ( mProbation) - { + if ( mProbation) { // packet is in sequence - if ( seq == mMaxSeq + 1) - { + if ( seq == mMaxSeq + 1) { Debug( 3, "Sequence in probation %d, in sequence", mProbation ); mProbation--; mMaxSeq = seq; - if ( mProbation == 0 ) - { + if ( mProbation == 0 ) { init( seq ); mReceivedPackets++; return( true ); } - } - else - { + } else { Warning( "Sequence in probation %d, out of sequence", mProbation ); mProbation = MIN_SEQUENTIAL - 1; mMaxSeq = seq; return( false ); } return( true ); - } - else if ( uDelta < MAX_DROPOUT ) - { - if ( uDelta == 1 ) - { + } else if ( uDelta < MAX_DROPOUT ) { + if ( uDelta == 1 ) { Debug( 4, "Packet in sequence, gap %d", uDelta ); - } - else - { + } else { Warning( "Packet in sequence, gap %d", uDelta ); } // in order, with permissible gap - if ( seq < mMaxSeq ) - { + if ( seq < mMaxSeq ) { // Sequence number wrapped - count another 64K cycle. mCycles += RTP_SEQ_MOD; } mMaxSeq = seq; - } - else if ( uDelta <= RTP_SEQ_MOD - MAX_MISORDER ) - { + } else if ( uDelta <= RTP_SEQ_MOD - MAX_MISORDER ) { Warning( "Packet out of sequence, gap %d", uDelta ); // the sequence number made a very large jump - if ( seq == mBadSeq ) - { + if ( seq == mBadSeq ) { Debug( 3, "Restarting sequence" ); // Two sequential packets -- assume that the other side // restarted without telling us so just re-sync // (i.e., pretend this was the first packet). init( seq ); - } - else - { + } else { mBadSeq = (seq + 1) & (RTP_SEQ_MOD-1); return( false ); } - } - else - { + } else { Warning( "Packet duplicate or reordered, gap %d", uDelta ); // duplicate or reordered packet return( false ); @@ -163,10 +153,8 @@ bool RtpSource::updateSeq( uint16_t seq ) return( uDelta==1?true:false ); } -void RtpSource::updateJitter( const RtpDataHeader *header ) -{ - if ( mRtpFactor > 0 ) - { +void RtpSource::updateJitter( const RtpDataHeader *header ) { + if ( mRtpFactor > 0 ) { Debug( 5, "Delta rtp = %.6f", tvDiffSec( mBaseTimeReal ) ); uint32_t localTimeRtp = mBaseTimeRtp + uint32_t( tvDiffSec( mBaseTimeReal ) * mRtpFactor ); Debug( 5, "Local RTP time = %x", localTimeRtp ); @@ -174,8 +162,7 @@ void RtpSource::updateJitter( const RtpDataHeader *header ) uint32_t packetTransit = localTimeRtp - ntohl(header->timestampN); Debug( 5, "Packet transit RTP time = %x", packetTransit ); - if ( mTransit > 0 ) - { + if ( mTransit > 0 ) { // Jitter int d = packetTransit - mTransit; Debug( 5, "Jitter D = %d", d ); @@ -185,28 +172,22 @@ void RtpSource::updateJitter( const RtpDataHeader *header ) mJitter += d - ((mJitter + 8) >> 4); } mTransit = packetTransit; - } - else - { + } else { mJitter = 0; } Debug( 5, "RTP Jitter: %d", mJitter ); } -void RtpSource::updateRtcpData( uint32_t ntpTimeSecs, uint32_t ntpTimeFrac, uint32_t rtpTime ) -{ +void RtpSource::updateRtcpData( uint32_t ntpTimeSecs, uint32_t ntpTimeFrac, uint32_t rtpTime ) { struct timeval ntpTime = tvMake( ntpTimeSecs, suseconds_t((USEC_PER_SEC*(ntpTimeFrac>>16))/(1<<16)) ); Debug( 5, "ntpTime: %ld.%06ld, rtpTime: %x", ntpTime.tv_sec, ntpTime.tv_usec, rtpTime ); - if ( mBaseTimeNtp.tv_sec == 0 ) - { + if ( mBaseTimeNtp.tv_sec == 0 ) { mBaseTimeReal = tvNow(); mBaseTimeNtp = ntpTime; mBaseTimeRtp = rtpTime; - } - else if ( !mRtpClock ) - { + } else if ( !mRtpClock ) { Debug( 5, "lastSrNtpTime: %ld.%06ld, rtpTime: %x", mLastSrTimeNtp.tv_sec, mLastSrTimeNtp.tv_usec, rtpTime ); Debug( 5, "ntpTime: %ld.%06ld, rtpTime: %x", ntpTime.tv_sec, ntpTime.tv_usec, rtpTime ); @@ -227,8 +208,7 @@ void RtpSource::updateRtcpData( uint32_t ntpTimeSecs, uint32_t ntpTimeFrac, uint mLastSrTimeRtp = rtpTime; } -void RtpSource::updateRtcpStats() -{ +void RtpSource::updateRtcpStats() { uint32_t extendedMax = mCycles + mMaxSeq; mExpectedPackets = extendedMax - mBaseSeq + 1; @@ -255,8 +235,7 @@ void RtpSource::updateRtcpStats() Debug( 5, "Lost fraction = %d", mLostFraction ); } -bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) -{ +bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) { const RtpDataHeader *rtpHeader; rtpHeader = (RtpDataHeader *)packet; int rtpHeaderSize = 12 + rtpHeader->cc * 4; @@ -269,39 +248,29 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) // that there is no marker bit by changing the number of bits in the payload type field. bool thisM = rtpHeader->m || h264FragmentEnd; - if ( updateSeq( ntohs(rtpHeader->seqN) ) ) - { + if ( updateSeq( ntohs(rtpHeader->seqN) ) ) { Hexdump( 4, packet+rtpHeaderSize, 16 ); - if ( mFrameGood ) - { + if ( mFrameGood ) { int extraHeader = 0; - if( mCodecId == AV_CODEC_ID_H264 ) - { + if ( mCodecId == AV_CODEC_ID_H264 ) { int nalType = (packet[rtpHeaderSize] & 0x1f); Debug( 3, "Have H264 frame: nal type is %d", nalType ); - switch (nalType) - { + switch (nalType) { case 24: // STAP-A - { extraHeader = 2; break; - } case 25: // STAP-B case 26: // MTAP-16 case 27: // MTAP-24 - { extraHeader = 3; break; - } // FU-A and FU-B case 28: case 29: - { // Is this NAL the first NAL in fragmentation sequence - if ( packet[rtpHeaderSize+1] & 0x80 ) - { + if ( packet[rtpHeaderSize+1] & 0x80 ) { // Now we will form new header of frame mFrame.append( "\x0\x0\x1\x0", 4 ); // Reconstruct NAL header from FU headers @@ -311,17 +280,14 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) extraHeader = 2; break; - } default: - { Debug(3, "Unhandled nalType %d", nalType ); - } } // Append NAL frame start code if ( !mFrame.size() ) mFrame.append( "\x0\x0\x1", 3 ); - } + } // end if H264 mFrame.append( packet+rtpHeaderSize+extraHeader, packetLen-rtpHeaderSize-extraHeader ); } else { Debug( 3, "NOT H264 frame: type is %d", mCodecId ); @@ -329,16 +295,13 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) Hexdump( 4, mFrame.head(), 16 ); - if ( thisM ) - { - if ( mFrameGood ) - { + if ( thisM ) { + if ( mFrameGood ) { Debug( 3, "Got new frame %d, %d bytes", mFrameCount, mFrame.size() ); mFrameProcessed.setValueImmediate( false ); mFrameReady.updateValueSignal( true ); - if ( !mFrameProcessed.getValueImmediate() ) - { + if ( !mFrameProcessed.getValueImmediate() ) { // What is the point of this for loop? Is it just me, or will it call getUpdatedValue once or twice? Could it not be better written as // if ( ! mFrameProcessed.getUpdatedValue( 1 ) && mFrameProcessed.getUpdatedValue( 1 ) ) return false; @@ -347,45 +310,34 @@ bool RtpSource::handlePacket( const unsigned char *packet, size_t packetLen ) return( false ); } mFrameCount++; - } - else - { + } else { Warning( "Discarding incomplete frame %d, %d bytes", mFrameCount, mFrame.size() ); } mFrame.clear(); } - } - else - { - if ( mFrame.size() ) - { + } else { + if ( mFrame.size() ) { Warning( "Discarding partial frame %d, %d bytes", mFrameCount, mFrame.size() ); - } - else - { + } else { Warning( "Discarding frame %d", mFrameCount ); } mFrameGood = false; mFrame.clear(); } - if ( thisM ) - { + if ( thisM ) { mFrameGood = true; prevM = true; - } - else + } else prevM = false; updateJitter( rtpHeader ); - return( true ); + return true; } -bool RtpSource::getFrame( Buffer &buffer ) -{ +bool RtpSource::getFrame( Buffer &buffer ) { Debug( 3, "Getting frame" ); - if ( !mFrameReady.getValueImmediate() ) - { + if ( !mFrameReady.getValueImmediate() ) { // Allow for a couple of spurious returns for ( int count = 0; !mFrameReady.getUpdatedValue( 1 ); count++ ) if ( count > 1 ) @@ -395,7 +347,7 @@ bool RtpSource::getFrame( Buffer &buffer ) mFrameReady.setValueImmediate( false ); mFrameProcessed.updateValueSignal( true ); Debug( 4, "Copied %d bytes", buffer.size() ); - return( true ); + return true; } #endif // HAVE_LIBAVCODEC diff --git a/src/zm_rtsp.cpp b/src/zm_rtsp.cpp index 703328e2e..5e2858e4f 100644 --- a/src/zm_rtsp.cpp +++ b/src/zm_rtsp.cpp @@ -46,53 +46,54 @@ bool RtspThread::sendCommand( std::string message ) { message += stringtf( "CSeq: %d\r\n\r\n", ++mSeq ); Debug( 2, "Sending RTSP message: %s", message.c_str() ); if ( mMethod == RTP_RTSP_HTTP ) { - message = base64Encode( message ); - Debug( 2, "Sending encoded RTSP message: %s", message.c_str() ); - if ( mRtspSocket2.send( message.c_str(), message.size() ) != (int)message.length() ) { - Error( "Unable to send message '%s': %s", message.c_str(), strerror(errno) ); - return( false ); + message = base64Encode(message); + Debug(2, "Sending encoded RTSP message: %s", message.c_str()); + if ( mRtspSocket2.send(message.c_str(), message.size()) != (int)message.length() ) { + Error("Unable to send message '%s': %s", message.c_str(), strerror(errno)); + return false; } } else { - if ( mRtspSocket.send( message.c_str(), message.size() ) != (int)message.length() ) { - Error( "Unable to send message '%s': %s", message.c_str(), strerror(errno) ); - return( false ); + if ( mRtspSocket.send(message.c_str(), message.size()) != (int)message.length() ) { + Error("Unable to send message '%s': %s", message.c_str(), strerror(errno)); + return false; } } - return( true ); + return true; } bool RtspThread::recvResponse( std::string &response ) { if ( mRtspSocket.recv( response ) < 0 ) - Error( "Recv failed; %s", strerror(errno) ); - Debug( 2, "Received RTSP response: %s (%zd bytes)", response.c_str(), response.size() ); + Error("Recv failed; %s", strerror(errno)); + Debug(2, "Received RTSP response: %s (%zd bytes)", response.c_str(), response.size()); float respVer = 0; respCode = -1; char respText[ZM_NETWORK_BUFSIZ]; - if ( sscanf( response.c_str(), "RTSP/%f %3d %[^\r\n]\r\n", &respVer, &respCode, respText ) != 3 ) { + if ( sscanf(response.c_str(), "RTSP/%f %3d %[^\r\n]\r\n", &respVer, &respCode, respText) != 3 ) { if ( isalnum(response[0]) ) { - Error( "Response parse failure in '%s'", response.c_str() ); + Error("Response parse failure in '%s'", response.c_str()); } else { - Error( "Response parse failure, %zd bytes follow", response.size() ); + Error("Response parse failure, %zd bytes follow", response.size()); if ( response.size() ) Hexdump( Logger::ERROR, response.data(), min(response.size(),16) ); } - return( false ); + return false; } - if ( respCode == 401) { + if ( respCode == 401 ) { Debug( 2, "Got 401 access denied response code, check WWW-Authenticate header and retry"); mAuthenticator->checkAuthResponse(response); mNeedAuth = true; - return( false ); + return false; } else if ( respCode != 200 ) { - Error( "Unexpected response code %d, text is '%s'", respCode, respText ); - return( false ); + Error("Unexpected response code %d, text is '%s'", respCode, respText); + return false; } - return( true ); -} + return true; +} // end RtspThread::recResponse int RtspThread::requestPorts() { if ( !smMinDataPort ) { char sql[ZM_SQL_SML_BUFSIZ]; + //FIXME Why not load specifically by Id? This will get ineffeicient with a lot of monitors strncpy( sql, "select Id from Monitors where Function != 'None' and Type = 'Remote' and Protocol = 'rtsp' and Method = 'rtpUni' order by Id asc", sizeof(sql) ); if ( mysql_query( &dbconn, sql ) ) { Error( "Can't run query: %s", mysql_error( &dbconn ) ); @@ -107,7 +108,7 @@ int RtspThread::requestPorts() { int nMonitors = mysql_num_rows( result ); int position = 0; if ( nMonitors ) { - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { + for ( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { int id = atoi(dbrow[0]); if ( mId == id ) { position = i; @@ -126,22 +127,30 @@ int RtspThread::requestPorts() { Debug( 2, "Assigned RTP port range is %d-%d", smMinDataPort, smMaxDataPort ); } for ( int i = smMinDataPort; i <= smMaxDataPort; i++ ) { - PortSet::const_iterator iter = smAssignedPorts.find( i ); + PortSet::const_iterator iter = smAssignedPorts.find(i); if ( iter == smAssignedPorts.end() ) { - smAssignedPorts.insert( i ); - return( i ); + smAssignedPorts.insert(i); + return i; } } - Panic( "Can assign RTP port, no ports left in pool" ); - return( -1 ); + Panic("Can assign RTP port, no ports left in pool"); + return -1; } void RtspThread::releasePorts( int port ) { if ( port > 0 ) - smAssignedPorts.erase( port ); + smAssignedPorts.erase(port); } -RtspThread::RtspThread( int id, RtspMethod method, const std::string &protocol, const std::string &host, const std::string &port, const std::string &path, const std::string &auth, bool rtsp_describe) : +RtspThread::RtspThread( + int id, + RtspMethod method, + const std::string &protocol, + const std::string &host, + const std::string &port, + const std::string &path, + const std::string &auth, + bool rtsp_describe) : mId( id ), mMethod( method ), mProtocol( protocol ), @@ -168,10 +177,10 @@ RtspThread::RtspThread( int id, RtspMethod method, const std::string &protocol, mSsrc = rand(); - Debug( 2, "RTSP Local SSRC is %x", mSsrc ); + Debug(2, "RTSP Local SSRC is %x", mSsrc); if ( mMethod == RTP_RTSP_HTTP ) - mHttpSession = stringtf( "%d", rand() ); + mHttpSession = stringtf("%d", rand()); mNeedAuth = false; StringVector parts = split(auth,":"); @@ -216,8 +225,8 @@ int RtspThread::run() { bool authTried = false; if ( mMethod == RTP_RTSP_HTTP ) { - if ( !mRtspSocket2.connect( mHost.c_str(), mPort.c_str() ) ) - Fatal( "Unable to connect auxiliary RTSP/HTTP socket" ); + if ( !mRtspSocket2.connect(mHost.c_str(), mPort.c_str()) ) + Fatal("Unable to connect auxiliary RTSP/HTTP socket"); //Select select( 0.25 ); //select.addReader( &mRtspSocket2 ); //while ( select.wait() ) @@ -240,15 +249,15 @@ int RtspThread::run() { message += "\r\n"; Debug( 2, "Sending HTTP message: %s", message.c_str() ); if ( mRtspSocket.send( message.c_str(), message.size() ) != (int)message.length() ) { - Error( "Unable to send message '%s': %s", message.c_str(), strerror(errno) ); - return( -1 ); + Error("Unable to send message '%s': %s", message.c_str(), strerror(errno)); + return -1; } if ( mRtspSocket.recv( response ) < 0 ) { - Error( "Recv failed; %s", strerror(errno) ); - return( -1 ); + Error("Recv failed; %s", strerror(errno)); + return -1; } - Debug( 2, "Received HTTP response: %s (%zd bytes)", response.c_str(), response.size() ); + Debug(2, "Received HTTP response: %s (%zd bytes)", response.c_str(), response.size()); float respVer = 0; respCode = -1; if ( sscanf( response.c_str(), "HTTP/%f %3d %[^\r\n]\r\n", &respVer, &respCode, respText ) != 3 ) { @@ -259,25 +268,25 @@ int RtspThread::run() { if ( response.size() ) Hexdump( Logger::ERROR, response.data(), min(response.size(),16) ); } - return( -1 ); + return -1; } // If Server requests authentication, check WWW-Authenticate header and fill required fields // for requested authentication method - if (respCode == 401 && !authTried) { + if ( respCode == 401 && !authTried ) { mNeedAuth = true; mAuthenticator->checkAuthResponse(response); Debug(2, "Processed 401 response"); mRtspSocket.close(); - if ( !mRtspSocket.connect( mHost.c_str(), mPort.c_str() ) ) - Fatal( "Unable to reconnect RTSP socket" ); + if ( !mRtspSocket.connect(mHost.c_str(), mPort.c_str()) ) + Fatal("Unable to reconnect RTSP socket"); Debug(2, "connection should be reopened now"); } } while (respCode == 401 && !authTried); if ( respCode != 200 ) { - Error( "Unexpected response code %d, text is '%s'", respCode, respText ); - return( -1 ); + Error("Unexpected response code %d, text is '%s'", respCode, respText); + return -1; } message = "POST "+mPath+" HTTP/1.0\r\n"; @@ -300,25 +309,25 @@ int RtspThread::run() { // Request supported RTSP commands by the server message = "OPTIONS "+mUrl+" RTSP/1.0\r\n"; if ( !sendCommand( message ) ) - return( -1 ); + return -1; // A negative return here may indicate auth failure, but we will have setup the auth mechanisms so we need to retry. - if ( !recvResponse( response ) ) { + if ( !recvResponse(response) ) { if ( mNeedAuth ) { Debug( 2, "Resending OPTIONS due to possible auth requirement" ); - if ( !sendCommand( message ) ) - return( -1 ); - if ( !recvResponse( response ) ) - return( -1 ); + if ( !sendCommand(message) ) + return -1; + if ( !recvResponse(response) ) + return -1; } else { - return( -1 ); + return -1; } } // end if failed response maybe due to auth char publicLine[256] = ""; - StringVector lines = split( response, "\r\n" ); + StringVector lines = split(response, "\r\n"); for ( size_t i = 0; i < lines.size(); i++ ) - sscanf( lines[i].c_str(), "Public: %[^\r\n]\r\n", publicLine ); + sscanf(lines[i].c_str(), "Public: %[^\r\n]\r\n", publicLine); // Check if the server supports the GET_PARAMETER command // If yes, it is likely that the server will request this command as a keepalive message @@ -331,44 +340,45 @@ int RtspThread::run() { do { if (mNeedAuth) authTried = true; - sendCommand( message ); - sleep( 1 ); - res = recvResponse( response ); - if (!res && respCode==401) + sendCommand(message); + // FIXME WHy sleep 1? + sleep(1); + res = recvResponse(response); + if ( !res && respCode==401 ) mNeedAuth = true; } while (!res && respCode==401 && !authTried); const std::string endOfHeaders = "\r\n\r\n"; - size_t sdpStart = response.find( endOfHeaders ); - if( sdpStart == std::string::npos ) - return( -1 ); + size_t sdpStart = response.find(endOfHeaders); + if ( sdpStart == std::string::npos ) + return -1; if ( mRtspDescribe ) { - std::string DescHeader = response.substr( 0,sdpStart ); - Debug( 1, "Processing DESCRIBE response header '%s'", DescHeader.c_str() ); + std::string DescHeader = response.substr(0, sdpStart); + Debug(1, "Processing DESCRIBE response header '%s'", DescHeader.c_str()); - lines = split( DescHeader, "\r\n" ); + lines = split(DescHeader, "\r\n"); for ( size_t i = 0; i < lines.size(); i++ ) { - // If the device sends us a url value for Content-Base in the response header, we should use that instead - if ( ( lines[i].size() > 13 ) && ( lines[i].substr( 0, 13 ) == "Content-Base:" ) ) { - mUrl = trimSpaces( lines[i].substr( 13 ) ); - Info("Received new Content-Base in DESCRIBE response header. Updated device Url to: '%s'", mUrl.c_str() ); - break; - } + // If the device sends us a url value for Content-Base in the response header, we should use that instead + if ( ( lines[i].size() > 13 ) && ( lines[i].substr( 0, 13 ) == "Content-Base:" ) ) { + mUrl = trimSpaces( lines[i].substr( 13 ) ); + Info("Received new Content-Base in DESCRIBE response header. Updated device Url to: '%s'", mUrl.c_str() ); + break; } - } + } // end foreach line + } // end if mRtspDescribe sdpStart += endOfHeaders.length(); - std::string sdp = response.substr( sdpStart ); - Debug( 1, "Processing SDP '%s'", sdp.c_str() ); + std::string sdp = response.substr(sdpStart); + Debug(1, "Processing SDP '%s'", sdp.c_str()); try { mSessDesc = new SessionDescriptor( mUrl, sdp ); mFormatContext = mSessDesc->generateFormatContext(); } catch( const Exception &e ) { Error( e.getMessage().c_str() ); - return( -1 ); + return -1; } #if 0 @@ -672,51 +682,36 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali Hexdump( 4, (char *)buffer, 16 ); rtpDataThread.recvPacket( buffer+4, len ); Debug( 4, "Received" ); - } - else if ( channel == remoteChannels[1] ) - { + } else if ( channel == remoteChannels[1] ) { // len = ntohs( *((unsigned short *)(buffer+2)) ); // Debug( 4, "Got %d bytes on control channel %d", nBytes, channel ); Debug( 4, "Got %d bytes on control channel %d, packet length is %d", buffer.size(), channel, len ); Hexdump( 4, (char *)buffer, 16 ); rtpCtrlThread.recvPackets( buffer+4, len ); - } - else - { + } else { Error( "Unexpected channel selector %d in RTSP interleaved data", buffer[1] ); buffer.clear(); break; } buffer.consume( len+4 ); nBytes -= len+4; - } - else - { - if ( keepaliveResponse.compare( 0, keepaliveResponse.size(), (char *)buffer, keepaliveResponse.size() ) == 0 ) - { + } else { + if ( keepaliveResponse.compare( 0, keepaliveResponse.size(), (char *)buffer, keepaliveResponse.size() ) == 0 ) { Debug( 4, "Got keepalive response '%s'", (char *)buffer ); //buffer.consume( keepaliveResponse.size() ); - if ( char *charPtr = (char *)memchr( (char *)buffer, '$', buffer.size() ) ) - { + if ( char *charPtr = (char *)memchr( (char *)buffer, '$', buffer.size() ) ) { int discardBytes = charPtr-(char *)buffer; buffer -= discardBytes; - } - else - { + } else { buffer.clear(); } - } - else - { - if ( char *charPtr = (char *)memchr( (char *)buffer, '$', buffer.size() ) ) - { + } else { + if ( char *charPtr = (char *)memchr( (char *)buffer, '$', buffer.size() ) ) { int discardBytes = charPtr-(char *)buffer; Warning( "Unexpected format RTSP interleaved data, resyncing by %d bytes", discardBytes ); Hexdump( -1, (char *)buffer, discardBytes ); buffer -= discardBytes; - } - else - { + } else { Warning( "Unexpected format RTSP interleaved data, dumping %d bytes", buffer.size() ); Hexdump( -1, (char *)buffer, 32 ); buffer.clear(); @@ -764,16 +759,14 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali rtpDataThread.start(); rtpCtrlThread.start(); - while( !mStop ) - { + while ( !mStop ) { // Send a keepalive message if the server supports this feature and we are close to the timeout expiration - if ( sendKeepalive && (timeout > 0) && ((time(NULL)-lastKeepalive) > (timeout-5)) ) - { + if ( sendKeepalive && (timeout > 0) && ((time(NULL)-lastKeepalive) > (timeout-5)) ) { if ( !sendCommand( message ) ) - return( -1 ); + return -1; lastKeepalive = time(NULL); } - usleep( 100000 ); + usleep(100000); } #if 0 message = "PAUSE "+mUrl+" RTSP/1.0\r\nSession: "+session+"\r\n"; @@ -783,10 +776,10 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali return( -1 ); #endif message = "TEARDOWN "+mUrl+" RTSP/1.0\r\nSession: "+session+"\r\n"; - if ( !sendCommand( message ) ) - return( -1 ); - if ( !recvResponse( response ) ) - return( -1 ); + if ( !sendCommand(message) ) + return -1; + if ( !recvResponse(response) ) + return -1; rtpDataThread.stop(); rtpCtrlThread.stop(); @@ -801,13 +794,11 @@ Debug(5, "sendkeepalive %d, timeout %d, now: %d last: %d since: %d", sendKeepali break; } default: - { - Panic( "Got unexpected method %d", mMethod ); + Panic("Got unexpected method %d", mMethod); break; - } } - return( 0 ); + return 0; } #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_sdp.cpp b/src/zm_sdp.cpp index af293d64a..c7bf1b578 100644 --- a/src/zm_sdp.cpp +++ b/src/zm_sdp.cpp @@ -26,17 +26,17 @@ #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) SessionDescriptor::StaticPayloadDesc SessionDescriptor::smStaticPayloads[] = { { 0, "PCMU", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_MULAW, 8000, 1 }, - { 3, "GSM", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, + { 3, "GSM", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, { 4, "G723", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, { 5, "DVI4", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, { 6, "DVI4", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 16000, 1 }, - { 7, "LPC", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, + { 7, "LPC", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, { 8, "PCMA", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_ALAW, 8000, 1 }, { 9, "G722", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, { 10, "L16", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_S16BE, 44100, 2 }, { 11, "L16", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_PCM_S16BE, 44100, 1 }, { 12, "QCELP", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_QCELP, 8000, 1 }, - { 13, "CN", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, + { 13, "CN", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, { 14, "MPA", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP2, -1, -1 }, { 14, "MPA", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_MP3, -1, -1 }, { 15, "G728", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, @@ -45,36 +45,36 @@ SessionDescriptor::StaticPayloadDesc SessionDescriptor::smStaticPayloads[] = { { 18, "G729", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_NONE, 8000, 1 }, { 25, "CelB", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_NONE, 90000, -1 }, { 26, "JPEG", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MJPEG, 90000, -1 }, - { 28, "nv", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_NONE, 90000, -1 }, + { 28, "nv", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_NONE, 90000, -1 }, { 31, "H261", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H261, 90000, -1 }, { 32, "MPV", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG1VIDEO, 90000, -1 }, { 32, "MPV", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG2VIDEO, 90000, -1 }, { 33, "MP2T", AVMEDIA_TYPE_DATA, AV_CODEC_ID_MPEG2TS, 90000, -1 }, { 34, "H263", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H263, 90000, -1 }, - { -1, "", AVMEDIA_TYPE_UNKNOWN, AV_CODEC_ID_NONE, -1, -1 } + { -1, "", AVMEDIA_TYPE_UNKNOWN, AV_CODEC_ID_NONE, -1, -1 } }; SessionDescriptor::DynamicPayloadDesc SessionDescriptor::smDynamicPayloads[] = { - { "MP4V-ES", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 }, - { "mpeg4-generic", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC }, - { "H264", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, - { "AMR", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AMR_NB }, + { "MP4V-ES", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_MPEG4 }, + { "mpeg4-generic", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AAC }, + { "H264", AVMEDIA_TYPE_VIDEO, AV_CODEC_ID_H264 }, + { "AMR", AVMEDIA_TYPE_AUDIO, AV_CODEC_ID_AMR_NB }, { "vnd.onvif.metadata", AVMEDIA_TYPE_DATA, AV_CODEC_ID_NONE } }; #else SessionDescriptor::StaticPayloadDesc SessionDescriptor::smStaticPayloads[] = { { 0, "PCMU", CODEC_TYPE_AUDIO, CODEC_ID_PCM_MULAW, 8001, 1 }, - { 3, "GSM", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, + { 3, "GSM", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, { 4, "G723", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, { 5, "DVI4", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, { 6, "DVI4", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 16000, 1 }, - { 7, "LPC", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, + { 7, "LPC", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, { 8, "PCMA", CODEC_TYPE_AUDIO, CODEC_ID_PCM_ALAW, 8000, 1 }, { 9, "G722", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, { 10, "L16", CODEC_TYPE_AUDIO, CODEC_ID_PCM_S16BE, 44100, 2 }, { 11, "L16", CODEC_TYPE_AUDIO, CODEC_ID_PCM_S16BE, 44100, 1 }, { 12, "QCELP", CODEC_TYPE_AUDIO, CODEC_ID_QCELP, 8000, 1 }, - { 13, "CN", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, + { 13, "CN", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, { 14, "MPA", CODEC_TYPE_AUDIO, CODEC_ID_MP2, -1, -1 }, { 14, "MPA", CODEC_TYPE_AUDIO, CODEC_ID_MP3, -1, -1 }, { 15, "G728", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, @@ -83,7 +83,7 @@ SessionDescriptor::StaticPayloadDesc SessionDescriptor::smStaticPayloads[] = { { 18, "G729", CODEC_TYPE_AUDIO, CODEC_ID_NONE, 8000, 1 }, { 25, "CelB", CODEC_TYPE_VIDEO, CODEC_ID_NONE, 90000, -1 }, { 26, "JPEG", CODEC_TYPE_VIDEO, CODEC_ID_MJPEG, 90000, -1 }, - { 28, "nv", CODEC_TYPE_VIDEO, CODEC_ID_NONE, 90000, -1 }, + { 28, "nv", CODEC_TYPE_VIDEO, CODEC_ID_NONE, 90000, -1 }, { 31, "H261", CODEC_TYPE_VIDEO, CODEC_ID_H261, 90000, -1 }, { 32, "MPV", CODEC_TYPE_VIDEO, CODEC_ID_MPEG1VIDEO, 90000, -1 }, { 32, "MPV", CODEC_TYPE_VIDEO, CODEC_ID_MPEG2VIDEO, 90000, -1 }, @@ -105,7 +105,7 @@ SessionDescriptor::ConnInfo::ConnInfo( const std::string &connInfo ) : mTtl( 16 ), mNoAddresses( 0 ) { - StringVector tokens = split( connInfo, " " ); + StringVector tokens = split(connInfo, " "); if ( tokens.size() < 3 ) throw Exception( "Unable to parse SDP connection info from '"+connInfo+"'" ); mNetworkType = tokens[0]; @@ -136,7 +136,12 @@ SessionDescriptor::BandInfo::BandInfo( const std::string &bandInfo ) : mValue = atoi(tokens[1].c_str()); } -SessionDescriptor::MediaDescriptor::MediaDescriptor( const std::string &type, int port, int numPorts, const std::string &transport, int payloadType ) : +SessionDescriptor::MediaDescriptor::MediaDescriptor( + const std::string &type, + int port, + int numPorts, + const std::string &transport, + int payloadType ) : mType( type ), mPort( port ), mNumPorts( numPorts ), @@ -164,14 +169,13 @@ SessionDescriptor::SessionDescriptor( const std::string &url, const std::string if ( line.empty() ) break; - Debug( 3, "Processing SDP line '%s'", line.c_str() ); + Debug(3, "Processing SDP line '%s'", line.c_str()); const char sdpType = line[0]; if ( line[1] != '=' ) - throw Exception( "Invalid SDP format at '"+line+"'" ); + throw Exception("Invalid SDP format at '"+line+"'"); - line.erase( 0, 2 ); - switch( sdpType ) - { + line.erase(0, 2); + switch( sdpType ) { case 'v' : mVersion = line; break; @@ -204,19 +208,13 @@ SessionDescriptor::SessionDescriptor( const std::string &url, const std::string mAttributes.push_back( line ); StringVector tokens = split( line, ":", 2 ); std::string attrName = tokens[0]; - if ( currMedia ) - { - if ( attrName == "control" ) - { + if ( currMedia ) { + if ( attrName == "control" ) { if ( tokens.size() < 2 ) throw Exception( "Unable to parse SDP control attribute '"+line+"' for media '"+currMedia->getType()+"'" ); currMedia->setControlUrl( tokens[1] ); - } - else if ( attrName == "range" ) - { - } - else if ( attrName == "rtpmap" ) - { + } else if ( attrName == "range" ) { + } else if ( attrName == "rtpmap" ) { // a=rtpmap:96 MP4V-ES/90000 if ( tokens.size() < 2 ) throw Exception( "Unable to parse SDP rtpmap attribute '"+line+"' for media '"+currMedia->getType()+"'" ); @@ -226,53 +224,46 @@ SessionDescriptor::SessionDescriptor( const std::string &url, const std::string throw Exception( stringtf( "Payload type mismatch, expected %d, got %d in '%s'", currMedia->getPayloadType(), payloadType, line.c_str() ) ); std::string payloadDesc = attrTokens[1]; //currMedia->setPayloadType( payloadType ); - if ( attrTokens.size() > 1 ) - { + if ( attrTokens.size() > 1 ) { StringVector payloadTokens = split( attrTokens[1], "/" ); std::string payloadDesc = payloadTokens[0]; int payloadClock = atoi(payloadTokens[1].c_str()); currMedia->setPayloadDesc( payloadDesc ); currMedia->setClock( payloadClock ); } - } - else if ( attrName == "framesize" ) - { + } else if ( attrName == "framesize" ) { // a=framesize:96 320-240 if ( tokens.size() < 2 ) - throw Exception( "Unable to parse SDP framesize attribute '"+line+"' for media '"+currMedia->getType()+"'" ); - StringVector attrTokens = split( tokens[1], " " ); + throw Exception("Unable to parse SDP framesize attribute '"+line+"' for media '"+currMedia->getType()+"'"); + StringVector attrTokens = split(tokens[1], " "); int payloadType = atoi(attrTokens[0].c_str()); if ( payloadType != currMedia->getPayloadType() ) - throw Exception( stringtf( "Payload type mismatch, expected %d, got %d in '%s'", currMedia->getPayloadType(), payloadType, line.c_str() ) ); + throw Exception( stringtf("Payload type mismatch, expected %d, got %d in '%s'", + currMedia->getPayloadType(), payloadType, line.c_str())); //currMedia->setPayloadType( payloadType ); - StringVector sizeTokens = split( attrTokens[1], "-" ); + StringVector sizeTokens = split(attrTokens[1], "-"); int width = atoi(sizeTokens[0].c_str()); int height = atoi(sizeTokens[1].c_str()); - currMedia->setFrameSize( width, height ); - } - else if ( attrName == "framerate" ) - { + currMedia->setFrameSize(width, height); + } else if ( attrName == "framerate" ) { // a=framerate:5.0 if ( tokens.size() < 2 ) - throw Exception( "Unable to parse SDP framerate attribute '"+line+"' for media '"+currMedia->getType()+"'" ); + throw Exception("Unable to parse SDP framerate attribute '"+line+"' for media '"+currMedia->getType()+"'"); double frameRate = atof(tokens[1].c_str()); - currMedia->setFrameRate( frameRate ); - } - else if ( attrName == "fmtp" ) - { + currMedia->setFrameRate(frameRate); + } else if ( attrName == "fmtp" ) { // a=fmtp:96 profile-level-id=247; config=000001B0F7000001B509000001000000012008D48D8803250F042D14440F if ( tokens.size() < 2 ) - throw Exception( "Unable to parse SDP fmtp attribute '"+line+"' for media '"+currMedia->getType()+"'" ); - StringVector attrTokens = split( tokens[1], " ", 2 ); + throw Exception("Unable to parse SDP fmtp attribute '"+line+"' for media '"+currMedia->getType()+"'"); + StringVector attrTokens = split(tokens[1], " ", 2); int payloadType = atoi(attrTokens[0].c_str()); if ( payloadType != currMedia->getPayloadType() ) - throw Exception( stringtf( "Payload type mismatch, expected %d, got %d in '%s'", currMedia->getPayloadType(), payloadType, line.c_str() ) ); + throw Exception(stringtf("Payload type mismatch, expected %d, got %d in '%s'", + currMedia->getPayloadType(), payloadType, line.c_str())); //currMedia->setPayloadType( payloadType ); - if ( attrTokens.size() > 1 ) - { + if ( attrTokens.size() > 1 ) { StringVector attr2Tokens = split( attrTokens[1], "; " ); - for ( unsigned int i = 0; i < attr2Tokens.size(); i++ ) - { + for ( unsigned int i = 0; i < attr2Tokens.size(); i++ ) { StringVector attr3Tokens = split( attr2Tokens[i], "=" ); //Info( "Name = %s, Value = %s", attr3Tokens[0].c_str(), attr3Tokens[1].c_str() ); if ( attr3Tokens[0] == "profile-level-id" ) { @@ -292,40 +283,39 @@ SessionDescriptor::SessionDescriptor( const std::string &url, const std::string } else if ( attrName == "mpeg4-esid" ) { // a=mpeg4-esid:201 } else { - Debug( 3, "Ignoring SDP attribute '%s' for media '%s'", line.c_str(), currMedia->getType().c_str() ) + Debug(3, "Ignoring SDP attribute '%s' for media '%s'", line.c_str(), currMedia->getType().c_str()); } } else { - Debug( 3, "Ignoring general SDP attribute '%s'", line.c_str() ); + Debug(3, "Ignoring general SDP attribute '%s'", line.c_str()); } break; } case 'm' : { - StringVector tokens = split( line, " " ); + StringVector tokens = split(line, " "); if ( tokens.size() < 4 ) - throw Exception( "Can't parse SDP media description '"+line+"'" ); + throw Exception("Can't parse SDP media description '"+line+"'"); std::string mediaType = tokens[0]; if ( mediaType != "audio" && mediaType != "video" && mediaType != "application" ) - throw Exception( "Unsupported media type '"+mediaType+"' in SDP media attribute '"+line+"'" ); - StringVector portTokens = split( tokens[1], "/" ); + throw Exception("Unsupported media type '"+mediaType+"' in SDP media attribute '"+line+"'"); + StringVector portTokens = split(tokens[1], "/"); int mediaPort = atoi(portTokens[0].c_str()); int mediaNumPorts = 1; if ( portTokens.size() > 1 ) mediaNumPorts = atoi(portTokens[1].c_str()); std::string mediaTransport = tokens[2]; if ( mediaTransport != "RTP/AVP" ) - throw Exception( "Unsupported media transport '"+mediaTransport+"' in SDP media attribute '"+line+"'" ); + throw Exception("Unsupported media transport '"+mediaTransport+"' in SDP media attribute '"+line+"'"); int payloadType = atoi(tokens[3].c_str()); - currMedia = new MediaDescriptor( mediaType, mediaPort, mediaNumPorts, mediaTransport, payloadType ); - mMediaList.push_back( currMedia ); + currMedia = new MediaDescriptor(mediaType, mediaPort, mediaNumPorts, mediaTransport, payloadType); + mMediaList.push_back(currMedia); break; } - } - } + } // end switch + } // end foreach line } -SessionDescriptor::~SessionDescriptor() -{ +SessionDescriptor::~SessionDescriptor() { if ( mConnInfo ) delete mConnInfo; if ( mBandInfo ) @@ -334,8 +324,7 @@ SessionDescriptor::~SessionDescriptor() delete mMediaList[i]; } -AVFormatContext *SessionDescriptor::generateFormatContext() const -{ +AVFormatContext *SessionDescriptor::generateFormatContext() const { AVFormatContext *formatContext = avformat_alloc_context(); #if (LIBAVFORMAT_VERSION_CHECK(58, 12, 0, 0, 100)) @@ -353,35 +342,40 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const for ( unsigned int i = 0; i < mMediaList.size(); i++ ) { const MediaDescriptor *mediaDesc = mMediaList[i]; #if !LIBAVFORMAT_VERSION_CHECK(53, 10, 0, 17, 0) - AVStream *stream = av_new_stream( formatContext, i ); + AVStream *stream = av_new_stream(formatContext, i); #else - AVStream *stream = avformat_new_stream( formatContext, NULL ); + AVStream *stream = avformat_new_stream(formatContext, NULL); stream->id = i; #endif #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) AVCodecContext *codec_context = avcodec_alloc_context3(NULL); avcodec_parameters_to_context(codec_context, stream->codecpar); + stream->codec = codec_context; #else AVCodecContext *codec_context = stream->codec; #endif - Debug( 1, "Looking for codec for %s payload type %d / %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); + std::string type = mediaDesc->getType(); + Debug(1, "Looking for codec for %s payload type %d / %s", + type.c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str()); #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) - if ( mediaDesc->getType() == "video" ) + if ( type == "video" ) codec_context->codec_type = AVMEDIA_TYPE_VIDEO; - else if ( mediaDesc->getType() == "audio" ) + else if ( type == "audio" ) codec_context->codec_type = AVMEDIA_TYPE_AUDIO; - else if ( mediaDesc->getType() == "application" ) + else if ( type == "application" ) codec_context->codec_type = AVMEDIA_TYPE_DATA; #else - if ( mediaDesc->getType() == "video" ) + if ( type == "video" ) codec_context->codec_type = CODEC_TYPE_VIDEO; - else if ( mediaDesc->getType() == "audio" ) + else if ( type == "audio" ) codec_context->codec_type = CODEC_TYPE_AUDIO; - else if ( mediaDesc->getType() == "application" ) + else if ( type == "application" ) codec_context->codec_type = CODEC_TYPE_DATA; #endif + else + Warning("Unknown media_type %s", type.c_str()); #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) std::string codec_name; @@ -392,9 +386,9 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if ( smStaticPayloads[i].payloadType == mediaDesc->getPayloadType() ) { Debug( 1, "Got static payload type %d, %s", smStaticPayloads[i].payloadType, smStaticPayloads[i].payloadName ); #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) - codec_name = std::string( smStaticPayloads[i].payloadName ); + codec_name = std::string(smStaticPayloads[i].payloadName); #else - strncpy( codec_context->codec_name, smStaticPayloads[i].payloadName, sizeof(codec_context->codec_name) );; + strncpy(codec_context->codec_name, smStaticPayloads[i].payloadName, sizeof(codec_context->codec_name)); #endif codec_context->codec_type = smStaticPayloads[i].codecType; codec_context->codec_id = smStaticPayloads[i].codecId; @@ -406,11 +400,11 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const // Look in dynamic table for ( unsigned int i = 0; i < (sizeof(smDynamicPayloads)/sizeof(*smDynamicPayloads)); i++ ) { if ( smDynamicPayloads[i].payloadName == mediaDesc->getPayloadDesc() ) { - Debug( 1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName ); + Debug(1, "Got dynamic payload type %d, %s", mediaDesc->getPayloadType(), smDynamicPayloads[i].payloadName); #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) - codec_name = std::string( smStaticPayloads[i].payloadName ); + codec_name = std::string(smStaticPayloads[i].payloadName); #else - strncpy( codec_context->codec_name, smDynamicPayloads[i].payloadName, sizeof(codec_context->codec_name) );; + strncpy(codec_context->codec_name, smDynamicPayloads[i].payloadName, sizeof(codec_context->codec_name)); #endif codec_context->codec_type = smDynamicPayloads[i].codecType; codec_context->codec_id = smDynamicPayloads[i].codecId; @@ -418,7 +412,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const break; } } - } + } /// end if static or dynamic #if LIBAVCODEC_VERSION_CHECK(55, 50, 3, 60, 103) if ( codec_name.empty() ) @@ -426,7 +420,8 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const if ( !stream->codec->codec_name[0] ) #endif { - Warning( "Can't find payload details for %s payload type %d, name %s", mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); + Warning( "Can't find payload details for %s payload type %d, name %s", + mediaDesc->getType().c_str(), mediaDesc->getPayloadType(), mediaDesc->getPayloadDesc().c_str() ); //return( 0 ); } if ( mediaDesc->getWidth() ) @@ -449,11 +444,11 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const while (*value && *value != ',' && (dst - base64packet) < (long)(sizeof(base64packet)) - 1) { - *dst++ = *value++; + *dst++ = *value++; } *dst++ = '\0'; - if (*value == ',') + if ( *value == ',' ) value++; packet_size= av_base64_decode(decoded_packet, (const char *)base64packet, (int)sizeof(decoded_packet)); @@ -468,23 +463,23 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const FF_INPUT_BUFFER_PADDING_SIZE #endif ); - if(dest) { - if(codec_context->extradata_size) { - // av_realloc? + if ( dest ) { + if ( codec_context->extradata_size ) { + // av_realloc? memcpy(dest, codec_context->extradata, codec_context->extradata_size); - av_free(codec_context->extradata); - } + av_free(codec_context->extradata); + } - memcpy(dest+codec_context->extradata_size, start_sequence, sizeof(start_sequence)); - memcpy(dest+codec_context->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); - memset(dest+codec_context->extradata_size+sizeof(start_sequence)+ - packet_size, 0, + memcpy(dest+codec_context->extradata_size, start_sequence, sizeof(start_sequence)); + memcpy(dest+codec_context->extradata_size+sizeof(start_sequence), decoded_packet, packet_size); + memset(dest+codec_context->extradata_size+sizeof(start_sequence)+ + packet_size, 0, #if LIBAVCODEC_VERSION_CHECK(57, 0, 0, 0, 0) - AV_INPUT_BUFFER_PADDING_SIZE + AV_INPUT_BUFFER_PADDING_SIZE #else - FF_INPUT_BUFFER_PADDING_SIZE + FF_INPUT_BUFFER_PADDING_SIZE #endif -); + ); codec_context->extradata= dest; codec_context->extradata_size+= sizeof(start_sequence)+packet_size; @@ -497,7 +492,7 @@ AVFormatContext *SessionDescriptor::generateFormatContext() const } } - return( formatContext ); + return formatContext; } #endif // HAVE_LIBAVFORMAT diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 95b4b26a6..0d3e22b4e 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -103,7 +103,6 @@ VideoStore::VideoStore( #endif } -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_out_stream = avformat_new_stream(oc, NULL); if ( !video_out_stream ) { Error("Unable to create video out stream"); @@ -112,6 +111,7 @@ VideoStore::VideoStore( Debug(2, "Success creating video out stream"); } +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // by allocating our own copy, we don't run into the problems when we free the streams video_out_ctx = avcodec_alloc_context3(video_out_codec); // Since we are not re-encoding, all we have to do is copy the parameters @@ -122,21 +122,9 @@ VideoStore::VideoStore( return; } #else - video_out_stream = avformat_new_stream(oc, NULL); - if ( !video_out_stream ) { - Error("Unable to create video out stream"); - return; - } else { - Debug(2, "Success creating video out stream"); - } video_out_ctx = video_out_stream->codec; // This will wipe out the codec defaults ret = avcodec_copy_context(video_out_ctx, video_in_ctx); - //video_out_ctx->width = video_in_ctx->width; - //video_out_ctx->height = video_in_ctx->height; - //video_out_ctx->pix_fmt = video_in_ctx->pix_fmt; - //video_out_ctx->max_b_frames = video_in_ctx->max_b_frames; - //video_out_ctx->has_b_frames = video_in_ctx->has_b_frames; if ( ret < 0 ) { Fatal("Unable to copy in video ctx to out video ctx %s", av_make_error_string(ret).c_str()); @@ -173,7 +161,6 @@ VideoStore::VideoStore( break; } - if ( !video_out_ctx->codec_tag ) { Debug(2, "No codec_tag"); if ( @@ -207,6 +194,7 @@ VideoStore::VideoStore( video_out_stream->r_frame_rate = video_in_stream->r_frame_rate; } #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) +#if 0 if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { //video_out_ctx->level = 32;I// video_out_ctx->bit_rate = 400*1024; @@ -218,6 +206,7 @@ VideoStore::VideoStore( Debug(2, "Not setting priv_data"); } } +#endif ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); if ( ret < 0 ) { Error("Could not initialize video_out_ctx parameters"); @@ -1016,7 +1005,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { zm_dump_frame(in_frame, "In frame from decode"); - if ( ! resample_audio() ) { + if ( !resample_audio() ) { //av_frame_unref(in_frame); return 0; } @@ -1146,11 +1135,22 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } } // end if encoding or copying + opkt.pos = -1; opkt.stream_index = audio_out_stream->index; opkt.flags = ipkt->flags; - if ( opkt.dts > opkt.pts ) { + if ( opkt.dts < audio_out_stream->cur_dts ) { + Warning("non increasing dts, fixing"); + opkt.dts = audio_out_stream->cur_dts; + if ( opkt.dts > opkt.pts ) { + Debug(1, + "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 ")." + "Decompression must happen before presentation.", + opkt.dts, opkt.pts); + opkt.pts = opkt.dts; + } + } else if ( opkt.dts > opkt.pts ) { Debug(1, "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 ")." "Decompression must happen before presentation.", @@ -1172,7 +1172,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt) int VideoStore::resample_audio() { - // Resample the in into the audioSampleBuffer until we process the whole + // 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) @@ -1192,8 +1192,8 @@ int VideoStore::resample_audio() { } /** Store the new samples in the FIFO buffer. */ ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples); - if ( ret < in_frame->nb_samples ) { - Error("Could not write data to FIFO on %d written", ret); + if ( ret < out_frame->nb_samples ) { + Error("Could not write data to FIFO on %d written, expecting %d", ret, out_frame->nb_samples); return 0; } diff --git a/web/ajax/event.php b/web/ajax/event.php index 1e78e740f..3d9c89c36 100644 --- a/web/ajax/event.php +++ b/web/ajax/event.php @@ -1,5 +1,5 @@ true, 'refreshParent'=>false)); break; case 'delete' : - $Event = new Event($_REQUEST['id']); + $Event = new ZM\Event($_REQUEST['id']); if ( ! $Event->Id() ) { ajaxResponse(array('refreshEvent'=>false, 'refreshParent'=>true, 'message'=> 'Event not found.')); } else { diff --git a/web/api/app/Controller/EventsController.php b/web/api/app/Controller/EventsController.php index 91a2de75c..2f6cfd494 100644 --- a/web/api/app/Controller/EventsController.php +++ b/web/api/app/Controller/EventsController.php @@ -288,9 +288,12 @@ class EventsController extends AppController { $this->Event->recursive = -1; $results = array(); $this->FilterComponent = $this->Components->load('Filter'); - $conditions = $this->FilterComponent->buildFilter($conditions); + if ( $this->request->params['named'] ) { + $conditions = $this->FilterComponent->buildFilter($this->request->params['named']); + } else { + $conditions = array(); + } array_push($conditions, array("StartTime >= DATE_SUB(NOW(), INTERVAL $expr $unit)")); - $query = $this->Event->find('all', array( 'fields' => array( 'MonitorId', diff --git a/web/lang/ba_ba.php b/web/lang/ba_ba.php index 02ad8e5f3..96a3ca4d1 100644 --- a/web/lang/ba_ba.php +++ b/web/lang/ba_ba.php @@ -294,7 +294,7 @@ $SLANG = array( 'Display' => 'Prikaz', 'Displaying' => 'Prikazujem', 'DonateAlready' => 'Ne, već sam napravio donaciju.', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'Donate' => 'Molimo donirajte', 'DonateRemindDay' => 'Ne još, podsjetime za 1 dan', 'DonateRemindHour' => 'Ne još, podsjetime za 1 sat', diff --git a/web/lang/big5_big5.php b/web/lang/big5_big5.php index 518cbe57c..922140698 100644 --- a/web/lang/big5_big5.php +++ b/web/lang/big5_big5.php @@ -293,7 +293,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Not yet, remind again in 1 day', 'DonateRemindHour' => 'Not yet, remind again in 1 hour', 'DonateRemindMonth' => 'Not yet, remind again in 1 month', diff --git a/web/lang/cn_zh.php b/web/lang/cn_zh.php index 8e2bfa8f9..0a751023e 100644 --- a/web/lang/cn_zh.php +++ b/web/lang/cn_zh.php @@ -289,7 +289,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => '请捐款', 'DonateAlready' => '不,我已经捐赠过了', - 'DonateEnticement' => '迄今,您已经运行ZoneMinder有一阵子了,希望它能够有助于增强您家或者办公区域的安全。尽管ZoneMinder是,并将保持免费和开源,该项目依然在研发和支持中投入了资金和精力。如果您愿意支持今后的开发和新功能,那么请考虑为该项目捐款。捐款不是必须的,任何数量的捐赠,我们都很感谢。

如果您愿意捐款,请选择下列选项,或者访问 http://www.zoneminder.com/donate.html 捐赠主页。

感谢您使用ZoneMinder,并且不要忘记访问访问ZoneMinder.com的论坛以获得支持或建议,这可以提升您的ZoneMinder的体验。', + 'DonateEnticement' => '迄今,您已经运行ZoneMinder有一阵子了,希望它能够有助于增强您家或者办公区域的安全。尽管ZoneMinder是,并将保持免费和开源,该项目依然在研发和支持中投入了资金和精力。如果您愿意支持今后的开发和新功能,那么请考虑为该项目捐款。捐款不是必须的,任何数量的捐赠,我们都很感谢。

如果您愿意捐款,请选择下列选项,或者访问 https://zoneminder.com/donate/ 捐赠主页。

感谢您使用ZoneMinder,并且不要忘记访问访问ZoneMinder.com的论坛以获得支持或建议,这可以提升您的ZoneMinder的体验。', 'DonateRemindDay' => '现在不,1天内再次提醒我', 'DonateRemindHour' => '现在不,1小时内再次提醒我', 'DonateRemindMonth' => '现在不,1个月内再次提醒我', diff --git a/web/lang/cs_cz.php b/web/lang/cs_cz.php index 8e76b20ba..c6340ae76 100644 --- a/web/lang/cs_cz.php +++ b/web/lang/cs_cz.php @@ -289,7 +289,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Prosím podpořte', 'DonateAlready' => 'Ne, už jsem podpořil', - 'DonateEnticement' => 'Již nějakou dobu používáte software ZoneMinder k ochraně svého majetku a předpokládám, že jej shledáváte užitečným. Přestože je ZoneMinder, znovu připomínám, zdarma a volně šířený software, stojí jeho vývoj a podpora nějaké peníze. Pokud byste chtěl/a podpořit budoucí vývoj a nové možnosti softwaru, prosím zvažte darování finanční pomoci. Darování je, samozřejmě, dobrovolné, ale zato velmi ceněné můžete přispět jakou částkou chcete.

Pokud máte zájem podpořit náš tým, prosím, vyberte níže uvedenou možnost, nebo navštivte http://www.zoneminder.com/donate.html.

Děkuji Vám že jste si vybral/a software ZoneMinder a nezapomeňte navštívit fórum na ZoneMinder.com pro podporu a návrhy jak udělat ZoneMinder ještě lepším než je dnes.', + 'DonateEnticement' => 'Již nějakou dobu používáte software ZoneMinder k ochraně svého majetku a předpokládám, že jej shledáváte užitečným. Přestože je ZoneMinder, znovu připomínám, zdarma a volně šířený software, stojí jeho vývoj a podpora nějaké peníze. Pokud byste chtěl/a podpořit budoucí vývoj a nové možnosti softwaru, prosím zvažte darování finanční pomoci. Darování je, samozřejmě, dobrovolné, ale zato velmi ceněné můžete přispět jakou částkou chcete.

Pokud máte zájem podpořit náš tým, prosím, vyberte níže uvedenou možnost, nebo navštivte https://zoneminder.com/donate/.

Děkuji Vám že jste si vybral/a software ZoneMinder a nezapomeňte navštívit fórum na ZoneMinder.com pro podporu a návrhy jak udělat ZoneMinder ještě lepším než je dnes.', 'DonateRemindDay' => 'Nyní ne, připomenout za 1 den', 'DonateRemindHour' => 'Nyní ne, připomenout za hodinu', 'DonateRemindMonth' => 'Nyní ne, připomenout za měsíc', diff --git a/web/lang/de_de.php b/web/lang/de_de.php index 37ea4d81c..e8bb8218a 100644 --- a/web/lang/de_de.php +++ b/web/lang/de_de.php @@ -291,7 +291,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Bitte spenden Sie.', 'DonateAlready' => 'Nein, ich habe schon gespendet', - 'DonateEnticement' => 'Sie benutzen ZoneMinder nun schon eine Weile und es ist hoffentlich eine nützliche Applikation zur Verbesserung Ihrer Heim- oder Arbeitssicherheit. Obwohl ZoneMinder eine freie Open-Source-Software ist und bleiben wird, entstehen Kosten bei der Entwicklung und dem Support.

Falls Sie ZoneMinder für Weiterentwicklung in der Zukunft unterstützen möchten, denken Sie bitte über eine Spende für das Projekt unter der Webadresse http://www.zoneminder.com/donate.html oder über nachfolgend stehende Option nach. Spenden sind, wie der Name schon sagt, immer freiwillig. Dem Projekt helfen kleine genauso wie größere Spenden sehr weiter und ein herzlicher Dank ist jedem Spender sicher.

Vielen Dank dafür, dass sie ZoneMinder benutzen. Vergessen Sie nicht die Foren unter ZoneMinder.com, um Support zu erhalten und Ihre Erfahrung mit ZoneMinder zu verbessern!', + 'DonateEnticement' => 'Sie benutzen ZoneMinder nun schon eine Weile und es ist hoffentlich eine nützliche Applikation zur Verbesserung Ihrer Heim- oder Arbeitssicherheit. Obwohl ZoneMinder eine freie Open-Source-Software ist und bleiben wird, entstehen Kosten bei der Entwicklung und dem Support.

Falls Sie ZoneMinder für Weiterentwicklung in der Zukunft unterstützen möchten, denken Sie bitte über eine Spende für das Projekt unter der Webadresse https://zoneminder.com/donate/ oder über nachfolgend stehende Option nach. Spenden sind, wie der Name schon sagt, immer freiwillig. Dem Projekt helfen kleine genauso wie größere Spenden sehr weiter und ein herzlicher Dank ist jedem Spender sicher.

Vielen Dank dafür, dass sie ZoneMinder benutzen. Vergessen Sie nicht die Foren unter ZoneMinder.com, um Support zu erhalten und Ihre Erfahrung mit ZoneMinder zu verbessern!', 'DonateRemindDay' => 'Noch nicht, erinnere mich in einem Tag noch mal.', 'DonateRemindHour' => 'Noch nicht, erinnere mich in einer Stunde noch mal.', 'DonateRemindMonth' => 'Noch nicht, erinnere mich in einem Monat noch mal.', diff --git a/web/lang/dk_dk.php b/web/lang/dk_dk.php index 26533a7fb..045b5345e 100644 --- a/web/lang/dk_dk.php +++ b/web/lang/dk_dk.php @@ -290,7 +290,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Venligst Donér', 'DonateAlready' => 'Nej, jeg har allerede doneret', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Ikke endnu, påmind igen on 1 dag', 'DonateRemindHour' => 'Ikke endnu, påmind igen on 1 time', 'DonateRemindMonth' => 'Ikke endnu, påmind igen on 1 måned', diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index 4eb493630..945d26bea 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -296,7 +296,7 @@ $SLANG = array( 'Display' => 'Display', 'Displaying' => 'Displaying', 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'Donate' => 'Please Donate', 'DonateRemindDay' => 'Not yet, remind again in 1 day', 'DonateRemindHour' => 'Not yet, remind again in 1 hour', diff --git a/web/lang/es_ar.php b/web/lang/es_ar.php index 114002620..a8da807be 100644 --- a/web/lang/es_ar.php +++ b/web/lang/es_ar.php @@ -240,7 +240,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Not yet, remind again in 1 day', 'DonateRemindHour' => 'Not yet, remind again in 1 hour', 'DonateRemindMonth' => 'Not yet, remind again in 1 month', diff --git a/web/lang/es_es.php b/web/lang/es_es.php index 767b58d97..f97ea0ff1 100644 --- a/web/lang/es_es.php +++ b/web/lang/es_es.php @@ -289,7 +289,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 'Donate' => 'Por favor, done', 'DonateAlready' => 'No, ya he donado', - 'DonateEnticement' => 'Ha estado ejecutando ZoneMinder por un tiempo y con suerte le resultará un útil complemento para su seguridad en hogar y trabajo. Aunque ZoneMinder es, y será, libre y de código abierto, cuesta dinero desarrollarlo y mantenerlo. Si quiere ayudar a mantener un futuro desarrollo y nuevas funciones entonces considere hacer un donativo por favor. Donar es, por supuesto, opcional pero muy apreciado y puede donar tanto como desee sin importar la cantidad.

Si desea hacer una donación por favor seleccione la opción de debajo o vaya a http://www.zoneminder.com/donate.html en su navegador.

Muchas gracias por usar ZoneMinder y no se olvide de vistar los foros en ZoneMinder.com para obtener soporte o hacer sugerencias sobre cómo mejorar su experiencia con ZoneMinder aún más.', + 'DonateEnticement' => 'Ha estado ejecutando ZoneMinder por un tiempo y con suerte le resultará un útil complemento para su seguridad en hogar y trabajo. Aunque ZoneMinder es, y será, libre y de código abierto, cuesta dinero desarrollarlo y mantenerlo. Si quiere ayudar a mantener un futuro desarrollo y nuevas funciones entonces considere hacer un donativo por favor. Donar es, por supuesto, opcional pero muy apreciado y puede donar tanto como desee sin importar la cantidad.

Si desea hacer una donación por favor seleccione la opción de debajo o vaya a https://zoneminder.com/donate/ en su navegador.

Muchas gracias por usar ZoneMinder y no se olvide de vistar los foros en ZoneMinder.com para obtener soporte o hacer sugerencias sobre cómo mejorar su experiencia con ZoneMinder aún más.', 'DonateRemindDay' => 'Aún no, recordarme de nuevo en 1 día', 'DonateRemindHour' => 'Aún no, recordarme de nuevo en 1 hora', 'DonateRemindMonth' => 'Aún no, recordarme de nuevo en 1 mes', diff --git a/web/lang/et_ee.php b/web/lang/et_ee.php index 19d6e777b..99a277144 100644 --- a/web/lang/et_ee.php +++ b/web/lang/et_ee.php @@ -296,7 +296,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 'Donate' => 'Palun Anneta', 'DonateAlready' => 'EI, Ma olen juba annetanud', - 'DonateEnticement' => 'Sa oled juba kasutanud ZoneMinderit juba mõnda aega. Nüüd kus sa oled leidnud, et see on kasulik lisa sinu kodule või sinu töökohale. Kuigi ZoneMinder on, jääb alatiseks, vabaks ja avatud lähtekoodiks, siiski selle arendamiseks kulub aega ja raha. Kui sa soovid meid aidata, siis toeta meid tuleviku arendusteks ja uute lisade loomiseks. Palun mõelge annetuse peale. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'Sa oled juba kasutanud ZoneMinderit juba mõnda aega. Nüüd kus sa oled leidnud, et see on kasulik lisa sinu kodule või sinu töökohale. Kuigi ZoneMinder on, jääb alatiseks, vabaks ja avatud lähtekoodiks, siiski selle arendamiseks kulub aega ja raha. Kui sa soovid meid aidata, siis toeta meid tuleviku arendusteks ja uute lisade loomiseks. Palun mõelge annetuse peale. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Ei veel, tuleta meelde ühe päeva pärast', 'DonateRemindHour' => 'Ei veel, tuleta meelde ühe tunni pärast', 'DonateRemindMonth' => 'Ei veel, tuleta meelde ühe kuu pärast', diff --git a/web/lang/fr_fr.php b/web/lang/fr_fr.php index 03ffc70ba..f379b04cd 100644 --- a/web/lang/fr_fr.php +++ b/web/lang/fr_fr.php @@ -295,7 +295,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Réaliser détection native', 'Donate' => 'Veuillez faire un don', 'DonateAlready' => 'Non, j\'ai déjà donné', - 'DonateEnticement' => 'Vous utilisez ZoneMinder depuis quelque temps et nous espérons que vous trouvez cette solution utile. Bien que ZoneMinder est, et restera, une solution libre et ouverte (open source), son développement et son maintien nécessitent des moyens financiers. Si vous voulez aider au développement et à l\'ajout de fonctionnalités, veuillez considérer la possibilité d\'effectuer un don. Les dons sont bien sûr optionnels mais grandement appréciés et vous pouvez donner le montant que vous désirez.

Si vous voulez effectuer un don, veuillez sélectionner l\'option ci-dessous ou veuillez vous rendre sur http://www.zoneminder.com/donate.html à l\'aide de votre navigateur internet.

Merci d\'utiliser ZoneMinder et n\'oubliez pas de visiter les forums sur ZoneMinder.com pour le support ou des suggestions pour rendre votre expérience de ZoneMinder encore meilleure.', + 'DonateEnticement' => 'Vous utilisez ZoneMinder depuis quelque temps et nous espérons que vous trouvez cette solution utile. Bien que ZoneMinder est, et restera, une solution libre et ouverte (open source), son développement et son maintien nécessitent des moyens financiers. Si vous voulez aider au développement et à l\'ajout de fonctionnalités, veuillez considérer la possibilité d\'effectuer un don. Les dons sont bien sûr optionnels mais grandement appréciés et vous pouvez donner le montant que vous désirez.

Si vous voulez effectuer un don, veuillez sélectionner l\'option ci-dessous ou veuillez vous rendre sur https://zoneminder.com/donate/ à l\'aide de votre navigateur internet.

Merci d\'utiliser ZoneMinder et n\'oubliez pas de visiter les forums sur ZoneMinder.com pour le support ou des suggestions pour rendre votre expérience de ZoneMinder encore meilleure.', 'DonateRemindDay' => 'Pas encore, me rappeler dans 1 jour', 'DonateRemindHour' => 'Pas encore, me rappeler dans 1 heure', 'DonateRemindMonth' => 'Pas encore, me rappeler dans 1 mois', diff --git a/web/lang/he_il.php b/web/lang/he_il.php index 26e8bcea6..b3e03c225 100644 --- a/web/lang/he_il.php +++ b/web/lang/he_il.php @@ -289,7 +289,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'úøåí áá÷ùä', 'DonateAlready' => 'ìà, úøîúé ëáø', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'òãééï ìà, äæëø ìà áòåã éåí àçã', 'DonateRemindHour' => 'òãééï ìà, äæëø ìé áòåã ùòä àçú', 'DonateRemindMonth' => 'òãééï ìà, äæëø ìé áòåã çåãù àçã', diff --git a/web/lang/hu_hu.php b/web/lang/hu_hu.php index 15cf72aab..7ef51dab3 100644 --- a/web/lang/hu_hu.php +++ b/web/lang/hu_hu.php @@ -332,7 +332,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 'Donate' => 'Kérem támogasson', 'DonateAlready' => 'Nem, én már támogattam', - 'DonateEnticement' => 'Ön már jó ideje használja a ZoneMindert, és reméljük hasznos eszköznek tartja háza vagy munkahelye biztonságában. Bár a ZoneMinder egy szabad, nyílt forráskódú termék és az is marad, a fejlesztése pénzbe kerül. Ha van lehetősége támogatni a jövőbeni fejlesztéseket és az új funkciókat kérem, tegye meg. A támogatás teljesen önkéntes, de nagyon megbecsült és mértéke is tetszőleges.

Ha támogatni szertne, kérem, válasszon az alábbi lehetőségekből vagy látogassa meg a http://www.zoneminder.com/donate.html oldalt.

Köszönjük, hogy használja a ZoneMinder-t és ne felejtse el meglátogatni a fórumokat a ZoneMinder.com oldalon támogatásért és ötletekért, hogy a jövőben is még jobban ki tudja használni a ZoneMinder lehetőségeit.', + 'DonateEnticement' => 'Ön már jó ideje használja a ZoneMindert, és reméljük hasznos eszköznek tartja háza vagy munkahelye biztonságában. Bár a ZoneMinder egy szabad, nyílt forráskódú termék és az is marad, a fejlesztése pénzbe kerül. Ha van lehetősége támogatni a jövőbeni fejlesztéseket és az új funkciókat kérem, tegye meg. A támogatás teljesen önkéntes, de nagyon megbecsült és mértéke is tetszőleges.

Ha támogatni szertne, kérem, válasszon az alábbi lehetőségekből vagy látogassa meg a https://zoneminder.com/donate/ oldalt.

Köszönjük, hogy használja a ZoneMinder-t és ne felejtse el meglátogatni a fórumokat a ZoneMinder.com oldalon támogatásért és ötletekért, hogy a jövőben is még jobban ki tudja használni a ZoneMinder lehetőségeit.', 'DonateRemindDay' => 'Nem most, figyelmeztessen egy nap múlva', 'DonateRemindHour' => 'Nem most, figyelmeztessen egy óra múlva', 'DonateRemindMonth' => 'Nem most, figyelmeztessen egy hónap múlva', diff --git a/web/lang/it_it.php b/web/lang/it_it.php index 9049b3c2f..cf2dbab8d 100644 --- a/web/lang/it_it.php +++ b/web/lang/it_it.php @@ -294,7 +294,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Donate,per favore', 'DonateAlready' => 'No, ho gia donato... ', - 'DonateEnticement' => 'Stai usando ZoneMinder da un po\' di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.

Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a http://www.zoneminder.com/donate.html .

Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.', + 'DonateEnticement' => 'Stai usando ZoneMinder da un po\' di tempo e spero che tu lo stia trovando utile per la sicurezza di casa tua o del tuo posto di lavoro..Anche se ZoneMinder e\' distribuito liberamente come software libero,costa soldi sia svilupparlo che supportarlo. Se preferisci che questo software continui ad avere supporto e sviluppo in futuro allora considera l\idea di fare una piccola donazione. Donare e\' ovviamente opzionale, ma apprezzato e puoi donare quanto vuoi,quel poco o tanto che tu desideri.

Se hai voglia per cortesia seleziona l\'opzione sotto o punta il tuo browser a https://zoneminder.com/donate/ .

Grazie per usare ZoneMinder e non dimenticare di visitare il forum in ZoneMinder.com se cerchi supporto o hai suggerimenti riguardo a come rendere migliore Zoneminder.', 'DonateRemindDay' => 'Non ancora, ricordamelo ancora tra 1 giorno', 'DonateRemindHour' => 'Non ancora, ricordamelo ancora tra 1 ora', 'DonateRemindMonth' => 'Non ancora, ricordamelo ancora tra 1 mese', diff --git a/web/lang/ja_jp.php b/web/lang/ja_jp.php index b34c9f3f0..55b13ae0a 100644 --- a/web/lang/ja_jp.php +++ b/web/lang/ja_jp.php @@ -290,7 +290,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Not yet, remind again in 1 day', 'DonateRemindHour' => 'Not yet, remind again in 1 hour', 'DonateRemindMonth' => 'Not yet, remind again in 1 month', diff --git a/web/lang/nl_nl.php b/web/lang/nl_nl.php index a2003b1c3..be741a6ac 100644 --- a/web/lang/nl_nl.php +++ b/web/lang/nl_nl.php @@ -290,7 +290,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', // Added - 2015-04-18 'Donate' => 'Geef a.u.b. een donatie', 'DonateAlready' => 'Nee, ik heb al gedoneerd', - 'DonateEnticement' => 'U gebruikt ZoneMinder nu voor een geruime tijd, hopelijk vindt u het een nuttige toevoeging voor uw huis- of werkplekbeveiliging. Natuurlijk is en blijft ZoneMinder gratis en open source software, maar het kost geld om te ontwikkelen, ondersteunen, en te onderhouden. Wij vragen u dan ook om er over na te denken een donatie te doen om zo de ontwikkeling van ZoneMinder te ondersteunen. Natuurlijk bent u hier vrij in, en elke donatie hoe klein dan ook wordt erg gewaardeerd.

Als u wilt doneren geef dat hieronder dan aan of ga naar http://www.zoneminder.com/donate.html in uw browser.

Bedankt voor het gebruiken van ZoneMinder en vergeet niet om ons forum op ZoneMinder.com te bezoeken voor ondersteuning of suggesties waarmee uw ZoneMinder beleving nog beter wordt.', + 'DonateEnticement' => 'U gebruikt ZoneMinder nu voor een geruime tijd, hopelijk vindt u het een nuttige toevoeging voor uw huis- of werkplekbeveiliging. Natuurlijk is en blijft ZoneMinder gratis en open source software, maar het kost geld om te ontwikkelen, ondersteunen, en te onderhouden. Wij vragen u dan ook om er over na te denken een donatie te doen om zo de ontwikkeling van ZoneMinder te ondersteunen. Natuurlijk bent u hier vrij in, en elke donatie hoe klein dan ook wordt erg gewaardeerd.

Als u wilt doneren geef dat hieronder dan aan of ga naar https://zoneminder.com/donate/ in uw browser.

Bedankt voor het gebruiken van ZoneMinder en vergeet niet om ons forum op ZoneMinder.com te bezoeken voor ondersteuning of suggesties waarmee uw ZoneMinder beleving nog beter wordt.', 'DonateRemindDay' => 'Nu niet, herinner mij over 1 dag hieraan', 'DonateRemindHour' => 'Nu niet, herinner mij over een uur hieraan', 'DonateRemindMonth' => 'Nu niet, herinner mij over een maand hieraan', diff --git a/web/lang/pl_pl.php b/web/lang/pl_pl.php index d41242317..0b36af11b 100644 --- a/web/lang/pl_pl.php +++ b/web/lang/pl_pl.php @@ -304,7 +304,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Not yet, remind again in 1 day', 'DonateRemindHour' => 'Not yet, remind again in 1 hour', 'DonateRemindMonth' => 'Not yet, remind again in 1 month', diff --git a/web/lang/pt_br.php b/web/lang/pt_br.php index 3d5a2cf83..80ded9e3d 100644 --- a/web/lang/pt_br.php +++ b/web/lang/pt_br.php @@ -229,7 +229,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Not yet, remind again in 1 day', 'DonateRemindHour' => 'Not yet, remind again in 1 hour', 'DonateRemindMonth' => 'Not yet, remind again in 1 month', diff --git a/web/lang/ro_ro.php b/web/lang/ro_ro.php index 97e07b836..20b2bf647 100644 --- a/web/lang/ro_ro.php +++ b/web/lang/ro_ro.php @@ -260,7 +260,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Please Donate', 'DonateAlready' => 'No, I\'ve already donated', - 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to http://www.zoneminder.com/donate.html in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', + 'DonateEnticement' => 'You\'ve been running ZoneMinder for a while now and hopefully are finding it a useful addition to your home or workplace security. Although ZoneMinder is, and will remain, free and open source, it costs money to develop and support. If you would like to help support future development and new features then please consider donating. Donating is, of course, optional but very much appreciated and you can donate as much or as little as you like.

If you would like to donate please select the option below or go to https://zoneminder.com/donate/ in your browser.

Thank you for using ZoneMinder and don\'t forget to visit the forums on ZoneMinder.com for support or suggestions about how to make your ZoneMinder experience even better.', 'DonateRemindDay' => 'Not yet, remind again in 1 day', 'DonateRemindHour' => 'Not yet, remind again in 1 hour', 'DonateRemindMonth' => 'Not yet, remind again in 1 month', diff --git a/web/lang/ru_ru.php b/web/lang/ru_ru.php index 11110745e..6664e4d97 100644 --- a/web/lang/ru_ru.php +++ b/web/lang/ru_ru.php @@ -20,6 +20,7 @@ // ZoneMinder Russian Translation by Borodin A.S. // ZoneMinder Russian Translation updated by IDDQDesnik, 2017 +// ZoneMinder Russian Translation updated by santos995, 2019 // Notes for Translators // 0. Get some credit, put your name in the line above (optional) @@ -76,11 +77,11 @@ $SLANG = array( '32BitColour' => '32 битный цвет', // Added - 2011-06-15 '8BitGrey' => '256 оттенков серого', 'Action' => 'Действие', - 'Actual' => 'Actual', // Added - 2018-08-30 + 'Actual' => 'Актуальный', // Edited - 2019-03-25 'AddNewControl' => 'Добавить новый', 'AddNewMonitor' => 'Добавить монитор', - 'AddNewServer' => 'Add New Server', // Added - 2018-08-30 - 'AddNewStorage' => 'Add New Storage', // Added - 2018-08-30 + 'AddNewServer' => 'Добавить новый сервер', // Edited - 2019-03-25 + 'AddNewStorage' => 'Добавить новое хранилище', // Edited - 2019-03-25 'AddNewUser' => 'Добавить пользователя', 'AddNewZone' => 'Добавить зону', 'Alarm' => 'Тревога', @@ -110,24 +111,24 @@ $SLANG = array( 'AttrCause' => 'Причина', 'AttrDiskBlocks' => 'Диск, блоки', 'AttrDiskPercent' => 'Диск, проценты', - 'AttrDiskSpace' => 'Disk Space', // Added - 2018-08-30 + 'AttrDiskSpace' => 'Дисковое пространство', // Edited - 2019-03-24 'AttrDuration' => 'Длительность', - 'AttrEndDate' => 'End Date', // Added - 2018-08-30 - 'AttrEndDateTime' => 'End Date/Time', // Added - 2018-08-30 - 'AttrEndTime' => 'End Time', // Added - 2018-08-30 + 'AttrEndDate' => 'Дата окончания', // Edited - 2019-03-24 + 'AttrEndDateTime' => 'Дата/время окончания', // Edited - 2019-03-24 + 'AttrEndTime' => 'Время окончания', // Edited - 2019-03-24 'AttrEndWeekday' => 'End Weekday', // Added - 2018-08-30 - 'AttrFilterServer' => 'Server Filter is Running On', // Added - 2018-08-30 + 'AttrFilterServer' => 'Фильтр для серверов запущен', // Edited - 2019-03-24 'AttrFrames' => 'Кол-во кадров', 'AttrId' => 'ИД', 'AttrMaxScore' => 'Макс. оценка', 'AttrMonitorId' => 'ИД Монитора', 'AttrMonitorName' => 'Название Монитора', - 'AttrMonitorServer' => 'Server Monitor is Running On', // Added - 2018-08-30 + 'AttrMonitorServer' => 'Монитор серверов запущен', // Edited - 2019-03-24 'AttrName' => 'Имя', 'AttrNotes' => 'Примечание', - 'AttrStartDate' => 'Start Date', // Added - 2018-08-30 - 'AttrStartDateTime' => 'Start Date/Time', // Added - 2018-08-30 - 'AttrStartTime' => 'Start Time', // Added - 2018-08-30 + 'AttrStartDate' => 'Дата начала', // Edited - 2019-03-24 + 'AttrStartDateTime' => 'Дата/Время начала', // Edited - 2019-03-24 + 'AttrStartTime' => 'Время начала', // Edited - 2019-03-24 'AttrStartWeekday' => 'Start Weekday', // Added - 2018-08-30 'AttrStateId' => 'Run State', // Added - 2018-08-30 'AttrStorageArea' => 'Storage Area', // Added - 2018-08-30 @@ -170,7 +171,7 @@ $SLANG = array( 'BadStreamReplayBuffer'=> 'Буфер потока повторного воспроизведения должен быть целочисленным и большим либо равным нулю', 'BadWarmupCount' => 'Кол-во кадров разогрева должно быть целочисленным и большим либо равным нулю', 'BadWebColour' => 'Цвет отметки должен быть правильным Web-цветом', - 'BadWebSitePath' => 'Please enter a complete website url, including the http:// or https:// prefix.', // Added - 2018-08-30 + 'BadWebSitePath' => 'Пожалуйста, введите полной название сайта url, включая http:// или https:// префикс.', // Edited - 2019-03-24 'BadWidth' => 'Неправильная ширина', 'Bandwidth' => 'канал', 'BandwidthHead' => 'канал', // This is the end of the bandwidth status on the top of the console, different in many language due to phrasing; @@ -178,9 +179,9 @@ $SLANG = array( 'BlobSizes' => 'Размер объектов', 'Blobs' => 'Кол-во объектов', 'Brightness' => 'Яркость', - 'Buffer' => 'Buffer', // Added - 2015-04-18 + 'Buffer' => 'Буфер', // Edited - 2019-03-24 'Buffers' => 'Буферы', - 'CSSDescription' => 'Change the default css for this computer', // Added - 2015-04-18 + 'CSSDescription' => 'Изменить стандартный CSS для данного компьютера', // Edited - 2019-03-24 'CanAutoFocus' => 'Автофокус', 'CanAutoGain' => 'Автоусиление', 'CanAutoIris' => 'Автодиафрагма', @@ -206,7 +207,7 @@ $SLANG = array( 'CanMoveRel' => 'Относительное перемещение', 'CanPan' => 'Панорама' , 'CanReset' => 'Сброс', - 'CanReboot' => 'Can Reboot', + 'CanReboot' => 'Перезагрузка', // Added - 2019-03-24 'CanSetPresets' => 'Создание предустановок', 'CanSleep' => 'Сон', 'CanTilt' => 'Наклон', @@ -225,17 +226,17 @@ $SLANG = array( 'CaptureHeight' => 'Размер по Y', 'CaptureMethod' => 'Метод захвата', // Added - 2009-02-08 'CapturePalette' => 'Режим захвата', - 'CaptureResolution' => 'Capture Resolution', // Added - 2015-04-18 + 'CaptureResolution' => 'Разрешение', // Edited - 2019-03-24 'CaptureWidth' => 'Размер по X', 'Cause' => 'Причина', 'CheckMethod' => 'Метод проверки тревоги', 'ChooseDetectedCamera' => 'Выберите камеру', // Added - 2009-03-31 'ChooseFilter' => 'Выбрать фильтр', - 'ChooseLogFormat' => 'Choose a log format', // Added - 2011-06-17 + 'ChooseLogFormat' => 'Выбрать формат лога', // Edited - 2019-03-25 'ChooseLogSelection' => 'Choose a log selection', // Added - 2011-06-17 'ChoosePreset' => 'Выберите предустановку', 'Clear' => 'Очистить', // Added - 2011-06-16 - 'CloneMonitor' => 'Clone', // Added - 2018-08-30 + 'CloneMonitor' => 'Клонировать', // Edited - 2019-03-25 'Close' => 'Закрыть', 'Colour' => 'Цвет', 'Command' => 'Command', @@ -249,7 +250,7 @@ $SLANG = array( 'ConjOr' => 'или', 'Console' => 'Сервер', 'ContactAdmin' => 'Пожалуйста обратитесь к вашему администратору.', - 'Continue' => 'Continue', + 'Continue' => 'Продолжить', // Added - 2019-03-25 'Contrast' => 'Контраст', 'Control' => 'Управление', 'ControlAddress' => 'Адрес устройства', @@ -263,12 +264,12 @@ $SLANG = array( 'CycleWatch' => 'Циклический просмотр', 'DateTime' => 'Дата/Время', // Added - 2011-06-16 'Day' => 'День', - 'Debug' => 'Debug', + 'Debug' => 'Отладка', // Added - 2019-03-25 'DefaultRate' => 'Скорость по умолчанию', 'DefaultScale' => 'Масштаб по умолчанию', 'DefaultView' => 'Вид по умолчанию', 'Deinterlacing' => 'Устранение чересстрочности', // Added - 2015-04-18 - 'Delay' => 'Delay', // Added - 2015-04-18 + 'Delay' => 'Задержка', // Edited - 2019-03-25 'Delete' => 'Удалить', 'DeleteAndNext' => 'Удалить & след.', 'DeleteAndPrev' => 'Удалить & пред.', @@ -276,18 +277,18 @@ $SLANG = array( 'Description' => 'Описание', 'DetectedCameras' => 'Найденные камеры', // Added - 2009-03-31 'DetectedProfiles' => 'Найденные профили', // Added - 2015-04-18 - 'Device' => 'Device', // Added - 2009-02-08 + 'Device' => 'Устройство', // Edited - 2019-03-25 'DeviceChannel' => 'Канал', 'DeviceFormat' => 'Формат', 'DeviceNumber' => 'Номер устройства', 'DevicePath' => 'Путь к устройству', - 'Devices' => 'Devices', + 'Devices' => 'Устройства', // Edited - 2019-03-25 'Dimensions' => 'Размеры', 'DisableAlarms' => 'Запретить тревогу', 'Disk' => 'Диск', 'Display' => 'Display', // Added - 2011-01-30 'Displaying' => 'Отображено', // Added - 2011-06-16 - 'DoNativeMotionDetection'=> 'Do Native Motion Detection', + 'DoNativeMotionDetection'=> 'Использовать встроенное обнаружение движения', // Edited - 2019-03-25 'Donate' => 'Поддержите проект', 'DonateAlready' => 'Нет, я уже сделал пожертвование', 'DonateEnticement' => 'Вы какое-то время используете ZoneMinder и, надеемся, находите его полезным дополнением к вашей домашней или рабочей безопасности. Хотя ZoneMinder есть и будет оставаться свободным и бесплатным, он требует денег на разработку и поддержку. Если Вы хотите поддержать его будущее развитие и новые функции, пожалуйста сделайте пожертвование. Это, конечно, необязательно, но очень высоко ценится. Вы можете пожертвовать любую сумму.

Если Вы хотите сделать пожертвование, то выберите соответствующий вариант ниже или перейдите по адресу https://www.bountysource.com/teams/zoneminder в вашем браузере.

Спасибо за использование ZoneMinder, и не забывайте посетить форум на ZoneMinder.com для поддержки и пожеланий как сделать ZoneMinder еще лучше.', @@ -298,11 +299,11 @@ $SLANG = array( 'DonateRemindWeek' => 'Нет, не сейчас, напомнить через неделю', 'DonateYes' => 'Да, я хотел бы сделать пожертвование', 'Download' => 'Скачать', - 'DownloadVideo' => 'Download Video', // Added - 2018-08-30 - 'DuplicateMonitorName' => 'Duplicate Monitor Name', // Added - 2009-03-31 + 'DownloadVideo' => 'Скачать видео', // Added - 2019-03-24 + 'DuplicateMonitorName' => 'Скопировать имя монитора', // Added - 2019-03-25 'Duration' => 'Длительность', 'Edit' => 'Редактирование', - 'EditLayout' => 'Edit Layout', // Added - 2018-08-30 + 'EditLayout' => 'Редактирование шаблона', // Added - 2019-03-25 'Email' => 'Email', 'EnableAlarms' => 'Разрешить тревогу', 'Enabled' => 'Включен', @@ -313,13 +314,13 @@ $SLANG = array( 'Etc' => 'и т.д.', 'Event' => 'Событие', 'EventFilter' => 'Фильтр событий', - 'EventId' => 'Event Id', - 'EventName' => 'Event Name', + 'EventId' => 'Id события', // Added - 2019-03-25 + 'EventName' => 'Имя события', // Added - 2019-03-25 'EventPrefix' => 'Префикс события', 'Events' => 'События', 'Exclude' => 'Исключить', 'Execute' => 'Выполнить', - 'Exif' => 'Embed EXIF data into image', // Added - 2018-08-30 + 'Exif' => 'Включить EXIF информацию в изображение', // Added - 2019-03-24 'Export' => 'Экспорт', 'ExportDetails' => 'Экспортировать описание события', 'ExportFailed' => 'Ошибка экспорта', @@ -351,14 +352,14 @@ $SLANG = array( 'FilterMessageEvents' => 'Message details of all matches', 'FilterMoveEvents' => 'Move all matches', // Added - 2018-08-30 'FilterPx' => 'Пкс фильтра', - 'FilterUnset' => 'You must specify a filter width and height', - 'FilterUpdateDiskSpace'=> 'Update used disk space', // Added - 2018-08-30 - 'FilterUploadEvents' => 'Upload all matches', - 'FilterVideoEvents' => 'Create video for all matches', + 'FilterUnset' => 'Вы должны указать ширину и высоту фильтра', // Added - 2019-03-25 + 'FilterUpdateDiskSpace'=> 'Обновить используемое дисковое пространство', // Edited - 2019-03-25 + 'FilterUploadEvents' => 'Загрузить все совпадения', // Added - 2019-03-25 + 'FilterVideoEvents' => 'Создать видео для всех совпадений', // Added - 2019-03-25 'Filters' => 'Фильтры', 'First' => 'Первый', - 'FlippedHori' => 'Flipped Horizontally', - 'FlippedVert' => 'Flipped Vertically', + 'FlippedHori' => 'Перевернутый горизонтально', // Added - 2019-03-25 + 'FlippedVert' => 'Перевернутый вертикально', // Added - 2019-03-25 'FnMocord' => 'Mocord', // Added 2013.08.16. 'FnModect' => 'Modect', // Added 2013.08.16. 'FnMonitor' => 'Monitor', // Added 2013.08.16. @@ -377,7 +378,7 @@ $SLANG = array( 'Function' => 'Функция', 'Gain' => 'Gain', 'General' => 'Основные', - 'GenerateDownload' => 'Generate Download', // Added - 2018-08-30 + 'GenerateDownload' => 'Сгенерировать загрузку', // Edited - 2019-03-25 'GenerateVideo' => 'Генерировать видео', 'GeneratingVideo' => 'Генерируется видео', 'GoToZoneMinder' => 'Перейти на ZoneMinder.com', @@ -398,7 +399,7 @@ $SLANG = array( 'High' => 'широкий', 'HighBW' => 'Широкий канал', 'Home' => 'Домой', - 'Hostname' => 'Hostname', // Added - 2018-08-30 + 'Hostname' => 'Имя хоста', // Edited - 2019-03-25 'Hour' => 'Час', 'Hue' => 'Оттенок', 'Id' => 'ИД', @@ -406,13 +407,13 @@ $SLANG = array( 'Ignore' => 'Игнорировать', 'Image' => 'Изображение', 'ImageBufferSize' => 'Буфер изображений', - 'Images' => 'Images', + 'Images' => 'Изображения', // Added - 2019-03-25 'In' => 'In', 'Include' => 'Включить', 'Inverted' => 'Инвертировать', 'Iris' => 'Наклон', 'KeyString' => 'Key String', - 'Label' => 'Label', + 'Label' => 'Имя', // Added - 2019-03-25 'Language' => 'Язык', 'Last' => 'Последний', 'Layout' => 'Раскладка', // Added - 2009-02-08 @@ -423,16 +424,16 @@ $SLANG = array( 'Line' => 'Строка', // Added - 2011-06-16 'LinkedMonitors' => 'Привязанные мониторы', 'List' => 'Список', - 'ListMatches' => 'List Matches', // Added - 2018-08-30 + 'ListMatches' => 'Список совпадений', // Edited - 2019-03-25 'Load' => 'Нагрузка', 'Local' => 'Локальный', 'Log' => 'Лог', // Added - 2011-06-16; 'LoggedInAs' => 'Пользователь', - 'Logging' => 'Logging', // Added - 2011-06-16 + 'Logging' => 'Логгирование', // Added - 2019-03-24 'LoggingIn' => 'Вход в систему', 'Login' => 'Войти', 'Logout' => 'Выйти', - 'Logs' => 'Logs', // Added - 2011-06-17 + 'Logs' => 'Логи', // Added - 2019-03-24 'Low' => 'узкий', 'LowBW' => 'Узкий канал', 'Main' => 'Основные', @@ -440,7 +441,7 @@ $SLANG = array( 'Manual' => 'Manual', 'Mark' => 'Метка', 'Max' => 'Макс.', - 'MaxBandwidth' => 'Max Bandwidth', + 'MaxBandwidth' => 'Макс. пропускная способность', // Added - 2019-03-25 'MaxBrScore' => 'Макс.
оценка', 'MaxFocusRange' => 'Макс. диап. фокуса', 'MaxFocusSpeed' => 'Макс. скор. фокуса', @@ -510,7 +511,7 @@ $SLANG = array( 'MonitorProbeIntro' => 'В этом списке показаны найденные аналоговые и сетевые камеры, как уже заведенные, так и доступные для выбора.

Выберите нужную из списка ниже.

Обратите внимание, что не все камеры могут быть найдены, и что выбор камеры может переписать настройки определенные для этого монитора.

', // Added - 2009-03-31 'Monitors' => 'Мониторы', 'Montage' => 'Монтаж', - 'MontageReview' => 'Montage Review', // Added - 2018-08-30 + 'MontageReview' => 'Обзор монтажа', // Added - 2019-03-24 'Month' => 'Месяц', 'More' => 'Еще', // Added - 2011-06-16 'MotionFrameSkip' => 'Кол-во пропуск. кадров движения', @@ -530,16 +531,16 @@ $SLANG = array( 'Network' => 'Сеть', 'New' => 'Нов.', 'NewGroup' => 'Новая группа', - 'NewLabel' => 'New Label', + 'NewLabel' => 'Новое имя', // Added - 2019-03-25 'NewPassword' => 'Новый пароль', 'NewState' => 'Новое состояние', 'NewUser' => 'Новый пользователь', 'Next' => 'След.', 'No' => 'Нет', - 'NoDetectedCameras' => 'No Detected Cameras', // Added - 2009-03-31 - 'NoDetectedProfiles' => 'No Detected Profiles', // Added - 2018-08-30 + 'NoDetectedCameras' => 'Нет камер', // Added - 2019-03-24 + 'NoDetectedProfiles' => 'Нет профилей', // Added - 2019-03-24 'NoFramesRecorded' => 'Это событие не содержит кадров', - 'NoGroup' => 'No Group', + 'NoGroup' => 'Нет группы', // Added - 2019-03-24 'NoSavedFilters' => 'нет сохраненных фильтров', 'NoStatisticsRecorded' => 'Статистика по этому событию/кадру не записана', 'None' => 'отсутствует', @@ -547,8 +548,8 @@ $SLANG = array( 'Normal' => 'Нормальная', 'Notes' => 'Примечание', 'NumPresets' => 'Кол-во предустановок', - 'Off' => 'Off', - 'On' => 'On', + 'Off' => 'Выкл.', // Added - 2019-03-25 + 'On' => 'Вкл.', // Added - 2019-03-25 'OnvifCredentialsIntro'=> 'Пожалуйста укажите имя пользователя и пароль для выбранной камеры.

Если пользователь для камеры не был создан, тогда будет создан новый с указанными данными.

', // Added - 2015-04-18 'OnvifProbe' => 'ONVIF', // Added - 2015-04-18 'OnvifProbeIntro' => 'В этом списке показаны найденные ONVIF камеры, как уже заведенные, так и доступные для выбора.

Выберите нужную из списка ниже.

Обратите внимание, что не все камеры могут быть найдены, и что выбор камеры может переписать настройки определенные для этого монитора.

', // Added - 2015-04-18 @@ -567,7 +568,7 @@ $SLANG = array( 'Open' => 'Открыть', 'OptionHelp' => 'Справка', 'OptionRestartWarning' => 'Эти изменения подействуют только после перезапуска программы.', - 'OptionalEncoderParam' => 'Optional Encoder Parameters', // Added - 2018-08-30 + 'OptionalEncoderParam' => 'Необязательные параметры кодировщика', // Added - 2019-03-24 'Options' => 'Опции', 'OrEnterNewName' => 'или введите новое имя', 'Order' => 'Сортировка', @@ -592,7 +593,7 @@ $SLANG = array( 'Play' => 'Играть', 'PlayAll' => 'Воспр. все', 'PleaseWait' => 'Пожалуйста подождите', - 'Plugins' => 'Plugins', + 'Plugins' => 'Плагины', // Edited - 2019-03-24 'Point' => 'Точка', 'PostEventImageBuffer' => 'Буфер после события', 'PreEventImageBuffer' => 'Буфер до события', @@ -605,13 +606,13 @@ $SLANG = array( 'ProfileProbeIntro' => 'В этом списке показаны существующие профили потока выбранной камеры.

Выберите нужный из списка ниже.

Обратите внимание, что ZoneMinder не может добавить дополнительный профиль, и что выбор профиля может переписать настройки определенные для этого монитора.

', // Added - 2015-04-18 'Progress' => 'Прогресс', // Added - 2015-04-18 'Protocol' => 'Протокол', - 'RTSPDescribe' => 'Use RTSP Response Media URL', // Added - 2018-08-30 - 'RTSPTransport' => 'RTSP Transport Protocol', // Added - 2018-08-30 + 'RTSPDescribe' => 'Использовать RTSP URL для ответа', // Edited - 2019-03-25 + 'RTSPTransport' => 'Транспортный протокол RTSP', // Edited - 2019-03-25 'Rate' => 'Скорость', 'Real' => 'Реальная', 'RecaptchaWarning' => 'Your reCaptcha secret key is invalid. Please correct it, or reCaptcha will not work', // Added - 2018-08-30 'Record' => 'Record', - 'RecordAudio' => 'Whether to store the audio stream when saving an event.', // Added - 2018-08-30 + 'RecordAudio' => 'Сохранять ли аудиопоток при сохранении события.', // Edited - 2019-03-25 'RefImageBlendPct' => 'Смешение опорного кадра, %', 'Refresh' => 'Обновить', 'Remote' => 'Удаленный', @@ -627,7 +628,7 @@ $SLANG = array( 'ReplayAll' => 'Все события', 'ReplayGapless' => 'События подряд', 'ReplaySingle' => 'Одно событие', - 'ReportEventAudit' => 'Audit Events Report', // Added - 2018-08-30 + 'ReportEventAudit' => 'Отчёт о событиях аудита', // Edited - 2019-03-24 'Reset' => 'Сбросить', 'ResetEventCounts' => 'Обнулить счетчик событий', 'Restart' => 'Перезапустить', @@ -639,14 +640,14 @@ $SLANG = array( 'Rewind' => 'Назад', 'RotateLeft' => 'Повернуть влево', 'RotateRight' => 'Повернуть вправо', - 'RunLocalUpdate' => 'Please run zmupdate.pl to update', // Added - 2011-05-25 + 'RunLocalUpdate' => 'Запустите zmupdate.pl для обновления', // Edited - 2019-03-24 'RunMode' => 'Режим работы', 'RunState' => 'Состояние', 'Running' => 'Выполняется', 'Save' => 'Сохранить', 'SaveAs' => 'Сохранить как', 'SaveFilter' => 'Сохранить фильтр', - 'SaveJPEGs' => 'Save JPEGs', // Added - 2018-08-30 + 'SaveJPEGs' => 'Сохранить JPEG-и', // Edited - 2019-03-24 'Scale' => 'Масштаб', 'Score' => 'Оценка', 'Secs' => 'Сек.', @@ -654,46 +655,46 @@ $SLANG = array( 'Select' => 'Выбор', 'SelectFormat' => 'Выберите формат', // Added - 2011-06-17 'SelectLog' => 'Выберите лог', // Added - 2011-06-17 - 'SelectMonitors' => 'Select Monitors', + 'SelectMonitors' => 'Выбрать Мониторы', // Edited - 2019-03-24 'SelfIntersecting' => 'Polygon edges must not intersect', - 'Set' => 'Set', + 'Set' => 'Установка', // Edited - 2019-03-24 'SetNewBandwidth' => 'Установка новой ширина канала', - 'SetPreset' => 'Set Preset', + 'SetPreset' => 'Установка пресета', // Edited - 2019-03-24 'Settings' => 'Настройки', 'ShowFilterWindow' => 'Показать окно фильтра', 'ShowTimeline' => 'Показать график', 'SignalCheckColour' => 'Цвет проверки сигнала', 'SignalCheckPoints' => 'Signal Check Points', // Added - 2018-08-30 - 'Size' => 'Size', - 'SkinDescription' => 'Change the default skin for this computer', // Added - 2011-01-30 + 'Size' => 'Размер', // Edited - 2019-03-24 + 'SkinDescription' => 'Смена стандартного скина для данного компьютера', // Edited - 2019-03-24 'Sleep' => 'Sleep', 'SortAsc' => 'По возр.', 'SortBy' => 'Сортировать', 'SortDesc' => 'По убыв.', 'Source' => 'Источник', - 'SourceColours' => 'Source Colours', // Added - 2009-02-08 + 'SourceColours' => 'Цвета источника', // Edited - 2019-03-24 'SourcePath' => 'Путь к источнику', // Added - 2009-02-08 'SourceType' => 'Тип источника', - 'Speed' => 'Speed', - 'SpeedHigh' => 'High Speed', - 'SpeedLow' => 'Low Speed', - 'SpeedMedium' => 'Medium Speed', - 'SpeedTurbo' => 'Turbo Speed', + 'Speed' => 'Скорость', //Edited - 2019-03-24 + 'SpeedHigh' => 'Высокая скорость', //Edited - 2019-03-24 + 'SpeedLow' => 'Низкая скорость', //Edited - 2019-03-24 + 'SpeedMedium' => 'Средняя скорость', + 'SpeedTurbo' => 'Максимальная скорость', // Edited - 2019-03-24 'Start' => 'Запустить', 'State' => 'Состояние', 'Stats' => 'Статистика', 'Status' => 'Статус', - 'StatusConnected' => 'Capturing', // Added - 2018-08-30 - 'StatusNotRunning' => 'Not Running', // Added - 2018-08-30 - 'StatusRunning' => 'Not Capturing', // Added - 2018-08-30 - 'StatusUnknown' => 'Unknown', // Added - 2018-08-30 + 'StatusConnected' => 'Записывается', // Edited - 2019-03-25 + 'StatusNotRunning' => 'Не запущен', // Edited - 2019-03-25 + 'StatusRunning' => 'Не записывается', // Edited - 2019-03-25 + 'StatusUnknown' => 'Неизвестно', // Edited - 2019-03-25 'Step' => 'Шаг', 'StepBack' => 'Кадр назад', 'StepForward' => 'Кадр вперед', - 'StepLarge' => 'Large Step', - 'StepMedium' => 'Medium Step', - 'StepNone' => 'No Step', - 'StepSmall' => 'Small Step', + 'StepLarge' => 'Большой шаг', // Added - 2019-03-25 + 'StepMedium' => 'Средний шаг', // Added - 2019-03-25 + 'StepNone' => 'Без шагов', // Added - 2019-03-25 + 'StepSmall' => 'Малый шаг', // Added - 2019-03-25 'Stills' => 'Стоп-кадры', 'Stop' => 'Остановить', 'Stopped' => 'Остановлен', @@ -758,24 +759,24 @@ $SLANG = array( 'VersionRemindNever' => 'Не говорить о новых версиях', 'VersionRemindWeek' => 'Напомнить через неделю', 'Video' => 'Видео', - 'VideoFormat' => 'Video Format', + 'VideoFormat' => 'Формат видео', // Edited - 2019-03-24 'VideoGenFailed' => 'Ошибка генерации видео!', 'VideoGenFiles' => 'Existing Video Files', - 'VideoGenNoFiles' => 'No Video Files Found', + 'VideoGenNoFiles' => 'Видео не найдено', // Edited - 2019-03-24 'VideoGenParms' => 'Параметры генерации видео', - 'VideoGenSucceeded' => 'Video Generation Succeeded!', + 'VideoGenSucceeded' => 'Видео сгенерировано!', // Edited - 2019-03-24 'VideoSize' => 'Размер изображения', 'VideoWriter' => 'Video Writer', // Added - 2018-08-30 'View' => 'Просмотр', 'ViewAll' => 'Просм. все', - 'ViewEvent' => 'View Event', + 'ViewEvent' => 'Просм. событие', // Edited - 2019-03-24 'ViewPaged' => 'Просм. постранично', 'Wake' => 'Wake', 'WarmupFrames' => 'Кадры разогрева', 'Watch' => 'Watch', 'Web' => 'Интерфейс', 'WebColour' => 'Цвет отметки', - 'WebSiteUrl' => 'Website URL', // Added - 2018-08-30 + 'WebSiteUrl' => 'URL сайта', // Edited - 2019-03-25 'Week' => 'Неделя', 'White' => 'Бал. белого', 'WhiteBalance' => 'White Balance', @@ -798,7 +799,7 @@ $SLANG = array( 'ZoneMinMaxBlobs' => 'Мин/Макс кол-во объектов', 'ZoneMinMaxFiltArea' => 'Мин/Макс разм. фильтр. зоны ', 'ZoneMinMaxPixelThres' => 'Мин/Макс порог изм. пикс. (0-255)', - 'ZoneMinderLog' => 'ZoneMinder Log', // Added - 2011-06-17 + 'ZoneMinderLog' => 'Лог ZoneMinder', // Edited - 2019-03-25 'ZoneOverloadFrames' => 'Кол-во игнор. кадров перегрузки', 'Zones' => 'Зоны', 'Zoom' => 'Увеличение', diff --git a/web/lang/se_se.php b/web/lang/se_se.php index 4245ae974..53dd25178 100644 --- a/web/lang/se_se.php +++ b/web/lang/se_se.php @@ -290,7 +290,7 @@ $SLANG = array( 'DoNativeMotionDetection'=> 'Do Native Motion Detection', 'Donate' => 'Var vänlig och donera', 'DonateAlready' => 'Nej, Jag har redan donerat', - 'DonateEnticement' => 'Du har kört ZoneMinder ett tag nu och förhoppningsvis har du sett att det fungerar bra hemma eller på ditt företag. Även om ZoneMinder är, och kommer att vara, fri programvara och öppen kallkod, så kostar det pengar att utveckla och underhålla. Om du vill hjälpa till med framtida utveckling och nya funktioner så var vanlig och bidrag med en slant. Bidragen är naturligtvis en option men mycket uppskattade och du kan bidra med precis hur mycket du vill.

Om du vill ge ett bidrag väljer du nedan eller surfar till http://www.zoneminder.com/donate.html.

Tack för att du använder ZoneMinder, glöm inte att besöka forumen på ZoneMinder.com för support och förslag om hur du får din ZoneMinder att fungera lite bättre.', + 'DonateEnticement' => 'Du har kört ZoneMinder ett tag nu och förhoppningsvis har du sett att det fungerar bra hemma eller på ditt företag. Även om ZoneMinder är, och kommer att vara, fri programvara och öppen kallkod, så kostar det pengar att utveckla och underhålla. Om du vill hjälpa till med framtida utveckling och nya funktioner så var vanlig och bidrag med en slant. Bidragen är naturligtvis en option men mycket uppskattade och du kan bidra med precis hur mycket du vill.

Om du vill ge ett bidrag väljer du nedan eller surfar till https://zoneminder.com/donate/.

Tack för att du använder ZoneMinder, glöm inte att besöka forumen på ZoneMinder.com för support och förslag om hur du får din ZoneMinder att fungera lite bättre.', 'DonateRemindDay' => 'Inte än, påminn om 1 dag', 'DonateRemindHour' => 'Inte än, påminn om en 1 timme', 'DonateRemindMonth' => 'Inte än, påminn om 1 månad', diff --git a/web/skins/classic/css/classic/views/control.css b/web/skins/classic/css/classic/views/control.css index 381c9687c..55613d041 100644 --- a/web/skins/classic/css/classic/views/control.css +++ b/web/skins/classic/css/classic/views/control.css @@ -115,7 +115,7 @@ } .ptzControls .controlsPanel .pantiltPanel .pantiltControls .centerBtn { - background: url("../skins/classic/graphics/graphics/center.png") no-repeat 0 0; + background: url("../skins/classic/graphics/center.png") no-repeat 0 0; } .ptzControls .controlsPanel .pantiltPanel .pantiltControls .rightBtn { diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index fa57411cd..2d71b2397 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -173,12 +173,12 @@ echo output_link_if_exists( array( - + - + Path(); $videoFormats = array();