diff --git a/src/zm_box.h b/src/zm_box.h index efc12cb18..ca3e6fd39 100644 --- a/src/zm_box.h +++ b/src/zm_box.h @@ -47,10 +47,14 @@ public: inline const Coord &Lo() const { return lo; } inline int LoX() const { return lo.X(); } + inline int LoX(int p_lo_x) { return lo.X(p_lo_x); } inline int LoY() const { return lo.Y(); } + inline int LoY(int p_lo_y) { return lo.Y(p_lo_y); } inline const Coord &Hi() const { return hi; } inline int HiX() const { return hi.X(); } + inline int HiX(int p_hi_x) { return hi.X(p_hi_x); } inline int HiY() const { return hi.Y(); } + inline int HiY(int p_hi_y) { return hi.Y(p_hi_y); } inline const Coord &Size() const { return size; } inline int Width() const { return size.X(); } inline int Height() const { return size.Y(); } diff --git a/src/zm_coord.h b/src/zm_coord.h index bb49c2f8b..d5167d46b 100644 --- a/src/zm_coord.h +++ b/src/zm_coord.h @@ -38,14 +38,14 @@ public: y = coord.y; return *this; } - inline int &X() { return( x ); } - inline const int &X() const { return( x ); } - inline int &Y() { return( y ); } - inline const int &Y() const { return( y ); } + inline int &X(int p_x) { x=p_x; return x; } + inline const int &X() const { return x; } + inline int &Y(int p_y) { y=p_y; return y; } + inline const int &Y() const { return y; } inline static Coord Range( const Coord &coord1, const Coord &coord2 ) { Coord result( (coord1.x-coord2.x)+1, (coord1.y-coord2.y)+1 ); - return( result ); + return result; } inline bool operator==( const Coord &coord ) const { return( x == coord.x && y == coord.y ); } diff --git a/src/zm_event.h b/src/zm_event.h index a8acaff18..ce94f68d7 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -178,6 +178,7 @@ class Event { return pre_alarm_count; } static void EmptyPreAlarmFrames() { +#if 0 while ( pre_alarm_count > 0 ) { int i = pre_alarm_count - 1; delete pre_alarm_data[i].image; @@ -188,6 +189,7 @@ class Event { } pre_alarm_count--; } +#endif pre_alarm_count = 0; } static void AddPreAlarmFrame( @@ -196,15 +198,18 @@ class Event { int score=0, Image *alarm_frame=nullptr ) { +#if 0 pre_alarm_data[pre_alarm_count].image = new Image(*image); pre_alarm_data[pre_alarm_count].timestamp = timestamp; pre_alarm_data[pre_alarm_count].score = score; if ( alarm_frame ) { pre_alarm_data[pre_alarm_count].alarm_frame = new Image(*alarm_frame); } +#endif pre_alarm_count++; } void SavePreAlarmFrames() { +#if 0 for ( int i = 0; i < pre_alarm_count; i++ ) { AddFrame( pre_alarm_data[i].image, @@ -212,6 +217,7 @@ class Event { pre_alarm_data[i].score, pre_alarm_data[i].alarm_frame); } +#endif EmptyPreAlarmFrames(); } }; diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index f7bf1c2cc..f7857da2c 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -207,7 +207,7 @@ int FfmpegCamera::PrimeCapture() { mAudioStreamId = -1; Debug(1, "Priming capture from %s", mPath.c_str()); - return ! OpenFfmpeg(); + return OpenFfmpeg(); } int FfmpegCamera::PreCapture() { diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 92410fc63..ca67ffbb3 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -17,26 +17,10 @@ FFmpeg_Input::~FFmpeg_Input() { if ( input_format_context ) { Close(); } - if ( streams ) { - for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { - avcodec_close(streams[i].context); - avcodec_free_context(&streams[i].context); - } - delete[] streams; - streams = nullptr; - } if ( frame ) { av_frame_free(&frame); frame = nullptr; } - if ( input_format_context ) { -#if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) - av_close_input_file(input_format_context); -#else - avformat_close_input(&input_format_context); -#endif - input_format_context = nullptr; - } } // end ~FFmpeg_Input() int FFmpeg_Input::Open( @@ -137,14 +121,16 @@ int FFmpeg_Input::Open(const char *filepath) { } // end int FFmpeg_Input::Open( const char * filepath ) int FFmpeg_Input::Close( ) { - for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { - if ( streams[i].context ) { + if ( streams ) { + for ( unsigned int i = 0; i < input_format_context->nb_streams; i += 1 ) { avcodec_close(streams[i].context); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) avcodec_free_context(&streams[i].context); + streams[i].context = nullptr; #endif - streams[i].context = NULL; } + delete[] streams; + streams = nullptr; } if ( input_format_context ) { @@ -153,7 +139,7 @@ int FFmpeg_Input::Close( ) { #else avformat_close_input(&input_format_context); #endif - input_format_context = NULL; + input_format_context = nullptr; } return 1; } // end int FFmpeg_Input::Close() @@ -164,7 +150,6 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) { av_init_packet(&packet); while ( !frameComplete ) { - int ret = av_read_frame(input_format_context, &packet); if ( ret < 0 ) { if ( @@ -184,33 +169,33 @@ AVFrame *FFmpeg_Input::get_frame(int stream_id) { if ( (stream_id >= 0) && (packet.stream_index != stream_id) ) { Debug(1,"Packet is not for our stream (%d)", packet.stream_index ); - return NULL; - } + continue; + } AVCodecContext *context = streams[packet.stream_index].context; - if ( frame ) { - av_frame_free(&frame); - frame = zm_av_frame_alloc(); + if ( frame ) { + av_frame_free(&frame); + frame = zm_av_frame_alloc(); + } else { + frame = zm_av_frame_alloc(); + } + ret = zm_send_packet_receive_frame(context, frame, packet); + if ( ret < 0 ) { + Error("Unable to decode frame at frame %d: %d %s, continuing", + streams[packet.stream_index].frame_count, ret, av_make_error_string(ret).c_str()); + zm_av_packet_unref(&packet); + av_frame_free(&frame); + continue; + } else { + if ( is_video_stream(input_format_context->streams[packet.stream_index]) ) { + zm_dump_video_frame(frame, "resulting video frame"); } else { - frame = zm_av_frame_alloc(); - } - ret = zm_send_packet_receive_frame(context, frame, packet); - if ( ret < 0 ) { - Error("Unable to decode frame at frame %d: %d %s, continuing", - streams[packet.stream_index].frame_count, ret, av_make_error_string(ret).c_str()); - zm_av_packet_unref(&packet); - av_frame_free(&frame); - continue; - } else { - if ( is_video_stream(input_format_context->streams[packet.stream_index]) ) { - zm_dump_video_frame(frame, "resulting video frame"); - } else { - zm_dump_frame(frame, "resulting frame"); - } + zm_dump_frame(frame, "resulting frame"); } + } - frameComplete = 1; + frameComplete = 1; zm_av_packet_unref(&packet); diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 808b3e149..1df651742 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -447,7 +447,7 @@ LocalCamera::LocalCamera( #if HAVE_LIBSWSCALE /* Try using swscale for the conversion */ conversion_type = 1; - Debug(2,"Using swscale for image conversion"); + Debug(2, "Using swscale for image conversion"); if ( colours == ZM_COLOUR_RGB32 ) { subpixelorder = ZM_SUBPIX_ORDER_RGBA; imagePixFormat = AV_PIX_FMT_RGBA; @@ -650,7 +650,7 @@ LocalCamera::LocalCamera( #if HAVE_LIBSWSCALE /* Initialize swscale stuff */ - if ( capture && conversion_type == 1 ) { + if ( capture and (conversion_type == 1) ) { #if LIBAVCODEC_VERSION_CHECK(55, 28, 1, 45, 101) tmpPicture = av_frame_alloc(); #else @@ -680,7 +680,7 @@ LocalCamera::LocalCamera( #endif mVideoStreamId = 0; mAudioStreamId = -1; - video_stream = NULL; + video_stream = nullptr; } // end LocalCamera::LocalCamera LocalCamera::~LocalCamera() { @@ -689,7 +689,7 @@ LocalCamera::~LocalCamera() { #if HAVE_LIBSWSCALE /* Clean up swscale stuff */ - if ( capture && conversion_type == 1 ) { + if ( capture && (conversion_type == 1) ) { sws_freeContext(imgConversionContext); imgConversionContext = nullptr; @@ -699,13 +699,6 @@ LocalCamera::~LocalCamera() { } // end LocalCamera::~LocalCamera void LocalCamera::Initialise() { -#if HAVE_LIBSWSCALE - if ( logDebugging() ) - av_log_set_level(AV_LOG_DEBUG); - else - av_log_set_level(AV_LOG_QUIET); -#endif // HAVE_LIBSWSCALE - Debug(3, "Opening video device %s", device.c_str()); //if ( (vid_fd = open( device.c_str(), O_RDWR|O_NONBLOCK, 0 )) < 0 ) if ( (vid_fd = open(device.c_str(), O_RDWR, 0)) < 0 ) @@ -2021,12 +2014,12 @@ int LocalCamera::PrimeCapture() { #endif // ZM_HAS_V4L1 mVideoStreamId = 0; - return 0; + return 1; } // end LocalCamera::PrimeCapture int LocalCamera::PreCapture() { //Debug(5, "Pre-capturing"); - return 0; + return 1; } int LocalCamera::Capture(ZMPacket &zm_packet) { @@ -2124,12 +2117,13 @@ int LocalCamera::Capture(ZMPacket &zm_packet) { } /* prime capture */ if ( ! zm_packet.image ) { + Debug(1, "Allocating image"); zm_packet.image = new Image(width, height, colours, subpixelorder); } if ( conversion_type != 0 ) { - Debug(3, "Performing format conversion"); + Debug(3, "Performing format conversion %d", conversion_type); /* Request a writeable buffer of the target image */ uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 286405262..d60a9c04a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -333,8 +333,8 @@ Monitor::Monitor() purpose(QUERY), auto_resume_time(0), last_motion_score(0), - camera(0), - event(0), + camera(nullptr), + event(nullptr), n_zones(0), zones(nullptr), timestamps(0), @@ -1768,14 +1768,6 @@ bool Monitor::Analyse() { packets_processed += 1; packetqueue->increment_analysis_it(); - if ( snap->packet.stream_index != video_stream_id ) { - snap->unlock(); - Debug(2, "skipping because audio"); - continue; - } - - struct timeval *timestamp = snap->timestamp; - Image *snap_image = snap->image; // signal is set by capture bool signal = shared_data->signal; @@ -1820,7 +1812,6 @@ bool Monitor::Analyse() { signalText = "Reacquired"; score += 100; } - Warning("%s: %s", SIGNAL_CAUSE, signalText); if ( event && !signal ) { Info("%s: %03d - Closing event %" PRIu64 ", signal loss", name, image_count, event->Id()); closeEvent(); @@ -1835,20 +1826,25 @@ bool Monitor::Analyse() { noteSetMap[SIGNAL_CAUSE] = noteSet; shared_data->state = state = IDLE; shared_data->active = signal; - ref_image.Assign(*snap_image); + ref_image.Assign(*(snap->image)); }// else if ( signal ) { + if ( snap->packet.stream_index == video_stream_id ) { + struct timeval *timestamp = snap->timestamp; + if ( Active() && (function == MODECT || function == MOCORD) ) { Debug(3, "signal and active and modect"); Event::StringSet zoneSet; + int motion_score = last_motion_score; if ( !(analysis_image_count % (motion_frame_skip+1) ) ) { if ( snap->image ) { // Get new score. - motion_score = DetectMotion(*snap_image, zoneSet); + motion_score = DetectMotion(*(snap->image), zoneSet); - Debug(3, "After motion detection, last_motion_score(%d), new motion score(%d)", last_motion_score, motion_score); + Debug(3, "After motion detection, score:%d last_motion_score(%d), new motion score(%d)", + score, last_motion_score, motion_score); } else { Warning("No image in snap"); } @@ -1862,7 +1858,6 @@ bool Monitor::Analyse() { cause += MOTION_CAUSE; noteSetMap[MOTION_CAUSE] = zoneSet; } // end if motion_score - //shared_data->active = signal; // unneccessary active gets set on signal change } // end if active and doing motion detection // Check to see if linked monitors are triggering. @@ -2028,45 +2023,69 @@ bool Monitor::Analyse() { // Back to IDLE shared_data->state = state = function != MOCORD ? IDLE : TAPE; } else { - Debug(1, "Not leaving ALERT beacuse image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%d) - recording.tv_src(%d) >= min_section_length(%d)", image_count, last_alarm_count, post_event_count, timestamp->tv_sec, video_store_data->recording.tv_sec, min_section_length); + Debug(1, "State %d ALERT beacuse image_count(%d)-last_alarm_count(%d) > post_event_count(%d) and timestamp.tv_sec(%d) - recording.tv_src(%d) >= min_section_length(%d)", + state, analysis_image_count, last_alarm_count, post_event_count, + timestamp->tv_sec, video_store_data->recording.tv_sec, min_section_length); } if ( Event::PreAlarmCount() ) Event::EmptyPreAlarmFrames(); } // end if score or not // Flag the packet so we don't analyse it again + Debug(1, "Scoring packet"); snap->score = score; - if ( state == PREALARM || state == ALARM ) { + if ( state == PREALARM ) { + // Generate analysis images if necessary if ( savejpegs > 1 ) { - bool got_anal_image = false; - Image *anal_image = new Image( *snap_image ); - //alarm_image.Assign( *snap_image ); - for( int i = 0; i < n_zones; i++ ) { + for ( int i = 0; i < n_zones; i++ ) { if ( zones[i]->Alarmed() ) { if ( zones[i]->AlarmImage() ) { - anal_image->Overlay( *(zones[i]->AlarmImage()) ); - got_anal_image = true; + if ( ! snap->analysis_image ) + snap->analysis_image = new Image(*(snap->image)); + snap->analysis_image->Overlay( *(zones[i]->AlarmImage()) ); } - if ( config.record_event_stats && (state == ALARM) ) + } // end if zone is alarmed + } // end foreach zone + } // end if savejpegs + + // incremement pre alarm image count + //have_pre_alarmed_frames ++; + Event::AddPreAlarmFrame(snap->image, *timestamp, score, nullptr); + } else if ( state == ALARM ) { + if ( savejpegs > 1 ) { + for ( int i = 0; i < n_zones; i++ ) { + if ( zones[i]->Alarmed() ) { + if ( zones[i]->AlarmImage() ) { + if ( ! snap->analysis_image ) + snap->analysis_image = new Image(*(snap->image)); + snap->analysis_image->Overlay(*(zones[i]->AlarmImage())); + } + if ( config.record_event_stats ) zones[i]->RecordStats(event); } // end if zone is alarmed } // end foreach zone - if ( got_anal_image ) { - snap->analysis_image = anal_image; - } else { - delete anal_image; - } - } else if ( config.record_event_stats && state == ALARM ) { - for ( int i = 0; i < n_zones; i++ ) { - if ( zones[i]->Alarmed() ) { - zones[i]->RecordStats(event); - } - } // end foreach zone - } // analsys_images or record stats - + } if ( noteSetMap.size() > 0 ) - event->updateNotes( noteSetMap ); + 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 + ); + closeEvent(); + event = new Event(this, *timestamp, cause, noteSetMap); + shared_data->last_event_id = event->Id(); + //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(); + } + } else if ( state == ALERT ) { // Alert means this frame has no motion, but we were alarmed and are still recording. if ( noteSetMap.size() > 0 ) @@ -2079,11 +2098,14 @@ bool Monitor::Analyse() { //event->AddFrame( snap_image, *timestamp ); //} //} - } - if ( function == MODECT || function == MOCORD ) { - ref_image.Blend( *snap_image, ( state==ALARM ? alarm_ref_blend_perc : ref_blend_perc ) ); - } - last_signal = signal; + } // end if state machine + + if ( function == MODECT || function == MOCORD ) { + ref_image.Blend(*(snap->image), ( state==ALARM ? alarm_ref_blend_perc : ref_blend_perc )); + } + last_signal = signal; + + } // end if videostream } // end if signal } else { @@ -2826,7 +2848,7 @@ unsigned int Monitor::SubpixelOrder() const { return camera->SubpixelOrder(); } int Monitor::PrimeCapture() { int ret = camera->PrimeCapture(); - if ( ret == 0 ) { + if ( ret > 0 ) { if ( packetqueue ) delete packetqueue; video_stream_id = camera->get_VideoStreamId(); @@ -2835,14 +2857,13 @@ int Monitor::PrimeCapture() { Debug(2, "Video stream id is %d, audio is %d, minimum_packets to keep in buffer %d", video_stream_id, audio_stream_id, pre_event_buffer_count); } else { - Debug(2, "Not Video stream id is %d, audio is %d, minimum_packets to keep in buffer %d", - video_stream_id, audio_stream_id, pre_event_buffer_count); + Debug(2, "Failed to prime %d", ret); } return ret; } int Monitor::PreCapture() const { return camera->PreCapture(); } -int Monitor::PostCapture() const { return camera->PostCapture() ; } +int Monitor::PostCapture() const { return camera->PostCapture(); } int Monitor::Close() { if ( packetqueue ) { delete packetqueue; diff --git a/src/zm_poly.h b/src/zm_poly.h index 53eafcf84..7c5ee4a07 100644 --- a/src/zm_poly.h +++ b/src/zm_poly.h @@ -100,9 +100,13 @@ public: inline const Box &Extent() const { return extent; } inline int LoX() const { return extent.LoX(); } + inline int LoX(int p_lo_x) { return extent.LoX(p_lo_x); } inline int HiX() const { return extent.HiX(); } + inline int HiX(int p_hi_x) { return extent.HiX(p_hi_x); } inline int LoY() const { return extent.LoY(); } + inline int LoY(int p_lo_y) { return extent.LoY(p_lo_y); } inline int HiY() const { return extent.HiY(); } + inline int HiY(int p_hi_y) { return extent.HiY(p_hi_y); } inline int Width() const { return extent.Width(); } inline int Height() const { return extent.Height(); } diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index 14014b003..ec97b3578 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -269,9 +269,9 @@ void *Thread::mThreadFunc( void *arg ) { } void Thread::start() { - Debug( 1, "Starting thread" ); + Debug(4, "Starting thread" ); if ( isThread() ) - throw ThreadException( "Can't self start thread" ); + throw ThreadException("Can't self start thread"); mThreadMutex.lock(); if ( !mStarted ) { pthread_attr_t threadAttrs; @@ -287,11 +287,11 @@ void Thread::start() { } mThreadCondition.wait(); mThreadMutex.unlock(); - Debug( 1, "Started thread %d", mPid ); + Debug(4, "Started thread %d", mPid); } void Thread::join() { - Debug( 1, "Joining thread %d", mPid ); + Debug(1, "Joining thread %d", mPid); if ( isThread() ) throw ThreadException( "Can't self join thread" ); mThreadMutex.lock(); diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 13c2e544c..cd450ac24 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -148,14 +148,14 @@ bool VideoStore::open() { int wanted_codec = monitor->OutputCodec(); if ( !wanted_codec ) { // default to h264 - Debug(2, "Defaulting to H264"); - wanted_codec = AV_CODEC_ID_H264; + //Debug(2, "Defaulting to H264"); + //wanted_codec = AV_CODEC_ID_H264; } else { Debug(2, "Codec is %d, wanted %d", video_in_ctx->codec_id, wanted_codec); } // FIXME Should check that we are set to passthrough. Might be same codec, but want privacy overlays - if ( video_in_ctx->codec_id == wanted_codec ) { + if ( (!wanted_codec) or (video_in_ctx->codec_id == wanted_codec) ) { // Copy params from instream to ctx #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); @@ -235,6 +235,8 @@ bool VideoStore::open() { AVDictionary *opts = 0; std::string Options = monitor->GetEncoderOptions(); + Debug(2, "Options?"); + Debug(2, "Options? %s", Options.c_str()); ret = av_dict_parse_string(&opts, Options.c_str(), "=", ",#\n", 0); if ( ret < 0 ) { Warning("Could not parse ffmpeg encoder options list '%s'\n", Options.c_str()); diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index a781d522d..047432f4e 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -891,10 +891,12 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { if ( polygon.LoX() < 0 || polygon.HiX() >= (int)monitor->Width() || polygon.LoY() < 0 || polygon.HiY() >= (int)monitor->Height() ) { - Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), ignoring", + Error("Zone %d/%s for monitor %s extends outside of image dimensions, (%d,%d), (%d,%d), fixing", Id, Name, monitor->Name(), polygon.LoX(), polygon.LoY(), polygon.HiX(), polygon.HiY()); - n_zones -= 1; - continue; + if ( polygon.LoX() < 0 ) polygon.LoX(0); + if ( polygon.HiX() >= (int)monitor->Width()) polygon.HiX((int)monitor->Width()); + if ( polygon.LoY() < 0 ) polygon.LoY(0); + if ( polygon.HiY() >= (int)monitor->Height() ) polygon.HiY((int)monitor->Height()); } if ( false && !strcmp( Units, "Percent" ) ) { diff --git a/src/zmc.cpp b/src/zmc.cpp index 1df6a5872..2fc4bfc7f 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -269,15 +269,18 @@ int main(int argc, char *argv[]) { } // end foreach monitor // Outer primary loop, handles connection to camera - if ( monitors[0]->PrimeCapture() < 0 ) { + if ( monitors[0]->PrimeCapture() <= 0 ) { if ( prime_capture_log_count % 60 ) { Error("Failed to prime capture of initial monitor"); } else { Debug(1, "Failed to prime capture of initial monitor"); } prime_capture_log_count ++; - if ( !zm_terminate ) - sleep(10); + monitors[0]->disconnect(); + if ( !zm_terminate ) { + Debug(1, "Sleeping"); + sleep(5); + } continue; } for ( int i = 0; i < n_monitors; i++ ) { @@ -415,6 +418,7 @@ int main(int argc, char *argv[]) { delete [] monitors; Image::Deinitialise(); + Debug(1,"terminating"); logTerm(); zmDbClose(); diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index e7b952a4a..015c98b3d 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -296,50 +296,44 @@ function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $ski ?>
-
+ + - @@ -350,30 +344,30 @@ function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $ski - + - + - +