From baa69da2cd30a5f2664489f0e5721c2f0b0cc699 Mon Sep 17 00:00:00 2001 From: Maurice ONeal Date: Sun, 12 Mar 2023 13:22:10 -0400 Subject: [PATCH] v2.0.t8 Adjusted the event loop and motion detection to make better stand alone m3u8 files. Hopefully doing this will make browsers treat the recorded events as VODs instead of streams. --- src/common.h | 62 ++++++++++++++++++------------------ src/main.cpp | 44 +++++++++++++------------ src/mo_detect.cpp | 81 +++++++++++++++++++++++++++-------------------- src/web.cpp | 7 ++-- 4 files changed, 104 insertions(+), 90 deletions(-) diff --git a/src/common.h b/src/common.h index 8dd567e..e7464c7 100644 --- a/src/common.h +++ b/src/common.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,7 @@ using namespace std; using namespace std::filesystem; using namespace std::chrono; -#define APP_VER "2.0.t7" +#define APP_VER "2.0.t8" #define APP_NAME "Motion Watch" #define REC_LOG_NAME "rec_log_lines.html" #define DET_LOG_NAME "det_log_lines.html" @@ -45,39 +46,40 @@ using namespace std::chrono; struct pls_t { - string fileName; - string clipPath; - string dstPath; - string extINF; - uint64_t createTime; - Mat thumbnail; + string evName; + string dstPath; + vector srcPaths; + vector dstPaths; + vector extINFs; + uint64_t createTime; + Mat thumbnail; }; struct shared_t { - vector recList; - string conf; - string recLog; - string detLog; - string upkLog; - string recordUrl; - string outDir; - string postCmd; - string camName; - string webBg; - string webTxt; - string webFont; - string webRoot; - bool skipCmd; - bool postCmdRunning; - int schSec; - int frameGap; - int pixThresh; - int imgThresh; - int maxDays; - int maxEvents; - int maxLogSize; - int retCode; + map recList; + string conf; + string recLog; + string detLog; + string upkLog; + string recordUrl; + string outDir; + string postCmd; + string camName; + string webBg; + string webTxt; + string webFont; + string webRoot; + bool skipCmd; + bool postCmdRunning; + int schSec; + int frameGap; + int pixThresh; + int imgThresh; + int maxDays; + int maxEvents; + int maxLogSize; + int retCode; }; string genVidNameFromLive(const string &tsPath); diff --git a/src/main.cpp b/src/main.cpp index af554fa..564e49f 100755 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,35 +27,37 @@ void eventLoop(shared_t *share) { while (share->retCode == 0) { - while (!share->recList.empty()) + for (auto it = share->recList.begin(); !share->recList.empty();) { - auto pls = share->recList[0]; - auto timeDiff = pls.createTime - genEpoch(); + auto evName = it->first; + auto event = it->second; + auto timeDiff = genEpoch() - event.createTime; // future time protection. this should never occur but // this is in place in case the system time is incorrect. - if (timeDiff < 0) timeDiff = 0; - - // wait at least 6 seconds before processing the event in - // queue. - if (timeDiff < 6) sleep(6 - timeDiff); - - try + if (timeDiff > 0) { - wrOutm3u8(pls, share); - genHTMLvid(pls.fileName); + // wait at least 61 seconds before processing the event in + // queue. + if (timeDiff < 61) sleep(61 - timeDiff); - if (!exists(pls.fileName + ".jpg")) + try { - imwrite(string(pls.fileName + ".jpg").c_str(), pls.thumbnail); - } - } - catch (filesystem_error &ex) - { - recLog(string("err: ") + ex.what(), share); - } + wrOutm3u8(event, share); + genHTMLvid(evName); - share->recList.erase(share->recList.begin()); + if (!exists(evName + ".jpg")) + { + imwrite(string(evName + ".jpg").c_str(), event.thumbnail); + } + } + catch (filesystem_error &ex) + { + recLog(string("err: ") + ex.what(), share); + } + + share->recList.erase(it); + } } sleep(5); diff --git a/src/mo_detect.cpp b/src/mo_detect.cpp index e0f6fa8..33c8603 100644 --- a/src/mo_detect.cpp +++ b/src/mo_detect.cpp @@ -15,7 +15,9 @@ void detectMoInStream(const string &bufPath, shared_t *share) { ifstream fileIn(bufPath); - pls_t clip; + string tsPath; + string extINF; + Mat thumbnail; auto clipPathFilter = genTimeStr("VIDEO_TS/live/%Y/%j/%H/"); @@ -23,25 +25,42 @@ void detectMoInStream(const string &bufPath, shared_t *share) { if (line.starts_with(clipPathFilter)) { - clip.clipPath = line; + tsPath = line; } else if (line.starts_with("#EXTINF")) { - clip.extINF = line; + extINF = line; } } - if (!clip.clipPath.empty() && !clip.extINF.empty()) + if (!tsPath.empty() && !extINF.empty()) { - if (moDetect(clip.clipPath, clip.thumbnail, share)) + if (moDetect(tsPath, thumbnail, share)) { - clip.fileName = genTimeStr("%Y-%j-%H-%M"); - clip.dstPath = genEventPath(clip.clipPath); - clip.createTime = genEpoch(); + auto eventName = genTimeStr("%Y-%j-%H-%M"); + + if (share->recList.find(eventName) != share->recList.end()) + { + share->recList[eventName].srcPaths.push_back(tsPath); + share->recList[eventName].dstPaths.push_back(genEventPath(tsPath)); + share->recList[eventName].extINFs.push_back(extINF); + } + else + { + pls_t event; + + event.srcPaths.push_back(tsPath); + event.dstPaths.push_back(genEventPath(tsPath)); + event.extINFs.push_back(extINF); + + event.createTime = genEpoch(); + event.thumbnail = thumbnail.clone(); + event.evName = eventName; + + share->recList.insert(pair{eventName, event}); + } share->skipCmd = true; - - share->recList.push_back(clip); } } } @@ -117,38 +136,32 @@ bool moDetect(const string &buffFile, Mat &vidThumb, shared_t *share) return mod; } -void wrOutm3u8(const pls_t &pls, shared_t *share) +void wrOutm3u8(const pls_t &event, shared_t *share) { - recLog("live-to-event-src: " + pls.clipPath, share); - recLog("live-to-event-dst: " + pls.dstPath, share); + auto plsFile = event.evName + ".m3u8"; - createDirTree(path(pls.dstPath).parent_path().string()); - copy_file(pls.clipPath, pls.dstPath); + ofstream file(plsFile.c_str()); - auto plsFile = pls.fileName + ".m3u8"; + file << "#EXTM3U" << endl; + file << "#EXT-X-VERSION:3" << endl; + file << "#EXT-X-TARGETDURATION:10" << endl; + file << "#EXT-X-MEDIA-SEQUENCE:0" << endl; + file << "#EXT-X-START:TIME-OFFSET=0" << endl; + file << "#EXT-X-PLAYLIST-TYPE:VOD" << endl; - if (exists(plsFile)) + for (auto i = 0; i < event.extINFs.size(); ++i) { - ofstream file(plsFile.c_str(), ofstream::app); + auto src = event.srcPaths[i]; + auto dst = event.dstPaths[i]; - file << endl; - file << pls.extINF << endl; - file << pls.dstPath; + createDirTree(path(dst).parent_path().string()); + copy_file(src, dst); - file.close(); + file << event.extINFs[i] << endl; + file << dst << endl; } - else - { - ofstream file(plsFile.c_str()); - file << "#EXTM3U" << endl; - file << "#EXT-X-VERSION:3" << endl; - file << "#EXT-X-TARGETDURATION:10" << endl; - file << "#EXT-X-MEDIA-SEQUENCE:0" << endl; - file << "#EXT-X-DISCONTINUITY" << endl; - file << pls.extINF << endl; - file << pls.dstPath; + file << "#EXT-X-ENDLIST" << endl; - file.close(); - } + file.close(); } diff --git a/src/web.cpp b/src/web.cpp index 5532276..1fff46c 100644 --- a/src/web.cpp +++ b/src/web.cpp @@ -51,10 +51,7 @@ void genHTMLul(const string &outputDir, const string &title, shared_t *share) htmlText += "\n"; htmlText += "

Motion Events

\n"; - if (!exists("stream.html")) - { - genHTMLvid("stream"); - } + genHTMLvid("stream"); } for (auto &®Name : regNames) @@ -71,7 +68,7 @@ void genHTMLul(const string &outputDir, const string &title, shared_t *share) // regName.substr(0, regName.size() - 5) removes .html auto name = regName.substr(0, regName.size() - 5); - htmlText += "\n"; + htmlText += "\n"; } }