From a3158fcc97315fcd8c34a4d94ac735ded8ef9ae5 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Wed, 2 May 2018 12:26:28 -0400 Subject: [PATCH 01/10] auth_key api for different situations (#2090) * auth_key api for different situations * added new flag to indicate if password needs to be appended * pure json view --- web/api/app/Controller/HostController.php | 42 ++++++++++++++++------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index 3f1770f42..cdde92e35 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -30,20 +30,36 @@ class HostController extends AppController { )); } - function getAuthHash() { - if ( $zmOptAuth == '1' ) { - require_once '../../../includes/auth.php'; - $this->set(array( - 'auth_hash' => generateAuthHash(ZM_AUTH_HASH_IPS), - '_serialize' => array('auth_hash') - ) ); - } else { - $this->set(array( - 'auth_hash' => '', - '_serialize' => array('auth_hash') - ) ); + function getCredentials() { + // ignore debug warnings from other functions + $this->view='Json'; + $appendPassword = 0; + $this->loadModel('Config'); + $isZmAuth = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')))['Config']['Value']; + $authVal = ""; + if ($isZmAuth) { + $zmAuthRelay = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY')))['Config']['Value']; + if ($zmAuthRelay == 'hashed') { + + $zmAuthHashIps= $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_IPS')))['Config']['Value']; + $authVal = 'auth='.generateAuthHash($zmAuthHashIps); + } + elseif ($zmAuthRelay == 'plain') { + // user will need to append the store password here + $authVal = "user=".$this->Session->read('user.Username')."&pass="; + $appendPassword = 1; + } + elseif ($zmAuthRelay == 'none') { + $authVal = "user=".$this->Session->read('user.Username'); + } } - } + $this->set(array( + 'auth_key'=> $authVal, + 'append_password'=>$appendPassword, + '_serialize' => array('auth_key', 'append_password') + ) ); + } + // If $mid is set, only return disk usage for that monitor // Else, return an array of total disk usage, and per-monitor From e953a04f615d820da1948339157c26edbba64de2 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Thu, 3 May 2018 14:03:49 -0400 Subject: [PATCH 02/10] naming consistency of attribute (#2096) --- web/api/app/Controller/HostController.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/web/api/app/Controller/HostController.php b/web/api/app/Controller/HostController.php index cdde92e35..0313bd97a 100644 --- a/web/api/app/Controller/HostController.php +++ b/web/api/app/Controller/HostController.php @@ -32,31 +32,32 @@ class HostController extends AppController { function getCredentials() { // ignore debug warnings from other functions - $this->view='Json'; - $appendPassword = 0; + $this->view='Json'; + $credentials = ""; + $appendPassword = 0; + $this->loadModel('Config'); $isZmAuth = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_OPT_USE_AUTH')))['Config']['Value']; - $authVal = ""; + if ($isZmAuth) { $zmAuthRelay = $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_RELAY')))['Config']['Value']; if ($zmAuthRelay == 'hashed') { - $zmAuthHashIps= $this->Config->find('first',array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_IPS')))['Config']['Value']; - $authVal = 'auth='.generateAuthHash($zmAuthHashIps); + $credentials = 'auth='.generateAuthHash($zmAuthHashIps); } elseif ($zmAuthRelay == 'plain') { // user will need to append the store password here - $authVal = "user=".$this->Session->read('user.Username')."&pass="; + $credentials = "user=".$this->Session->read('user.Username')."&pass="; $appendPassword = 1; } elseif ($zmAuthRelay == 'none') { - $authVal = "user=".$this->Session->read('user.Username'); + $credentials = "user=".$this->Session->read('user.Username'); } } $this->set(array( - 'auth_key'=> $authVal, + 'credentials'=> $credentials, 'append_password'=>$appendPassword, - '_serialize' => array('auth_key', 'append_password') + '_serialize' => array('credentials', 'append_password') ) ); } From 375af59657dc39b064fd432e7fd4943c5505b72e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 4 May 2018 09:58:22 -0400 Subject: [PATCH 03/10] use unsigned for formatting --- src/zm_event.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 3a82a40c5..721f1a3b5 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -69,7 +69,7 @@ Event::Event( untimedEvent = true; start_time = now; } else if ( start_time.tv_sec > now.tv_sec ) { - Error("StartTime in the future %d.%d > %d.%d", + Error("StartTime in the future %u.%u > %u.%u", start_time.tv_sec, start_time.tv_usec, now.tv_sec, now.tv_usec ); start_time = now; From 7bc2c6dbc5339fbd683d3f1ed2055252a994c2e8 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Fri, 4 May 2018 12:04:28 -0500 Subject: [PATCH 04/10] Downgrade Unable to send stream to warning Downgraded this from en Error to a Warning. This message can trigger following the normal closing of a monitor. Thus, it's not necessarily an error. --- src/zm_monitorstream.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index d41b73a70..48d83200c 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -330,7 +330,7 @@ bool MonitorStream::sendFrame(const char *filepath, struct timeval *timestamp) { fprintf(stdout, "Content-Length: %d\r\n", img_buffer_size); if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) { if ( ! zm_terminate ) - Error("Unable to send stream frame: %s", strerror(errno)); + Warning("Unable to send stream frame: %s", strerror(errno)); return false; } fputs("\r\n\r\n", stdout); @@ -407,7 +407,7 @@ bool MonitorStream::sendFrame(Image *image, struct timeval *timestamp) { if ( fwrite(img_buffer, img_buffer_size, 1, stdout) != 1 ) { if ( !zm_terminate ){ // If the pipe was closed, we will get signalled SIGPIPE to exit, which will set zm_terminate - Error("Unable to send stream frame: %s", strerror(errno)); + Warning("Unable to send stream frame: %s", strerror(errno)); } return false; } From d9b6f4bd85d004d7085082d2f425af288226fb08 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 4 May 2018 16:00:55 -0400 Subject: [PATCH 05/10] test for value in DBI::errstr --- scripts/zmdc.pl.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/zmdc.pl.in b/scripts/zmdc.pl.in index 6b1a95adb..eb0b3f2d7 100644 --- a/scripts/zmdc.pl.in +++ b/scripts/zmdc.pl.in @@ -302,7 +302,7 @@ sub run { if ( ! ( $secs_count % 60 ) ) { Debug("Connecting"); while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) { - Warning("Not connected to db ($dbh)".($dbh?" ping(".$dbh->ping().")":''). " errstr($DBI::errstr). Reconnecting"); + Warning("Not connected to db ($dbh)".($dbh?" ping(".$dbh->ping().")":''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting'); $dbh = zmDbConnect(); } my @cpuload = CpuLoad(); From 4d4a7a4221424fcc26770601c4163cd2870f4fe8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 7 May 2018 10:27:06 -0400 Subject: [PATCH 06/10] Initialize bytes to zero in camera constructor. --- src/zm_camera.cpp | 67 +++++++++++++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 26 deletions(-) diff --git a/src/zm_camera.cpp b/src/zm_camera.cpp index afcce7616..3e600a378 100644 --- a/src/zm_camera.cpp +++ b/src/zm_camera.cpp @@ -1,51 +1,66 @@ // // ZoneMinder Camera Class Implementation, $Date$, $Revision$ // Copyright (C) 2001-2008 Philip Coombes -// +// // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. -// +// // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. -// +// // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -// +// #include "zm.h" #include "zm_camera.h" -Camera::Camera( unsigned int p_monitor_id, SourceType p_type, unsigned int p_width, unsigned int p_height, int p_colours, int p_subpixelorder, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : - monitor_id( p_monitor_id ), - type( p_type ), - width( p_width), - height( p_height ), - colours( p_colours ), - subpixelorder( p_subpixelorder ), - brightness( p_brightness ), - hue( p_hue ), - colour( p_colour ), - contrast( p_contrast ), - capture( p_capture ), - record_audio( p_record_audio ) +Camera::Camera( + unsigned int p_monitor_id, + SourceType p_type, + unsigned int p_width, + unsigned int p_height, + int p_colours, + int p_subpixelorder, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio + ) : + monitor_id(p_monitor_id), + type(p_type), + width(p_width), + height(p_height), + colours(p_colours), + subpixelorder(p_subpixelorder), + brightness(p_brightness), + hue(p_hue), + colour(p_colour), + contrast(p_contrast), + capture(p_capture), + record_audio(p_record_audio), + bytes(0) { pixels = width * height; imagesize = pixels * colours; - - Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d",monitor_id,width,height,colours,subpixelorder,capture); - + + Debug(2,"New camera id: %d width: %d height: %d colours: %d subpixelorder: %d capture: %d", + monitor_id,width,height,colours,subpixelorder,capture); + /* Because many loops are unrolled and work on 16 colours/time or 4 pixels/time, we have to meet requirements */ - if((colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0) { + if ( (colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB32) && (imagesize % 64) != 0 ) { Fatal("Image size is not multiples of 64"); - } else if(colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0)) { + } else if ( colours == ZM_COLOUR_RGB24 && ((imagesize % 64) != 0 || (imagesize % 12) != 0) ) { Fatal("Image size is not multiples of 12 and 64"); } - monitor = NULL; + monitor = NULL; } Camera::~Camera() { @@ -53,11 +68,11 @@ Camera::~Camera() { Monitor *Camera::getMonitor() { if ( ! monitor ) - monitor = Monitor::Load( monitor_id, false, Monitor::QUERY ); + monitor = Monitor::Load(monitor_id, false, Monitor::QUERY); return monitor; -} +} -void Camera::setMonitor( Monitor *p_monitor ) { +void Camera::setMonitor(Monitor *p_monitor) { monitor = p_monitor; monitor_id = monitor->Id(); } From 8ed015966b352da7ed952060a910b250b204977c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 7 May 2018 10:27:26 -0400 Subject: [PATCH 07/10] add zm_terminate to main while loop --- src/zm_libvlc_camera.cpp | 88 +++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 24 deletions(-) diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index bc259fd8f..6508dcdf9 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -18,6 +18,7 @@ */ #include "zm.h" +#include "zm_signal.h" #include "zm_libvlc_camera.h" #if HAVE_LIBVLC @@ -39,7 +40,7 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { LibvlcPrivateData* data = reinterpret_cast(opaque); bool newFrame = false; - for( uint32_t i = 0; i < data->bufferSize; i++ ) { + for( unsigned int i=0; i < data->bufferSize; i++ ) { if ( data->buffer[i] != data->prevBuffer[i] ) { newFrame = true; break; @@ -56,11 +57,38 @@ void LibvlcUnlockBuffer(void* opaque, void* picture, void *const *planes) { } } -LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::string &p_method, const std::string &p_options, int p_width, int p_height, int p_colours, int p_brightness, int p_contrast, int p_hue, int p_colour, bool p_capture, bool p_record_audio ) : - Camera( p_id, LIBVLC_SRC, p_width, p_height, p_colours, ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), p_brightness, p_contrast, p_hue, p_colour, p_capture, p_record_audio ), - mPath( p_path ), - mMethod( p_method ), - mOptions( p_options ) +LibvlcCamera::LibvlcCamera( + int p_id, + const std::string &p_path, + const std::string &p_method, + const std::string &p_options, + int p_width, + int p_height, + int p_colours, + int p_brightness, + int p_contrast, + int p_hue, + int p_colour, + bool p_capture, + bool p_record_audio + ) : + Camera( + p_id, + LIBVLC_SRC, + p_width, + p_height, + p_colours, + ZM_SUBPIX_ORDER_DEFAULT_FOR_COLOUR(p_colours), + p_brightness, + p_contrast, + p_hue, + p_colour, + p_capture, + p_record_audio + ), + mPath(p_path), + mMethod(p_method), + mOptions(p_options) { mLibvlcInstance = NULL; mLibvlcMedia = NULL; @@ -70,15 +98,15 @@ LibvlcCamera::LibvlcCamera( int p_id, const std::string &p_path, const std::stri mOptArgV = NULL; /* 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_BGRA; mTargetChroma = "RV32"; mBpp = 4; - } else if(colours == ZM_COLOUR_RGB24) { + } else if ( colours == ZM_COLOUR_RGB24 ) { subpixelorder = ZM_SUBPIX_ORDER_BGR; mTargetChroma = "RV24"; mBpp = 3; - } else if(colours == ZM_COLOUR_GRAY8) { + } else if ( colours == ZM_COLOUR_GRAY8 ) { subpixelorder = ZM_SUBPIX_ORDER_NONE; mTargetChroma = "GREY"; mBpp = 1; @@ -118,11 +146,13 @@ void LibvlcCamera::Initialise() { void LibvlcCamera::Terminate() { libvlc_media_player_stop(mLibvlcMediaPlayer); - if(mLibvlcData.buffer != NULL) { + if ( mLibvlcData.buffer ) { zm_freealigned(mLibvlcData.buffer); + mLibvlcData.buffer = NULL; } - if(mLibvlcData.prevBuffer != NULL) { + if ( mLibvlcData.prevBuffer ) { zm_freealigned(mLibvlcData.prevBuffer); + mLibvlcData.prevBuffer = NULL; } } @@ -139,6 +169,8 @@ int LibvlcCamera::PrimeCapture() { else if ( Method() == "rtpRtspHttp" ) opVect.push_back("--rtsp-http"); + opVect.push_back("--no-audio"); + if ( opVect.size() > 0 ) { mOptArgV = new char*[opVect.size()]; Debug(2, "Number of Options: %d",opVect.size()); @@ -149,17 +181,23 @@ int LibvlcCamera::PrimeCapture() { } } - mLibvlcInstance = libvlc_new (opVect.size(), (const char* const*)mOptArgV); - if ( mLibvlcInstance == NULL ) - Fatal("Unable to create libvlc instance due to: %s", libvlc_errmsg()); + mLibvlcInstance = libvlc_new(opVect.size(), (const char* const*)mOptArgV); + if ( mLibvlcInstance == NULL ) { + Error("Unable to create libvlc instance due to: %s", libvlc_errmsg()); + return -1; + } mLibvlcMedia = libvlc_media_new_location(mLibvlcInstance, mPath.c_str()); - if(mLibvlcMedia == NULL) - Fatal("Unable to open input %s due to: %s", mPath.c_str(), libvlc_errmsg()); + if ( mLibvlcMedia == NULL ) { + Error("Unable to open input %s due to: %s", mPath.c_str(), libvlc_errmsg()); + return -1; + } mLibvlcMediaPlayer = libvlc_media_player_new_from_media(mLibvlcMedia); - if(mLibvlcMediaPlayer == NULL) - Fatal("Unable to create player for %s due to: %s", mPath.c_str(), libvlc_errmsg()); + if ( mLibvlcMediaPlayer == NULL ) { + Error("Unable to create player for %s due to: %s", mPath.c_str(), libvlc_errmsg()); + return -1; + } libvlc_video_set_format(mLibvlcMediaPlayer, mTargetChroma.c_str(), width, height, width * mBpp); libvlc_video_set_callbacks(mLibvlcMediaPlayer, &LibvlcLockBuffer, &LibvlcUnlockBuffer, NULL, &mLibvlcData); @@ -177,13 +215,16 @@ int LibvlcCamera::PrimeCapture() { } int LibvlcCamera::PreCapture() { - return(0); + return 0; } // Should not return -1 as cancels capture. Always wait for image if available. -int LibvlcCamera::Capture( Image &image ) { - while(!mLibvlcData.newImage.getValueImmediate()) +int LibvlcCamera::Capture(Image &image) { + while( !mLibvlcData.newImage.getValueImmediate() ) { + if (zm_terminate) + return 0; mLibvlcData.newImage.getUpdatedValue(1); + } mLibvlcData.mutex.lock(); image.Assign(width, height, colours, subpixelorder, mLibvlcData.buffer, width * height * mBpp); @@ -193,13 +234,12 @@ int LibvlcCamera::Capture( Image &image ) { return 1; } -// Should not return -1 as cancels capture. Always wait for image if available. int LibvlcCamera::CaptureAndRecord(Image &image, timeval recording, char* event_directory) { - return (0); + return 0; } int LibvlcCamera::PostCapture() { - return(0); + return 0; } #endif // HAVE_LIBVLC From b6887c277d499bf38b62376f88d0e39518b21f0b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 7 May 2018 10:27:40 -0400 Subject: [PATCH 08/10] google code style --- src/zm_libvlc_camera.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zm_libvlc_camera.h b/src/zm_libvlc_camera.h index 1a061780b..f5c659e72 100644 --- a/src/zm_libvlc_camera.h +++ b/src/zm_libvlc_camera.h @@ -41,8 +41,7 @@ struct LibvlcPrivateData ThreadData newImage; }; -class LibvlcCamera : public Camera -{ +class LibvlcCamera : public Camera { protected: std::string mPath; std::string mMethod; From cdf53e36e9fa8115b7929b8af1bd0b455d35a5be Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 7 May 2018 11:07:58 -0400 Subject: [PATCH 09/10] Google code style --- src/zm_thread.cpp | 44 +++++++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index ca5784e7c..8bb854e26 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -142,31 +142,29 @@ template const T ThreadData::getValue() const { mMutex.lock(); const T valueCopy = mValue; mMutex.unlock(); - return( valueCopy ); + return valueCopy; } -template T ThreadData::setValue( const T value ) { +template T ThreadData::setValue(const T value) { mMutex.lock(); const T valueCopy = mValue = value; mMutex.unlock(); - return( valueCopy ); + return valueCopy; } template const T ThreadData::getUpdatedValue() const { - Debug( 8, "Waiting for value update, %p", this ); + Debug(8, "Waiting for value update, %p", this); mMutex.lock(); mChanged = false; - //do { - mCondition.wait(); - //} while ( !mChanged ); + mCondition.wait(); const T valueCopy = mValue; mMutex.unlock(); - Debug( 9, "Got value update, %p", this ); - return( valueCopy ); + Debug(9, "Got value update, %p", this); + return valueCopy; } -template const T ThreadData::getUpdatedValue( double secs ) const { - Debug( 8, "Waiting for value update, %.2f secs, %p", secs, this ); +template const T ThreadData::getUpdatedValue(double secs) const { + Debug(8, "Waiting for value update, %.2f secs, %p", secs, this); mMutex.lock(); mChanged = false; //do { @@ -174,41 +172,41 @@ template const T ThreadData::getUpdatedValue( double secs ) const { //} while ( !mChanged ); const T valueCopy = mValue; mMutex.unlock(); - Debug( 9, "Got value update, %p", this ); - return( valueCopy ); + Debug(9, "Got value update, %p", this ); + return valueCopy; } -template const T ThreadData::getUpdatedValue( int secs ) const { - Debug( 8, "Waiting for value update, %d secs, %p", secs, this ); +template const T ThreadData::getUpdatedValue(int secs) const { + Debug(8, "Waiting for value update, %d secs, %p", secs, this); mMutex.lock(); mChanged = false; //do { - mCondition.wait( secs ); + mCondition.wait(secs); //} while ( !mChanged ); const T valueCopy = mValue; mMutex.unlock(); - Debug( 9, "Got value update, %p", this ); - return( valueCopy ); + Debug(9, "Got value update, %p", this); + return valueCopy; } -template void ThreadData::updateValueSignal( const T value ) { - Debug( 8, "Updating value with signal, %p", this ); +template void ThreadData::updateValueSignal(const T value) { + Debug(8, "Updating value with signal, %p", this); mMutex.lock(); mValue = value; mChanged = true; mCondition.signal(); mMutex.unlock(); - Debug( 9, "Updated value, %p", this ); + Debug(9, "Updated value, %p", this); } template void ThreadData::updateValueBroadcast( const T value ) { - Debug( 8, "Updating value with broadcast, %p", this ); + Debug(8, "Updating value with broadcast, %p", this); mMutex.lock(); mValue = value; mChanged = true; mCondition.broadcast(); mMutex.unlock(); - Debug( 9, "Updated value, %p", this ); + Debug(9, "Updated value, %p", this); } Thread::Thread() : From d31b33ffc6ad561dc8b46d272dbf85faf1a94011 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 7 May 2018 11:08:06 -0400 Subject: [PATCH 10/10] add a code comment --- src/zm_libvlc_camera.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index 6508dcdf9..833666144 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -220,6 +220,8 @@ int LibvlcCamera::PreCapture() { // Should not return -1 as cancels capture. Always wait for image if available. int LibvlcCamera::Capture(Image &image) { + + // newImage is a mutex/condition based flag to tell us when there is an image available while( !mLibvlcData.newImage.getValueImmediate() ) { if (zm_terminate) return 0;