diff --git a/.eslintignore b/.eslintignore index f5529e8ee..55fe41a49 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,6 +5,7 @@ web/api/lib web/includes/csrf/ web/js/videojs.zoomrotate.js web/skins/classic/js/bootstrap-4.5.0.js +web/skins/classic/js/bootstrap.bundle.min.js web/skins/classic/js/chosen web/skins/classic/js/dateTimePicker web/skins/classic/js/jquery-*.js diff --git a/distros/ubuntu2004/control b/distros/ubuntu2004/control index 54ca58af1..a73713976 100644 --- a/distros/ubuntu2004/control +++ b/distros/ubuntu2004/control @@ -42,7 +42,7 @@ Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends} ,libswscale5|libswscale4 ,libswresample3|libswresample2 ,ffmpeg - ,libcurl4 + ,libcurl4, libcurl4-gnutls-dev ,libdatetime-perl, libdate-manip-perl, libmime-lite-perl, libmime-tools-perl ,libdbd-mysql-perl ,libphp-serialization-perl diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 7260791a5..ea785195e 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -95,6 +95,7 @@ void Image::update_function_pointers() { delta8_abgr = &std_delta8_abgr; delta8_gray8 = &std_delta8_gray8; blend = &std_blend; + Warning("Using slow std functions"); } else { // Use either sse or neon, or loop unrolled version delta8_rgb = fptr_delta8_rgb; @@ -1737,7 +1738,6 @@ void Image::Overlay( const Image &image, const unsigned int lo_x, const unsigned } // end void Image::Overlay( const Image &image, unsigned int x, unsigned int y ) void Image::Blend( const Image &image, int transparency ) { - uint8_t* new_buffer; if ( !( width == image.width && height == image.height @@ -1751,7 +1751,7 @@ void Image::Blend( const Image &image, int transparency ) { if ( transparency <= 0 ) return; - new_buffer = AllocBuffer(size); + uint8_t* new_buffer = AllocBuffer(size); #ifdef ZM_IMAGE_PROFILING TimePoint start = std::chrono::steady_clock::now(); @@ -3397,6 +3397,7 @@ __attribute__((noinline)) void neon64_armv8_fastblend(const uint8_t* col1, const } __attribute__((noinline)) void std_blend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent) { + Warning("Using slow std_blend"); double divide = blendpercent / 100.0; double opacity = 1.0 - divide; const uint8_t* const max_ptr = result + count; diff --git a/web/ajax/status.php b/web/ajax/status.php index 7ddc85176..0d17213a5 100644 --- a/web/ajax/status.php +++ b/web/ajax/status.php @@ -387,6 +387,7 @@ function getFrameImage() { $sql = 'SELECT * FROM Frames WHERE EventId = ? AND FrameId = ?'; if ( !($frame = dbFetchOne($sql, NULL, array($eventId, $frameId))) ) { + ZM\Error("Frame not found for event $eventId frame $frameId"); $frame = array(); $frame['EventId'] = $eventId; $frame['FrameId'] = $frameId; diff --git a/web/includes/actions/options.php b/web/includes/actions/options.php index 07b71c001..9b0033f4e 100644 --- a/web/includes/actions/options.php +++ b/web/includes/actions/options.php @@ -24,6 +24,8 @@ if ( !canEdit('System') ) { return; } +global $error_message; + if ( $action == 'delete' ) { if ( isset($_REQUEST['object']) ) { if ( $_REQUEST['object'] == 'server' ) { @@ -65,10 +67,19 @@ if ( $action == 'delete' ) { } if ( isset($newValue) && ($newValue != $config['Value']) ) { + # Handle special cases first + if ($config['Name'] == 'ZM_LANG_DEFAULT') { + # Verify that the language file exists in the lang directory. + if (!file_exists(ZM_PATH_WEB.'/lang/'.$newValue.'.php')) { + $error_message .= 'Error setting ' . $config['Name'].'. New value ' .$newValue.' not saved because '.ZM_PATH_WEB.'/lang/'.$newValue.'.php doesn\'t exist.
'; + ZM\Error($error_message); + continue; + } + } dbQuery('UPDATE Config SET Value=? WHERE Name=?', array($newValue, $config['Name'])); $changed = true; - } - } + } # end if value changed + } # end foreach config entry if ( $changed ) { switch ( $_REQUEST['tab'] ) { case 'system' : diff --git a/web/includes/actions/user.php b/web/includes/actions/user.php index b13471231..75bcf3f7f 100644 --- a/web/includes/actions/user.php +++ b/web/includes/actions/user.php @@ -44,12 +44,21 @@ if ($action == 'Save') { } else { unset($_REQUEST['newUser']['Password']); } + if (isset($_REQUEST['newUser']['Language']) and $_REQUEST['newUser']['Language']) { + # Verify that the language file exists in the lang directory. + if (!file_exists(ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php')) { + $error_message .= 'Error setting Language. New value ' .$_REQUEST['newUser']['Language'].' not saved because '.ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php doesn\'t exist.
'; + ZM\Error($error_message); + unset($_REQUEST['newUser']['Language']); + unset($_REQUEST['redirect']); + } + } $changes = $dbUser->changes($_REQUEST['newUser']); - ZM\Debug("Changes: " . print_r($changes, true)); + ZM\Debug('Changes: ' . print_r($changes, true)); if (count($changes)) { if (!$dbUser->save($changes)) { - $error_message = $dbUser->get_last_error(); + $error_message .= $dbUser->get_last_error().'
'; unset($_REQUEST['redirect']); return; } @@ -73,6 +82,15 @@ if ($action == 'Save') { } else { unset($_REQUEST['newUser']['Password']); } + if (isset($_REQUEST['newUser']['Language']) and $_REQUEST['newUser']['Language']) { + # Verify that the language file exists in the lang directory. + if (!file_exists(ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php')) { + $error_message .= 'Error setting Language. New value ' .$_REQUEST['newUser']['Language'].' not saved because '.ZM_PATH_WEB.'/lang/'.$_REQUEST['newUser']['Language'].'.php doesn\'t exist.
'; + ZM\Error($error_message); + unset($_REQUEST['newUser']['Language']); + unset($_REQUEST['redirect']); + } + } $fields = array('Password'=>'', 'Language'=>'', 'HomeView'=>''); ZM\Debug("changes: ".print_r(array_intersect_key($_REQUEST['newUser'], $fields),true)); $changes = $dbUser->changes(array_intersect_key($_REQUEST['newUser'], $fields)); @@ -80,7 +98,7 @@ if ($action == 'Save') { if (count($changes)) { if (!$dbUser->save($changes)) { - $error_message = $dbUser->get_last_error(); + $error_message .= $dbUser->get_last_error(); unset($_REQUEST['redirect']); return; } diff --git a/web/includes/lang.php b/web/includes/lang.php index 78a64a0e1..9fb4c8193 100644 --- a/web/includes/lang.php +++ b/web/includes/lang.php @@ -30,20 +30,21 @@ function translate($name) { function loadLanguage($prefix='') { global $user; - if ( $prefix ) + if ($prefix) $prefix = $prefix.'/'; - if ( isset($user['Language']) and $user['Language'] ) { - $userLangFile = $prefix.'lang/'.$user['Language'].'.php'; + if (isset($user['Language']) and $user['Language']) { + # Languages can only have letters, numbers and underscore + $userLangFile = $prefix.'lang/'.preg_replace('/[^[:alnum:]_]+/', '', $user['Language']).'.php'; - if ( file_exists($userLangFile) ) { + if (file_exists($userLangFile)) { return $userLangFile; } else { ZM\Warning("User language file $userLangFile does not exist."); } } - $systemLangFile = $prefix.'lang/'.ZM_LANG_DEFAULT.'.php'; + $systemLangFile = $prefix.'lang/'.preg_replace('/[^[:alnum:]_]+/', '', ZM_LANG_DEFAULT).'.php'; if ( file_exists($systemLangFile) ) { return $systemLangFile; } else { diff --git a/web/skins/classic/css/base/skin.css b/web/skins/classic/css/base/skin.css index ff37e5dd8..07e79bf20 100644 --- a/web/skins/classic/css/base/skin.css +++ b/web/skins/classic/css/base/skin.css @@ -340,6 +340,14 @@ ul.tabList li.active a { .alarm, .errorText, .error { color: #ff3f34; } +/* Refers to the error box at the top of the web UI */ +#error { + width: 100%; + padding: 5px; + font-weight: bold; + background-color: white; + color: #ff3f34; +} .timedErrorBox { color:white; diff --git a/web/skins/classic/css/base/views/timeline.css b/web/skins/classic/css/base/views/timeline.css index 815492bb6..5c09fb4f7 100644 --- a/web/skins/classic/css/base/views/timeline.css +++ b/web/skins/classic/css/base/views/timeline.css @@ -36,18 +36,23 @@ #topPanel { position: relative; - height: 220px; + min-height: 220px; margin: 4px auto 6px; } +#topPanel:after { + content: "."; + display: block; + height: 0; + font-size: 0; + clear: both; + visibility: hidden; +} -#topPanel #imagePanel -{ - width: 50%; - float: left; +#topPanel .imagePanel { text-align: right; } -#topPanel #image { +#topPanel .image { margin: 0 auto; text-align: right; margin-right: 2px; @@ -57,7 +62,7 @@ width: 100%; } -#topPanel #image img { +#topPanel .image img { width: auto; max-width: 100%; height: 100%; @@ -66,6 +71,7 @@ bottom: 0; left: 0; right: 0; + margin: 0 auto; } #topPanel #dataPanel { @@ -89,6 +95,7 @@ } #topPanel #navPanel { + float: left; width: 100%; height: 70px; margin: 4px auto; diff --git a/web/skins/classic/css/base/views/timeline.css.php b/web/skins/classic/css/base/views/timeline.css.php index d993ce9a0..586fdbe85 100644 --- a/web/skins/classic/css/base/views/timeline.css.php +++ b/web/skins/classic/css/base/views/timeline.css.php @@ -8,7 +8,9 @@ .chartSize { - height: px; +/* + min-height: px; +*/ } .graphSize { diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 6055a5805..0f0a9352b 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -169,7 +169,7 @@ function getBodyTopHTML() { '; global $error_message; if ( $error_message ) { - echo '
'.$error_message.'
'; + echo '
'.$error_message.'
'; } } // end function getBodyTopHTML @@ -203,7 +203,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $skin) $status = runtimeStatus($running); ?> -
+
- +JanusEnabled() ) { +?> + + diff --git a/web/skins/classic/views/export.php b/web/skins/classic/views/export.php index 306a61083..ab444e551 100644 --- a/web/skins/classic/views/export.php +++ b/web/skins/classic/views/export.php @@ -86,7 +86,7 @@ $limitQuery = ''; if ( $user['MonitorIds'] ) { $user_monitor_ids = ' M.Id in ('.$user['MonitorIds'].')'; $eventsSql .= $user_monitor_ids; -} else { +} else if ( !isset($_REQUEST['filter']) ) { $eventsSql .= ' 1'; } @@ -98,7 +98,7 @@ if ( isset($_REQUEST['eid']) and $_REQUEST['eid'] ) { $eventsValues += $_REQUEST['eids']; } else if ( isset($_REQUEST['filter']) ) { parseSort(); - $filter = Filter::parse($_REQUEST['filter']); + $filter = ZM\Filter::parse($_REQUEST['filter']); $filterQuery = $filter->querystring(); if ( $filter->sql() ) { diff --git a/web/skins/classic/views/js/timeline.js b/web/skins/classic/views/js/timeline.js index 9e2548b23..0a18353e7 100644 --- a/web/skins/classic/views/js/timeline.js +++ b/web/skins/classic/views/js/timeline.js @@ -1,4 +1,3 @@ -var events = {}; function showEvent(e) { var eid = e.getAttribute('data-event-id'); @@ -33,60 +32,60 @@ function showEventDetail(eventHtml) { function eventDataResponse(respObj, respText) { var zm_event = respObj.event; - if ( !zm_event ) { + if (!zm_event) { console.log('Null event'); return; } events[zm_event.Id] = zm_event; - if ( respObj.loopback ) { + if (respObj.loopback) { requestFrameData(zm_event.Id, respObj.loopback); } } -function frameDataResponse( respObj, respText ) { +function frameDataResponse(respObj, respText) { var frame = respObj.frameimage; - if ( !frame.FrameId ) { + if (!frame.FrameId) { console.log('Null frame'); return; } var zm_event = events[frame.EventId]; - if ( !zm_event ) { + if (!zm_event) { console.error('No event '+frame.eventId+' found'); return; } - if ( !zm_event['frames'] ) { - console.log('No frames data in event response'); - console.log(zm_event); - console.log(respObj); + if (!zm_event['frames']) { zm_event['frames'] = {}; } zm_event['frames'][frame.FrameId] = frame; zm_event['frames'][frame.FrameId]['html'] = createEventHtml( zm_event, frame ); - showEventData(frame.EventId, frame.FrameId); + showEventData(zm_event, frame.FrameId); } -function showEventData(eventId, frameId) { - if ( events[eventId] ) { - var zm_event = events[eventId]; - if ( zm_event['frames'] ) { - if ( zm_event['frames'][frameId] ) { - showEventDetail( zm_event['frames'][frameId]['html'] ); - var imagePath = 'index.php?view=image&eid='+eventId+'&fid='+frameId; - loadEventImage(imagePath, eventId, frameId); +function showEventData(zm_event, frameId) { + if (zm_event) { + if (zm_event['frames']) { + if (zm_event['frames'][frameId]) { + $j('#instruction').hide(); + eventData = $j('#eventData'+zm_event.MonitorId); + eventData.html(zm_event['frames'][frameId]['html']); + eventData.show(); + var imagePath = 'index.php?view=image&eid='+zm_event.Id+'&fid='+frameId; + loadEventImage(imagePath, zm_event, frameId); return; } else { console.log('No frames for ' + frameId); } } else { console.log('No frames'); + requestFrameData(zm_event.Id, frameId); } } else { - console.log('No event for ' + eventId); + console.log('No event'); } } @@ -102,10 +101,10 @@ function frameQuery(data) { .fail(logAjaxFail); } -function requestFrameData( eventId, frameId ) { +function requestFrameData(eventId, frameId) { var data = {}; - if ( !events[eventId] ) { + if (!events[eventId]) { data.id = eventId; data.loopback = frameId; eventQuery(data); @@ -118,32 +117,39 @@ function requestFrameData( eventId, frameId ) { function previewEvent(slot) { eventId = slot.getAttribute('data-event-id'); frameId = slot.getAttribute('data-frame-id'); - if ( events[eventId] && events[eventId]['frames'] && events[eventId]['frames'][frameId] ) { - showEventData(eventId, frameId); + if (events[eventId] && events[eventId]['frames'] && events[eventId]['frames'][frameId]) { + showEventData(events[eventId], frameId); } else { requestFrameData(eventId, frameId); } } -function loadEventImage( imagePath, eid, fid ) { - var eventData = $j('#eventData'); - var imageSrc = $j('#imageSrc'); +function loadEventImage(imagePath, zm_event, fid) { + if (!zm_event) { + console.log("No event object passed to loadEventImage"); + return; + } + + const imageSrc = $j('#imageSrc'+zm_event.MonitorId); imageSrc.show(); imageSrc.attr('src', imagePath); - imageSrc.attr('data-event-id', eid); + imageSrc.attr('data-event-id', zm_event.Id); imageSrc.attr('data-frame-id', fid); imageSrc.off('click'); - imageSrc.click(function() { + imageSrc.on('click', function() { showEvent(this); }); - eventData.attr('data-event-id', eid); - eventData.attr('data-frame-id', fid); - eventData.off('click'); - eventData.click(function() { - showEvent(this); - }); + var eventData = $j('#eventData'+zm_event.MonitorId); + if ( eventData.length ) { + eventData.off('click'); + eventData.on('click', function() { + showEvent(this); + }); + } else { + console.log("No eventdata area found for monitor " + zm_event.MonitorId); + } } function tlZoomBounds(event) { @@ -204,6 +210,11 @@ function initPage() { window.location.assign('?view=events'+filterQuery); }); + for (const mid in monitors) { + const monitor = monitors[mid]; + showEventData(events[monitor.FirstEventId], 1); + } + // Bind the data-on-click attributes associated with a div divDataOnClick(); } diff --git a/web/skins/classic/views/js/timeline.js.php b/web/skins/classic/views/js/timeline.js.php index 474e403e0..aa9d73986 100644 --- a/web/skins/classic/views/js/timeline.js.php +++ b/web/skins/classic/views/js/timeline.js.php @@ -6,18 +6,28 @@ global $maxTime; global $range; global $majXScale; + global $monEventSlots; + global $monFrameSlots; ?> var filterQuery = ''; +var events = {}; $field(); } + $firstEvent = reset($monEventSlots[$monitor->Id()])['event']; + + $jsMonitor['FirstEventId'] = $firstEvent['Id']; + echo 'events['.$firstEvent['Id'].']='.json_encode($firstEvent).';'.PHP_EOL; + $jsMonitors[$monitor->Id()] = $jsMonitor; } ?> @@ -30,3 +40,4 @@ var midTime = ''; var maxTime = ''; var range = ''; var zoomout_range = ''; + diff --git a/web/skins/classic/views/js/watch.js b/web/skins/classic/views/js/watch.js index a33f87750..66bd74b4f 100644 --- a/web/skins/classic/views/js/watch.js +++ b/web/skins/classic/views/js/watch.js @@ -807,7 +807,15 @@ function initPage() { if (monitorType == 'Local') getSettingsModal(); } // Only enable the settings button for local cameras - settingsBtn.prop('disabled', !(canView.Control && (monitorType == 'Local'))); + if (!canView.Control) { + settingsBtn.prop('disabled', true); + settingsBtn.prop('title', 'Disbled due to lack of Control View permission.'); + } else if (monitorType != 'Local') { + settingsBtn.prop('disabled', true); + settingsBtn.prop('title', 'Settings only available for Local monitors.'); + } else { + settingsBtn.prop('disabled', false); + } if (monitorType != 'WebSite') { monitorStream = new MonitorStream(monitorData[monIdx]); diff --git a/web/skins/classic/views/montage.php b/web/skins/classic/views/montage.php index a96e8a88e..b880d42e6 100644 --- a/web/skins/classic/views/montage.php +++ b/web/skins/classic/views/montage.php @@ -117,6 +117,7 @@ include('_monitor_filters.php'); $filterbar = ob_get_contents(); ob_end_clean(); +$need_janus = false; $monitors = array(); foreach ( $displayMonitors as &$row ) { if ( $row['Function'] == 'None' ) @@ -133,7 +134,10 @@ foreach ( $displayMonitors as &$row ) { if ( ! isset($heights[$row['Height']]) ) { $heights[$row['Height']] = $row['Height'].'px'; } - $monitors[] = new ZM\Monitor($row); + $monitor = $monitors[] = new ZM\Monitor($row); + if ($monitor->JanusEnabled()) { + $need_janus = true; + } } # end foreach Monitor xhtmlHeaders(__FILE__, translate('Montage')); @@ -319,6 +323,8 @@ foreach (array_reverse($zones) as $zone) {
+ + diff --git a/web/skins/classic/views/options.php b/web/skins/classic/views/options.php index 25cad40cc..5f648ba27 100644 --- a/web/skins/classic/views/options.php +++ b/web/skins/classic/views/options.php @@ -54,9 +54,9 @@ else $focusWindow = true; xhtmlHeaders(__FILE__, translate('Options')); +getBodyTopHTML(); +echo getNavBarHTML(); ?> - -
+
+

+

+

+

+
-
-
- <?php echo translate('ViewEvent') ?> -
-
-
-
-
-

-

-

-

-
-
+ +
+
> +
+ <?php echo translate('ViewEvent') ?>
+
> +
+
+
+
+
+
+ -
diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index 340ee8e33..fdcdae06d 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -397,6 +397,12 @@ if ( ZM_WEB_SOUND_ON_ALARM ) {
+JanusEnabled() ) { +?> + diff --git a/web/views/image.php b/web/views/image.php index 8e8cfdd2c..6e2c47714 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -65,7 +65,7 @@ if ( empty($_REQUEST['path']) ) { if ( empty($_REQUEST['fid']) ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('No Frame ID specified'); + ZM\Error('No Frame ID specified'); return; } @@ -73,47 +73,50 @@ if ( empty($_REQUEST['path']) ) { $Event = ZM\Event::find_one(array('Id'=>$_REQUEST['eid'])); if ( !$Event ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('Event '.$_REQUEST['eid'].' Not found'); + ZM\Error('Event '.$_REQUEST['eid'].' Not found'); return; } if ( $_REQUEST['fid'] == 'objdetect' ) { - // if animation file is found, return that, else return image - // we are only looking for GIF or jpg here, not mp4 - // as most often, browsers asking for this link will be expecting - // media types that can be rendered as - $path_anim_gif = $Event->Path().'/objdetect.gif'; - $path_image = $Event->Path().'/objdetect.jpg'; - if (file_exists($path_anim_gif)) { - // we found the animation gif file - $media_type = 'image/gif'; - ZM\Debug("Animation file found at $path"); - $path = $path_anim_gif; - } else if (file_exists($path_image)) { - // animation not found, but image found - ZM\Debug("Image file found at $path"); - $path = $path_image; - } else { - // neither animation nor image found - header('HTTP/1.0 404 Not Found'); - ZM\Fatal("Object detection animation and image not found for this event"); - } - $Frame = new ZM\Frame(); - $Frame->Id('objdetect'); - } else if ( $_REQUEST['fid'] == 'objdetect_mp4' ) { - $path = $Event->Path().'/objdetect.mp4'; - if ( !file_exists($path) ) { - header('HTTP/1.0 404 Not Found'); - ZM\Fatal("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation"); - } - $Frame = new ZM\Frame(); - $Frame->Id('objdetect'); - $media_type = 'video/mp4'; - } else if ( $_REQUEST['fid'] == 'objdetect_gif' ) { - $path = $Event->Path().'/objdetect.gif'; - if ( !file_exists($path) ) { - header('HTTP/1.0 404 Not Found'); - ZM\Fatal("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation"); + // if animation file is found, return that, else return image + // we are only looking for GIF or jpg here, not mp4 + // as most often, browsers asking for this link will be expecting + // media types that can be rendered as + $path_anim_gif = $Event->Path().'/objdetect.gif'; + $path_image = $Event->Path().'/objdetect.jpg'; + if (file_exists($path_anim_gif)) { + // we found the animation gif file + $media_type = 'image/gif'; + ZM\Debug("Animation file found at $path"); + $path = $path_anim_gif; + } else if (file_exists($path_image)) { + // animation not found, but image found + ZM\Debug("Image file found at $path"); + $path = $path_image; + } else { + // neither animation nor image found + header('HTTP/1.0 404 Not Found'); + ZM\Error('Object detection animation and image not found for this event'); + return; + } + $Frame = new ZM\Frame(); + $Frame->Id('objdetect'); + } else if ( $_REQUEST['fid'] == 'objdetect_mp4' ) { + $path = $Event->Path().'/objdetect.mp4'; + if ( !file_exists($path) ) { + header('HTTP/1.0 404 Not Found'); + ZM\Error("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation"); + return; + } + $Frame = new ZM\Frame(); + $Frame->Id('objdetect'); + $media_type = 'video/mp4'; + } else if ( $_REQUEST['fid'] == 'objdetect_gif' ) { + $path = $Event->Path().'/objdetect.gif'; + if ( !file_exists($path) ) { + header('HTTP/1.0 404 Not Found'); + ZM\Error("File $path does not exist. You might not have enabled create_animation in objectconfig.ini. If you have, inspect debug logs for errors during creation"); + return; } $Frame = new ZM\Frame(); $Frame->Id('objdetect'); @@ -122,7 +125,8 @@ if ( empty($_REQUEST['path']) ) { $path = $Event->Path().'/objdetect.jpg'; if ( !file_exists($path) ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); + ZM\Error("File $path does not exist. Please make sure store_frame_in_zm is enabled in the object detection config"); + return; } $Frame = new ZM\Frame(); $Frame->Id('objdetect'); @@ -149,7 +153,7 @@ if ( empty($_REQUEST['path']) ) { $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg'; } else { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('No alarm jpg found for event '.$_REQUEST['eid']); + ZM\Error('No alarm jpg found for event '.$_REQUEST['eid']); return; } } else { @@ -189,11 +193,12 @@ if ( empty($_REQUEST['path']) ) { ZM\Debug("Command: $command, retval: $retval, output: " . implode("\n", $output)); if ( ! file_exists($path) ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('Can\'t create frame images from video for this event '.$Event->DefaultVideo().' + ZM\Error('Can\'t create frame images from video for this event '.$Event->DefaultVideo().' Command was: '.$command.' Output was: '.implode(PHP_EOL,$output) ); + return; } # Generating an image file will use up more disk space, so update the Event record. if ( $Event->EndDateTime() ) { @@ -202,7 +207,7 @@ if ( empty($_REQUEST['path']) ) { } } else { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('No snapshot jpg found for event '.$_REQUEST['eid']); + ZM\Error('No snapshot jpg found for event '.$_REQUEST['eid']); return; } } # end if stored jpgs @@ -231,7 +236,8 @@ if ( empty($_REQUEST['path']) ) { $Frame->Delta($previousBulkFrame['Delta'] + floor( 100* ( $nextBulkFrame['Delta'] - $previousBulkFrame['Delta'] ) * $percentage )/100); ZM\Debug('Got virtual frame from Bulk Frames previous delta: ' . $previousBulkFrame['Delta'] . ' + nextdelta:' . $nextBulkFrame['Delta'] . ' - ' . $previousBulkFrame['Delta'] . ' * ' . $percentage ); } else { - ZM\Fatal('No Frame found for event('.$_REQUEST['eid'].') and frame id('.$_REQUEST['fid'].')'); + ZM\Error('No Frame found for event('.$_REQUEST['eid'].') and frame id('.$_REQUEST['fid'].')'); + return; } } # end if !Frame // Frame can be non-existent. We have Bulk frames. So now we should try to load the bulk frame @@ -244,14 +250,14 @@ if ( empty($_REQUEST['path']) ) { $Frame = ZM\Frame::find_one(array('Id'=>$_REQUEST['fid'])); if ( !$Frame ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('Frame ' . $_REQUEST['fid'] . ' Not Found'); + ZM\Error('Frame ' . $_REQUEST['fid'] . ' Not Found'); return; } $Event = ZM\Event::find_one(array('Id'=>$Frame->EventId())); if ( !$Event ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('Event ' . $Frame->EventId() . ' Not Found'); + ZM\Error('Event ' . $Frame->EventId() . ' Not Found'); return; } $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg'; @@ -263,7 +269,8 @@ if ( empty($_REQUEST['path']) ) { if ( ($show == 'capture') and $Event->DefaultVideo() ) { if ( !file_exists($Event->Path().'/'.$Event->DefaultVideo()) ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal("Can't create frame images from video because there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() ); + ZM\Error("Can't create frame images from video because there is no video file for this event at (".$Event->Path().'/'.$Event->DefaultVideo() ); + return; } $command = ZM_PATH_FFMPEG.' -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -frames:v 1 '.$path . ' 2>&1'; #$command ='ffmpeg -ss '. $Frame->Delta() .' -i '.$Event->Path().'/'.$Event->DefaultVideo().' -vf "select=gte(n\\,'.$Frame->FrameId().'),setpts=PTS-STARTPTS" '.$path; @@ -275,11 +282,12 @@ if ( empty($_REQUEST['path']) ) { ZM\Debug("Command: $command, retval: $retval, output: " . implode("\n", $output)); if ( ! file_exists($path) ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal('Can\'t create frame images from video for this event '.$Event->DefaultVideo().' + ZM\Error('Can\'t create frame images from video for this event '.$Event->DefaultVideo().' Command was: '.$command.' Output was: '.implode(PHP_EOL,$output) ); + return; } # Generating an image file will use up more disk space, so update the Event record. if ( $Event->EndDateTime() ) { @@ -288,8 +296,9 @@ Output was: '.implode(PHP_EOL,$output) ); } } else { header('HTTP/1.0 404 Not Found'); - ZM\Fatal("Can't create frame $show images from video because there is no video file for this event at ". + ZM\Error("Can't create frame $show images from video because there is no video file for this event at ". $Event->Path().'/'.$Event->DefaultVideo() ); + return; } } # end if ! file_exists($path) @@ -317,7 +326,8 @@ Output was: '.implode(PHP_EOL,$output) ); } if ( !file_exists($path) ) { header('HTTP/1.0 404 Not Found'); - ZM\Fatal("Image not found at $path"); + ZM\Error("Image not found at $path"); + return; } }