diff --git a/Source/IpFreely.pro b/Source/IpFreely.pro index f2de73c..c523376 100644 --- a/Source/IpFreely.pro +++ b/Source/IpFreely.pro @@ -68,7 +68,7 @@ else { QMAKE_CXXFLAGS += -std=c++14 # Set version info for library. - VERSION = 1.1.1 + VERSION = 1.1.2 INCLUDEPATH += /usr/local/include \ /home/duncan/projects/ThirdParty \ diff --git a/Source/IpFreely.rc b/Source/IpFreely.rc index 90a3c7a..2243033 100644 --- a/Source/IpFreely.rc +++ b/Source/IpFreely.rc @@ -7,8 +7,8 @@ IDI_ICON1 ICON DISCARDABLE "IpFreely.ico" VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,1,1,0 - PRODUCTVERSION 1,1,1,0 + FILEVERSION 1,1,2,0 + PRODUCTVERSION 1,1,2,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS VS_FF_DEBUG @@ -25,11 +25,11 @@ VS_VERSION_INFO VERSIONINFO BEGIN VALUE "CompanyName", "~\0" VALUE "FileDescription", "IP Freely (IP/Web camera stream viewer and recorder)\0" - VALUE "FileVersion", "1.1.1.0\0" + VALUE "FileVersion", "1.1.2.0\0" VALUE "LegalCopyright", "Copyright 2018 Duncan Crutchley\0" VALUE "OriginalFilename", "IpFreely\0" VALUE "ProductName", "IpFreely\0" - VALUE "ProductVersion", "1.1.1.0\0" + VALUE "ProductVersion", "1.1.2.0\0" END END BLOCK "VarFileInfo" diff --git a/Source/IpFreelyMainWindow.cpp b/Source/IpFreelyMainWindow.cpp index 02369aa..7fae7dd 100644 --- a/Source/IpFreelyMainWindow.cpp +++ b/Source/IpFreelyMainWindow.cpp @@ -1135,8 +1135,8 @@ void IpFreelyMainWindow::ConnectionHandler(ipfreely::IpCamera const& camera, } catch (std::exception& e) { - DEBUG_MESSAGE_EX_ERROR("Stream Error, camera: " << camName - << ", error message: " << e.what()); + DEBUG_MESSAGE_EX_ERROR( + "Stream Error, camera: " << camName << ", error message: " << e.what()); QMessageBox::critical(this, "Stream Error", QString::fromLocal8Bit(e.what()), @@ -1498,8 +1498,8 @@ void IpFreelyMainWindow::VideoFrameAreaSelection(int const cameraId, return; } - ipfreely::IpCamera::point_t leftTop(percentageSelection.left(), percentageSelection.top()); - ipfreely::IpCamera::point_t widthHeight(percentageSelection.width(), + ipfreely::IpCamera::point_t leftTop(percentageSelection.left(), percentageSelection.top()); + ipfreely::IpCamera::point_t widthHeight(percentageSelection.width(), percentageSelection.height()); ipfreely::IpCamera::region_t region(leftTop, widthHeight); m_camMotionRegions[camId].emplace_back(region); @@ -1610,5 +1610,8 @@ void IpFreelyMainWindow::ReconnectCamera(ipfreely::eCamId const camId) EnableMotionRegionsSetup( camId, true, ui->cam4RemoveMotionRegionsToolButton, ui->cam4MotionRegionsToolButton); break; + case ipfreely::eCamId::noCam: + // Do nothing + break; } } diff --git a/Source/IpFreelyMotionDetector.cpp b/Source/IpFreelyMotionDetector.cpp index 1b08364..9e87d00 100644 --- a/Source/IpFreelyMotionDetector.cpp +++ b/Source/IpFreelyMotionDetector.cpp @@ -417,6 +417,10 @@ bool IpFreelyMotionDetector::CheckForIntersections() if (mr.intersects(r)) { motionIntersection = true; + + DEBUG_MESSAGE_EX_INFO("Motion detector intersection found, camera stream URL: " + << m_cameraDetails.streamUrl); + break; } } @@ -468,6 +472,9 @@ bool IpFreelyMotionDetector::MessageHandler(video_frame_t& msg) // and finally set recording flag to false. if (m_holdOffFrameCount == m_holdOffFrameCountLimit) { + DEBUG_MESSAGE_EX_INFO("Motion detector hold-off period finished, camera stream URL: " + << m_cameraDetails.streamUrl); + m_holdOffFrameCount = 0; m_videoWriter.release(); recording = false; @@ -491,6 +498,9 @@ void IpFreelyMotionDetector::CreateCaptureObjects() { if (m_fileDurationSecs < m_requiredFileDurationSecs) { + DEBUG_MESSAGE_EX_DEBUG( + "Motion detector file duration reached for current video file, camera stream URL: " + << m_cameraDetails.streamUrl); return; } diff --git a/Source/IpFreelyMotionDetector.h b/Source/IpFreelyMotionDetector.h index c5aed11..911327f 100644 --- a/Source/IpFreelyMotionDetector.h +++ b/Source/IpFreelyMotionDetector.h @@ -106,6 +106,7 @@ class IpFreelyMotionDetector final private: mutable std::mutex m_motionMutex{}; mutable std::mutex m_writingMutex{}; + mutable std::mutex m_fpsMutex{}; std::string m_name{"cam"}; IpCamera m_cameraDetails{}; std::string m_saveFolderPath{}; diff --git a/Source/IpFreelyStreamProcessor.cpp b/Source/IpFreelyStreamProcessor.cpp index 8def736..ac17047 100644 --- a/Source/IpFreelyStreamProcessor.cpp +++ b/Source/IpFreelyStreamProcessor.cpp @@ -24,6 +24,7 @@ */ #include "IpFreelyStreamProcessor.h" #include +#include #include #include #include "IpFreelyMotionDetector.h" @@ -137,21 +138,8 @@ IpFreelyStreamProcessor::IpFreelyStreamProcessor( m_videoWidth = static_cast(m_videoCapture->get(CV_CAP_PROP_FRAME_WIDTH)); m_videoHeight = static_cast(m_videoCapture->get(CV_CAP_PROP_FRAME_HEIGHT)); - m_fps = m_videoCapture->get(CV_CAP_PROP_FPS); - if ((m_fps < MIN_FPS) || (m_fps > MAX_FPS)) - { - m_fps = cameraDetails.cameraMaxFps; - } - - m_updatePeriodMillisecs = static_cast(1000.0 / m_fps); - - DEBUG_MESSAGE_EX_INFO("Stream at: " - << m_cameraDetails.streamUrl << " running with FPS of: " << m_fps - << ", thread update period (ms): " << m_updatePeriodMillisecs); - - m_eventThread = std::make_shared( - std::bind(&IpFreelyStreamProcessor::ThreadEventCallback, this), m_updatePeriodMillisecs); + CheckFps(); } IpFreelyStreamProcessor::~IpFreelyStreamProcessor() @@ -308,6 +296,7 @@ void IpFreelyStreamProcessor::ThreadEventCallback() noexcept CheckMotionDetector(); CreateCaptureObjects(); WriteVideoFrame(); + CheckFps(); } catch (...) { @@ -488,4 +477,58 @@ void IpFreelyStreamProcessor::CheckMotionDetector() m_motionDetector->AddNextFrame(m_videoFrame); } +void IpFreelyStreamProcessor::CheckFps() +{ + auto fps = m_videoCapture->get(CV_CAP_PROP_FPS); + + if ((fps < MIN_FPS) || (fps > MAX_FPS)) + { + fps = m_cameraDetails.cameraMaxFps; + + DEBUG_MESSAGE_EX_WARNING( + "Invalid FPS obtained from stream defaulting to user preference FPS, stream URL: " + << m_cameraDetails.streamUrl); + } + + if (std::abs(fps - m_fps) > 0.1) + { + m_fps = fps; + m_updatePeriodMillisecs = static_cast(1000.0 / m_fps); + + DEBUG_MESSAGE_EX_INFO("Stream at: " << m_cameraDetails.streamUrl << " running with FPS of: " + << m_fps + << ", thread update period (ms): " + << m_updatePeriodMillisecs); + + if (m_videoWriter) + { + DEBUG_MESSAGE_EX_INFO("Releasing video writer due to FPS change, stream URL: " + << m_cameraDetails.streamUrl); + m_videoWriter.release(); + } + + if (m_motionDetector) + { + DEBUG_MESSAGE_EX_INFO("Recreating motion detector with new FPS, stream URL: " + << m_cameraDetails.streamUrl); + m_motionDetector.reset(); + m_motionDetector = std::make_shared(m_name, + m_cameraDetails, + m_saveFolderPath, + m_requiredFileDurationSecs, + m_fps, + m_videoWidth, + m_videoHeight); + } + + DEBUG_MESSAGE_EX_INFO( + "Recreating event thread for stream URL: " << m_cameraDetails.streamUrl); + + m_eventThread.reset(); + m_eventThread = std::make_shared( + std::bind(&IpFreelyStreamProcessor::ThreadEventCallback, this), + m_updatePeriodMillisecs); + } +} + } // namespace ipfreely diff --git a/Source/IpFreelyStreamProcessor.h b/Source/IpFreelyStreamProcessor.h index be6b10e..d5c1ecc 100644 --- a/Source/IpFreelyStreamProcessor.h +++ b/Source/IpFreelyStreamProcessor.h @@ -125,16 +125,17 @@ class IpFreelyStreamProcessor final static bool IsScheduleEnabled(std::vector> const& schedule); static bool VerifySchedule(std::string const& scheduleId, std::vector> const& schedule); - void ThreadEventCallback() noexcept; - void SetEnableVideoWriting(bool enable) noexcept; - bool GetEnableVideoWriting() const noexcept; - void CheckRecordingSchedule(); - void CreateCaptureObjects(); - void GrabVideoFrame(); - void WriteVideoFrame(); - bool CheckMotionSchedule() const; - void InitialiseMotionDetector(); - void CheckMotionDetector(); + void ThreadEventCallback() noexcept; + void SetEnableVideoWriting(bool enable) noexcept; + bool GetEnableVideoWriting() const noexcept; + void CheckRecordingSchedule(); + void CreateCaptureObjects(); + void GrabVideoFrame(); + void WriteVideoFrame(); + bool CheckMotionSchedule() const; + void InitialiseMotionDetector(); + void CheckMotionDetector(); + void CheckFps(); private: mutable std::mutex m_writingMutex{}; @@ -146,8 +147,8 @@ class IpFreelyStreamProcessor final double m_requiredFileDurationSecs{0.0}; std::vector> m_recordingSchedule{}; std::vector> m_motionSchedule{}; - unsigned int m_updatePeriodMillisecs{40}; - double m_fps{25.0}; + unsigned int m_updatePeriodMillisecs{0}; + double m_fps{0.0}; bool m_useRecordingSchedule{false}; bool m_useMotionSchedule{false}; bool m_enableVideoWriting{false}; diff --git a/Source/main.cpp b/Source/main.cpp index e9196f0..a325dd8 100644 --- a/Source/main.cpp +++ b/Source/main.cpp @@ -75,7 +75,7 @@ std::string GetAppVersion(const std::string& appFilePath) return appVersion; } #else -#define IPFREELY_VERSION "1.1.1.0" +#define IPFREELY_VERSION "1.1.2.0" #endif int main(int argc, char* argv[])