Skip to content

Commit ed23445

Browse files
authored
Merge branch 'ZoneMinder:master' into patch-160
2 parents b8ca4f2 + 9aa5b65 commit ed23445

File tree

14 files changed

+144
-63
lines changed

14 files changed

+144
-63
lines changed

src/zm_event.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,7 @@ void Event::Run() {
686686
// The idea is to process the queue no matter what so that all packets get processed.
687687
// We only break if the queue is empty
688688
while (!terminate_ and !zm_terminate) {
689-
ZMLockedPacket *packet_lock = packetqueue->get_packet(packetqueue_it);
689+
ZMLockedPacket *packet_lock = packetqueue->get_packet_no_wait(packetqueue_it);
690690
if (packet_lock) {
691691
std::shared_ptr<ZMPacket> packet = packet_lock->packet_;
692692
if (!packet->decoded) {
@@ -697,7 +697,6 @@ void Event::Run() {
697697
std::this_thread::sleep_for(sleep_for);
698698
continue;
699699
}
700-
packetqueue->increment_it(packetqueue_it);
701700

702701
Debug(1, "Adding packet %d", packet->image_index);
703702
this->AddPacket_(packet);
@@ -719,8 +718,11 @@ void Event::Run() {
719718
} // end if packet->image
720719
Debug(1, "Deleting packet lock");
721720
delete packet_lock;
721+
// Important not to increment it until after we are done with the packet because clearPackets checks for iterators pointing to it.
722+
packetqueue->increment_it(packetqueue_it);
722723
} else {
723-
return;
724+
if (terminate_ or zm_terminate) return;
725+
usleep(10000);
724726
} // end if packet_lock
725727
} // end while
726728
} // end Run()

src/zm_ffmpeg_camera.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,8 +213,9 @@ int FfmpegCamera::Capture(std::shared_ptr<ZMPacket> &zm_packet) {
213213
Info("Unable to read packet from stream %d: error %d \"%s\".",
214214
packet->stream_index, ret, av_make_error_string(ret).c_str());
215215
} else {
216-
Error("Unable to read packet from stream %d: error %d \"%s\".",
217-
packet->stream_index, ret, av_make_error_string(ret).c_str());
216+
logPrintf(Logger::ERROR + monitor->Importance(),
217+
"Unable to read packet from stream %d: error %d \"%s\".",
218+
packet->stream_index, ret, av_make_error_string(ret).c_str());
218219
}
219220
return -1;
220221
}
@@ -541,6 +542,8 @@ int FfmpegCamera::OpenFfmpeg() {
541542

542543
if (!mOptions.empty()) {
543544
ret = av_dict_parse_string(&opts, mOptions.c_str(), "=", ",", 0);
545+
// reorder_queue is for avformat not codec
546+
av_dict_set(&opts, "reorder_queue_size", nullptr, AV_DICT_MATCH_CASE);
544547
}
545548
ret = avcodec_open2(mVideoCodecContext, mVideoCodec, &opts);
546549

src/zm_monitor.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,9 +1201,11 @@ bool Monitor::connect() {
12011201
const char *RequestMessageID = soap_wsa_compl ? soap_wsa_rand_uuid(soap) : "RequestMessageID";
12021202
if ((!soap_wsa_compl) || (soap_wsa_request(soap, RequestMessageID, proxyEvent.soap_endpoint, "CreatePullPointSubscriptionRequest") == SOAP_OK)) {
12031203
Debug(1, "ONVIF Endpoint: %s", proxyEvent.soap_endpoint);
1204-
if (proxyEvent.CreatePullPointSubscription(&request, response) != SOAP_OK) {
1204+
int rc = proxyEvent.CreatePullPointSubscription(&request, response);
1205+
1206+
if (rc != SOAP_OK) {
12051207
const char *detail = soap_fault_detail(soap);
1206-
Error("ONVIF Couldn't create subscription! fault:%s, detail:%s", soap_fault_string(soap), detail ? detail : "null");
1208+
Error("ONVIF Couldn't create subscription! %d, fault:%s, detail:%s", rc, soap_fault_string(soap), detail ? detail : "null");
12071209
_wsnt__Unsubscribe wsnt__Unsubscribe;
12081210
_wsnt__UnsubscribeResponse wsnt__UnsubscribeResponse;
12091211
proxyEvent.Unsubscribe(response.SubscriptionReference.Address, NULL, &wsnt__Unsubscribe, wsnt__UnsubscribeResponse);
@@ -2576,8 +2578,8 @@ bool Monitor::Analyse() {
25762578
//snap->out_frame = nullptr;
25772579
}
25782580
} // end scope for event_lock
2579-
delete packet_lock;
25802581

2582+
packetqueue.unlock(packet_lock);
25812583
packetqueue.increment_it(analysis_it);
25822584
shared_data->last_read_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
25832585

@@ -3156,10 +3158,10 @@ Event * Monitor::openEvent(
31563158
return nullptr;
31573159
}
31583160
std::shared_ptr<ZMPacket> starting_packet = starting_packet_lock->packet_;
3161+
delete starting_packet_lock;
31593162
ZM_DUMP_PACKET(starting_packet->packet, "First packet from start");
31603163
event = new Event(this, start_it, starting_packet->timestamp, cause, noteSetMap);
31613164
SetVideoWriterStartTime(starting_packet->timestamp);
3162-
delete starting_packet_lock;
31633165
} else {
31643166
ZM_DUMP_PACKET(snap->packet, "First packet from alarm");
31653167
event = new Event(this, start_it, snap->timestamp, cause, noteSetMap);

src/zm_packetqueue.cpp

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,15 +311,22 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
311311
}
312312

313313
int keyframe_interval_count = 1;
314+
int video_packets_to_delete = 0; // This is a count of how many packets we will delete so we know when to stop looking
314315

315316
ZMLockedPacket *lp = new ZMLockedPacket(zm_packet);
316317
if (!lp->trylock()) {
317318
Debug(4, "Failed getting lock on first packet");
318319
delete lp;
319320
return;
320321
} // end if first packet not locked
322+
323+
if (is_there_an_iterator_pointing_to_packet(zm_packet)) {
324+
Debug(3, "Found iterator Counted %d video packets. Which would leave %d in packetqueue tail count is %d",
325+
video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count);
326+
delete lp;
327+
return;
328+
}
321329

322-
int video_packets_to_delete = 0; // This is a count of how many packets we will delete so we know when to stop looking
323330
++it;
324331
delete lp;
325332

@@ -335,7 +342,7 @@ void PacketQueue::clearPackets(const std::shared_ptr<ZMPacket> &add_packet) {
335342
delete lp;
336343

337344
if (is_there_an_iterator_pointing_to_packet(zm_packet)) {
338-
Debug(3, "Foudn iterator Counted %d video packets. Which would leave %d in packetqueue tail count is %d",
345+
Debug(3, "Found iterator Counted %d video packets. Which would leave %d in packetqueue tail count is %d",
339346
video_packets_to_delete, packet_counts[video_stream_id]-video_packets_to_delete, tail_count);
340347
break;
341348
}
@@ -453,6 +460,32 @@ int PacketQueue::packet_count(int stream_id) {
453460
return packet_counts[stream_id];
454461
} // end int PacketQueue::packet_count(int stream_id)
455462

463+
ZMLockedPacket *PacketQueue::get_packet_no_wait(packetqueue_iterator *it) {
464+
if (deleting or zm_terminate)
465+
return nullptr;
466+
467+
Debug(4, "Locking in get_packet using it %p queue end? %d",
468+
std::addressof(*it), (*it == pktQueue.end()));
469+
470+
// scope for lock
471+
std::unique_lock<std::mutex> lck(mutex);
472+
Debug(4, "Have Lock in get_packet");
473+
if ((*it == pktQueue.end()) and !(deleting or zm_terminate)) {
474+
Debug(2, "waiting. Queue size %zu it == end? %d", pktQueue.size(), (*it == pktQueue.end()));
475+
condition.wait(lck);
476+
}
477+
if ((*it == pktQueue.end()) or deleting or zm_terminate) return nullptr;
478+
479+
std::shared_ptr<ZMPacket> p = *(*it);
480+
ZMLockedPacket *lp = new ZMLockedPacket(p);
481+
if (lp->trylock()) {
482+
Debug(2, "Locked packet %d, unlocking packetqueue mutex", p->image_index);
483+
return lp;
484+
}
485+
delete lp;
486+
return nullptr;
487+
}
488+
456489
// Returns a packet. Packet will be locked
457490
ZMLockedPacket *PacketQueue::get_packet(packetqueue_iterator *it) {
458491
if (deleting or zm_terminate)
@@ -595,6 +628,7 @@ packetqueue_iterator *PacketQueue::get_event_start_packet_it(
595628

596629
packetqueue_iterator *it = new packetqueue_iterator;
597630
iterators.push_back(it);
631+
Debug(4, "Have event start iterator %p", std::addressof(*it));
598632

599633
*it = snapshot_it;
600634
std::shared_ptr<ZMPacket> packet = *(*it);
@@ -714,6 +748,7 @@ bool PacketQueue::is_there_an_iterator_pointing_to_packet(const std::shared_ptr<
714748
) {
715749
packetqueue_iterator *iterator_it = *iterators_it;
716750
if (*iterator_it == pktQueue.end()) {
751+
Debug(4, "Checking iterator %p == end", std::addressof(*iterator_it));
717752
continue;
718753
}
719754
Debug(4, "Checking iterator %p == packet ? %d", std::addressof(*iterator_it), ( *(*iterator_it) == zm_packet ));

src/zm_packetqueue.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ class PacketQueue {
7777
bool increment_it(packetqueue_iterator *it);
7878
bool increment_it(packetqueue_iterator *it, int stream_id);
7979
ZMLockedPacket *get_packet(packetqueue_iterator *);
80+
ZMLockedPacket *get_packet_no_wait(packetqueue_iterator *);
8081
ZMLockedPacket *get_packet_and_increment_it(packetqueue_iterator *);
8182
packetqueue_iterator *get_video_it(bool wait);
8283
packetqueue_iterator *get_stream_it(int stream_id);

src/zm_videostore.cpp

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,24 +1288,31 @@ int VideoStore::writeVideoFramePacket(const std::shared_ptr<ZMPacket> zm_packet)
12881288
pkt_guard.acquire(opkt);
12891289

12901290
if (monitor->WallClockTimestamps()) {
1291-
Microseconds useconds = std::chrono::duration_cast<Microseconds>(
1292-
zm_packet->timestamp - SystemTimePoint(Microseconds(video_first_pts)));
1293-
opkt->pts = opkt->dts = av_rescale_q(useconds.count(), AV_TIME_BASE_Q, video_in_stream->time_base);
1294-
} else if (ipkt->dts != AV_NOPTS_VALUE) {
1291+
int64_t ts = static_cast<int64>(std::chrono::duration_cast<Microseconds>(zm_packet->timestamp.time_since_epoch()).count());
12951292
if (video_first_dts == AV_NOPTS_VALUE) {
1296-
Debug(2, "Starting video first_dts will become %" PRId64, ipkt->dts);
1297-
video_first_dts = ipkt->dts;
1293+
Debug(2, "Starting video first_dts will become %" PRId64, ts);
1294+
video_first_dts = ts;
1295+
}
1296+
opkt->pts = opkt->dts = av_rescale_q(ts-video_first_dts, AV_TIME_BASE_Q, video_out_stream->time_base);
1297+
1298+
Debug(2, "dts from timestamp, set to (%" PRId64 ") secs(%.2f), minus first_dts %" PRId64 " = %" PRId64,
1299+
ts,
1300+
FPSeconds(zm_packet->timestamp.time_since_epoch()).count(),
1301+
video_first_dts, ts - video_first_dts);
1302+
} else {
1303+
if (ipkt->dts != AV_NOPTS_VALUE) {
1304+
if (video_first_dts == AV_NOPTS_VALUE) {
1305+
Debug(2, "Starting video first_dts will become %" PRId64, ipkt->dts);
1306+
video_first_dts = ipkt->dts;
1307+
}
1308+
opkt->dts = ipkt->dts - video_first_dts;
1309+
}
1310+
if (ipkt->pts != AV_NOPTS_VALUE) {
1311+
opkt->pts = ipkt->pts - video_first_dts;
12981312
}
1299-
opkt->dts = ipkt->dts - video_first_dts;
1300-
//} else {
1301-
//opkt.dts = next_dts[video_out_stream->index] ? av_rescale_q(next_dts[video_out_stream->index], video_out_stream->time_base, video_in_stream->time_base) : 0;
1302-
//Debug(3, "Setting dts to video_next_dts %" PRId64 " from %" PRId64, opkt.dts, next_dts[video_out_stream->index]);
1303-
}
1304-
if ((ipkt->pts != AV_NOPTS_VALUE) and (video_first_dts != AV_NOPTS_VALUE)) {
1305-
opkt->pts = ipkt->pts - video_first_dts;
1306-
}
13071313

1308-
av_packet_rescale_ts(opkt.get(), video_in_stream->time_base, video_out_stream->time_base);
1314+
av_packet_rescale_ts(opkt.get(), video_in_stream->time_base, video_out_stream->time_base);
1315+
} // end if wallclock or not
13091316
} // end if codec matches
13101317

13111318
write_packet(opkt.get(), video_out_stream);
@@ -1411,8 +1418,8 @@ int VideoStore::write_packet(AVPacket *pkt, AVStream *stream) {
14111418
if (pkt->dts > pkt->pts) pkt->pts = pkt->dts; // Do it here to avoid warning below
14121419
} else if (pkt->dts == last_dts[stream->index]) {
14131420
// Commonly seen
1414-
Debug(1, "non increasing dts, fixing. our dts %" PRId64 " stream %d last_dts %" PRId64 ". reorder_queue_size=%zu",
1415-
pkt->dts, stream->index, last_dts[stream->index], reorder_queue_size);
1421+
Debug(1, "non increasing dts, fixing. our dts %" PRId64 " stream %d last_dts %" PRId64 " stream %d. reorder_queue_size=%zu",
1422+
pkt->dts, stream->index, last_dts[stream->index], stream->index, reorder_queue_size);
14161423
// dts MUST monotonically increase, so add 1 which should be a small enough time difference to not matter.
14171424
pkt->dts = last_dts[stream->index]+last_duration[stream->index];
14181425
if (pkt->dts > pkt->pts) pkt->pts = pkt->dts; // Do it here to avoid warning below

web/includes/Filter.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class Filter extends ZM_Object {
3030
'EmailSubject' => '',
3131
'EmailBody' => '',
3232
'EmailFormat' => 'Individual',
33+
'EmailServer' => '',
3334
'AutoDelete' => 0,
3435
'AutoArchive' => 0,
3536
'AutoUnarchive' => 0,

web/js/MonitorStream.js

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ const streaming = [];
55
function MonitorStream(monitorData) {
66
this.id = monitorData.id;
77
this.connKey = monitorData.connKey;
8-
this.auth_relay = auth_relay;
9-
this.auth_hash = auth_hash;
108
this.url = monitorData.url;
119
this.url_to_zms = monitorData.url_to_zms;
1210
this.width = monitorData.width;
@@ -85,7 +83,7 @@ function MonitorStream(monitorData) {
8583
this.show = function() {
8684
const stream = this.getElement();
8785
if (!stream.src) {
88-
stream.src = this.url_to_zms+"&mode=single&scale="+this.scale+"&connkey="+this.connKey+this.auth_relay;
86+
stream.src = this.url_to_zms+"&mode=single&scale="+this.scale+"&connkey="+this.connKey+'&'+auth_relay;
8987
}
9088
};
9189

@@ -311,7 +309,7 @@ function MonitorStream(monitorData) {
311309
stream.setAttribute('loading', 'eager');
312310
}
313311
let src = stream.src.replace(/mode=single/i, 'mode=jpeg');
314-
src = src.replace(/auth=\w+/i, 'auth='+this.auth_hash);
312+
src = src.replace(/auth=\w+/i, 'auth='+auth_hash);
315313
if (-1 == src.search('connkey')) {
316314
src += '&connkey='+this.connKey;
317315
}
@@ -650,10 +648,11 @@ function MonitorStream(monitorData) {
650648
} // end if canEdit.Monitors
651649

652650
if (this.status.auth) {
653-
if (this.status.auth != this.auth_hash) {
651+
if (this.status.auth != auth_hash) {
654652
// Don't reload the stream because it causes annoying flickering. Wait until the stream breaks.
655-
console.log("Changed auth from " + this.auth_hash + " to " + this.status.auth);
656-
this.streamCmdParms.auth = auth_hash = this.auth_hash = this.status.auth;
653+
console.log("Changed auth from " + auth_hash + " to " + this.status.auth);
654+
auth_hash = this.status.auth;
655+
auth_relay = this.status.auth_relay;
657656
}
658657
} // end if have a new auth hash
659658
} // end if has state
@@ -663,7 +662,7 @@ function MonitorStream(monitorData) {
663662
if (stream.src) {
664663
console.log('Reloading stream: ' + stream.src);
665664
let src = stream.src.replace(/rand=\d+/i, 'rand='+Math.floor((Math.random() * 1000000) ));
666-
src = src.replace(/auth=\w+/i, 'auth='+this.auth_hash);
665+
src = src.replace(/auth=\w+/i, 'auth='+auth_hash);
667666
// Maybe updated auth
668667
if (src != stream.src) {
669668
stream.src = '';
@@ -756,20 +755,20 @@ function MonitorStream(monitorData) {
756755
this.setAlarmState(monitorStatus);
757756

758757
if (respObj.auth_hash) {
759-
if (this.auth_hash != respObj.auth_hash) {
758+
if (auth_hash != respObj.auth_hash) {
760759
// Don't reload the stream because it causes annoying flickering. Wait until the stream breaks.
761-
console.log("Changed auth from " + this.auth_hash + " to " + respObj.auth_hash);
762-
this.streamCmdParms.auth = this.auth_hash = respObj.auth_hash;
763-
this.auth_relay = respObj.auth_relay;
760+
console.log("Changed auth from " + auth_hash + " to " + respObj.auth_hash);
761+
auth_hash = respObj.auth_hash;
762+
auth_relay = respObj.auth_relay;
764763
}
765764
} // end if have a new auth hash
766765
} else {
767766
checkStreamForErrors('getStatusCmdResponse', respObj);
768767
}
769768
}; // this.getStatusCmdResponse
770769

771-
this.statusCmdQuery=function() {
772-
$j.getJSON(this.url + '?view=request&request=status&entity=monitor&element[]=Status&element[]=CaptureFPS&element[]=AnalysisFPS&element[]=Analysing&element[]=Recording&id='+this.id+'&'+this.auth_relay)
770+
this.statusCmdQuery = function() {
771+
$j.getJSON(this.url + '?view=request&request=status&entity=monitor&element[]=Status&element[]=CaptureFPS&element[]=AnalysisFPS&element[]=Analysing&element[]=Recording&id='+this.id+'&'+auth_relay)
773772
.done(this.getStatusCmdResponse.bind(this))
774773
.fail(logAjaxFail);
775774
};
@@ -805,7 +804,7 @@ function MonitorStream(monitorData) {
805804

806805
this.alarmCommand = function(command) {
807806
if (this.ajaxQueue) {
808-
console.log("Aborting in progress ajax for alarm");
807+
console.log('Aborting in progress ajax for alarm');
809808
// Doing this for responsiveness, but we could be aborting something important. Need smarter logic
810809
this.ajaxQueue.abort();
811810
}
@@ -818,7 +817,7 @@ function MonitorStream(monitorData) {
818817
url: this.url + (auth_relay?'?'+auth_relay:''),
819818
xhrFields: {withCredentials: true},
820819
data: alarmCmdParms,
821-
dataType: "json"
820+
dataType: 'json'
822821
})
823822
.done(this.getStreamCmdResponse.bind(this))
824823
.fail(this.onFailure.bind(this));
@@ -832,7 +831,7 @@ function MonitorStream(monitorData) {
832831
url: this.url + (auth_relay?'?'+auth_relay:''),
833832
xhrFields: {withCredentials: true},
834833
data: streamCmdParms,
835-
dataType: "json"
834+
dataType: 'json'
836835
})
837836
.done(this.getStreamCmdResponse.bind(this))
838837
.fail(this.onFailure.bind(this));

web/skins/classic/css/base/views/events.css

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,13 @@ body.sticky #eventTable thead {
7777
.term-value, .chosen-container{
7878
width: 100% !important;
7979
}
80+
81+
.bs-bars {
82+
width: 100%;
83+
}
84+
#toolbar .row {
85+
width: 100%;
86+
}
87+
#toolbar .row >div {
88+
padding: 0;
89+
}

web/skins/classic/js/skin.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -491,14 +491,14 @@ if ( currentView != 'none' && currentView != 'login' ) {
491491
// Update authentication token.
492492
auth_hash = data.auth;
493493
}
494+
delete data.auth;
494495
}
495496
if (data.auth_relay) {
496497
auth_relay = data.auth_relay;
498+
delete data.auth_relay;
497499
}
498500
// iterate through all the keys then update each element id with the same name
499-
for (var key of Object.keys(data)) {
500-
if ( key == "auth" ) continue;
501-
if ( key == "auth_relay" ) continue;
501+
for (const key of Object.keys(data)) {
502502
if ( $j('#'+key).hasClass("show") ) continue; // don't update if the user has the dropdown open
503503
if ( $j('#'+key).length ) $j('#'+key).replaceWith(data[key]);
504504
if ( key == 'getBandwidthHTML' ) bwClickFunction();

0 commit comments

Comments
 (0)