// This file is part of Motion Watch. // Motion Watch 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 3 of the License, or // (at your option) any later version. // Motion Watch 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. #include "mo_detect.h" void detectMoInStream(const string &streamFile, shared_t *share) { if (share->procTime >= share->schSec) { if (!share->skipCmd) { detLog("no motion detected, running post command: " + share->postCmd, share); system(share->postCmd.c_str()); } else { share->skipCmd = false; share->procTime = 0; detLog("motion detected, skipping the post command.", share); } } ifstream fileIn(streamFile); string tsPath; Mat thumbnail; for (string line; getline(fileIn, line); ) { if (line.starts_with("live/")) { tsPath = line; } } if (!tsPath.empty()) { if (moDetect(tsPath, thumbnail, share)) { auto eventName = genTimeStr("%Y-%j-%H-%M"); if (share->recList.find(eventName) != share->recList.end()) { share->recList[eventName].srcPaths.push_back(tsPath); } else { pls_t event; event.srcPaths.push_back(tsPath); event.createTime = genEpoch(); event.thumbnail = thumbnail.clone(); event.evName = eventName; share->recList.insert(pair{eventName, event}); } share->skipCmd = true; } share->procTime += 10; } } bool imgDiff(const Mat &prev, const Mat &next, int &score, shared_t *share) { Mat prevGray; Mat nextGray; cvtColor(prev, prevGray, COLOR_BGR2GRAY); cvtColor(next, nextGray, COLOR_BGR2GRAY); Mat diff; absdiff(prevGray, nextGray, diff); threshold(diff, diff, share->pixThresh, 255, THRESH_BINARY); score = countNonZero(diff); detLog("diff_score: " + to_string(score) + " tresh: " + to_string(share->imgThresh), share); return score >= share->imgThresh; } bool moDetect(const string &buffFile, Mat &vidThumb, shared_t *share) { auto maxScore = 0; auto score = 0; detLog("stream_clip: " + buffFile, share); VideoCapture capture(buffFile.c_str(), CAP_FFMPEG); if (capture.isOpened()) { Mat prev; Mat next; detLog("capture open successful.", share); while (capture.grab()) { if (prev.empty()) { capture.retrieve(prev); } else { capture.retrieve(next); if (!next.empty()) { if (imgDiff(prev, next, score, share)) { if (score > maxScore) { maxScore = score; resize(next, vidThumb, Size(720, 480), INTER_LINEAR); } } } prev.release(); next.release(); } sleep(1); } } else { detLog("capture open failure, check debug output.", share); } capture.release(); return maxScore > 0; } void wrOutVod(const pls_t &event, shared_t *share) { auto concat = event.evName + ".tmp"; ofstream file(concat.c_str()); for (auto i = 0; i < event.srcPaths.size(); ++i) { file << "file '" << event.srcPaths[i] << "''" << endl; } file.close(); system(string("ffmpeg -f concat -safe 0 -i " + concat + " -c copy events/" + event.evName + ".mp4").c_str()); remove(concat); }