Merge branch 'master' of github.com:ZoneMinder/zoneminder

This commit is contained in:
Isaac Connor 2021-11-03 17:08:59 -04:00
commit b2d9e5608f
8 changed files with 62 additions and 89 deletions

View File

@ -60,8 +60,8 @@ Event::Event(
//snapshit_file(),
//alarm_file(""),
videoStore(nullptr),
//video_name(""),
//video_file(""),
//video_path(""),
last_db_frame(0),
have_video_keyframe(false),
//scheme
@ -104,6 +104,13 @@ Event::Event(
// Copy it in case opening the mp4 doesn't work we can set it to another value
save_jpegs = monitor->GetOptSaveJPEGs();
Storage * storage = monitor->getStorage();
if (monitor->GetOptVideoWriter() != 0) {
container = monitor->OutputContainer();
if ( container == "auto" || container == "" ) {
container = "mp4";
}
video_incomplete_file = "incomplete."+container;
}
std::string sql = stringtf(
"INSERT INTO `Events` "
@ -120,7 +127,7 @@ Event::Event(
state_id,
monitor->getOrientation(),
0,
"",
video_incomplete_file.c_str(),
save_jpegs,
storage->SchemeString().c_str()
);
@ -178,24 +185,16 @@ Event::Event(
} // end if ! setPath(Storage)
Debug(1, "Using storage area at %s", path.c_str());
video_name = "";
snapshot_file = path + "/snapshot.jpg";
alarm_file = path + "/alarm.jpg";
/* Save as video */
video_incomplete_path = path + "/" + video_incomplete_file;
if ( monitor->GetOptVideoWriter() != 0 ) {
std::string container = monitor->OutputContainer();
if ( container == "auto" || container == "" ) {
container = "mp4";
}
if (monitor->GetOptVideoWriter() != 0) {
/* Save as video */
video_name = stringtf("%" PRIu64 "-%s.%s", id, "video", container.c_str());
video_file = path + "/" + video_name;
Debug(1, "Writing video file to %s", video_file.c_str());
videoStore = new VideoStore(
video_file.c_str(),
video_incomplete_path.c_str(),
container.c_str(),
monitor->GetVideoStream(),
monitor->GetVideoCodecContext(),
@ -213,8 +212,10 @@ Event::Event(
zmDbDo(sql);
}
} else {
sql = stringtf("UPDATE Events SET Videoed=1, DefaultVideo = '%s' WHERE Id=%" PRIu64, video_name.c_str(), id);
zmDbDo(sql);
std::string codec = videoStore->get_codec();
video_file = stringtf("%" PRIu64 "-%s.%s.%s", id, "video", codec.c_str(), container.c_str());
video_path = path + "/" + video_file;
Debug(1, "Video file is %s", video_file.c_str());
}
} // end if GetOptVideoWriter
}
@ -223,10 +224,18 @@ Event::~Event() {
// We close the videowriter first, because if we finish the event, we might try to view the file, but we aren't done writing it yet.
/* Close the video file */
if ( videoStore != nullptr ) {
if (videoStore != nullptr) {
Debug(4, "Deleting video store");
delete videoStore;
videoStore = nullptr;
int result = rename(video_incomplete_path.c_str(), video_path.c_str());
if (result == 0) {
Debug(1, "File successfully renamed");
} else {
Error("Failed renaming %s to %s", video_incomplete_path.c_str(), video_path.c_str());
// So that we don't update the event record
video_file = video_incomplete_file;
}
}
// endtime is set in AddFrame, so SHOULD be set to the value of the last frame timestamp.
@ -245,21 +254,23 @@ Event::~Event() {
}
std::string sql = stringtf(
"UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64 " AND Name='New Event'",
"UPDATE Events SET Name='%s%" PRIu64 "', EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64 " AND Name='New Event'",
monitor->EventPrefix(), id, std::chrono::system_clock::to_time_t(end_time),
delta_time.count(),
frames, alarm_frames,
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
video_file.c_str(), // defaults to ""
id);
if (!zmDbDoUpdate(sql)) {
// Name might have been changed during recording, so just do the update without changing the name.
sql = stringtf(
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64,
"UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %.2f, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo='%s' WHERE Id = %" PRIu64,
std::chrono::system_clock::to_time_t(end_time),
delta_time.count(),
frames, alarm_frames,
tot_score, static_cast<uint32>(alarm_frames ? (tot_score / alarm_frames) : 0), max_score,
video_file.c_str(), // defaults to ""
id);
zmDbDoUpdate(sql);
} // end if no changed rows due to Name change during recording

View File

@ -84,8 +84,13 @@ class Event {
std::string alarm_file;
VideoStore *videoStore;
std::string video_name;
std::string container;
std::string codec;
std::string video_file;
std::string video_path;
std::string video_incomplete_file;
std::string video_incomplete_path;
int last_db_frame;
bool have_video_keyframe; // a flag to tell us if we have had a video keyframe when writing an mp4. The first frame SHOULD be a video keyframe.
Storage::Schemes scheme;

View File

@ -270,7 +270,6 @@ int Image::PopulateFrame(AVFrame *frame) {
frame->width = width;
frame->height = height;
frame->format = imagePixFormat;
Debug(1, "PopulateFrame: width %d height %d linesize %d colours %d imagesize %d", width, height, linesize, colours, size);
zm_dump_video_frame(frame, "Image.Populate(frame)");
return 1;
} // int Image::PopulateFrame(AVFrame *frame)

View File

@ -1656,7 +1656,7 @@ void Monitor::CheckAction() {
}
}
void Monitor::UpdateCaptureFPS() {
void Monitor::UpdateFPS() {
if ( fps_report_interval and
(
!(image_count%fps_report_interval)
@ -1675,82 +1675,35 @@ void Monitor::UpdateCaptureFPS() {
uint32 new_camera_bytes = camera->Bytes();
uint32 new_capture_bandwidth =
static_cast<uint32>((new_camera_bytes - last_camera_bytes) / elapsed.count());
last_camera_bytes = new_camera_bytes;
double new_analysis_fps = (motion_frame_count - last_motion_frame_count) / elapsed.count();
Debug(4, "%s: %d - last %d = %d now:%lf, last %lf, elapsed %lf = %lffps",
"Capturing",
Debug(4, "FPS: capture count %d - last capture count %d = %d now:%lf, last %lf, elapsed %lf = capture: %lf fps analysis: %lf fps",
image_count,
last_capture_image_count,
image_count - last_capture_image_count,
FPSeconds(now.time_since_epoch()).count(),
FPSeconds(last_analysis_fps_time.time_since_epoch()).count(),
FPSeconds(last_fps_time.time_since_epoch()).count(),
elapsed.count(),
new_capture_fps);
new_capture_fps,
new_analysis_fps);
Info("%s: %d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec",
name.c_str(), image_count, new_capture_fps, new_capture_bandwidth);
Info("%s: %d - Capturing at %.2lf fps, capturing bandwidth %ubytes/sec Analysing at %.2lf fps",
name.c_str(), image_count, new_capture_fps, new_capture_bandwidth, new_analysis_fps);
shared_data->capture_fps = new_capture_fps;
last_fps_time = now;
last_capture_image_count = image_count;
shared_data->analysis_fps = new_analysis_fps;
last_motion_frame_count = motion_frame_count;
last_camera_bytes = new_camera_bytes;
std::string sql = stringtf(
"UPDATE LOW_PRIORITY Monitor_Status SET CaptureFPS = %.2lf, CaptureBandwidth=%u WHERE MonitorId=%u",
new_capture_fps, new_capture_bandwidth, id);
"UPDATE LOW_PRIORITY Monitor_Status SET CaptureFPS = %.2lf, CaptureBandwidth=%u, AnalysisFPS = %.2lf WHERE MonitorId=%u",
new_capture_fps, new_capture_bandwidth, new_analysis_fps, id);
dbQueue.push(std::move(sql));
} // now != last_fps_time
} // end if report fps
} // void Monitor::UpdateCaptureFPS()
void Monitor::UpdateAnalysisFPS() {
Debug(1, "analysis_image_count(%d) motion_count(%d) fps_report_interval(%d) mod%d",
analysis_image_count, motion_frame_count, fps_report_interval,
((analysis_image_count && fps_report_interval) ? !(analysis_image_count%fps_report_interval) : -1 ) );
if (
( analysis_image_count and fps_report_interval and !(analysis_image_count%fps_report_interval) )
or
// In startup do faster updates
( (analysis_image_count < fps_report_interval) and !(analysis_image_count%10) )
) {
SystemTimePoint now = std::chrono::system_clock::now();
FPSeconds elapsed = now - last_analysis_fps_time;
Debug(4, "%s: %d - now: %.2f, last %lf, diff %lf",
name.c_str(),
analysis_image_count,
FPSeconds(now.time_since_epoch()).count(),
FPSeconds(last_analysis_fps_time.time_since_epoch()).count(),
elapsed.count());
if (elapsed > Seconds(1)) {
double new_analysis_fps = (motion_frame_count - last_motion_frame_count) / elapsed.count();
Info("%s: %d - Analysing at %.2lf fps from %d - %d=%d / %lf - %lf = %lf",
name.c_str(),
analysis_image_count,
new_analysis_fps,
motion_frame_count,
last_motion_frame_count,
(motion_frame_count - last_motion_frame_count),
FPSeconds(now.time_since_epoch()).count(),
FPSeconds(last_analysis_fps_time.time_since_epoch()).count(),
elapsed.count());
if (new_analysis_fps != shared_data->analysis_fps) {
shared_data->analysis_fps = new_analysis_fps;
std::string sql = stringtf("UPDATE LOW_PRIORITY Monitor_Status SET AnalysisFPS = %.2lf WHERE MonitorId=%u",
new_analysis_fps, id);
dbQueue.push(std::move(sql));
last_analysis_fps_time = now;
last_motion_frame_count = motion_frame_count;
} else {
Debug(4, "No change in fps");
} // end if change in fps
} // end if at least 1 second has passed since last update
} // end if time to do an update
} // end void Monitor::UpdateAnalysisFPS
} // void Monitor::UpdateFPS()
// Would be nice if this JUST did analysis
// This idea is that we should be analysing as close to the capture frame as possible.
@ -2299,8 +2252,6 @@ bool Monitor::Analyse() {
// Only do these if it's a video packet.
shared_data->last_read_index = snap->image_index;
analysis_image_count++;
if (function == MODECT or function == MOCORD)
UpdateAnalysisFPS();
}
packetqueue.increment_it(analysis_it);
packetqueue.unlock(packet_lock);
@ -2585,7 +2536,6 @@ int Monitor::Capture() {
// Will only be queued if there are iterators allocated in the queue.
packetqueue.queuePacket(packet);
UpdateCaptureFPS();
} else { // result == 0
// Question is, do we update last_write_index etc?
return 0;
@ -2625,7 +2575,7 @@ bool Monitor::Decode() {
//
//capture_image = packet->image = new Image(width, height, camera->Colours(), camera->SubpixelOrder());
int ret = packet->decode(camera->getVideoCodecContext());
if (ret > 0) {
if (ret > 0 and !zm_terminate) {
if (packet->in_frame and !packet->image) {
packet->image = new Image(camera_width, camera_height, camera->Colours(), camera->SubpixelOrder());
AVFrame *input_frame = packet->in_frame;

View File

@ -546,8 +546,7 @@ public:
unsigned int GetLastWriteIndex() const;
uint64_t GetLastEventId() const;
double GetFPS() const;
void UpdateAnalysisFPS();
void UpdateCaptureFPS();
void UpdateFPS();
void ForceAlarmOn( int force_score, const char *force_case, const char *force_text="" );
void ForceAlarmOff();
void CancelForced();

View File

@ -46,6 +46,7 @@ RETSIGTYPE zm_die_handler(int signal, siginfo_t * info, void *context)
RETSIGTYPE zm_die_handler(int signal)
#endif
{
zm_terminate = true;
Error("Got signal %d (%s), crashing", signal, strsignal(signal));
#if (defined(__i386__) || defined(__x86_64__))
// Get more information if available

View File

@ -111,6 +111,13 @@ class VideoStore {
int writePacket(const std::shared_ptr<ZMPacket> &pkt);
int write_packets(PacketQueue &queue);
void flush_codecs();
const char *get_codec() {
if (chosen_codec_data)
return chosen_codec_data->codec_codec;
if (video_out_stream)
return avcodec_get_name(video_out_stream->codecpar->codec_id);
return "";
}
};
#endif // ZM_VIDEOSTORE_H

View File

@ -268,7 +268,7 @@ int main(int argc, char *argv[]) {
std::this_thread::sleep_for(sleep_time);
}
if (zm_terminate){
if (zm_terminate) {
break;
}
@ -308,6 +308,7 @@ int main(int argc, char *argv[]) {
result = -1;
break;
}
monitors[i]->UpdateFPS();
// capture_delay is the amount of time we should sleep in useconds to achieve the desired framerate.
Microseconds delay = (monitors[i]->GetState() == Monitor::ALARM) ? monitors[i]->GetAlarmCaptureDelay()