From 78a5e78e4c82491b9b22608d51f478f9c77fb47c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 18 Feb 2021 16:59:17 -0500 Subject: [PATCH 01/57] Add locking to get_event_start_it. Packets could get deleted while we are figuring this out. --- src/zm_packetqueue.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index cd60b5c40..a8ca850bb 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -500,6 +500,8 @@ packetqueue_iterator *PacketQueue::get_event_start_packet_it( unsigned int pre_event_count ) { + std::unique_lock lck(mutex); + packetqueue_iterator *it = new packetqueue_iterator; iterators.push_back(it); From 045cd219f865b6ec9fa966c494ddb64e617c5472 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 18 Feb 2021 19:25:40 -0500 Subject: [PATCH 02/57] Move clear packetqueue logic to it's own function and call it from the analysis thread. --- src/zm_monitor.cpp | 3 +- src/zm_packetqueue.cpp | 123 ++++++++++++++++++++++------------------- src/zm_packetqueue.h | 1 + 3 files changed, 69 insertions(+), 58 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index c38737617..75e121104 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1950,7 +1950,7 @@ bool Monitor::Analyse() { // If doing record, check to see if we need to close the event or not. if ( event ) { - Debug(2, "Have event in mocord"); + Debug(2, "Have event %" PRIu64 " in mocord", event->Id()); if ( section_length && ( ( timestamp->tv_sec - video_store_data->recording.tv_sec ) >= section_length ) && ( (function == MOCORD && (event_close_mode != CLOSE_TIME)) || ! ( timestamp->tv_sec % section_length ) ) @@ -2229,6 +2229,7 @@ bool Monitor::Analyse() { shared_data->last_read_time = time(nullptr); analysis_image_count++; UpdateAnalysisFPS(); + packetqueue.clearPackets(snap); return true; } // end Monitor::Analyse diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index cd60b5c40..95ba99aff 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -99,7 +99,15 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) { --(*iterator_it); } } // end foreach iterator + mutex.unlock(); + // We signal on every packet because someday we may analyze sound + Debug(4, "packetqueue queuepacket, unlocked signalling"); + condition.notify_all(); + return true; +} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet) + +void PacketQueue::clearPackets(ZMPacket *add_packet) { // Only do queueCleaning if we are adding a video keyframe, so that we guarantee that there is one. // No good. Have to satisfy two conditions: // 1. packetqueue starts with a video keyframe @@ -109,77 +117,78 @@ bool PacketQueue::queuePacket(ZMPacket* add_packet) { // // So start at the beginning, counting video packets until the next keyframe. // Then if deleting those packets doesn't break 1 and 2, then go ahead and delete them. - if ( add_packet->packet.stream_index == video_stream_id + if ( ! ( + add_packet->packet.stream_index == video_stream_id and add_packet->keyframe and (packet_counts[video_stream_id] > max_video_packet_count) and *(pktQueue.begin()) != add_packet + ) ) { - packetqueue_iterator it = pktQueue.begin(); - packetqueue_iterator next_front = pktQueue.begin(); + return; + } + std::unique_lock lck(mutex); - // First packet is special because we know it is a video keyframe and only need to check for lock - ZMPacket *zm_packet = *it; - if ( zm_packet->trylock() ) { - ++it; + packetqueue_iterator it = pktQueue.begin(); + packetqueue_iterator next_front = pktQueue.begin(); + + // First packet is special because we know it is a video keyframe and only need to check for lock + ZMPacket *zm_packet = *it; + if ( zm_packet->trylock() ) { + ++it; + zm_packet->unlock(); + + // Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that + while ( *it != add_packet ) { + zm_packet = *it; + Debug(1, "Checking packet to see if we can delete them"); + if ( !zm_packet->trylock() ) { + Debug(1, "Have locked packet %d", zm_packet->image_index); + break; + } zm_packet->unlock(); - // Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that - while ( *it != add_packet ) { - zm_packet = *it; - Debug(1, "Checking packet to see if we can delete them"); - if ( !zm_packet->trylock() ) { - Debug(1, "Have locked packet %d", zm_packet->image_index); - break; - } - zm_packet->unlock(); - - if ( is_there_an_iterator_pointing_to_packet(zm_packet) ) { - Debug(4, "Found IT at beginning of queue. Threads not keeping up"); - break; - } - - if ( zm_packet->packet.stream_index == video_stream_id ) { - if ( zm_packet->keyframe ) { - Debug(1, "Have a video keyframe so breaking out"); - next_front = it; - } - } - it++; - } // end while - } // end if first packet not locked - Debug(1, "Resulting pointing at latest packet? %d, have next front? %d", - ( *it == add_packet ), - ( next_front == pktQueue.begin() ) - ); - if ( next_front != pktQueue.begin() ) { - Debug(1, "Deleting packets"); - // It is enough to delete the packets tested above. A subsequent queuePacket can clear a second set - while ( pktQueue.begin() != next_front ) { - ZMPacket *zm_packet = *pktQueue.begin(); - if ( !zm_packet ) { - Error("NULL zm_packet in queue"); - continue; - } - - Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d", - zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size()); - pktQueue.pop_front(); - packet_counts[zm_packet->packet.stream_index] -= 1; - delete zm_packet; + if ( is_there_an_iterator_pointing_to_packet(zm_packet) ) { + Debug(4, "Found IT at beginning of queue. Threads not keeping up"); + break; } - } // end if have at least max_video_packet_count video packets remaining - } // end if this is a video keyframe - mutex.unlock(); + if ( zm_packet->packet.stream_index == video_stream_id ) { + if ( zm_packet->keyframe ) { + Debug(1, "Have a video keyframe so breaking out"); + next_front = it; + } + } + it++; + } // end while + } // end if first packet not locked + Debug(1, "Resulting pointing at latest packet? %d, have next front? %d", + ( *it == add_packet ), + ( next_front == pktQueue.begin() ) + ); + if ( next_front != pktQueue.begin() ) { + Debug(1, "Deleting packets"); + // It is enough to delete the packets tested above. A subsequent queuePacket can clear a second set + while ( pktQueue.begin() != next_front ) { + ZMPacket *zm_packet = *pktQueue.begin(); + if ( !zm_packet ) { + Error("NULL zm_packet in queue"); + continue; + } + + Debug(1, "Deleting a packet with stream index:%d image_index:%d with keyframe:%d, video frames in queue:%d max: %d, queuesize:%d", + zm_packet->packet.stream_index, zm_packet->image_index, zm_packet->keyframe, packet_counts[video_stream_id], max_video_packet_count, pktQueue.size()); + pktQueue.pop_front(); + packet_counts[zm_packet->packet.stream_index] -= 1; + delete zm_packet; + } + } // end if have at least max_video_packet_count video packets remaining // We signal on every packet because someday we may analyze sound - Debug(4, "packetqueue queuepacket, unlocked signalling"); - condition.notify_all(); - return true; -} // end bool PacketQueue::queuePacket(ZMPacket* zm_packet) + return; +} // end voidPacketQueue::clearPackets(ZMPacket* zm_packet) ZMPacket* PacketQueue::popPacket( ) { Debug(4, "pktQueue size %d", pktQueue.size()); diff --git a/src/zm_packetqueue.h b/src/zm_packetqueue.h index 4cbd0739d..cd88648b9 100644 --- a/src/zm_packetqueue.h +++ b/src/zm_packetqueue.h @@ -63,6 +63,7 @@ class PacketQueue { unsigned int get_packet_count(int stream_id) const { return packet_counts[stream_id]; }; void clear_unwanted_packets(timeval *recording, int pre_event_count, int mVideoStreamId); + void clearPackets(ZMPacket *); int packet_count(int stream_id); bool increment_it(packetqueue_iterator *it); From 3fb10540935c7812fade0506d95be15074a02945 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Thu, 18 Feb 2021 20:22:19 -0600 Subject: [PATCH 03/57] bstable export requires tableExport plugin --- web/skins/classic/includes/functions.php | 1 + web/skins/classic/js/tableExport.min.js | 94 ++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 web/skins/classic/js/tableExport.min.js diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 503f3f155..734eb1b11 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -867,6 +867,7 @@ function xhtmlFooter() { e&&"undefined"!==typeof S[e]&&-1!==d.inArray(S[e],a.ignoreColumn))&&(p=!0):p=!0;return p}function E(b,c,e,p,f){if("function"===typeof f){var l=!1;"function"===typeof a.onIgnoreRow&&(l=a.onIgnoreRow(d(b),e));if(!1===l&& +(0===a.ignoreRow.length||-1===d.inArray(e,a.ignoreRow)&&-1===d.inArray(e-p,a.ignoreRow))&&I(d(b))){b=v(d(b),c);var q=b.length,h=0,u=0;b.each(function(){var b=d(this),a=J(this),c=T(this),l;d.each(G,function(){if(e>this.s.r&&e<=this.e.r&&h>=this.s.c&&h<=this.e.c)for(l=0;l<=this.e.c-this.s.c;++l)q++,u++,f(null,e,h++)});if(c||a)a=a||1,G.push({s:{r:e,c:h},e:{r:e+(c||1)-1,c:h+a-1}});!1===ta(b,q,u++)&&f(this,e,h++);if(1=this.s.r&&e<=this.e.r&& +h>=this.s.c&&h<=this.e.c)for(da=0;da<=this.e.c-this.s.c;++da)f(null,e,h++)})}}}function ua(b,a,e,d){if("undefined"!==typeof d.images&&(e=d.images[e],"undefined"!==typeof e)){a=a.getBoundingClientRect();var c=b.width/b.height,l=a.width/a.height,p=b.width,h=b.height,u=19.049976/25.4,g=0;l<=c?(h=Math.min(b.height,a.height),p=a.width*h/a.height):l>c&&(p=Math.min(b.width,a.width),h=a.height*p/a.width);p*=u;h*=u;hb.textPos.x&&p+g>b.textPos.x+b.width&&(0<=".,!%*;:=-".indexOf(u.charAt(0))&&(k=u.charAt(0),g=e.doc.getStringUnitWidth(k)*e.doc.internal.getFontSize(),p+g<=b.textPos.x+b.width&&(e.doc.autoTableText(k,p,f,l),u=u.substring(1,u.length)),g= +e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize()),p=b.textPos.x,f+=e.doc.internal.getFontSize());if("visible"!==b.styles.overflow)for(;u.length&&p+g>b.textPos.x+b.width;)u=u.substring(0,u.length-1),g=e.doc.getStringUnitWidth(u)*e.doc.internal.getFontSize();e.doc.autoTableText(u,p,f,l);p+=g}if(q||h)d(c).is("b")?q=!1:d(c).is("i")&&(h=!1),e.doc.setFontType(q||h?q?"bold":"italic":"normal");c=c.nextSibling}b.textPos.x=p;b.textPos.y=f}else e.doc.autoTableText(b.text,b.textPos.x,b.textPos.y,l)}} +function V(b,a,e){return null==b?"":b.toString().replace(new RegExp(null==a?"":a.toString().replace(/([.*+?^=!:${}()|\[\]\/\\])/g,"\\$1"),"g"),e)}function la(b){return null==b?"":b.toString().replace(/^\s+/,"")}function ma(b){return null==b?"":b.toString().replace(/\s+$/,"")}function La(b){if(0===a.date.html.length)return!1;a.date.pattern.lastIndex=0;var c=a.date.pattern.exec(b);if(null==c)return!1;b=+c[a.date.match_y];if(0>b||8099]*)>)/gi,"\u2060"),n=d("
").html(m).contents();b=!1;m="";d.each(n.text().split("\u2028"),function(b,c){0b?1:0)).split(".");1===n.length&&(n[1]="");var t=3b?"-":"")+(a.numbers.output.thousandsSeparator?(t?n[0].substr(0,t)+a.numbers.output.thousandsSeparator: +"")+n[0].substr(t).replace(/(\d{3})(?=\d)/g,"$1"+a.numbers.output.thousandsSeparator):n[0])+(n[1].length?a.numbers.output.decimalMark+n[1]:"")}}else f=h;!0===a.escape&&(f=escape(f));"function"===typeof a.onCellData&&(f=a.onCellData(q,c,e,f,l),q.data("teUserDefText",1))}void 0!==p&&(p.type=l);return f}function Ba(b){return 0l?f+=String.fromCharCode(l):(127l?f+=String.fromCharCode(l>>6|192):(f+=String.fromCharCode(l>>12|224),f+=String.fromCharCode(l>>6&63|128)),f+=String.fromCharCode(l&63|128))}a=f}for(;p>2;q=(q&3)<<4|f>>4;var h=(f&15)<<2|b>>6;var g=b&63;isNaN(f)?h=g=64:isNaN(b)&&(g=64);d=d+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(l)+ +"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(q)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(h)+"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=".charAt(g)}return d}var a={csvEnclosure:'"',csvSeparator:",",csvUseBOM:!0,date:{html:"dd/mm/yyyy"},displayTableName:!1,escape:!1,exportHiddenCells:!1,fileName:"tableExport",htmlContent:!1,htmlHyperlink:"content",ignoreColumn:[],ignoreRow:[],jsonScope:"all",jspdf:{orientation:"p", +unit:"pt",format:"a4",margins:{left:20,right:10,top:10,bottom:10},onDocCreated:null,autotable:{styles:{cellPadding:2,rowHeight:12,fontSize:8,fillColor:255,textColor:50,fontStyle:"normal",overflow:"ellipsize",halign:"inherit",valign:"middle"},headerStyles:{fillColor:[52,73,94],textColor:255,fontStyle:"bold",halign:"inherit",valign:"middle"},alternateRowStyles:{fillColor:245},tableExport:{doc:null,onAfterAutotable:null,onBeforeAutotable:null,onAutotableText:null,onTable:null,outputImages:!0}}},mso:{fileFormat:"xlshtml", +onMsoNumberFormat:null,pageFormat:"a4",pageOrientation:"portrait",rtl:!1,styles:[],worksheetName:"",xslx:{formatId:{date:14,numbers:2}}},numbers:{html:{decimalMark:".",thousandsSeparator:","},output:{decimalMark:".",thousandsSeparator:","}},onAfterSaveToFile:null,onBeforeSaveToFile:null,onCellData:null,onCellHtmlData:null,onCellHtmlHyperlink:null,onIgnoreRow:null,onTableExportBegin:null,onTableExportEnd:null,outputMode:"file",pdfmake:{enabled:!1,docDefinition:{pageOrientation:"portrait",defaultStyle:{font:"Roboto"}}, +fonts:{}},preserve:{leadingWS:!1,trailingWS:!1},preventInjection:!0,sql:{tableEnclosure:"`",columnEnclosure:"`"},tbodySelector:"tr",tfootSelector:"tr",theadSelector:"tr",tableName:"Table",type:"csv"},O={a0:[2383.94,3370.39],a1:[1683.78,2383.94],a2:[1190.55,1683.78],a3:[841.89,1190.55],a4:[595.28,841.89],a5:[419.53,595.28],a6:[297.64,419.53],a7:[209.76,297.64],a8:[147.4,209.76],a9:[104.88,147.4],a10:[73.7,104.88],b0:[2834.65,4008.19],b1:[2004.09,2834.65],b2:[1417.32,2004.09],b3:[1000.63,1417.32],b4:[708.66, +1000.63],b5:[498.9,708.66],b6:[354.33,498.9],b7:[249.45,354.33],b8:[175.75,249.45],b9:[124.72,175.75],b10:[87.87,124.72],c0:[2599.37,3676.54],c1:[1836.85,2599.37],c2:[1298.27,1836.85],c3:[918.43,1298.27],c4:[649.13,918.43],c5:[459.21,649.13],c6:[323.15,459.21],c7:[229.61,323.15],c8:[161.57,229.61],c9:[113.39,161.57],c10:[79.37,113.39],dl:[311.81,623.62],letter:[612,792],"government-letter":[576,756],legal:[612,1008],"junior-legal":[576,360],ledger:[1224,792],tabloid:[792,1224],"credit-card":[153, +243]},B=this,ha=null,r=[],w=[],n=0,t="",S=[],G=[],Ea,K=[],U=!1;d.extend(!0,a,k);"xlsx"===a.type&&(a.mso.fileFormat=a.type,a.type="excel");"undefined"!==typeof a.excelFileFormat&&"undefined"===a.mso.fileFormat&&(a.mso.fileFormat=a.excelFileFormat);"undefined"!==typeof a.excelPageFormat&&"undefined"===a.mso.pageFormat&&(a.mso.pageFormat=a.excelPageFormat);"undefined"!==typeof a.excelPageOrientation&&"undefined"===a.mso.pageOrientation&&(a.mso.pageOrientation=a.excelPageOrientation);"undefined"!==typeof a.excelRTL&& +"undefined"===a.mso.rtl&&(a.mso.rtl=a.excelRTL);"undefined"!==typeof a.excelstyles&&"undefined"===a.mso.styles&&(a.mso.styles=a.excelstyles);"undefined"!==typeof a.onMsoNumberFormat&&"undefined"===a.mso.onMsoNumberFormat&&(a.mso.onMsoNumberFormat=a.onMsoNumberFormat);"undefined"!==typeof a.worksheetName&&"undefined"===a.mso.worksheetName&&(a.mso.worksheetName=a.worksheetName);a.mso.pageOrientation="l"===a.mso.pageOrientation.substr(0,1)?"landscape":"portrait";a.date.html=a.date.html||"";if(a.date.html.length){k= +[];k.dd="(3[01]|[12][0-9]|0?[1-9])";k.mm="(1[012]|0?[1-9])";k.yyyy="((?:1[6-9]|2[0-2])\\d{2})";k.yy="(\\d{2})";var z=a.date.html.match(/[^a-zA-Z0-9]/)[0];z=a.date.html.toLowerCase().split(z);a.date.regex="^\\s*";a.date.regex+=k[z[0]];a.date.regex+="(.)";a.date.regex+=k[z[1]];a.date.regex+="\\2";a.date.regex+=k[z[2]];a.date.regex+="\\s*$";a.date.pattern=new RegExp(a.date.regex,"g");k=z.indexOf("dd")+1;a.date.match_d=k+(1"+D(a,d,e)+""});n++});Q+="";var Fa= +1;w=C(d(B));d(w).each(function(){var a=1;t="";E(this,"td,th",n,r.length+w.length,function(b,d,g){t+=""+D(b,d,g)+"";a++});0"!==t&&(Q+=''+t+"",Fa++);n++});Q+="";if("string"===a.outputMode)return Q;if("base64"===a.outputMode)return L(Q);N(Q,a.fileName+".xml","application/xml","utf-8","base64",!1)}else if("excel"===a.type&&"xmlss"===a.mso.fileFormat){var sa=[],F=[];d(B).filter(function(){return I(d(this))}).each(function(){function b(a, +b,c){var e=[];d(a).each(function(){var b=0,f=0;t="";E(this,"td,th",n,c+a.length,function(a,c,l){if(null!==a){var h="";c=D(a,c,l);l="String";if(!1!==jQuery.isNumeric(c))l="Number";else{var g=Ma(c);!1!==g&&(c=g,l="Number",h+=' ss:StyleID="pct1"')}"Number"!==l&&(c=c.replace(/\n/g,"
"));g=J(a);a=T(a);d.each(e,function(){if(n>=this.s.r&&n<=this.e.r&&f>=this.s.c&&f<=this.e.c)for(var a=0;a<=this.e.c-this.s.c;++a)f++,b++});if(a||g)a=a||1,g=g||1,e.push({s:{r:n,c:f},e:{r:n+a-1,c:f+g-1}});1'+d("
").text(c).html()+"\r";f++}});0\r'+t+"\r");n++});return a.length}var c=d(this),e="";"string"===typeof a.mso.worksheetName&&a.mso.worksheetName.length?e=a.mso.worksheetName+" "+(F.length+1):"undefined"!==typeof a.mso.worksheetName[F.length]&&(e=a.mso.worksheetName[F.length]);e.length|| +(e=c.find("caption").text()||"");e.length||(e="Table "+(F.length+1));e=d.trim(e.replace(/[\\\/[\]*:?'"]/g,"").substring(0,31));F.push(d("
").text(e).html());!1===a.exportHiddenCells&&(K=c.find("tr, th, td").filter(":hidden"),U=0\r";e=b(y(c),"th,td",0);b(C(c),"td,th",e);H+="\r";sa.push(H)});k={};z={};for(var m,Z,X=0,da=F.length;X\r\r\r\r '+(new Date).toISOString()+'\r\r\r \r\r\r 9000\r 13860\r 0\r 0\r False\r False\r\r\r \r \r \r\r'; +for(z=0;z\r'+sa[z],k=a.mso.rtl?k+'\r\r\r':k+'\r',k+="\r";k+="\r";if("string"===a.outputMode)return k;if("base64"===a.outputMode)return L(k);N(k,a.fileName+".xml","application/xml","utf-8","base64",!1)}else if("excel"=== +a.type&&"xlsx"===a.mso.fileFormat){var aa=[],Ga=XLSX.utils.book_new();d(B).filter(function(){return I(d(this))}).each(function(){for(var b=d(this),c={},e=this.getElementsByTagName("tr"),g={s:{r:0,c:0},e:{r:0,c:0}},f=[],l,q=[],h=0,u=0,k,m,n,t,r,w=XLSX.SSF.get_table();hu;++h)if(k=e[h],m=!1,"function"===typeof a.onIgnoreRow&&(m=a.onIgnoreRow(d(k),h)),!0!==m&&(0===a.ignoreRow.length||-1===d.inArray(h,a.ignoreRow)&&-1===d.inArray(h-e.length,a.ignoreRow))&&!1!==I(d(k))){var y=k.children, +B=0;for(k=0;kx||36x||48===x)A="n";else if("date"===C.type||13x||44x||56===x)A="d"}else A="s";if(null!=l)if(0===l.length)v.t="z";else if(0!==l.trim().length&&"s"!==A)if("function"===C.type)v={f:l};else if("TRUE"===l)v={t:"b",v:!0};else if("FALSE"===l)v={t:"b",v:!1};else if(""===A&&d(r).find("a").length)l= +"href"!==a.htmlHyperlink?l:"",v={f:'=HYPERLINK("'+d(r).find("a").attr("href")+(l.length?'","'+l:"")+'")'};else if("n"===A||isFinite(Da(l,a.numbers.output))){if(r=Da(l,a.numbers.output),0===x&&"function"!==typeof a.mso.xslx.formatId.numbers&&(x=a.mso.xslx.formatId.numbers),isFinite(r)||isFinite(l))v={t:"n",v:isFinite(r)?r:l,z:"string"===typeof x?x:x in w?w[x]:"0.00"}}else if(!1!==(r=La(l))||"d"===A)0===x&&"function"!==typeof a.mso.xslx.formatId.date&&(x=a.mso.xslx.formatId.date),v={t:"d",v:!1!==r? +r:l,z:"string"===typeof x?x:x in w?w[x]:"m/d/yy"};c[oa({c:m,r:u})]=v;g.e.c";r=y(b);d(r).each(function(){var b=d(this);t="";E(this,"th,td",n,r.length,function(d,c,f){if(null!==d){var e="";t+=""}});0"+t+"");n++});H+="";w=C(b);d(w).each(function(){var b=d(this);t="";E(this,"td,th",n,r.length+ +w.length,function(c,g,f){if(null!==c){var e=D(c,g,f),q="",h=d(c).attr("data-tableexport-msonumberformat");"undefined"===typeof h&&"function"===typeof a.mso.onMsoNumberFormat&&(h=a.mso.onMsoNumberFormat(c,g,f));"undefined"!==typeof h&&""!==h&&(q="style=\"mso-number-format:'"+h+"'");if(a.mso.styles.length){g=document.defaultView.getComputedStyle(c,null);f=document.defaultView.getComputedStyle(b[0],null);for(var k in a.mso.styles)h=g[a.mso.styles[k]],""===h&&(h=f[a.mso.styles[k]]),""!==h&&"0px none rgb(0, 0, 0)"!== +h&&"rgba(0, 0, 0, 0)"!==h&&(q+=""===q?'style="':";",q+=a.mso.styles[k]+":"+h)}t+=""));t+=">"+e+""}});0"+t+"");n++});a.displayTableName&&(H+=""+D(d("

"+a.tableName+"

"))+"");H+=""});m=''+('')+"";"excel"===k&&(m+="\x3c!--[if gte mso 9]>",m+="",m+="",m+="",m+="",m+="",m+=ba,m+="",m+="",m+="",a.mso.rtl&&(m+=""),m+="",m+="",m+="",m+="",m+= +"",m+="";m+="@page { size:"+a.mso.pageOrientation+"; mso-page-orientation:"+a.mso.pageOrientation+"; }";m+="@page Section1 {size:"+O[a.mso.pageFormat][0]+"pt "+O[a.mso.pageFormat][1]+"pt";m+="; margin:1.0in 1.25in 1.0in 1.25in;mso-header-margin:.5in;mso-footer-margin:.5in;mso-paper-source:0;}";m+="div.Section1 {page:Section1;}";m+="@page Section2 {size:"+O[a.mso.pageFormat][1]+"pt "+O[a.mso.pageFormat][0]+"pt";m+=";mso-page-orientation:"+a.mso.pageOrientation+";margin:1.25in 1.0in 1.25in 1.0in;mso-header-margin:.5in;mso-footer-margin:.5in;mso-paper-source:0;}"; +m+="div.Section2 {page:Section2;}";m+="br {mso-data-placement:same-cell;}";m+="";m+="";m+="";m+='
';m+=H;m+="
";m+="";m+="";if("string"===a.outputMode)return m;if("base64"===a.outputMode)return L(m);N(m,a.fileName+"."+z,"application/vnd.ms-"+k,"","base64",!1)}else if("png"===a.type)html2canvas(d(B)[0]).then(function(b){b=b.toDataURL();for(var c=atob(b.substring(22)),d=new ArrayBuffer(c.length), +g=new Uint8Array(d),f=0;fIa){a>O.a0[0]&&(ja="a0",ca="l");for(var c in O)O.hasOwnProperty(c)&&O[c][1]>a&&(ja=c,ca="l",O[c][0]>a&&(ca="p"));Ia=a}}});a.jspdf.format=""===ja?"a4":ja;a.jspdf.orientation=""===ca?"w":ca}if(null==g.doc&&(g.doc=new jsPDF(a.jspdf.orientation,a.jspdf.unit,a.jspdf.format),g.wScaleFactor=1,g.hScaleFactor=1,"function"===typeof a.jspdf.onDocCreated))a.jspdf.onDocCreated(g.doc);!0===g.outputImages&&(g.images={});"undefined"!==typeof g.images&&(d(B).filter(function(){return I(d(this))}).each(function(){var b= +0;G=[];!1===a.exportHiddenCells&&(K=d(this).find("tr, th, td").filter(":hidden"),U=0a.styles.rowHeight&&(a.styles.rowHeight=f)}a.styles.halign="inherit"===c.headerStyles.halign?"center":c.headerStyles.halign;a.styles.valign=c.headerStyles.valign;"undefined"!==typeof e.style&&!0!==e.style.hidden&&("inherit"===c.headerStyles.halign&&(a.styles.halign=e.style.align),"inherit"===c.styles.fillColor&&(a.styles.fillColor=e.style.bcolor),"inherit"===c.styles.textColor&&(a.styles.textColor=e.style.color),"inherit"===c.styles.fontStyle&&(a.styles.fontStyle=e.style.fstyle))}}); +"function"!==typeof c.createdCell&&(c.createdCell=function(a,b){b=g.teCells[b.row.index+":"+b.column.dataKey];a.styles.halign="inherit"===c.styles.halign?"center":c.styles.halign;a.styles.valign=c.styles.valign;"undefined"!==typeof b&&"undefined"!==typeof b.style&&!0!==b.style.hidden&&("inherit"===c.styles.halign&&(a.styles.halign=b.style.align),"inherit"===c.styles.fillColor&&(a.styles.fillColor=b.style.bcolor),"inherit"===c.styles.textColor&&(a.styles.textColor=b.style.color),"inherit"===c.styles.fontStyle&& +(a.styles.fontStyle=b.style.fstyle))});"function"!==typeof c.drawHeaderCell&&(c.drawHeaderCell=function(a,b){var d=g.columns[b.column.dataKey];return(!0!==d.style.hasOwnProperty("hidden")||!0!==d.style.hidden)&&0<=d.rowIndex?wa(a,b,d):!1});"function"!==typeof c.drawCell&&(c.drawCell=function(a,b){var c=g.teCells[b.row.index+":"+b.column.dataKey];if(!0!==("undefined"!==typeof c&&c.isCanvas))wa(a,b,c)&&(g.doc.rect(a.x,a.y,a.width,a.height,a.styles.fillStyle),"undefined"===typeof c||"undefined"!==typeof c.hasUserDefText&& +!0===c.hasUserDefText||"undefined"===typeof c.elements||!c.elements.length?Aa(a,{},g):(b=a.height/c.rect.height,b>g.hScaleFactor&&(g.hScaleFactor=b),g.wScaleFactor=a.width/c.rect.width,b=a.textPos.y,za(a,c.elements,g),a.textPos.y=b,Aa(a,c.elements,g)));else{c=c.elements[0];var e=d(c).attr("data-tableexport-canvas"),f=c.getBoundingClientRect();a.width=f.width*g.wScaleFactor;a.height=f.height*g.hScaleFactor;b.row.height=a.height;ua(a,c,e,g)}return!1});g.headerrows=[];r=y(d(this));d(r).each(function(){b= +0;g.headerrows[n]=[];E(this,"th,td",n,r.length,function(a,c,d){var e=Ca(a);e.title=D(a,c,d);e.key=b++;e.rowIndex=n;g.headerrows[n].push(e)});n++});if(0 Date: Fri, 19 Feb 2021 12:07:12 -0500 Subject: [PATCH 04/57] watch for zm_terminate in db while loops --- src/zm_db.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index bb8da3a1f..02265e680 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -19,6 +19,7 @@ #include "zm_db.h" #include "zm_logger.h" +#include "zm_signal.h" #include MYSQL dbconn; @@ -178,7 +179,7 @@ MYSQL_RES *zmDbRow::fetch(const char *query) { int zmDbDo(const char *query) { db_mutex.lock(); int rc; - while ( rc = mysql_query(&dbconn, query) ) { + while ( (rc = mysql_query(&dbconn, query)) and !zm_terminate) { db_mutex.unlock(); Error("Can't run query %s: %s", query, mysql_error(&dbconn)); if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) ) @@ -193,7 +194,7 @@ int zmDbDo(const char *query) { int zmDbDoInsert(const char *query) { db_mutex.lock(); int rc; - while ( rc = mysql_query(&dbconn, query) ) { + while ( (rc = mysql_query(&dbconn, query)) and !zm_terminate) { db_mutex.unlock(); Error("Can't run query %s: %s", query, mysql_error(&dbconn)); if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) ) From d8afd580724c92a5e36c91be976ab02d3d5035fe Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:07:59 -0500 Subject: [PATCH 05/57] Remove 1 seconds sleeps from db timeout loops. 1 second is a long time. Remove UpdateFramesDelta code which is no longer needed --- src/zm_event.cpp | 37 ++----------------------------------- src/zm_event.h | 1 - 2 files changed, 2 insertions(+), 36 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 58c9cd234..f55fb432a 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -255,7 +255,6 @@ Event::~Event() { while ( mysql_query(&dbconn, sql) && !zm_terminate ) { db_mutex.unlock(); Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); - sleep(1); db_mutex.lock(); } if ( !mysql_affected_rows(&dbconn) ) { @@ -270,7 +269,6 @@ Event::~Event() { while ( mysql_query(&dbconn, sql) && !zm_terminate ) { db_mutex.unlock(); Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); - sleep(1); db_mutex.lock(); } } // end if no changed rows due to Name change during recording @@ -427,11 +425,7 @@ void Event::updateNotes(const StringSetMap &newNoteSetMap) { mysql_real_escape_string(&dbconn, escapedNotes, notes.c_str(), notes.length()); snprintf(sql, sizeof(sql), "UPDATE `Events` SET `Notes` = '%s' WHERE `Id` = %" PRIu64, escapedNotes, id); - db_mutex.lock(); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't insert event: %s", mysql_error(&dbconn)); - } - db_mutex.unlock(); + zmDbDo(sql); #endif } // end if update } // void Event::updateNotes(const StringSetMap &newNoteSetMap) @@ -564,26 +558,6 @@ void Event::WriteDbFrames() { } } // end void Event::WriteDbFrames() -// Subtract an offset time from frames deltas to match with video start time -void Event::UpdateFramesDelta(double offset) { - char sql[ZM_SQL_MED_BUFSIZ]; - - if ( offset == 0.0 ) return; - // the table is set to auto update timestamp so we force it to keep current value - snprintf(sql, sizeof(sql), - "UPDATE Frames SET timestamp = timestamp, Delta = Delta - (%.4f) WHERE EventId = %" PRIu64, - offset, id); - - db_mutex.lock(); - if ( mysql_query(&dbconn, sql) ) { - db_mutex.unlock(); - Error("Can't update frames: %s, sql was %s", mysql_error(&dbconn), sql); - return; - } - db_mutex.unlock(); - Info("Updating frames delta by %0.2f sec to match video file", offset); -} - void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) { if (!timestamp.tv_sec) { Warning("Not adding new frame, zero timestamp"); @@ -686,14 +660,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a max_score, id ); - db_mutex.lock(); - while (mysql_query(&dbconn, sql) && !zm_terminate) { - Error("Can't update event: %s", mysql_error(&dbconn)); - db_mutex.unlock(); - sleep(1); - db_mutex.lock(); - } - db_mutex.unlock(); + zmDbDo(sql); } else { Debug(1, "Not Adding %d frames to DB because write_to_db:%d or frames > analysis fps %f or BULK", frame_data.size(), write_to_db, fps); diff --git a/src/zm_event.h b/src/zm_event.h index a3eec79ed..7ba4b03ba 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -134,7 +134,6 @@ class Event { Image **images, struct timeval **timestamps); void WriteDbFrames(); - void UpdateFramesDelta(double offset); bool SetPath(Storage *storage); public: From 4ba290a9ca8aa7c0a186519876c72da6c704648c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:08:19 -0500 Subject: [PATCH 06/57] Use zmDbDo where appropriate and fix some logging while holding the lock --- src/zm_monitor.cpp | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 75e121104..6dd858edd 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1313,25 +1313,17 @@ void Monitor::actionReload() { void Monitor::actionEnable() { shared_data->action |= RELOAD; - db_mutex.lock(); - static char sql[ZM_SQL_SML_BUFSIZ]; + char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "UPDATE `Monitors` SET `Enabled` = 1 WHERE `Id` = %d", id); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } - db_mutex.unlock(); + zmDbDo(sql); } void Monitor::actionDisable() { shared_data->action |= RELOAD; - static char sql[ZM_SQL_SML_BUFSIZ]; + char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "UPDATE `Monitors` SET `Enabled` = 0 WHERE `Id` = %d", id); - db_mutex.lock(); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } - db_mutex.unlock(); + zmDbDo(sql); } void Monitor::actionSuspend() { @@ -1711,10 +1703,9 @@ void Monitor::UpdateCaptureFPS() { "VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE " "CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'", id, new_capture_fps, new_capture_bandwidth, new_capture_fps, new_capture_bandwidth); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } + int rc = mysql_query(&dbconn, sql); db_mutex.unlock(); + if ( rc ) Error("Can't run query: %s", mysql_error(&dbconn)); } // now != last_fps_time } // end if report fps } // void Monitor::UpdateCaptureFPS() @@ -1756,10 +1747,9 @@ void Monitor::UpdateAnalysisFPS() { " ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, new_analysis_fps, new_analysis_fps); db_mutex.lock(); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } + int rc = mysql_query(&dbconn, sql); db_mutex.unlock(); + if ( rc ) Error("Can't run query: %s", mysql_error(&dbconn)); last_analysis_fps_time = now_double; last_motion_frame_count = motion_frame_count; } else { From 3dab7d3eccf8bed4f9ad948717b1d8496719e72b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:08:48 -0500 Subject: [PATCH 07/57] Don't need to Disconnect when Capture will return -1, as we will call Close() which calls Disconnect() --- src/zm_remote_camera_http.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index b520e21e9..188bef05f 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -540,10 +540,8 @@ int RemoteCameraHttp::GetResponse() { } case HEADERCONT : case SUBHEADERCONT : - { // Ignore break; - } } } } else @@ -1062,7 +1060,6 @@ int RemoteCameraHttp::PreCapture() { if ( mode == SINGLE_IMAGE ) { if ( SendRequest() < 0 ) { Error("Unable to send request"); - Disconnect(); return -1; } } @@ -1072,12 +1069,11 @@ int RemoteCameraHttp::PreCapture() { int RemoteCameraHttp::Capture(ZMPacket &packet) { int content_length = GetResponse(); if ( content_length == 0 ) { - Warning( "Unable to capture image, retrying" ); + Warning("Unable to capture image, retrying"); return 0; } if ( content_length < 0 ) { - Error( "Unable to get response, disconnecting" ); - Disconnect(); + Error("Unable to get response, disconnecting"); return -1; } @@ -1094,7 +1090,6 @@ int RemoteCameraHttp::Capture(ZMPacket &packet) { case JPEG : if ( !image->DecodeJpeg(buffer.extract(content_length), content_length, colours, subpixelorder) ) { Error("Unable to decode jpeg"); - Disconnect(); return -1; } break; @@ -1102,7 +1097,6 @@ int RemoteCameraHttp::Capture(ZMPacket &packet) { if ( content_length != (long)image->Size() ) { Error("Image length mismatch, expected %d bytes, content length was %d", image->Size(), content_length); - Disconnect(); return -1; } image->Assign(width, height, colours, subpixelorder, buffer, imagesize); @@ -1110,14 +1104,12 @@ int RemoteCameraHttp::Capture(ZMPacket &packet) { case X_RGBZ : if ( !image->Unzip( buffer.extract( content_length ), content_length ) ) { Error("Unable to unzip RGB image"); - Disconnect(); return -1; } image->Assign(width, height, colours, subpixelorder, buffer, imagesize); break; default : Error("Unexpected image format encountered"); - Disconnect(); return -1; } return 1; From 124d9bf798d9450f68193266e0fd654b441e2087 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:09:02 -0500 Subject: [PATCH 08/57] Fix logging when holding db lock --- src/zm_zone.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index e0a7c3ecb..0e39123dc 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -833,8 +833,8 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { "OverloadFrames,ExtendAlarmFrames" " FROM Zones WHERE MonitorId = %d ORDER BY Type, Id", monitor->Id()); if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); db_mutex.unlock(); + Error("Can't run query: %s", mysql_error(&dbconn)); return 0; } From 2c0261bef46e3c4453370340e1d6de6669c71fd1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:43:02 -0500 Subject: [PATCH 09/57] Include time_base in DUMP_PACKET --- src/zm_ffmpeg.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index cd5f4cbed..ec22bfc33 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -369,10 +369,12 @@ void zm_dump_codecpar(const AVCodecParameters *par); if (logDebugging()) { \ double pts_time = static_cast(av_rescale_q(pkt.pts, stream->time_base, AV_TIME_BASE_Q)) / AV_TIME_BASE; \ \ - Debug(2, "%s: pts: %" PRId64 "=%f, dts: %" PRId64 \ + Debug(2, "%s: pts: %" PRId64 " * %u/%u=%f, dts: %" PRId64 \ ", size: %d, stream_index: %d, flags: %04x, keyframe(%d) pos: %" PRId64", duration: %" AV_PACKET_DURATION_FMT, \ text, \ pkt.pts, \ + stream->time_base.num, \ + stream->time_base.den, \ pts_time, \ pkt.dts, \ pkt.size, \ From ed6fc9fca6712a481217bb49569278ff7dcc0dad Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:43:36 -0500 Subject: [PATCH 10/57] use av_frame_copy_props to copy frame members instead of doing it manually --- src/zm_packet.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 2126c295c..4257dc710 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -219,7 +219,12 @@ int ZMPacket::decode(AVCodecContext *ctx) { av_frame_free(&new_frame); return 0; } - new_frame->pts = in_frame->pts; + ret = av_frame_copy_props(new_frame, in_frame); + if ( ret < 0 ) { + Error("Unable to copy props: %s, continuing", + av_make_error_string(ret).c_str()); + } + zm_dump_video_frame(new_frame, "After hwtransfer"); #if 0 if ( new_frame->format == AV_PIX_FMT_RGB0 ) { From d85e4121ef3523075c7fad530e47519d47c02067 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:43:53 -0500 Subject: [PATCH 11/57] set pts of dest_frame to make debug less confusing --- src/zm_image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 55b04d339..13e0b3946 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -276,7 +276,7 @@ void Image::Assign(const AVFrame *frame) { AVFrame *dest_frame = zm_av_frame_alloc(); PopulateFrame(dest_frame); zm_dump_video_frame(frame, "source frame before convert"); - zm_dump_video_frame(dest_frame, "dest frame before convert"); + dest_frame->pts = frame->pts; #if HAVE_LIBSWSCALE sws_convert_context = sws_getCachedContext( sws_convert_context, From 551e35b4bf97c9ca5e6768eea70cdd5cde2c7db0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:44:13 -0500 Subject: [PATCH 12/57] dump incoming video packet for debug --- src/zm_videostore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 98bf8692e..0f67935a3 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -1097,7 +1097,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) { } else { // Passthrough AVPacket *ipkt = &zm_packet->packet; - Debug(3, "Doing passthrough, just copy packet"); + ZM_DUMP_STREAM_PACKET(video_in_stream, (*ipkt), "Doing passthrough, just copy packet"); // Just copy it because the codec is the same av_init_packet(&opkt); opkt.data = ipkt->data; @@ -1149,6 +1149,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { audio_next_pts = audio_out_ctx->frame_size; } + Debug(3, "audio first_dts to %" PRId64, audio_first_dts); // Need to adjust pts before feeding to decoder.... should really copy the pkt instead of modifying it ipkt->pts -= audio_first_dts; ipkt->dts -= audio_first_dts; From 415dd83d0685f1cee1d975ba2ddbaa7d8c9a1550 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 12:44:20 -0500 Subject: [PATCH 13/57] spacing --- src/zm_packetqueue.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index e4b0cd7cc..310e03a7f 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -434,7 +434,7 @@ int PacketQueue::packet_count(int stream_id) { return -1; } return packet_counts[stream_id]; -} // end int PacketQueue::packet_count(int stream_id) +} // end int PacketQueue::packet_count(int stream_id) // Returns a packet. Packet will be locked @@ -470,7 +470,7 @@ ZMPacket *PacketQueue::get_packet(packetqueue_iterator *it) { } Debug(2, "Locked packet, unlocking packetqueue mutex"); return p; -} // end ZMPacket *PacketQueue::get_packet(it) +} // end ZMPacket *PacketQueue::get_packet(it) bool PacketQueue::increment_it(packetqueue_iterator *it) { Debug(2, "Incrementing %p, queue size %d, end? %d", it, pktQueue.size(), ((*it) == pktQueue.end())); From d8e37945a341b4e41c6f1fc89b03d588f90c7204 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 13:44:37 -0500 Subject: [PATCH 14/57] TRY OUT SWS_POINT|SWS_BITEXACT scaling --- src/zm_image.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 13e0b3946..10ede025d 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -282,7 +282,9 @@ void Image::Assign(const AVFrame *frame) { sws_convert_context, frame->width, frame->height, (AVPixelFormat)frame->format, width, height, format, - SWS_BICUBIC, nullptr, nullptr, nullptr); + //SWS_BICUBIC, + SWS_POINT | SWS_BITEXACT, + nullptr, nullptr, nullptr); if ( sws_convert_context == nullptr ) Fatal("Unable to create conversion context"); From b9669ad69f8ed14b16ad941d2d5f14906288ac3d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 15:56:30 -0500 Subject: [PATCH 15/57] Log new signal on signal change --- src/zm_monitor.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 6dd858edd..bb867ebba 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1830,7 +1830,7 @@ bool Monitor::Analyse() { } // end if trigger_on if ( signal_change ) { - Debug(2, "Signal change"); + Debug(2, "Signal change, new signal is %d", signal); const char *signalText = "Unknown"; if ( !signal ) { signalText = "Lost"; @@ -2503,6 +2503,7 @@ int Monitor::Capture() { Debug(2, "Queueing audio packet"); packetqueue.queuePacket(packet); } else { + Debug(4, "Not Queueing audio packet"); delete packet; } // Don't update last_write_index because that is used for live streaming From 507cbf7f0f053a2ab49799eee49fe4eb93432ad0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 15:56:42 -0500 Subject: [PATCH 16/57] Remove some debugging --- src/zm_packetqueue.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 310e03a7f..1b6270c05 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -143,15 +143,13 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) { // Since we have many packets in the queue, we should NOT be pointing at end so don't need to test for that while ( *it != add_packet ) { zm_packet = *it; - Debug(1, "Checking packet to see if we can delete them"); if ( !zm_packet->trylock() ) { - Debug(1, "Have locked packet %d", zm_packet->image_index); break; } zm_packet->unlock(); if ( is_there_an_iterator_pointing_to_packet(zm_packet) ) { - Debug(4, "Found IT at beginning of queue. Threads not keeping up"); + Warning("Found iterator at beginning of queue. Some thread isn't keeping up"); break; } @@ -169,8 +167,6 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) { ( next_front == pktQueue.begin() ) ); if ( next_front != pktQueue.begin() ) { - Debug(1, "Deleting packets"); - // It is enough to delete the packets tested above. A subsequent queuePacket can clear a second set while ( pktQueue.begin() != next_front ) { ZMPacket *zm_packet = *pktQueue.begin(); if ( !zm_packet ) { From 2f917b4fac84ed384a871b3ce0fe31876d55c00c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 15:58:49 -0500 Subject: [PATCH 17/57] Must copy input packet before modifying pts/dts. --- src/zm_videostore.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 0f67935a3..8026b968e 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -1134,7 +1134,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) { int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { - AVPacket *ipkt = &zm_packet->packet; + AVPacket *ipkt = av_packet_clone(&zm_packet->packet); int ret; if ( !audio_out_stream ) { @@ -1215,6 +1215,7 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { zm_av_packet_unref(&opkt); } // end if encoding or copying + av_packet_free(&ipkt); return 0; } // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt) From 16773573ad4c1be23749ff077d03f80209a656b5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 16:36:06 -0500 Subject: [PATCH 18/57] Since audio encoding uses it's own pts counting, we don't need to copy the ipkt. --- src/zm_videostore.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 8026b968e..19e822d15 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -1134,7 +1134,7 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) { int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { - AVPacket *ipkt = av_packet_clone(&zm_packet->packet); + AVPacket *ipkt = &zm_packet->packet; int ret; if ( !audio_out_stream ) { @@ -1151,9 +1151,6 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { Debug(3, "audio first_dts to %" PRId64, audio_first_dts); // Need to adjust pts before feeding to decoder.... should really copy the pkt instead of modifying it - ipkt->pts -= audio_first_dts; - ipkt->dts -= audio_first_dts; - ZM_DUMP_STREAM_PACKET(audio_in_stream, (*ipkt), "after pts adjustment"); if ( audio_out_codec ) { // I wonder if we can get multiple frames per packet? Probably @@ -1207,15 +1204,16 @@ int VideoStore::writeAudioFramePacket(ZMPacket *zm_packet) { opkt.flags = ipkt->flags; opkt.duration = ipkt->duration; - opkt.pts = ipkt->pts; - opkt.dts = ipkt->dts; + opkt.pts = ipkt->pts - audio_first_dts; + opkt.dts = ipkt->dts - audio_first_dts; + + ZM_DUMP_STREAM_PACKET(audio_in_stream, (*ipkt), "after pts adjustment"); av_packet_rescale_ts(&opkt, audio_in_stream->time_base, audio_out_stream->time_base); ZM_DUMP_STREAM_PACKET(audio_out_stream, opkt, "after stream pts adjustment"); write_packet(&opkt, audio_out_stream); zm_av_packet_unref(&opkt); } // end if encoding or copying - av_packet_free(&ipkt); return 0; } // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt) From a5ad7462e0a726e354a08efe98992a794fbc42b3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 20:41:41 -0500 Subject: [PATCH 19/57] add dlclose --- src/zm_libvlc_camera.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/zm_libvlc_camera.cpp b/src/zm_libvlc_camera.cpp index 2cab3ee80..fd4d077b8 100644 --- a/src/zm_libvlc_camera.cpp +++ b/src/zm_libvlc_camera.cpp @@ -177,6 +177,10 @@ LibvlcCamera::~LibvlcCamera() { (*libvlc_release_f)(mLibvlcInstance); mLibvlcInstance = nullptr; } + if (libvlc_lib) { + dlclose(libvlc_lib); + libvlc_lib = nullptr; + } if ( mOptArgV != nullptr ) { delete[] mOptArgV; } From f440ecb235b8d6e0eb1f03349edd4fb09f1a3854 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 20:42:07 -0500 Subject: [PATCH 20/57] Add dlcose, and a resize() function to allocate the framebuffer our own way --- src/zm_libvnc_camera.cpp | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index 4344b4997..cdb08d06c 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -61,6 +61,19 @@ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ return c; } +static rfbBool resize(rfbClient* client) { + if ( client->frameBuffer ) { + Debug(1, "Freeing old frame buffer"); + av_free(client->frameBuffer); + } + + int mBufferSize = SWScale::GetBufferSize(AV_PIX_FMT_RGBA, client->width, client->height); + client->frameBuffer = (uint8_t *)av_malloc(mBufferSize); + Debug(1, "Allocing new frame buffer %dx%d = %d", client->width, client->height, mBufferSize); + + return TRUE; +} + VncCamera::VncCamera( const Monitor *monitor, const std::string &host, @@ -124,6 +137,10 @@ VncCamera::~VncCamera() { free(mRfb->frameBuffer); (*rfbClientCleanup_f)(mRfb); } + if (libvnc_lib) { + dlclose(libvnc_lib); + libvnc_lib = nullptr; + } } int VncCamera::PrimeCapture() { @@ -134,12 +151,8 @@ int VncCamera::PrimeCapture() { mVncData.width = 0; mVncData.height = 0; - mBufferSize = SWScale::GetBufferSize(AV_PIX_FMT_RGBA, width, height); - mRfb = (*rfbGetClient_f)(8 /* bits per sample */, 3 /* samples per pixel */, 4 /* bytes Per Pixel */); - mRfb->frameBuffer = nullptr; - //(uint8_t *)av_malloc(mBufferSize); - mRfb->canHandleNewFBSize = false; + mRfb->MallocFrameBuffer=resize; (*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData); (*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str()); @@ -186,7 +199,7 @@ int VncCamera::Capture(ZMPacket &zm_packet) { return 0; } if ( !zm_packet.image ) { - Debug(1, "Allocating image %dx%d %dcolours = %d", width, height, colours, pixels); + Debug(1, "Allocating image %dx%d %dcolours = %d", width, height, colours, colours*pixels); zm_packet.image = new Image(width, height, colours, subpixelorder); } zm_packet.keyframe = 1; @@ -194,6 +207,16 @@ int VncCamera::Capture(ZMPacket &zm_packet) { zm_packet.packet.stream_index = mVideoStreamId; uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder); + Debug(1, "scale src %p, %d, dest %p %d %d %dx%d %dx%d", mVncData.buffer, + mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, + directbuffer, + width * height * colours, + mImgPixFmt, + mRfb->si.framebufferWidth, + mRfb->si.framebufferHeight, + width, + height); + int rc = scale.Convert( mVncData.buffer, mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, From 86d424baf02cf9d98af5025a2d4e11d75534ec58 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 20:42:36 -0500 Subject: [PATCH 21/57] Move closeEvent to Close(). If we are closing the camera, we have to close the event as well. --- src/zm_monitor.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index bb867ebba..c75d5329a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1071,11 +1071,6 @@ Monitor::~Monitor() { Close(); if (mem_ptr != nullptr) { - std::lock_guard lck(event_mutex); - if (event) { - Info("%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name, image_count, event->Id()); - closeEvent(); - } if (purpose != QUERY) { shared_data->state = state = IDLE; shared_data->last_read_index = image_buffer_count; @@ -2923,10 +2918,16 @@ int Monitor::PrimeCapture() { int Monitor::PreCapture() const { return camera->PreCapture(); } int Monitor::PostCapture() const { return camera->PostCapture(); } int Monitor::Close() { + std::lock_guard lck(event_mutex); + if (event) { + Info("%s: image_count:%d - Closing event %" PRIu64 ", shutting down", name, image_count, event->Id()); + closeEvent(); + } if (camera) camera->Close(); packetqueue.clear(); return 1; } + Monitor::Orientation Monitor::getOrientation() const { return orientation; } // Wait for camera to get an image, and then assign it as the base reference image. From bf0ae8b270c5b2adbe97b00b9b2e9170c4fcc27b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 20:43:24 -0500 Subject: [PATCH 22/57] use fix_deprecated_pix_fmt function. Fix logic on out_buffer_size. --- src/zm_swscale.cpp | 66 +++++++++++++--------------------------------- 1 file changed, 18 insertions(+), 48 deletions(-) diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp index c30428007..899801db6 100644 --- a/src/zm_swscale.cpp +++ b/src/zm_swscale.cpp @@ -91,25 +91,7 @@ int SWScale::Convert( AVFrame *out_frame ) { - // THe J formats are deprecated, so we need to convert - AVPixelFormat format; - switch ( in_frame->format ) { - case AV_PIX_FMT_YUVJ420P : - format = AV_PIX_FMT_YUV420P; - break; - case AV_PIX_FMT_YUVJ422P : - format = AV_PIX_FMT_YUV422P; - break; - case AV_PIX_FMT_YUVJ444P : - format = AV_PIX_FMT_YUV444P; - break; - case AV_PIX_FMT_YUVJ440P : - format = AV_PIX_FMT_YUV440P; - break; - default: - format = (AVPixelFormat)in_frame->format; - break; - } + AVPixelFormat format = fix_deprecated_pix_fmt((AVPixelFormat)in_frame->format); /* Get the context */ swscale_ctx = sws_getCachedContext(swscale_ctx, in_frame->width, in_frame->height, format, @@ -120,7 +102,9 @@ int SWScale::Convert( return -6; } /* Do the conversion */ - if ( !sws_scale(swscale_ctx, in_frame->data, in_frame->linesize, 0, in_frame->height, out_frame->data, out_frame->linesize ) ) { + if (!sws_scale(swscale_ctx, + in_frame->data, in_frame->linesize, 0, in_frame->height, + out_frame->data, out_frame->linesize)) { Error("swscale conversion failed"); return -10; } @@ -140,8 +124,9 @@ int SWScale::Convert( unsigned int new_width, unsigned int new_height ) { - Debug(1, "Convert: in_buffer %p in_buffer_size %d out_buffer %p size %d width %d height %d width %d height %d", - in_buffer, in_buffer_size, out_buffer, out_buffer_size, width, height, new_width, new_height); + Debug(1, "Convert: in_buffer %p in_buffer_size %d out_buffer %p size %d width %d height %d width %d height %d %d %d", + in_buffer, in_buffer_size, out_buffer, out_buffer_size, width, height, new_width, new_height, + in_pf, out_pf); /* Parameter checking */ if ( in_buffer == nullptr ) { Error("NULL Input buffer"); @@ -160,23 +145,7 @@ int SWScale::Convert( return -3; } - // THe J formats are deprecated, so we need to convert - switch ( in_pf ) { - case AV_PIX_FMT_YUVJ420P : - in_pf = AV_PIX_FMT_YUV420P; - break; - case AV_PIX_FMT_YUVJ422P : - in_pf = AV_PIX_FMT_YUV422P; - break; - case AV_PIX_FMT_YUVJ444P : - in_pf = AV_PIX_FMT_YUV444P; - break; - case AV_PIX_FMT_YUVJ440P : - in_pf = AV_PIX_FMT_YUV440P; - break; - default: - break; - } + in_pf = fix_deprecated_pix_fmt(in_pf); #if LIBSWSCALE_VERSION_CHECK(0, 8, 0, 8, 0) /* Warn if the input or output pixelformat is not supported */ @@ -192,11 +161,11 @@ int SWScale::Convert( /* Check the buffer sizes */ size_t insize = GetBufferSize(in_pf, width, height); - if ( insize != in_buffer_size ) { - Debug(1, "The input buffer size does not match the expected size for the input format. Required: %d Available: %d", insize, in_buffer_size); + if ( insize > in_buffer_size ) { + Debug(1, "The input buffer size does not match the expected size for the input format. Required: %d for %dx%d %d Available: %d", insize, width, height, in_pf, in_buffer_size); } size_t outsize = GetBufferSize(out_pf, new_width, new_height); - if ( outsize < out_buffer_size ) { + if ( outsize > out_buffer_size ) { Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size); return -5; } @@ -212,8 +181,8 @@ int SWScale::Convert( /* Fill in the buffers */ #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - if ( av_image_fill_arrays(input_avframe->data, input_avframe->linesize, - (uint8_t*) in_buffer, in_pf, width, height, 1) <= 0) { + if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize, + (uint8_t*) in_buffer, in_pf, width, height, 32) <= 0) { #else if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer, in_pf, width, height) <= 0) { @@ -222,10 +191,10 @@ int SWScale::Convert( return -7; } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - if ( av_image_fill_arrays(output_avframe->data, output_avframe->linesize, - out_buffer, out_pf, new_width, new_height, 1) <= 0) { + if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize, + out_buffer, out_pf, new_width, new_height, 32) <= 0) { #else - if ( avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width, + if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width, new_height) <= 0) { #endif Error("Failed filling output frame with output buffer"); @@ -235,7 +204,8 @@ int SWScale::Convert( /* Do the conversion */ if ( !sws_scale(swscale_ctx, input_avframe->data, input_avframe->linesize, - 0, height, output_avframe->data, output_avframe->linesize ) ) { + 0, height, + output_avframe->data, output_avframe->linesize) ) { Error("swscale conversion failed"); return -10; } From e562888ed0f1dce5f636674fe58c91355faae82a Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Feb 2021 21:03:10 -0500 Subject: [PATCH 23/57] Fix crash when decoder returns 0 and when are using hwaccel --- src/zm_packet.cpp | 133 +++++++++++++++++++++++----------------------- 1 file changed, 66 insertions(+), 67 deletions(-) diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 4257dc710..fc2f3bfa4 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -159,95 +159,94 @@ int ZMPacket::decode(AVCodecContext *ctx) { return 0; } int bytes_consumed = ret; - if ( ret > 0 ) + if ( ret > 0 ) { zm_dump_video_frame(in_frame, "got frame"); #if HAVE_LIBAVUTIL_HWCONTEXT_H #if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0) - if ( ctx->sw_pix_fmt != in_frame->format ) { - Debug(1, "Have different format %s != %s.", - av_get_pix_fmt_name(ctx->pix_fmt), - av_get_pix_fmt_name(ctx->sw_pix_fmt) - ); + if ( ctx->sw_pix_fmt != in_frame->format ) { + Debug(1, "Have different format %s != %s.", + av_get_pix_fmt_name(ctx->pix_fmt), + av_get_pix_fmt_name(ctx->sw_pix_fmt) + ); #if 0 - if ( target_format == AV_PIX_FMT_NONE and ctx->hw_frames_ctx and (image->Colours() == 4) ) { - // Look for rgb0 in list of supported formats - enum AVPixelFormat *formats; - if ( 0 <= av_hwframe_transfer_get_formats( - ctx->hw_frames_ctx, - AV_HWFRAME_TRANSFER_DIRECTION_FROM, - &formats, - 0 - ) ) { - for (int i = 0; formats[i] != AV_PIX_FMT_NONE; i++) { - Debug(1, "Available dest formats %d %s", - formats[i], - av_get_pix_fmt_name(formats[i]) - ); - if ( formats[i] == AV_PIX_FMT_RGB0 ) { - target_format = formats[i]; - break; - } // endif RGB0 - } // end foreach support format - av_freep(&formats); - } // endif success getting list of formats - } // end if target_format not set + if ( target_format == AV_PIX_FMT_NONE and ctx->hw_frames_ctx and (image->Colours() == 4) ) { + // Look for rgb0 in list of supported formats + enum AVPixelFormat *formats; + if ( 0 <= av_hwframe_transfer_get_formats( + ctx->hw_frames_ctx, + AV_HWFRAME_TRANSFER_DIRECTION_FROM, + &formats, + 0 + ) ) { + for (int i = 0; formats[i] != AV_PIX_FMT_NONE; i++) { + Debug(1, "Available dest formats %d %s", + formats[i], + av_get_pix_fmt_name(formats[i]) + ); + if ( formats[i] == AV_PIX_FMT_RGB0 ) { + target_format = formats[i]; + break; + } // endif RGB0 + } // end foreach support format + av_freep(&formats); + } // endif success getting list of formats + } // end if target_format not set #endif - AVFrame *new_frame = zm_av_frame_alloc(); + AVFrame *new_frame = zm_av_frame_alloc(); #if 0 - if ( target_format == AV_PIX_FMT_RGB0 ) { - if ( image ) { - if ( 0 > image->PopulateFrame(new_frame) ) { - delete new_frame; - new_frame = zm_av_frame_alloc(); - delete image; - image = nullptr; - new_frame->format = target_format; + if ( target_format == AV_PIX_FMT_RGB0 ) { + if ( image ) { + if ( 0 > image->PopulateFrame(new_frame) ) { + delete new_frame; + new_frame = zm_av_frame_alloc(); + delete image; + image = nullptr; + new_frame->format = target_format; + } } } - } #endif - /* retrieve data from GPU to CPU */ - zm_dump_video_frame(in_frame, "Before hwtransfer"); - ret = av_hwframe_transfer_data(new_frame, in_frame, 0); - if ( ret < 0 ) { - Error("Unable to transfer frame: %s, continuing", - av_make_error_string(ret).c_str()); - av_frame_free(&in_frame); - av_frame_free(&new_frame); - return 0; - } - ret = av_frame_copy_props(new_frame, in_frame); - if ( ret < 0 ) { - Error("Unable to copy props: %s, continuing", - av_make_error_string(ret).c_str()); - } + /* retrieve data from GPU to CPU */ + zm_dump_video_frame(in_frame, "Before hwtransfer"); + ret = av_hwframe_transfer_data(new_frame, in_frame, 0); + if ( ret < 0 ) { + Error("Unable to transfer frame: %s, continuing", + av_make_error_string(ret).c_str()); + av_frame_free(&in_frame); + av_frame_free(&new_frame); + return 0; + } + ret = av_frame_copy_props(new_frame, in_frame); + if ( ret < 0 ) { + Error("Unable to copy props: %s, continuing", + av_make_error_string(ret).c_str()); + } - zm_dump_video_frame(new_frame, "After hwtransfer"); + zm_dump_video_frame(new_frame, "After hwtransfer"); #if 0 - if ( new_frame->format == AV_PIX_FMT_RGB0 ) { - new_frame->format = AV_PIX_FMT_RGBA; - zm_dump_video_frame(new_frame, "After hwtransfer setting to rgba"); - } + if ( new_frame->format == AV_PIX_FMT_RGB0 ) { + new_frame->format = AV_PIX_FMT_RGBA; + zm_dump_video_frame(new_frame, "After hwtransfer setting to rgba"); + } #endif - av_frame_free(&in_frame); - in_frame = new_frame; - } else + av_frame_free(&in_frame); + in_frame = new_frame; + } else #endif #endif - if ( ret > 0 ) { - Debug(2, "Same pix format %s so not hwtransferring. sw_pix_fmt is %s", - av_get_pix_fmt_name(ctx->pix_fmt), - av_get_pix_fmt_name(ctx->sw_pix_fmt) - ); + Debug(2, "Same pix format %s so not hwtransferring. sw_pix_fmt is %s", + av_get_pix_fmt_name(ctx->pix_fmt), + av_get_pix_fmt_name(ctx->sw_pix_fmt) + ); #if 0 if ( image ) { image->Assign(in_frame); } #endif - } + } // end if if ( ret > 0 ) { return bytes_consumed; } // end ZMPacket::decode From 0fc4b00ac10db00951826df8ad7753fa94e55e27 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 20 Feb 2021 12:32:38 -0500 Subject: [PATCH 24/57] Allow null as well as NULL infilter values --- web/includes/FilterTerm.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/includes/FilterTerm.php b/web/includes/FilterTerm.php index 42f939128..c6c3cf312 100644 --- a/web/includes/FilterTerm.php +++ b/web/includes/FilterTerm.php @@ -68,7 +68,7 @@ class FilterTerm { $vals = is_array($this->val) ? $this->val : preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $this->val)); foreach ( $vals as $value ) { - + $value_upper = strtoupper($value); switch ( $this->attr ) { case 'AlarmedZoneId': @@ -96,36 +96,36 @@ class FilterTerm { case 'ServerId': if ( $value == 'ZM_SERVER_ID' ) { $value = ZM_SERVER_ID; - } else if ( $value == 'NULL' ) { + } else if ( $value_upper == 'NULL' ) { } else { $value = dbEscape($value); } break; case 'StorageId': - if ( $value != 'NULL' ) { + if ( $value_upper != 'NULL' ) { $value = dbEscape($value); } break; case 'DateTime': case 'StartDateTime': case 'EndDateTime': - if ( $value != 'NULL' ) + if ( $value_upper != 'NULL' ) $value = '\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\''; break; case 'Date': case 'StartDate': case 'EndDate': - if ( $value == 'CURDATE()' or $value == 'NOW()' ) { + if ( $value_upper == 'CURDATE()' or $value_upper == 'NOW()' ) { $value = 'to_days('.$value.')'; - } else if ( $value != 'NULL' ) { + } else if ( $value_upper != 'NULL' ) { $value = 'to_days(\''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; } break; case 'Time': case 'StartTime': case 'EndTime': - if ( $value != 'NULL' ) + if ( $value_upper != 'NULL' ) $value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; break; default : @@ -133,7 +133,7 @@ class FilterTerm { $value = 1; } else if ( $value == 'Even' ) { $value = 0; - } else if ( $value != 'NULL' ) + } else if ( $value_upper != 'NULL' ) $value = dbEscape($value); break; } From 4d739f35ef07cd5e8d0922a31f443fe8d4955d24 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 20 Feb 2021 17:07:07 -0500 Subject: [PATCH 25/57] Fix parseTree when using iS or ISNOT. Add strtoupper comparisons for NULL values. --- web/includes/Filter.php | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/web/includes/Filter.php b/web/includes/Filter.php index 934c66aa8..b8e2d4088 100644 --- a/web/includes/Filter.php +++ b/web/includes/Filter.php @@ -349,6 +349,8 @@ class Filter extends ZM_Object { '![]' => 2, 'and' => 3, 'or' => 4, + 'IS' => 2, + 'IS NOT' => 2, ); for ( $i = 0; $i < count($terms); $i++ ) { @@ -476,6 +478,7 @@ class Filter extends ZM_Object { } } # end if attr + $sqlValue = ''; if ( isset($term['op']) ) { if ( empty($term['op']) ) { $term['op'] = '='; @@ -507,11 +510,11 @@ class Filter extends ZM_Object { case 'IS' : case 'IS NOT' : if ( $term['val'] == 'Odd' ) { - $sqlValue .= ' % 2 = 1'; + $sqlValue = ' % 2 = 1'; } else if ( $term['val'] == 'Even' ) { - $sqlValue .= ' % 2 = 0'; + $sqlValue = ' % 2 = 0'; } else { - $sqlValue .= ' '.$term['op']; + $sqlValue = ' '.$term['op']; } break; default : @@ -522,10 +525,10 @@ class Filter extends ZM_Object { if ( !count($postfixStack) ) { $postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue); break; - } elseif ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) { + } else if ( $postfixStack[count($postfixStack)-1]['type'] == 'obr' ) { $postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue); break; - } elseif ( $priorities[$term['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) { + } else if ( $priorities[$term['op']] < $priorities[$postfixStack[count($postfixStack)-1]['value']] ) { $postfixStack[] = array('type'=>'op', 'value'=>$term['op'], 'sqlValue'=>$sqlValue ); break; } else { @@ -537,6 +540,7 @@ class Filter extends ZM_Object { if ( isset($term['val']) ) { $valueList = array(); foreach ( preg_split('/["\'\s]*?,["\'\s]*?/', preg_replace('/^["\']+?(.+)["\']+?$/', '$1', $term['val'])) as $value ) { + $value_upper = strtoupper($value); switch ( $term['attr'] ) { case 'MonitorName': case 'Name': @@ -551,9 +555,9 @@ class Filter extends ZM_Object { case 'FilterServerId': case 'StorageServerId': case 'ServerId': - if ( $value == 'ZM_SERVER_ID' ) { + if ( $value_upper == 'ZM_SERVER_ID' ) { $value = ZM_SERVER_ID; - } else if ( $value == 'NULL' ) { + } else if ( $value_upper == 'NULL' ) { } else { $value = dbEscape($value); @@ -567,7 +571,8 @@ class Filter extends ZM_Object { case 'DateTime': case 'EndDateTime': case 'StartDateTime': - $value = "'".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."'"; + if ( $value_upper != 'NULL' ) + $value = "'".strftime(STRF_FMT_DATETIME_DB, strtotime($value))."'"; break; case 'Date': case 'EndDate': @@ -580,7 +585,7 @@ class Filter extends ZM_Object { $value = 'extract(hour_second from \''.strftime(STRF_FMT_DATETIME_DB, strtotime($value)).'\')'; break; default : - if ( $value != 'NULL' ) + if ( $value_upper != 'NULL' ) $value = dbEscape($value); } // end switch attribute $valueList[] = $value; From 5d826fd558cc737d1593496658b75069bbb77280 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sat, 20 Feb 2021 17:11:20 -0500 Subject: [PATCH 26/57] Don't try to addup/update DIskSpace used by incomplete events. --- web/includes/Storage.php | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/web/includes/Storage.php b/web/includes/Storage.php index 71bc021d2..11519b0e1 100644 --- a/web/includes/Storage.php +++ b/web/includes/Storage.php @@ -132,19 +132,7 @@ class Storage extends ZM_Object { public function event_disk_space() { # This isn't a function like this in php, so we have to add up the space used in each event. if ( (! property_exists($this, 'DiskSpace')) or (!isset($this->{'DiskSpace'})) ) { - $used = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id())); - - do { - # Do in batches of 1000 so as to not useup all ram, Event will do caching though... - $events = Event::find(array('StorageId'=>$this->Id(), 'DiskSpace'=>null), array('limit'=>1000)); - foreach ( $events as $Event ) { - $Event->Storage($this); // Prevent further db hit - # DiskSpace will update the event - $used += $Event->DiskSpace(); - } #end foreach - Event::clear_cache(); - } while ( count($events) == 1000 ); - $this->{'DiskSpace'} = $used; + $this->{'DiskSpace'} = dbFetchOne('SELECT SUM(DiskSpace) AS DiskSpace FROM Events WHERE StorageId=? AND DiskSpace IS NOT NULL', 'DiskSpace', array($this->Id())); } return $this->{'DiskSpace'}; } // end function event_disk_space From 7c042c7837a311fbe1d1cd3416b47e3b22f930d0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 21 Feb 2021 20:24:36 -0500 Subject: [PATCH 27/57] If doing encoding, we don't care about keyframe --- src/zm_event.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index f55fb432a..87f32c528 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -506,7 +506,9 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str void Event::AddPacket(ZMPacket *packet) { - have_video_keyframe = have_video_keyframe || ( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) && packet->keyframe ); + have_video_keyframe = have_video_keyframe || + ( ( packet->codec_type == AVMEDIA_TYPE_VIDEO ) && + ( packet->keyframe || monitor->GetOptVideoWriter() == Monitor::ENCODE) ); Debug(2, "have_video_keyframe %d codec_type %d == video? %d packet keyframe %d", have_video_keyframe, packet->codec_type, (packet->codec_type == AVMEDIA_TYPE_VIDEO), packet->keyframe); ZM_DUMP_PACKET(packet->packet, "Adding to event"); From 9fec32fdc5b35d316bc1f85552d838833e9b8582 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 09:55:40 -0500 Subject: [PATCH 28/57] We now support audio when doing video encoding --- web/skins/classic/views/monitor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index 70e22fda7..e760b097a 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -993,7 +993,7 @@ $videowriter_encoders = array( 'mpeg1' => 'mpeg1', 'mpeg2' => 'mpeg2', ); - echo htmlSelect( 'newMonitor[Encoder]', $videowriter_encoders, $monitor->Encoder() );?> + echo htmlSelect('newMonitor[Encoder]', $videowriter_encoders, $monitor->Encoder());?> @@ -1017,7 +1017,7 @@ echo htmlSelect('newMonitor[OutputContainer]', $videowriter_containers, $monitor Type() == 'Ffmpeg' ) { ?> RecordAudio() ) { ?> checked="checked"/> - Audio recording only available with FFMPEG using H264 Passthrough + Audio recording only available with FFMPEG From 7a17a6f9e8ab74ff2b4a4c510d1b2a80c1386434 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 11:14:00 -0500 Subject: [PATCH 29/57] Fix always returning YUV420P despite being valid format. --- src/zm_ffmpeg.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 1d7bfd065..a0131d75f 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -385,8 +385,9 @@ enum AVPixelFormat fix_deprecated_pix_fmt(enum AVPixelFormat fmt) { return AV_PIX_FMT_YUV440P; case AV_PIX_FMT_NONE : case AV_PIX_FMT_YUVJ420P : - default: return AV_PIX_FMT_YUV420P; + default: + return fmt; } } From 88f3d732b47dd2b482606e1637d4c008fa16d148 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 11:17:17 -0500 Subject: [PATCH 30/57] Always use AV_TIME_BASE_Q in video encoding mode as we use packet->timestamp instead of pts. Fixes duration problems with encoded video. Fixes #3160 --- src/zm_videostore.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 19e822d15..3da2a0d67 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -190,12 +190,8 @@ bool VideoStore::open() { #endif } - video_out_ctx->time_base = video_in_ctx ? video_in_ctx->time_base : AV_TIME_BASE_Q; - if ( ! (video_out_ctx->time_base.num && video_out_ctx->time_base.den) ) { - Debug(2, "No timebase found in video in context, defaulting to Q which is microseconds"); - video_out_ctx->time_base = AV_TIME_BASE_Q; - } - + // When encoding, we are going to use the timestamp values instead of packet pts/dts + video_out_ctx->time_base = AV_TIME_BASE_Q; video_out_ctx->codec_id = codec_data[i].codec_id; video_out_ctx->pix_fmt = codec_data[i].pix_fmt; video_out_ctx->level = 32; @@ -254,6 +250,7 @@ bool VideoStore::open() { } //av_dict_free(&opts); if ( video_out_codec ) break; + avcodec_free_context(&video_out_ctx); } // end foreach codec if ( !video_out_codec ) { @@ -1015,21 +1012,25 @@ int VideoStore::writeVideoFramePacket(ZMPacket *zm_packet) { //zm_packet->out_frame->sample_aspect_ratio = (AVRational){ 0, 1 }; // Do this to allow the encoder to choose whether to use I/P/B frame //zm_packet->out_frame->pict_type = AV_PICTURE_TYPE_NONE; - zm_packet->out_frame->key_frame = zm_packet->keyframe; + //zm_packet->out_frame->key_frame = zm_packet->keyframe; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) zm_packet->out_frame->pkt_duration = 0; #endif + int64_t in_pts = zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec; if ( !video_first_pts ) { - video_first_pts = zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec; + video_first_pts = in_pts; Debug(2, "No video_first_pts, set to (%" PRId64 ") secs(%d) usecs(%d)", video_first_pts, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec); zm_packet->out_frame->pts = 0; } else { - uint64_t useconds = ( zm_packet->timestamp->tv_sec * (uint64_t)1000000 + zm_packet->timestamp->tv_usec ) - video_first_pts; - zm_packet->out_frame->pts = av_rescale_q(useconds, video_in_stream->time_base, video_out_ctx->time_base); - Debug(2, " Setting pts for frame(%d) to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d)", - frame_count, zm_packet->out_frame->pts, video_first_pts, useconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec); + uint64_t useconds = in_pts - video_first_pts; + zm_packet->out_frame->pts = av_rescale_q(useconds, AV_TIME_BASE_Q, video_out_ctx->time_base); + Debug(2, " Setting pts for frame(%d) to (%" PRId64 ") from (start %" PRIu64 " - %" PRIu64 " - secs(%d) usecs(%d) @ %d/%d", + frame_count, zm_packet->out_frame->pts, video_first_pts, useconds, zm_packet->timestamp->tv_sec, zm_packet->timestamp->tv_usec, + video_out_ctx->time_base.num, + video_out_ctx->time_base.den + ); } av_init_packet(&opkt); From 9aad09a7353825f177d23a54c60414746f8d278c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 11:24:30 -0500 Subject: [PATCH 31/57] Refresh bootstrap table if the ajax fails. --- web/skins/classic/views/js/events.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index e125cd0e8..0c5ca5ef1 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -45,7 +45,10 @@ function ajaxRequest(params) { // rearrange the result into what bootstrap-table expects params.success({total: data.total, totalNotFiltered: data.totalNotFiltered, rows: rows}); }) - .fail(logAjaxFail); + .fail(function(jqXHR) { + logAjaxFail(jqXHR); + $j('#eventTable').bootstrapTable('refresh'); + }); } function processRows(rows) { @@ -118,7 +121,11 @@ function manageDelConfirmModalBtns() { $j('#eventTable').bootstrapTable('refresh'); $j('#deleteConfirm').modal('hide'); }) - .fail(logAjaxFail); + .fail( function(jqxhr) { + logAjaxFail(jqxhr); + $j('#eventTable').bootstrapTable('refresh'); + $j('#deleteConfirm').modal('hide'); + }); }); // Manage the CANCEL modal button @@ -196,11 +203,14 @@ function initPage() { window.history.back(); }); + + /* // Manage the REFRESH Button document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { evt.preventDefault(); window.location.reload(true); }); + */ // Manage the TIMELINE Button document.getElementById("tlineBtn").addEventListener("click", function onTlineClick(evt) { From 3a8e2ff869ee535730646472f18989a866ea02d7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 11:25:00 -0500 Subject: [PATCH 32/57] Hide duplicated refresh button --- web/skins/classic/views/events.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 52cb5c3f0..49003301e 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -52,7 +52,7 @@ getBodyTopHTML();
- + From 82c4a1a41774937d9fb2045fca6cbc06ee00edd2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 11:57:27 -0500 Subject: [PATCH 33/57] put third refresh button back for now --- web/skins/classic/views/events.php | 2 +- web/skins/classic/views/js/events.js | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 49003301e..52cb5c3f0 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -52,7 +52,7 @@ getBodyTopHTML();
- + diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 0c5ca5ef1..3cb6a8d6b 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -204,13 +204,11 @@ function initPage() { }); - /* // Manage the REFRESH Button document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { evt.preventDefault(); window.location.reload(true); }); - */ // Manage the TIMELINE Button document.getElementById("tlineBtn").addEventListener("click", function onTlineClick(evt) { From 6c013f0e651aa3022320e43b6331a605998c110c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 08:03:10 -0500 Subject: [PATCH 34/57] Put back includes needed on FreeBSD. Fixes #3165 --- src/zm_comms.h | 1 + src/zm_config.cpp | 1 + src/zm_eventstream.cpp | 5 ++++- src/zm_logger.cpp | 1 + src/zm_monitor.cpp | 4 ++++ src/zm_monitorstream.cpp | 4 ++++ src/zm_mpeg.h | 1 + src/zm_remote_camera.cpp | 1 + src/zm_remote_camera_http.cpp | 1 + src/zm_thread.cpp | 1 + 10 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/zm_comms.h b/src/zm_comms.h index 22b9515d8..30c217ddc 100644 --- a/src/zm_comms.h +++ b/src/zm_comms.h @@ -22,6 +22,7 @@ #include "zm_exception.h" #include "zm_logger.h" +#include #include #include #include diff --git a/src/zm_config.cpp b/src/zm_config.cpp index 595a5b91a..f7cd609bf 100644 --- a/src/zm_config.cpp +++ b/src/zm_config.cpp @@ -22,6 +22,7 @@ #include "zm_db.h" #include "zm_logger.h" #include "zm_utils.h" +#include #include #include #include diff --git a/src/zm_eventstream.cpp b/src/zm_eventstream.cpp index 961c4f69b..da1263384 100644 --- a/src/zm_eventstream.cpp +++ b/src/zm_eventstream.cpp @@ -27,6 +27,9 @@ #include "zm_storage.h" #include #include +#ifdef __FreeBSD__ +#include +#endif const std::string EventStream::StreamMode_Strings[4] = { "None", @@ -348,7 +351,7 @@ void EventStream::processCommand(const CmdMsg *msg) { curr_frame_id = 1; } else { Debug(1, "mode is %s, current frame is %ld, frame count is %ld, last frame id is %ld", - StreamMode_Strings[(int)mode], curr_frame_id, event_data->frame_count ); + StreamMode_Strings[(int)mode].c_str(), curr_frame_id, event_data->frame_count ); } replay_rate = ZM_RATE_BASE; diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index d10840848..1b314f7b7 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -21,6 +21,7 @@ #include "zm_db.h" #include "zm_utils.h" +#include #include #include #include diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index c75d5329a..674d457d0 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -651,6 +651,7 @@ void Monitor::LoadCamera() { switch (type) { case LOCAL: { +#if ZM_HAS_V4L int extras = (deinterlacing >> 24) & 0xff; camera = ZM::make_unique(this, @@ -672,6 +673,9 @@ void Monitor::LoadCamera() { record_audio, extras ); +#else + Fatal("Not compiled with local v4l camera support"); +#endif break; } case REMOTE: { diff --git a/src/zm_monitorstream.cpp b/src/zm_monitorstream.cpp index 4bbc8d3a6..09cdb5f5c 100644 --- a/src/zm_monitorstream.cpp +++ b/src/zm_monitorstream.cpp @@ -24,7 +24,11 @@ #include "zm_time.h" #include #include +#include #include +#ifdef __FreeBSD__ +#include +#endif const int MAX_SLEEP_USEC = 1000000; // 1 sec diff --git a/src/zm_mpeg.h b/src/zm_mpeg.h index 6e75f8743..4999f1328 100644 --- a/src/zm_mpeg.h +++ b/src/zm_mpeg.h @@ -21,6 +21,7 @@ #define ZM_MPEG_H #include "zm_ffmpeg.h" +#include #if HAVE_LIBAVCODEC diff --git a/src/zm_remote_camera.cpp b/src/zm_remote_camera.cpp index ff26b580c..c1a252c3d 100644 --- a/src/zm_remote_camera.cpp +++ b/src/zm_remote_camera.cpp @@ -22,6 +22,7 @@ #include "zm_utils.h" #include #include +#include RemoteCamera::RemoteCamera( const Monitor *monitor, diff --git a/src/zm_remote_camera_http.cpp b/src/zm_remote_camera_http.cpp index 188bef05f..5304a77ac 100644 --- a/src/zm_remote_camera_http.cpp +++ b/src/zm_remote_camera_http.cpp @@ -26,6 +26,7 @@ #include "zm_utils.h" #include #include +#include #ifdef SOLARIS #include // FIONREAD and friends diff --git a/src/zm_thread.cpp b/src/zm_thread.cpp index f6c6cdb7f..63a8bdbb2 100644 --- a/src/zm_thread.cpp +++ b/src/zm_thread.cpp @@ -21,6 +21,7 @@ #include "zm_logger.h" #include "zm_utils.h" +#include #include #include #include From 5f207664d5769c68b0485aa91ea2704ee8edea62 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 08:15:36 -0500 Subject: [PATCH 35/57] Add override to processCommand declarations. --- src/zm_eventstream.h | 2 +- src/zm_monitorstream.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_eventstream.h b/src/zm_eventstream.h index 636ef3726..ef873c25d 100644 --- a/src/zm_eventstream.h +++ b/src/zm_eventstream.h @@ -90,7 +90,7 @@ class EventStream : public StreamBase { bool loadInitialEventData(int monitor_id, time_t event_time); bool checkEventLoaded(); - void processCommand(const CmdMsg *msg); + void processCommand(const CmdMsg *msg) override; bool sendFrame(int delta_us); public: diff --git a/src/zm_monitorstream.h b/src/zm_monitorstream.h index 241c8cf2b..0c1f92777 100644 --- a/src/zm_monitorstream.h +++ b/src/zm_monitorstream.h @@ -47,7 +47,7 @@ class MonitorStream : public StreamBase { bool checkSwapPath(const char *path, bool create_path); bool sendFrame(const char *filepath, struct timeval *timestamp); bool sendFrame(Image *image, struct timeval *timestamp); - void processCommand(const CmdMsg *msg); + void processCommand(const CmdMsg *msg) override; void SingleImage(int scale=100); void SingleImageRaw(int scale=100); #ifdef HAVE_ZLIB_H From 8a417bb8d296a6cf9925b08358480c4add800617 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 08:15:48 -0500 Subject: [PATCH 36/57] Add override to processCommand declarations. Remove unused fd var --- src/zm_fifo.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/zm_fifo.h b/src/zm_fifo.h index 42c313051..e99d56dd2 100644 --- a/src/zm_fifo.h +++ b/src/zm_fifo.h @@ -44,7 +44,6 @@ int zmFifoDbgInit(Monitor * monitor); class FifoStream : public StreamBase { private: char * stream_path; - int fd; int total_read; int bytes_read; unsigned int frame_count; @@ -59,12 +58,11 @@ class FifoStream : public StreamBase { StreamType stream_type; bool sendMJEGFrames(); bool sendRAWFrames(); - void processCommand(const CmdMsg *msg) {} + void processCommand(const CmdMsg *msg) override {} public: FifoStream() : stream_path(nullptr), - fd(0), total_read(0), bytes_read(0), frame_count(0), From 730cd815d325ea2a75d0afeac2876edc7a1e2aa8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 15:48:16 -0500 Subject: [PATCH 37/57] Add frame format to debug logging. Use fix_deprecated_fmt to fix when ctx->fmt is yuvj420p instead of yuv420p --- src/zm_packet.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index fc2f3bfa4..95ed6b8de 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -165,10 +165,11 @@ int ZMPacket::decode(AVCodecContext *ctx) { #if HAVE_LIBAVUTIL_HWCONTEXT_H #if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0) - if ( ctx->sw_pix_fmt != in_frame->format ) { - Debug(1, "Have different format %s != %s.", + if ( fix_deprecated_pix_fmt(ctx->sw_pix_fmt) != in_frame->format ) { + Debug(1, "Have different format ctx->pix_fmt %s ?= ctx->sw_pix_fmt %s in_frame->format %s.", av_get_pix_fmt_name(ctx->pix_fmt), - av_get_pix_fmt_name(ctx->sw_pix_fmt) + av_get_pix_fmt_name(ctx->sw_pix_fmt), + av_get_pix_fmt_name(static_cast(in_frame->format)) ); #if 0 if ( target_format == AV_PIX_FMT_NONE and ctx->hw_frames_ctx and (image->Colours() == 4) ) { From c8be0d58d5d158d93234c5e104428a557af9d495 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 22 Feb 2021 19:02:24 -0600 Subject: [PATCH 38/57] eslint - fix whitespace --- web/skins/classic/views/js/events.js | 1 - 1 file changed, 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 3cb6a8d6b..72dc27de5 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -203,7 +203,6 @@ function initPage() { window.history.back(); }); - // Manage the REFRESH Button document.getElementById("refreshBtn").addEventListener("click", function onRefreshClick(evt) { evt.preventDefault(); From 62da77db50dcc53c8bcc4305b0f9bb01f13f57f1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 17:12:16 -0500 Subject: [PATCH 39/57] Don't set a default crf. Many codecs don't support it. Failure to open encoder should only be a warning if we have specified it --- src/zm_videostore.cpp | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 3da2a0d67..0a3cc6002 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -205,14 +205,6 @@ bool VideoStore::open() { video_out_ctx->bit_rate = 2000000; video_out_ctx->gop_size = 12; video_out_ctx->max_b_frames = 1; - - ret = av_opt_set(video_out_ctx, "crf", "36", AV_OPT_SEARCH_CHILDREN); - if ( ret < 0 ) { - Error("Could not set 'crf' for output codec %s. %s", - codec_data[i].codec_name, - av_make_error_string(ret).c_str() - ); - } } else if ( video_out_ctx->codec_id == AV_CODEC_ID_MPEG2VIDEO ) { /* just for testing, we also add B frames */ video_out_ctx->max_b_frames = 2; @@ -237,10 +229,17 @@ bool VideoStore::open() { } if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { - Warning("Can't open video codec (%s) %s", - video_out_codec->name, - av_make_error_string(ret).c_str() - ); + if ( wanted_encoder != "" and wanted_encoder != "auto" ) { + Warning("Can't open video codec (%s) %s", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + } else { + Debug(1, "Can't open video codec (%s) %s", + video_out_codec->name, + av_make_error_string(ret).c_str() + ); + } video_out_codec = nullptr; } From 64c601fc7bda72030a6978bf5dd3f0778fc2e5ec Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 20:40:10 -0500 Subject: [PATCH 40/57] Must fix_deprecations on both values --- src/zm_packet.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_packet.cpp b/src/zm_packet.cpp index 95ed6b8de..133747ea2 100644 --- a/src/zm_packet.cpp +++ b/src/zm_packet.cpp @@ -165,7 +165,7 @@ int ZMPacket::decode(AVCodecContext *ctx) { #if HAVE_LIBAVUTIL_HWCONTEXT_H #if LIBAVCODEC_VERSION_CHECK(57, 89, 0, 89, 0) - if ( fix_deprecated_pix_fmt(ctx->sw_pix_fmt) != in_frame->format ) { + if ( fix_deprecated_pix_fmt(ctx->sw_pix_fmt) != fix_deprecated_pix_fmt(static_cast(in_frame->format)) ) { Debug(1, "Have different format ctx->pix_fmt %s ?= ctx->sw_pix_fmt %s in_frame->format %s.", av_get_pix_fmt_name(ctx->pix_fmt), av_get_pix_fmt_name(ctx->sw_pix_fmt), From 0ac3e6fd5bf4653895b28fb5fb692177d3bb4be6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Feb 2021 20:40:22 -0500 Subject: [PATCH 41/57] remove unneeded strlen --- src/zm_ffmpeg.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index a0131d75f..6ff053c34 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -64,11 +64,15 @@ void log_libav_callback(void *ptr, int level, const char *fmt, va_list vargs) { if ( log ) { char logString[8192]; - vsnprintf(logString, sizeof(logString)-1, fmt, vargs); - int length = strlen(logString); - // ffmpeg logs have a carriage return, so replace it with terminator - logString[length-1] = 0; - log->logPrint(false, __FILE__, __LINE__, log_level, logString); + int length = vsnprintf(logString, sizeof(logString)-1, fmt, vargs); + if ( length > 0 ) { + if ( static_cast(length) > sizeof(logString)-1 ) length = sizeof(logString)-1; + // ffmpeg logs have a carriage return, so replace it with terminator + logString[length-1] = 0; + log->logPrint(false, __FILE__, __LINE__, log_level, logString); + } else { + log->logPrint(false, __FILE__, __LINE__, AV_LOG_ERROR, "Can't encode log from av. fmt was %s", fmt); + } } } From 32258512246cd240eb9aea227114e51e32cc1829 Mon Sep 17 00:00:00 2001 From: Isaac Isaac Date: Tue, 23 Feb 2021 13:11:34 -0500 Subject: [PATCH 42/57] Move call to Initialise into Constructor making sure that it only gets called once. Move channel switching out of PostCapture into just after capturing image in order to free up more time for image to stabilise while we do other things like timestamping etc which happen in Capture. --- src/zm_local_camera.cpp | 167 +++++++++++++++++++++------------------- 1 file changed, 86 insertions(+), 81 deletions(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 67b3a8ac6..f5c884532 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -340,7 +340,7 @@ LocalCamera::LocalCamera( Debug(2, "V4L support enabled, using V4L%d api", v4l_version); } - if ( !last_camera || channel != last_camera->channel ) { + if ( (!last_camera) || (channel != last_camera->channel) ) { // We are the first, or only, input that uses this channel channel_prime = true; channel_index = channel_count++; @@ -382,19 +382,19 @@ LocalCamera::LocalCamera( } #endif - if ( capture ) { - if ( last_camera ) { - if ( (p_method == "v4l2" && v4l_version != 2) || (p_method == "v4l1" && v4l_version != 1) ) - Fatal( "Different Video For Linux version used for monitors sharing same device" ); + if (capture) { + if (last_camera) { + if ((p_method == "v4l2" && v4l_version != 2) || (p_method == "v4l1" && v4l_version != 1)) + Fatal("Different Video For Linux version used for monitors sharing same device"); - if ( standard != last_camera->standard ) - Warning( "Different video standards defined for monitors sharing same device, results may be unpredictable or completely wrong" ); + if (standard != last_camera->standard) + Warning("Different video standards defined for monitors sharing same device, results may be unpredictable or completely wrong"); - if ( palette != last_camera->palette ) - Warning( "Different video palettes defined for monitors sharing same device, results may be unpredictable or completely wrong" ); + if (palette != last_camera->palette) + Warning("Different video palettes defined for monitors sharing same device, results may be unpredictable or completely wrong"); - if ( width != last_camera->width || height != last_camera->height ) - Warning( "Different capture sizes defined for monitors sharing same device, results may be unpredictable or completely wrong" ); + if (width != last_camera->width or height != last_camera->height) + Warning("Different capture sizes defined for monitors sharing same device, results may be unpredictable or completely wrong"); } #if HAVE_LIBSWSCALE @@ -676,6 +676,8 @@ LocalCamera::LocalCamera( imgConversionContext = nullptr; } // end if capture and conversion_tye == swscale #endif + if ( device_prime ) + Initialise(); } // end LocalCamera::LocalCamera LocalCamera::~LocalCamera() { @@ -1971,7 +1973,10 @@ int LocalCamera::Contrast( int p_contrast ) { } int LocalCamera::PrimeCapture() { - Initialise(); + + get_VideoStream(); + if ( !device_prime ) + return 1; Debug(2, "Priming capture"); #if ZM_HAS_V4L2 @@ -1989,8 +1994,10 @@ int LocalCamera::PrimeCapture() { vid_buf.memory = v4l2_data.reqbufs.memory; vid_buf.index = frame; - if ( vidioctl(vid_fd, VIDIOC_QBUF, &vid_buf) < 0 ) - Fatal("Failed to queue buffer %d: %s", frame, strerror(errno)); + if (vidioctl(vid_fd, VIDIOC_QBUF, &vid_buf) < 0) { + Error("Failed to queue buffer %d: %s", frame, strerror(errno)); + return 0; + } } v4l2_data.bufptr = nullptr; @@ -1998,9 +2005,11 @@ int LocalCamera::PrimeCapture() { //enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; //enum v4l2_buf_type type = v4l2_data.fmt.type; enum v4l2_buf_type type = (v4l2_buf_type)v4l2_data.fmt.type; - if ( vidioctl(vid_fd, VIDIOC_STREAMON, &type) < 0 ) - Fatal("Failed to start capture stream: %s", strerror(errno)); - } + if (vidioctl(vid_fd, VIDIOC_STREAMON, &type) < 0) { + Error("Failed to start capture stream: %s", strerror(errno)); + return -1; + } + } // end if v4l_version == 2 #endif // ZM_HAS_V4L2 #if ZM_HAS_V4L1 if ( v4l_version == 1 ) { @@ -2013,7 +2022,6 @@ int LocalCamera::PrimeCapture() { } } #endif // ZM_HAS_V4L1 - mVideoStreamId = 0; return 1; } // end LocalCamera::PrimeCapture @@ -2046,7 +2054,6 @@ int LocalCamera::Capture(ZMPacket &zm_packet) { memset(&vid_buf, 0, sizeof(vid_buf)); vid_buf.type = v4l2_data.fmt.type; - //vid_buf.memory = V4L2_MEMORY_MMAP; vid_buf.memory = v4l2_data.reqbufs.memory; Debug(3, "Capturing %d frames", captures_per_frame); @@ -2114,6 +2121,65 @@ int LocalCamera::Capture(ZMPacket &zm_packet) { buffer = v4l1_data.bufptr+v4l1_data.frames.offsets[capture_frame]; } #endif // ZM_HAS_V4L1 +#if ZM_HAS_V4L2 + if ( v4l_version == 2 ) { + if ( channel_count > 1 ) { + int next_channel = (channel_index+1)%channel_count; + Debug(3, "Switching video source to %d", channels[next_channel]); + if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channels[next_channel]) < 0 ) { + Error("Failed to set camera source %d: %s", channels[next_channel], strerror(errno)); + return -1; + } + + v4l2_std_id stdId = standards[next_channel]; + if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) { + Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno)); + } + } + if ( v4l2_data.bufptr ) { + Debug(3, "Requeueing buffer %d", v4l2_data.bufptr->index); + if ( vidioctl(vid_fd, VIDIOC_QBUF, v4l2_data.bufptr) < 0 ) { + Error("Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno)); + return -1; + } + } else { + Error("Unable to requeue buffer due to not v4l2_data") + } + } +#if ZM_HAS_V4L1 + else +#endif // ZM_HAS_V4L1 +#endif // ZM_HAS_V4L2 +#if ZM_HAS_V4L1 + if ( v4l_version == 1 ) { + if ( channel_count > 1 ) { + Debug(3, "Switching video source"); + int next_channel = (channel_index+1)%channel_count; + struct video_channel vid_src; + memset(&vid_src, 0, sizeof(vid_src)); + vid_src.channel = channel; + if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) { + Error("Failed to get camera source %d: %s", channel, strerror(errno)); + return -1; + } + + vid_src.channel = channels[next_channel]; + vid_src.norm = standards[next_channel]; + vid_src.flags = 0; + vid_src.type = VIDEO_TYPE_CAMERA; + if ( ioctl(vid_fd, VIDIOCSCHAN, &vid_src) < 0 ) { + Error("Failed to set camera source %d: %s", channel, strerror(errno)); + return -1; + } + } + Debug(3, "Requeueing frame %d", v4l1_data.active_frame); + if ( ioctl(vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame]) < 0 ) { + Error("Capture failure for frame %d: %s", v4l1_data.active_frame, strerror(errno)); + return -1; + } + v4l1_data.active_frame = (v4l1_data.active_frame+1)%v4l1_data.frames.frames; + } +#endif // ZM_HAS_V4L1 } /* prime capture */ @@ -2179,69 +2245,8 @@ int LocalCamera::Capture(ZMPacket &zm_packet) { } // end int LocalCamera::Capture() int LocalCamera::PostCapture() { + return 1; Debug(4, "Post-capturing"); - // Requeue the buffer unless we need to switch or are a duplicate camera on a channel - if ( channel_count > 1 || channel_prime ) { -#if ZM_HAS_V4L2 - if ( v4l_version == 2 ) { - if ( channel_count > 1 ) { - int next_channel = (channel_index+1)%channel_count; - Debug(3, "Switching video source to %d", channels[next_channel]); - if ( vidioctl(vid_fd, VIDIOC_S_INPUT, &channels[next_channel]) < 0 ) { - Error("Failed to set camera source %d: %s", channels[next_channel], strerror(errno)); - return -1; - } - - v4l2_std_id stdId = standards[next_channel]; - if ( vidioctl(vid_fd, VIDIOC_S_STD, &stdId) < 0 ) { - Error("Failed to set video format %d: %s", standards[next_channel], strerror(errno)); - } - } - if ( v4l2_data.bufptr ) { - Debug(3, "Requeueing buffer %d", v4l2_data.bufptr->index); - if ( vidioctl(vid_fd, VIDIOC_QBUF, v4l2_data.bufptr) < 0 ) { - Error("Unable to requeue buffer %d: %s", v4l2_data.bufptr->index, strerror(errno)); - return -1; - } - } else { - Error("Unable to requeue buffer due to not v4l2_data") - } - } -#if ZM_HAS_V4L1 - else -#endif // ZM_HAS_V4L1 -#endif // ZM_HAS_V4L2 -#if ZM_HAS_V4L1 - if ( v4l_version == 1 ) { - if ( channel_count > 1 ) { - Debug(3, "Switching video source"); - int next_channel = (channel_index+1)%channel_count; - struct video_channel vid_src; - memset(&vid_src, 0, sizeof(vid_src)); - vid_src.channel = channel; - if ( ioctl(vid_fd, VIDIOCGCHAN, &vid_src) < 0 ) { - Error("Failed to get camera source %d: %s", channel, strerror(errno)); - return -1; - } - - vid_src.channel = channels[next_channel]; - vid_src.norm = standards[next_channel]; - vid_src.flags = 0; - vid_src.type = VIDEO_TYPE_CAMERA; - if ( ioctl(vid_fd, VIDIOCSCHAN, &vid_src) < 0 ) { - Error("Failed to set camera source %d: %s", channel, strerror(errno)); - return -1; - } - } - Debug(3, "Requeueing frame %d", v4l1_data.active_frame); - if ( ioctl(vid_fd, VIDIOCMCAPTURE, &v4l1_data.buffers[v4l1_data.active_frame]) < 0 ) { - Error("Capture failure for frame %d: %s", v4l1_data.active_frame, strerror(errno)); - return -1; - } - v4l1_data.active_frame = (v4l1_data.active_frame+1)%v4l1_data.frames.frames; - } -#endif // ZM_HAS_V4L1 - } return 0; } From f2143fd0928294c443921fb6aa5b358bc88e853a Mon Sep 17 00:00:00 2001 From: Isaac Isaac Date: Tue, 23 Feb 2021 13:12:09 -0500 Subject: [PATCH 43/57] Improve debug logs --- src/zm_packetqueue.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_packetqueue.cpp b/src/zm_packetqueue.cpp index 1b6270c05..c89347692 100644 --- a/src/zm_packetqueue.cpp +++ b/src/zm_packetqueue.cpp @@ -155,14 +155,14 @@ void PacketQueue::clearPackets(ZMPacket *add_packet) { if ( zm_packet->packet.stream_index == video_stream_id ) { if ( zm_packet->keyframe ) { - Debug(1, "Have a video keyframe so breaking out"); + Debug(1, "Have a video keyframe so setting next front to it"); next_front = it; } } it++; } // end while } // end if first packet not locked - Debug(1, "Resulting pointing at latest packet? %d, have next front? %d", + Debug(1, "Resulting pointing at latest packet? %d, next front points to begin? %d", ( *it == add_packet ), ( next_front == pktQueue.begin() ) ); @@ -426,7 +426,7 @@ unsigned int PacketQueue::size() { int PacketQueue::packet_count(int stream_id) { if ( stream_id < 0 or stream_id > max_stream_id ) { - Error("Invalid stream_id %d", stream_id); + Error("Invalid stream_id %d max is %d", stream_id, max_stream_id); return -1; } return packet_counts[stream_id]; From 3eb67fa2fc840e96f42a31681f2d99313e4143ab Mon Sep 17 00:00:00 2001 From: Isaac Isaac Date: Tue, 23 Feb 2021 13:12:40 -0500 Subject: [PATCH 44/57] We have to Prime every monitor not just the first one. --- src/zmc.cpp | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 059c727d6..504ac80ef 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -251,25 +251,23 @@ int main(int argc, char *argv[]) { if (mysql_query(&dbconn, sql)) { Error("Can't run query: %s", mysql_error(&dbconn)); } - } // end foreach monitor - // Outer primary loop, handles connection to camera - if (monitors[0]->PrimeCapture() <= 0) { - if (prime_capture_log_count % 60) { - Error("Failed to prime capture of initial monitor"); - } else { - Debug(1, "Failed to prime capture of initial monitor"); - } - prime_capture_log_count ++; - monitors[0]->disconnect(); - if (!zm_terminate) { - Debug(1, "Sleeping"); + while (monitor->PrimeCapture() <= 0) { + if (prime_capture_log_count % 60) { + Error("Failed to prime capture of initial monitor"); + } else { + Debug(1, "Failed to prime capture of initial monitor"); + } + prime_capture_log_count ++; + monitor->disconnect(); + if (zm_terminate) break; sleep(5); + if (!monitor->connect()) { + Warning("Couldn't connect to monitor %d", monitor->Id()); + } } - continue; - } + if (zm_terminate) break; - for (std::shared_ptr &monitor : monitors) { snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='Connected'", monitor->Id()); From 3ce0564e9c1487d0a608857d5787986c96725c3c Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 10:09:21 -0500 Subject: [PATCH 45/57] Code style spacing and cleanups. --- src/zm_libvnc_camera.cpp | 54 +++++++++++++++++++++------------------- src/zm_libvnc_camera.h | 3 +-- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index cdb08d06c..7ea9d9c58 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -18,11 +18,11 @@ static int (*WaitForMessage_f)(rfbClient*, unsigned int) = nullptr; static rfbBool (*HandleRFBServerMessage_f)(rfbClient*) = nullptr; void bind_libvnc_symbols() { - if ( libvnc_lib != nullptr ) // Safe-check + if (libvnc_lib != nullptr) // Safe-check return; libvnc_lib = dlopen("libvncclient.so", RTLD_LAZY | RTLD_GLOBAL); - if ( !libvnc_lib ) { + if (!libvnc_lib) { Error("Error loading libvncclient: %s", dlerror()); return; } @@ -43,14 +43,14 @@ static void GotFrameBufferUpdateCallback(rfbClient *rfb, int x, int y, int w, in x,y,w,h, rfb->width, rfb->height, rfb->frameBuffer); } -static char* GetPasswordCallback(rfbClient* cl){ +static char* GetPasswordCallback(rfbClient* cl) { Debug(1, "Getcredentials: %s", (*rfbClientGetClientData_f)(cl, &TAG_1)); return strdup((const char *)(*rfbClientGetClientData_f)(cl, &TAG_1)); } static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ rfbCredential *c = (rfbCredential *)malloc(sizeof(rfbCredential)); - if ( credentialType != rfbCredentialTypeUser ) { + if (credentialType != rfbCredentialTypeUser) { free(c); return nullptr; } @@ -62,14 +62,16 @@ static rfbCredential* GetCredentialsCallback(rfbClient* cl, int credentialType){ } static rfbBool resize(rfbClient* client) { - if ( client->frameBuffer ) { + if (client->frameBuffer) { Debug(1, "Freeing old frame buffer"); av_free(client->frameBuffer); } - int mBufferSize = SWScale::GetBufferSize(AV_PIX_FMT_RGBA, client->width, client->height); - client->frameBuffer = (uint8_t *)av_malloc(mBufferSize); - Debug(1, "Allocing new frame buffer %dx%d = %d", client->width, client->height, mBufferSize); + int bufferSize = 4*client->width*client->height; + // libVNC doesn't do alignment or padding in each line + //SWScale::GetBufferSize(AV_PIX_FMT_RGBA, client->width, client->height); + client->frameBuffer = (uint8_t *)av_malloc(bufferSize); + Debug(1, "Allocing new frame buffer %dx%d = %d", client->width, client->height, bufferSize); return TRUE; } @@ -109,22 +111,20 @@ VncCamera::VncCamera( mUser(user), mPass(pass) { - Debug(2, "Host:%s Port: %s User: %s Pass:%s", mHost.c_str(), mPort.c_str(), mUser.c_str(), mPass.c_str()); - - if ( colours == ZM_COLOUR_RGB32 ) { + if (colours == ZM_COLOUR_RGB32) { subpixelorder = ZM_SUBPIX_ORDER_RGBA; mImgPixFmt = AV_PIX_FMT_RGBA; - } else if ( colours == ZM_COLOUR_RGB24 ) { + } else if (colours == ZM_COLOUR_RGB24) { subpixelorder = ZM_SUBPIX_ORDER_RGB; mImgPixFmt = AV_PIX_FMT_RGB24; - } else if ( colours == ZM_COLOUR_GRAY8 ) { + } else if (colours == ZM_COLOUR_GRAY8) { subpixelorder = ZM_SUBPIX_ORDER_NONE; mImgPixFmt = AV_PIX_FMT_GRAY8; } else { Panic("Unexpected colours: %d", colours); } - if ( capture ) { + if (capture) { Debug(3, "Initializing Client"); bind_libvnc_symbols(); scale.init(); @@ -132,8 +132,8 @@ VncCamera::VncCamera( } VncCamera::~VncCamera() { - if ( capture ) { - if ( mRfb->frameBuffer ) + if (capture) { + if (mRfb->frameBuffer) free(mRfb->frameBuffer); (*rfbClientCleanup_f)(mRfb); } @@ -151,8 +151,9 @@ int VncCamera::PrimeCapture() { mVncData.width = 0; mVncData.height = 0; + // TODO, support 8bit or 24bit mRfb = (*rfbGetClient_f)(8 /* bits per sample */, 3 /* samples per pixel */, 4 /* bytes Per Pixel */); - mRfb->MallocFrameBuffer=resize; + mRfb->MallocFrameBuffer = resize; (*rfbClientSetClientData_f)(mRfb, &TAG_0, &mVncData); (*rfbClientSetClientData_f)(mRfb, &TAG_1, (void *)mPass.c_str()); @@ -166,13 +167,13 @@ int VncCamera::PrimeCapture() { mRfb->serverHost = strdup(mHost.c_str()); mRfb->serverPort = atoi(mPort.c_str()); } - if ( ! (*rfbInitClient_f)(mRfb, 0, nullptr) ) { + if (!(*rfbInitClient_f)(mRfb, 0, nullptr)) { /* IF rfbInitClient fails, it calls rdbClientCleanup which will free mRfb */ Warning("Failed to Prime capture from %s", mHost.c_str()); mRfb = nullptr; return -1; } - if ( ((unsigned int)mRfb->width != width) or ((unsigned int)mRfb->height != height) ) { + if (((unsigned int)mRfb->width != width) or ((unsigned int)mRfb->height != height)) { Warning("Specified dimensions do not match screen size monitor: (%dx%d) != vnc: (%dx%d)", width, height, mRfb->width, mRfb->height); } @@ -183,9 +184,9 @@ int VncCamera::PrimeCapture() { int VncCamera::PreCapture() { int rc = (*WaitForMessage_f)(mRfb, 500); - if ( rc < 0 ) { + if (rc < 0) { return -1; - } else if ( !rc ) { + } else if (!rc) { return rc; } rfbBool res = (*HandleRFBServerMessage_f)(mRfb); @@ -194,11 +195,11 @@ int VncCamera::PreCapture() { } int VncCamera::Capture(ZMPacket &zm_packet) { - if ( !mVncData.buffer ) { + if (!mVncData.buffer) { Debug(1, "No buffer"); return 0; } - if ( !zm_packet.image ) { + if (!zm_packet.image) { Debug(1, "Allocating image %dx%d %dcolours = %d", width, height, colours, colours*pixels); zm_packet.image = new Image(width, height, colours, subpixelorder); } @@ -208,10 +209,10 @@ int VncCamera::Capture(ZMPacket &zm_packet) { uint8_t *directbuffer = zm_packet.image->WriteBuffer(width, height, colours, subpixelorder); Debug(1, "scale src %p, %d, dest %p %d %d %dx%d %dx%d", mVncData.buffer, - mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, + mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4, directbuffer, width * height * colours, - mImgPixFmt, + mImgPixFmt, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight, width, @@ -219,7 +220,8 @@ int VncCamera::Capture(ZMPacket &zm_packet) { int rc = scale.Convert( mVncData.buffer, - mRfb->si.framebufferHeight * mRfb->si.framebufferWidth * 4, + mRfb->si.framebufferWidth * mRfb->si.framebufferHeight * 4, + //SWScale::GetBufferSize(AV_PIX_FMT_RGBA, mRfb->si.framebufferWidth, mRfb->si.framebufferHeight), directbuffer, width * height * colours, AV_PIX_FMT_RGBA, diff --git a/src/zm_libvnc_camera.h b/src/zm_libvnc_camera.h index 089603dad..c1f847991 100644 --- a/src/zm_libvnc_camera.h +++ b/src/zm_libvnc_camera.h @@ -26,7 +26,6 @@ class VncCamera : public Camera { protected: rfbClient *mRfb; VncPrivateData mVncData; - int mBufferSize; SWScale scale; AVPixelFormat mImgPixFmt; std::string mHost; @@ -48,7 +47,7 @@ public: int p_hue, int p_colour, bool p_capture, - bool p_record_audio ); + bool p_record_audio); ~VncCamera(); From c8abeddc9cc473f9bf5b64d68b04659e13eb3f67 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 10:10:34 -0500 Subject: [PATCH 46/57] swscale is a problem. When to use alignment/padding? Defaulting to alignment=1 makes libvnc work, but is less performant. Some scale operations require padding. --- src/zm_swscale.cpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/zm_swscale.cpp b/src/zm_swscale.cpp index 899801db6..2390155c2 100644 --- a/src/zm_swscale.cpp +++ b/src/zm_swscale.cpp @@ -159,21 +159,24 @@ int SWScale::Convert( } #endif + int alignment = 1; /* Check the buffer sizes */ - size_t insize = GetBufferSize(in_pf, width, height); - if ( insize > in_buffer_size ) { - Debug(1, "The input buffer size does not match the expected size for the input format. Required: %d for %dx%d %d Available: %d", insize, width, height, in_pf, in_buffer_size); + size_t needed_insize = GetBufferSize(in_pf, width, height); + if ( needed_insize > in_buffer_size ) { + Debug(1, "The input buffer size does not match the expected size for the input format. Required: %d for %dx%d %d Available: %d", + needed_insize, width, height, in_pf, in_buffer_size); } - size_t outsize = GetBufferSize(out_pf, new_width, new_height); - if ( outsize > out_buffer_size ) { - Error("The output buffer is undersized for the output format. Required: %d Available: %d", outsize, out_buffer_size); + size_t needed_outsize = GetBufferSize(out_pf, new_width, new_height); + if ( needed_outsize > out_buffer_size ) { + Error("The output buffer is undersized for the output format. Required: %d Available: %d", needed_outsize, out_buffer_size); return -5; } /* Get the context */ - swscale_ctx = sws_getCachedContext( - swscale_ctx, width, height, in_pf, new_width, new_height, - out_pf, SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); + swscale_ctx = sws_getCachedContext(swscale_ctx, + width, height, in_pf, + new_width, new_height, out_pf, + SWS_FAST_BILINEAR, nullptr, nullptr, nullptr); if ( swscale_ctx == nullptr ) { Error("Failed getting swscale context"); return -6; @@ -182,7 +185,7 @@ int SWScale::Convert( /* Fill in the buffers */ #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) if (av_image_fill_arrays(input_avframe->data, input_avframe->linesize, - (uint8_t*) in_buffer, in_pf, width, height, 32) <= 0) { + (uint8_t*) in_buffer, in_pf, width, height, alignment) <= 0) { #else if (avpicture_fill((AVPicture*) input_avframe, (uint8_t*) in_buffer, in_pf, width, height) <= 0) { @@ -192,7 +195,7 @@ int SWScale::Convert( } #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) if (av_image_fill_arrays(output_avframe->data, output_avframe->linesize, - out_buffer, out_pf, new_width, new_height, 32) <= 0) { + out_buffer, out_pf, new_width, new_height, alignment) <= 0) { #else if (avpicture_fill((AVPicture*) output_avframe, out_buffer, out_pf, new_width, new_height) <= 0) { @@ -268,7 +271,7 @@ int SWScale::ConvertDefaults(const uint8_t* in_buffer, const size_t in_buffer_si size_t SWScale::GetBufferSize(enum _AVPIXELFORMAT pf, unsigned int width, unsigned int height) { #if LIBAVUTIL_VERSION_CHECK(54, 6, 0, 6, 0) - return av_image_get_buffer_size(pf, width, height, 32); + return av_image_get_buffer_size(pf, width, height, 1); #else return outsize = avpicture_get_size(pf, width,height); #endif From 381b7e1b2547993cf9938a72e6068e8040015eb7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 10:29:26 -0500 Subject: [PATCH 47/57] Don't disconnect/reconnect while PrimeCapture is failing. Don't sleep if there is failure in capturing and zm_terminate is set. --- src/zmc.cpp | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/zmc.cpp b/src/zmc.cpp index 504ac80ef..adaf7116f 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -214,7 +214,6 @@ int main(int argc, char *argv[]) { exit(-1); } else { Debug(2, "%d monitors loaded", monitors.size()); - } Info("Starting Capture version %s", ZM_VERSION); @@ -230,10 +229,9 @@ int main(int argc, char *argv[]) { sigaddset(&block_set, SIGUSR2); int result = 0; - int prime_capture_log_count = 0; - while ( !zm_terminate ) { + while (!zm_terminate) { result = 0; static char sql[ZM_SQL_SML_BUFSIZ]; for (const std::shared_ptr &monitor : monitors) { @@ -246,11 +244,10 @@ int main(int argc, char *argv[]) { monitor->setStartupTime(now); snprintf(sql, sizeof(sql), - "INSERT INTO Monitor_Status (MonitorId,Status,CaptureFPS,AnalysisFPS) VALUES (%d, 'Running',0,0) ON DUPLICATE KEY UPDATE Status='Running',CaptureFPS=0,AnalysisFPS=0", - monitor->Id()); - if (mysql_query(&dbconn, sql)) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } + "INSERT INTO Monitor_Status (MonitorId,Status,CaptureFPS,AnalysisFPS)" + " VALUES (%d, 'Running',0,0) ON DUPLICATE KEY UPDATE Status='Running',CaptureFPS=0,AnalysisFPS=0", + monitor->Id()); + zmDbDo(sql); while (monitor->PrimeCapture() <= 0) { if (prime_capture_log_count % 60) { @@ -259,22 +256,16 @@ int main(int argc, char *argv[]) { Debug(1, "Failed to prime capture of initial monitor"); } prime_capture_log_count ++; - monitor->disconnect(); if (zm_terminate) break; - sleep(5); - if (!monitor->connect()) { - Warning("Couldn't connect to monitor %d", monitor->Id()); - } + sleep(1); } if (zm_terminate) break; snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='Connected'", monitor->Id()); - if ( mysql_query(&dbconn, sql) ) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } - } + zmDbDo(sql); + } // end foreach monitor #if HAVE_RTSP_SERVER RTSPServerThread ** rtsp_server_threads = nullptr; @@ -300,12 +291,12 @@ int main(int argc, char *argv[]) { capture_delays[i], alarm_capture_delays[i]); Monitor::Function function = monitors[0]->GetFunction(); - if ( function != Monitor::MONITOR ) { + if (function != Monitor::MONITOR) { Debug(1, "Starting an analysis thread for monitor (%d)", monitors[i]->Id()); analysis_threads.emplace_back(ZM::make_unique(monitors[i])); } #if HAVE_RTSP_SERVER - if ( rtsp_server_threads ) { + if (rtsp_server_threads) { rtsp_server_threads[i] = new RTSPServerThread(monitors[i]); rtsp_server_threads[i]->addStream(monitors[i]->GetVideoStream(), monitors[i]->GetAudioStream()); rtsp_server_threads[i]->start(); @@ -363,17 +354,12 @@ int main(int argc, char *argv[]) { } } // end if has a last_capture time last_capture_times[i] = now; - } // end foreach n_monitors - if (result < 0) { + if (result < 0 or zm_reload) { // Failure, try reconnecting break; } - - if ( zm_reload ) { - break; - } } // end while ! zm_terminate and connected for (std::unique_ptr &analysis_thread: analysis_threads) @@ -410,7 +396,7 @@ int main(int argc, char *argv[]) { delete [] capture_delays; delete [] last_capture_times; - if (result < 0) { + if (result < 0 and !zm_terminate) { // Failure, try reconnecting Debug(1, "Sleeping for 5"); sleep(5); From 099ca9251cd5fbe13316c2cfaf6896de81dccac0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 10:33:29 -0500 Subject: [PATCH 48/57] Only init camera if capturing --- src/zm_local_camera.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index f5c884532..038f7b42a 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -676,7 +676,7 @@ LocalCamera::LocalCamera( imgConversionContext = nullptr; } // end if capture and conversion_tye == swscale #endif - if ( device_prime ) + if ( capture and device_prime ) Initialise(); } // end LocalCamera::LocalCamera From 58e3d96f8c28d039d757ffefb99bf16359dde2f6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 12:23:02 -0500 Subject: [PATCH 49/57] Instead of using basename and doing a strdup etc, just use strrchr because the filepath is going to one of the sources files in zm. --- src/zm_logger.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 1b314f7b7..744d8d005 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -439,8 +439,8 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con va_list argPtr; struct timeval timeVal; - char *filecopy = strdup(filepath); - const char * const file = basename(filecopy); + const char *base = strrchr(filepath, '/'); + const char *file = base ? base+1 : filepath; const char *classString = smCodes[level].c_str(); if ( level < PANIC || level > DEBUG9 ) @@ -567,7 +567,6 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con syslog(smSyslogPriorities[level], "%s [%s] [%s]", classString, mId.c_str(), syslogStart); } - free(filecopy); log_mutex.unlock(); if ( level <= FATAL ) { logTerm(); From 9959464ef7f5bffcd4c96e3a2ce9adb67f9f53c8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 12:37:09 -0500 Subject: [PATCH 50/57] Fix ]\n being included in the db Logs entry. Also removes a strlen so performance should improve --- src/zm_logger.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 744d8d005..75a188abb 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -536,8 +536,9 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con if ( level <= mDatabaseLevel ) { if (db_mutex.try_lock_for(1)) { - char escapedString[(strlen(syslogStart)*2)+1]; - mysql_real_escape_string(&dbconn, escapedString, syslogStart, strlen(syslogStart)); + int syslogSize = syslogEnd-syslogStart; + char escapedString[(syslogSize*2)+1]; + mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize); char sql[ZM_SQL_MED_BUFSIZ]; snprintf(sql, sizeof(sql), From 0d2febc958b67cb49337ee82d7e9895786e53444 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 12:38:12 -0500 Subject: [PATCH 51/57] Make monitor column open the event instead of monitor edit --- web/skins/classic/views/js/events.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/js/events.js b/web/skins/classic/views/js/events.js index 72dc27de5..770903eda 100644 --- a/web/skins/classic/views/js/events.js +++ b/web/skins/classic/views/js/events.js @@ -61,7 +61,7 @@ function processRows(rows) { row.Id = '' + eid + ''; row.Name = '' + row.Name + '' + '
' + archived + emailed + '
'; - if ( canEdit.Monitors ) row.Monitor = '' + row.Monitor + ''; + if ( canEdit.Monitors ) row.Monitor = '' + row.Monitor + ''; if ( canEdit.Events ) row.Cause = '' + row.Cause + ''; if ( row.Notes.indexOf('detected:') >= 0 ) { row.Cause = row.Cause + '
' + row.Notes + '
'; From 778a4f1d8428d0079bce8393788135eca918b695 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 13:48:36 -0500 Subject: [PATCH 52/57] We cannot wait for the db lock. Do not wait. --- src/zm_logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 75a188abb..f5b788512 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -535,7 +535,7 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con } // end if level <= mFileLevel if ( level <= mDatabaseLevel ) { - if (db_mutex.try_lock_for(1)) { + if (db_mutex.try_lock) { int syslogSize = syslogEnd-syslogStart; char escapedString[(syslogSize*2)+1]; mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize); From 6f89eba1549ef3b79399cb16ead7dca05b47d918 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 13:48:59 -0500 Subject: [PATCH 53/57] add missing () --- src/zm_logger.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index f5b788512..58d763bae 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -535,7 +535,7 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con } // end if level <= mFileLevel if ( level <= mDatabaseLevel ) { - if (db_mutex.try_lock) { + if (db_mutex.try_lock()) { int syslogSize = syslogEnd-syslogStart; char escapedString[(syslogSize*2)+1]; mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize); From d106c2fcc385be186258fabcfd71f4bba3b33279 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 15:03:11 -0500 Subject: [PATCH 54/57] Add 4MP and 6MP resoolutions --- web/skins/classic/views/monitor.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index e760b097a..62801c6de 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -871,6 +871,8 @@ include('_monitor_source_nvsocket.php'); '2048x1536'=>'2048x1536 3MP', '2560x1440'=>'2560x1440 1440p QHD WQHD', '2592x1944'=>'2592x1944 5MP', + '2688x1520'=>'2688x1520 4MP', + '3072x2048'=>'3072x2048 6MP', '3840x2160'=>'3840x2160 4K UHD', ); $selected = ''; From fdf515ca109b03b45f77d26f81f9dd2bd3310683 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 24 Feb 2021 19:59:55 -0500 Subject: [PATCH 55/57] rough in a db queue thread. Use it in zm_logger so that we don't have to aquire the db lock --- src/zm_db.cpp | 34 ++++++++++++++++++++++++++++++++++ src/zm_db.h | 25 +++++++++++++++++++++++-- src/zm_logger.cpp | 36 +++++++++++------------------------- 3 files changed, 68 insertions(+), 27 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 02265e680..073e41697 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -24,6 +24,7 @@ MYSQL dbconn; RecursiveMutex db_mutex; +zmDbQueue dbQueue; bool zmDbConnected = false; @@ -214,3 +215,36 @@ zmDbRow::~zmDbRow() { } row = nullptr; } + +zmDbQueue::zmDbQueue() : + mThread(&zmDbQueue::process, this), + mTerminate(false) +{ } + +zmDbQueue::~zmDbQueue() { + mTerminate = true; + mCondition.notify_all(); + mThread.join(); +} +void zmDbQueue::process() { + std::unique_lock lock(mMutex); + + while (!mTerminate and !zm_terminate) { + if (mQueue.empty()) { + mCondition.wait(lock); + } + if (!mQueue.empty()) { + std::string sql = mQueue.front(); + mQueue.pop(); + lock.unlock(); + zmDbDo(sql.c_str()); + lock.lock(); + } + } +} // end void zmDbQueue::process() + +void zmDbQueue::push(std::string sql) { + std::unique_lock lock(mMutex); + mQueue.push(sql); + mCondition.notify_all(); +} diff --git a/src/zm_db.h b/src/zm_db.h index 22e684c67..de4154ab2 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -23,6 +23,26 @@ #include "zm_thread.h" #include #include +#include +#include +#include +#include +#include + +class zmDbQueue { + private: + std::queue mQueue; + std::thread mThread; + std::mutex mMutex; + std::condition_variable mCondition; + bool mTerminate; + public: + zmDbQueue(); + ~zmDbQueue(); + void push(const char *sql) { return push(std::string(sql)); }; + void push(std::string); + void process(); +}; class zmDbRow { private: @@ -43,6 +63,7 @@ class zmDbRow { extern MYSQL dbconn; extern RecursiveMutex db_mutex; +extern zmDbQueue dbQueue; extern bool zmDbConnected; @@ -51,7 +72,7 @@ void zmDbClose(); int zmDbDo(const char *query); int zmDbDoInsert(const char *query); -MYSQL_RES * zmDbFetch( const char *query ); -zmDbRow *zmDbFetchOne( const char *query ); +MYSQL_RES * zmDbFetch(const char *query); +zmDbRow *zmDbFetchOne(const char *query); #endif // ZM_DB_H diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index 58d763bae..e264c3c3a 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -535,32 +535,18 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con } // end if level <= mFileLevel if ( level <= mDatabaseLevel ) { - if (db_mutex.try_lock()) { - int syslogSize = syslogEnd-syslogStart; - char escapedString[(syslogSize*2)+1]; - mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize); + int syslogSize = syslogEnd-syslogStart; + char escapedString[(syslogSize*2)+1]; + mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize); - char sql[ZM_SQL_MED_BUFSIZ]; - snprintf(sql, sizeof(sql), - "INSERT INTO `Logs` " - "( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )" - " VALUES " - "( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", - timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line - ); - if ( mysql_query(&dbconn, sql) ) { - Level tempDatabaseLevel = mDatabaseLevel; - databaseLevel(NOLOG); - Error("Can't insert log entry: sql(%s) error(%s)", sql, mysql_error(&dbconn)); - databaseLevel(tempDatabaseLevel); - } - db_mutex.unlock(); - } else { - Level tempDatabaseLevel = mDatabaseLevel; - databaseLevel(NOLOG); - Error("Can't insert log entry since the DB lock could not be obtained. Message: %s", syslogStart); - databaseLevel(tempDatabaseLevel); - } + std::string sql_string = stringtf( + "INSERT INTO `Logs` " + "( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )" + " VALUES " + "( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", + timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line + ); + dbQueue.push(sql_string); } // end if level <= mDatabaseLevel if ( level <= mSyslogLevel ) { From 8aeb4ab758b0f10d8cdc74555476397de7fe87b1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 25 Feb 2021 12:26:26 -0500 Subject: [PATCH 56/57] Switch db_mutex to a std::mutex. Use modern locking with it. Use zmDbDo or dbQueue.push where appropriate. code cleanup. --- src/zm_db.cpp | 52 ++++++--------- src/zm_db.h | 2 +- src/zm_event.cpp | 55 +++++----------- src/zm_libvnc_camera.cpp | 3 +- src/zm_logger.cpp | 137 ++++++++++++++++++--------------------- src/zm_logger.h | 12 +--- src/zm_monitor.cpp | 24 +++---- src/zm_zone.cpp | 40 +++++------- src/zmc.cpp | 5 +- 9 files changed, 135 insertions(+), 195 deletions(-) diff --git a/src/zm_db.cpp b/src/zm_db.cpp index 073e41697..9ffaed26a 100644 --- a/src/zm_db.cpp +++ b/src/zm_db.cpp @@ -23,7 +23,7 @@ #include MYSQL dbconn; -RecursiveMutex db_mutex; +std::mutex db_mutex; zmDbQueue dbQueue; bool zmDbConnected = false; @@ -108,46 +108,36 @@ bool zmDbConnect() { void zmDbClose() { if (zmDbConnected) { - db_mutex.lock(); + std::lock_guard lck(db_mutex); mysql_close(&dbconn); // mysql_init() call implicitly mysql_library_init() but // mysql_close() does not call mysql_library_end() mysql_library_end(); zmDbConnected = false; - db_mutex.unlock(); } } MYSQL_RES * zmDbFetch(const char * query) { - if ( !zmDbConnected ) { - Error("Not connected."); - return nullptr; - } - db_mutex.lock(); - // Might have been disconnected while we waited for the lock - if ( !zmDbConnected ) { - db_mutex.unlock(); + std::lock_guard lck(db_mutex); + if (!zmDbConnected) { Error("Not connected."); return nullptr; } - if ( mysql_query(&dbconn, query) ) { - db_mutex.unlock(); + if (mysql_query(&dbconn, query)) { Error("Can't run query: %s", mysql_error(&dbconn)); return nullptr; } - Debug(4, "Success running query: %s", query); MYSQL_RES *result = mysql_store_result(&dbconn); - if ( !result ) { + if (!result) { Error("Can't use query result: %s for query %s", mysql_error(&dbconn), query); } - db_mutex.unlock(); return result; } // end MYSQL_RES * zmDbFetch(const char * query); zmDbRow *zmDbFetchOne(const char *query) { zmDbRow *row = new zmDbRow(); - if ( row->fetch(query) ) { + if (row->fetch(query)) { return row; } delete row; @@ -156,10 +146,10 @@ zmDbRow *zmDbFetchOne(const char *query) { MYSQL_RES *zmDbRow::fetch(const char *query) { result_set = zmDbFetch(query); - if ( ! result_set ) return result_set; + if (!result_set) return result_set; int n_rows = mysql_num_rows(result_set); - if ( n_rows != 1 ) { + if (n_rows != 1) { Error("Bogus number of lines return from query, %d returned for query %s.", n_rows, query); mysql_free_result(result_set); result_set = nullptr; @@ -167,7 +157,7 @@ MYSQL_RES *zmDbRow::fetch(const char *query) { } row = mysql_fetch_row(result_set); - if ( !row ) { + if (!row) { mysql_free_result(result_set); result_set = nullptr; Error("Error getting row from query %s. Error is %s", query, mysql_error(&dbconn)); @@ -178,38 +168,34 @@ MYSQL_RES *zmDbRow::fetch(const char *query) { } int zmDbDo(const char *query) { - db_mutex.lock(); + std::lock_guard lck(db_mutex); + if (!zmDbConnected) + return 0; int rc; - while ( (rc = mysql_query(&dbconn, query)) and !zm_terminate) { - db_mutex.unlock(); + while ((rc = mysql_query(&dbconn, query)) and !zm_terminate) { Error("Can't run query %s: %s", query, mysql_error(&dbconn)); - if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) ) + if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) ) { return rc; - - db_mutex.lock(); + } } - db_mutex.unlock(); return 1; } int zmDbDoInsert(const char *query) { - db_mutex.lock(); + std::lock_guard lck(db_mutex); + if (!zmDbConnected) return 0; int rc; while ( (rc = mysql_query(&dbconn, query)) and !zm_terminate) { - db_mutex.unlock(); Error("Can't run query %s: %s", query, mysql_error(&dbconn)); if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) ) return 0; - - db_mutex.lock(); } int id = mysql_insert_id(&dbconn); - db_mutex.unlock(); return id; } zmDbRow::~zmDbRow() { - if ( result_set ) { + if (result_set) { mysql_free_result(result_set); result_set = nullptr; } diff --git a/src/zm_db.h b/src/zm_db.h index de4154ab2..a4e2daf25 100644 --- a/src/zm_db.h +++ b/src/zm_db.h @@ -62,7 +62,7 @@ class zmDbRow { }; extern MYSQL dbconn; -extern RecursiveMutex db_mutex; +extern std::mutex db_mutex; extern zmDbQueue dbQueue; extern bool zmDbConnected; diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 87f32c528..aebd3f93e 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -251,28 +251,25 @@ Event::~Event() { frames, alarm_frames, tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, id); - db_mutex.lock(); - while ( mysql_query(&dbconn, sql) && !zm_terminate ) { - db_mutex.unlock(); - Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); - db_mutex.lock(); - } - if ( !mysql_affected_rows(&dbconn) ) { - // Name might have been changed during recording, so just do the update without changing the name. - snprintf(sql, sizeof(sql), - "UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, - end_time.tv_sec, - delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, - frames, alarm_frames, - tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, - id); + { // scope for lock + std::lock_guard lck(db_mutex); while ( mysql_query(&dbconn, sql) && !zm_terminate ) { - db_mutex.unlock(); Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); - db_mutex.lock(); } - } // end if no changed rows due to Name change during recording - db_mutex.unlock(); + if ( !mysql_affected_rows(&dbconn) ) { + // Name might have been changed during recording, so just do the update without changing the name. + snprintf(sql, sizeof(sql), + "UPDATE Events SET EndDateTime = from_unixtime(%ld), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d WHERE Id = %" PRIu64, + end_time.tv_sec, + delta_time.positive?"":"-", delta_time.sec, delta_time.fsec, + frames, alarm_frames, + tot_score, (int)(alarm_frames?(tot_score/alarm_frames):0), max_score, + id); + while ( mysql_query(&dbconn, sql) && !zm_terminate ) { + Error("Can't update event: %s reason: %s", sql, mysql_error(&dbconn)); + } + } // end if no changed rows due to Name change during recording + } } // Event::~Event() void Event::createNotes(std::string ¬es) { @@ -489,14 +486,7 @@ void Event::AddFramesInternal(int n_frames, int start_frame, Image **images, str if ( frameCount ) { *(frame_insert_values-1) = '\0'; - db_mutex.lock(); - int rc = mysql_query(&dbconn, frame_insert_sql); - db_mutex.unlock(); - if ( rc ) { - Error("Can't insert frames: %s, sql was (%s)", mysql_error(&dbconn), frame_insert_sql); - } else { - Debug(1, "INSERT %d/%d frames sql %s", frameCount, n_frames, frame_insert_sql); - } + zmDbDo(frame_insert_sql); last_db_frame = frames; } else { Debug(1, "No valid pre-capture frames to add"); @@ -548,16 +538,7 @@ void Event::WriteDbFrames() { delete frame; } *(frame_insert_values_ptr-1) = '\0'; // The -1 is for the extra , added for values above - db_mutex.lock(); - int rc = mysql_query(&dbconn, frame_insert_sql); - db_mutex.unlock(); - - if ( rc ) { - Error("Can't insert frames: %s, sql was %s", mysql_error(&dbconn), frame_insert_sql); - return; - } else { - Debug(1, "INSERT FRAMES: sql was %s", frame_insert_sql); - } + zmDbDo(frame_insert_sql); } // end void Event::WriteDbFrames() void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *alarm_image) { diff --git a/src/zm_libvnc_camera.cpp b/src/zm_libvnc_camera.cpp index 7ea9d9c58..c00a37e30 100644 --- a/src/zm_libvnc_camera.cpp +++ b/src/zm_libvnc_camera.cpp @@ -132,7 +132,7 @@ VncCamera::VncCamera( } VncCamera::~VncCamera() { - if (capture) { + if (capture and mRfb) { if (mRfb->frameBuffer) free(mRfb->frameBuffer); (*rfbClientCleanup_f)(mRfb); @@ -164,6 +164,7 @@ int VncCamera::PrimeCapture() { mRfb->GetCredential = GetCredentialsCallback; mRfb->programName = "Zoneminder VNC Monitor"; + if ( mRfb->serverHost ) free(mRfb->serverHost); mRfb->serverHost = strdup(mHost.c_str()); mRfb->serverPort = atoi(mPort.c_str()); } diff --git a/src/zm_logger.cpp b/src/zm_logger.cpp index e264c3c3a..429b99bcf 100644 --- a/src/zm_logger.cpp +++ b/src/zm_logger.cpp @@ -21,10 +21,7 @@ #include "zm_db.h" #include "zm_utils.h" -#include -#include -#include -#include + #include #include #include @@ -32,6 +29,11 @@ #ifdef __FreeBSD__ #include #endif +#include +#include +#include +#include + bool Logger::smInitialised = false; Logger *Logger::smInstance = nullptr; @@ -57,16 +59,15 @@ Logger::Logger() : mEffectiveLevel(NOLOG), mDbConnected(false), mLogPath(staticConfig.PATH_LOGS.c_str()), - //mLogFile( mLogPath+"/"+mId+".log" ), + // mLogFile( mLogPath+"/"+mId+".log" ), mLogFileFP(nullptr), mHasTerminal(false), mFlush(false) { - - if ( smInstance ) { + if (smInstance) { Panic("Attempt to create second instance of Logger class"); } - if ( !smInitialised ) { + if (!smInitialised) { smCodes[INFO] = "INF"; smCodes[WARNING] = "WAR"; smCodes[ERROR] = "ERR"; @@ -81,16 +82,16 @@ Logger::Logger() : smSyslogPriorities[PANIC] = LOG_ERR; char code[4] = ""; - for ( int i = DEBUG1; i <= DEBUG9; i++ ) { + for (int i = DEBUG1; i <= DEBUG9; i++) { snprintf(code, sizeof(code), "DB%d", i); smCodes[i] = code; smSyslogPriorities[i] = LOG_DEBUG; } smInitialised = true; - } + } // end if ! smInitialised - if ( fileno(stderr) && isatty(fileno(stderr)) ) { + if (fileno(stderr) && isatty(fileno(stderr))) { mHasTerminal = true; mTerminalLevel = WARNING; } @@ -101,14 +102,6 @@ Logger::~Logger() { smCodes.clear(); smSyslogPriorities.clear(); smInitialised = false; -#if 0 - for ( StringMap::iterator itr = smCodes.begin(); itr != smCodes.end(); itr ++ ) { - smCodes.erase( itr ); - } - for ( IntMap::iterator itr = smSyslogPriorities.begin(); itr != smSyslogPriorities.end(); itr ++ ) { - smSyslogPriorities.erase(itr); - } -#endif } void Logger::initialise(const std::string &id, const Options &options) { @@ -185,7 +178,7 @@ void Logger::initialise(const std::string &id, const Options &options) { } } } - } // end foreach target + } // end foreach target } else { // if we don't have debug turned on, then the max effective log level is INFO if ( tempSyslogLevel > INFO ) tempSyslogLevel = INFO; @@ -193,7 +186,7 @@ void Logger::initialise(const std::string &id, const Options &options) { if ( tempTerminalLevel > INFO ) tempTerminalLevel = INFO; if ( tempDatabaseLevel > INFO ) tempDatabaseLevel = INFO; if ( tempLevel > INFO ) tempLevel = INFO; - } // end if config.log_debug + } // end if config.log_debug logFile(tempLogFile); @@ -355,11 +348,11 @@ Logger::Level Logger::databaseLevel(Logger::Level databaseLevel) { } Logger::Level Logger::fileLevel(Logger::Level fileLevel) { - if ( fileLevel > NOOPT ) { + if (fileLevel > NOOPT) { fileLevel = limit(fileLevel); // Always close, because we may have changed file names - if ( mFileLevel > NOLOG ) - closeFile(); + if (mFileLevel > NOLOG) + closeFile(); mFileLevel = fileLevel; // Don't try to open it here because it will create the log file even if we never write to it. } @@ -367,13 +360,13 @@ Logger::Level Logger::fileLevel(Logger::Level fileLevel) { } Logger::Level Logger::syslogLevel(Logger::Level syslogLevel) { - if ( syslogLevel > NOOPT ) { + if (syslogLevel > NOOPT) { syslogLevel = limit(syslogLevel); - if ( mSyslogLevel != syslogLevel ) { - if ( mSyslogLevel > NOLOG ) + if (mSyslogLevel != syslogLevel) { + if (mSyslogLevel > NOLOG) closeSyslog(); mSyslogLevel = syslogLevel; - if ( mSyslogLevel > NOLOG ) + if (mSyslogLevel > NOLOG) openSyslog(); } } @@ -383,31 +376,31 @@ Logger::Level Logger::syslogLevel(Logger::Level syslogLevel) { void Logger::logFile(const std::string &logFile) { bool addLogPid = false; std::string tempLogFile = logFile; - if ( tempLogFile[tempLogFile.length()-1] == '+' ) { + if (tempLogFile[tempLogFile.length()-1] == '+') { tempLogFile.resize(tempLogFile.length()-1); addLogPid = true; } - if ( addLogPid ) + if (addLogPid) mLogFile = stringtf("%s.%05d", tempLogFile.c_str(), getpid()); else mLogFile = tempLogFile; } void Logger::openFile() { - if ( mLogFile.size() ) { - if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == nullptr ) { - mFileLevel = NOLOG; - Error("fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno)); - } + if (mLogFile.size()) { + if ( (mLogFileFP = fopen(mLogFile.c_str(), "a")) == nullptr ) { + mFileLevel = NOLOG; + Error("fopen() for %s, error = %s", mLogFile.c_str(), strerror(errno)); + } } else { puts("Called Logger::openFile() without a filename"); } } void Logger::closeFile() { - if ( mLogFileFP ) { + if (mLogFileFP) { fflush(mLogFileFP); - if ( fclose(mLogFileFP) < 0 ) { + if (fclose(mLogFileFP) < 0) { mLogFileFP = nullptr; Error("fclose(), error = %s", strerror(errno)); } @@ -416,7 +409,6 @@ void Logger::closeFile() { } void Logger::closeDatabase() { - } void Logger::openSyslog() { @@ -428,12 +420,12 @@ void Logger::closeSyslog() { } void Logger::logPrint(bool hex, const char * const filepath, const int line, const int level, const char *fstring, ...) { - - if ( level > mEffectiveLevel ) { - return; - } + if (level > mEffectiveLevel) return; + if (level < PANIC || level > DEBUG9) + Panic("Invalid logger level %d", level); log_mutex.lock(); + // Can we save some cycles by having these as members and not allocate them on the fly? I think so. char timeString[64]; char logString[8192]; va_list argPtr; @@ -443,9 +435,6 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con const char *file = base ? base+1 : filepath; const char *classString = smCodes[level].c_str(); - if ( level < PANIC || level > DEBUG9 ) - Panic("Invalid logger level %d", level); - gettimeofday(&timeVal, nullptr); #if 0 @@ -474,12 +463,12 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con #else #ifdef HAVE_SYSCALL #ifdef __FreeBSD_kernel__ - if ( (syscall(SYS_thr_self, &tid)) < 0 ) // Thread/Process id + if ((syscall(SYS_thr_self, &tid)) < 0) // Thread/Process id # else // SOLARIS doesn't have SYS_gettid; don't assume #ifdef SYS_gettid - if ( (tid = syscall(SYS_gettid)) < 0 ) // Thread/Process id + if ((tid = syscall(SYS_gettid)) < 0) // Thread/Process id #endif // SYS_gettid #endif #endif // HAVE_SYSCALL @@ -513,61 +502,63 @@ void Logger::logPrint(bool hex, const char * const filepath, const int line, con char *syslogEnd = logPtr; strncpy(logPtr, "]\n", sizeof(logString)-(logPtr-logString)); - if ( level <= mTerminalLevel ) { + if (level <= mTerminalLevel) { puts(logString); fflush(stdout); } - if ( level <= mFileLevel ) { - if ( !mLogFileFP ) { - // We do this here so that we only create the file if we ever write to it. + if (level <= mFileLevel) { + if (!mLogFileFP) { + // FIXME unlocking here is a problem. Another thread could sneak in. log_mutex.unlock(); + // We do this here so that we only create the file if we ever write to it. openFile(); log_mutex.lock(); } - if ( mLogFileFP ) { + if (mLogFileFP) { fputs(logString, mLogFileFP); - if ( mFlush ) - fflush(mLogFileFP); + if (mFlush) fflush(mLogFileFP); } else { puts("Logging to file, but failed to open it\n"); } } // end if level <= mFileLevel - if ( level <= mDatabaseLevel ) { - int syslogSize = syslogEnd-syslogStart; - char escapedString[(syslogSize*2)+1]; - mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize); + if (level <= mDatabaseLevel) { + if (zmDbConnected) { + int syslogSize = syslogEnd-syslogStart; + char escapedString[(syslogSize*2)+1]; + mysql_real_escape_string(&dbconn, escapedString, syslogStart, syslogSize); - std::string sql_string = stringtf( - "INSERT INTO `Logs` " - "( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )" - " VALUES " - "( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", - timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line - ); - dbQueue.push(sql_string); + std::string sql_string = stringtf( + "INSERT INTO `Logs` " + "( `TimeKey`, `Component`, `ServerId`, `Pid`, `Level`, `Code`, `Message`, `File`, `Line` )" + " VALUES " + "( %ld.%06ld, '%s', %d, %d, %d, '%s', '%s', '%s', %d )", + timeVal.tv_sec, timeVal.tv_usec, mId.c_str(), staticConfig.SERVER_ID, tid, level, classString, escapedString, file, line + ); + dbQueue.push(sql_string); + } else { + puts("Db is closed"); + } } // end if level <= mDatabaseLevel - if ( level <= mSyslogLevel ) { + if (level <= mSyslogLevel) { *syslogEnd = '\0'; syslog(smSyslogPriorities[level], "%s [%s] [%s]", classString, mId.c_str(), syslogStart); } log_mutex.unlock(); - if ( level <= FATAL ) { + if (level <= FATAL) { logTerm(); zmDbClose(); - if ( level <= PANIC ) - abort(); + if (level <= PANIC) abort(); exit(-1); } } // end logPrint void logInit(const char *name, const Logger::Options &options) { - if ( Logger::smInstance ) { + if (Logger::smInstance) { delete Logger::smInstance; - Logger::smInstance = nullptr; } Logger::smInstance = new Logger(); @@ -575,7 +566,7 @@ void logInit(const char *name, const Logger::Options &options) { } void logTerm() { - if ( Logger::smInstance ) { + if (Logger::smInstance) { delete Logger::smInstance; Logger::smInstance = nullptr; } diff --git a/src/zm_logger.h b/src/zm_logger.h index 6350449a5..ee358b206 100644 --- a/src/zm_logger.h +++ b/src/zm_logger.h @@ -153,18 +153,12 @@ public: void terminate(); const std::string &id(const std::string &id); - const std::string &id() const { - return mId; - } + const std::string &id() const { return mId; } - Level level() const { - return mLevel; - } + Level level() const { return mLevel; } Level level(Level=NOOPT); - bool debugOn() const { - return mEffectiveLevel >= DEBUG1; - } + bool debugOn() const { return mEffectiveLevel >= DEBUG1; } Level terminalLevel(Level=NOOPT); Level databaseLevel(Level=NOOPT); diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 674d457d0..b1e18221a 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1692,7 +1692,6 @@ void Monitor::UpdateCaptureFPS() { last_fps_time = now_double; last_capture_image_count = image_count; - db_mutex.lock(); static char sql[ZM_SQL_SML_BUFSIZ]; // The reason we update the Status as well is because if mysql restarts, the Monitor_Status table is lost, // and nothing else will update the status until zmc restarts. Since we are successfully capturing we can @@ -1702,9 +1701,7 @@ void Monitor::UpdateCaptureFPS() { "VALUES (%d, %.2lf, %u, 'Connected') ON DUPLICATE KEY UPDATE " "CaptureFPS = %.2lf, CaptureBandwidth=%u, Status='Connected'", id, new_capture_fps, new_capture_bandwidth, new_capture_fps, new_capture_bandwidth); - int rc = mysql_query(&dbconn, sql); - db_mutex.unlock(); - if ( rc ) Error("Can't run query: %s", mysql_error(&dbconn)); + dbQueue.push(sql); } // now != last_fps_time } // end if report fps } // void Monitor::UpdateCaptureFPS() @@ -1745,10 +1742,7 @@ void Monitor::UpdateAnalysisFPS() { "INSERT INTO Monitor_Status (MonitorId,AnalysisFPS) VALUES (%d, %.2lf)" " ON DUPLICATE KEY UPDATE AnalysisFPS = %.2lf", id, new_analysis_fps, new_analysis_fps); - db_mutex.lock(); - int rc = mysql_query(&dbconn, sql); - db_mutex.unlock(); - if ( rc ) Error("Can't run query: %s", mysql_error(&dbconn)); + dbQueue.push(sql); last_analysis_fps_time = now_double; last_motion_frame_count = motion_frame_count; } else { @@ -2324,7 +2318,7 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { for ( int i = 0; i < n_link_ids; i++ ) { Debug(1, "Checking linked monitor %d", link_ids[i]); - db_mutex.lock(); + std::lock_guard lck(db_mutex); static char sql[ZM_SQL_SML_BUFSIZ]; snprintf(sql, sizeof(sql), "SELECT `Id`, `Name` FROM `Monitors`" @@ -2333,14 +2327,12 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { " AND `Function` != 'Monitor'" " AND `Enabled`=1", link_ids[i]); - if ( mysql_query(&dbconn, sql) ) { - db_mutex.unlock(); + if (mysql_query(&dbconn, sql)) { Error("Can't run query: %s", mysql_error(&dbconn)); continue; } MYSQL_RES *result = mysql_store_result(&dbconn); - db_mutex.unlock(); if ( !result ) { Error("Can't use query result: %s", mysql_error(&dbconn)); continue; @@ -2354,11 +2346,11 @@ void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) { Warning("Can't link to monitor %d, invalid id, function or not enabled", link_ids[i]); } mysql_free_result(result); - } // end foreach link_id + } // end foreach link_id n_linked_monitors = count; - } // end if has link_ids - } // end if p_linked_monitors -} // end void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) + } // end if has link_ids + } // end if p_linked_monitors +} // end void Monitor::ReloadLinkedMonitors(const char *p_linked_monitors) std::vector> Monitor::LoadMonitors(std::string sql, Purpose purpose) { Debug(1, "Loading Monitors with %s", sql.c_str()); diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 0e39123dc..21d99295d 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -134,16 +134,11 @@ Zone::~Zone() { void Zone::RecordStats(const Event *event) { static char sql[ZM_SQL_MED_BUFSIZ]; - db_mutex.lock(); snprintf(sql, sizeof(sql), "INSERT INTO Stats SET MonitorId=%d, ZoneId=%d, EventId=%" PRIu64 ", FrameId=%d, PixelDiff=%d, AlarmPixels=%d, FilterPixels=%d, BlobPixels=%d, Blobs=%d, MinBlobSize=%d, MaxBlobSize=%d, MinX=%d, MinY=%d, MaxX=%d, MaxY=%d, Score=%d", monitor->Id(), id, event->Id(), event->Frames(), pixel_diff, alarm_pixels, alarm_filter_pixels, alarm_blob_pixels, alarm_blobs, min_blob_size, max_blob_size, alarm_box.LoX(), alarm_box.LoY(), alarm_box.HiX(), alarm_box.HiY(), score ); - int rc = mysql_query(&dbconn, sql); - db_mutex.unlock(); - if ( rc ) { - Error("Can't insert event stats: %s", mysql_error(&dbconn)); - } + zmDbDo(sql); } // end void Zone::RecordStats( const Event *event ) bool Zone::CheckOverloadCount() { @@ -824,23 +819,24 @@ bool Zone::ParseZoneString(const char *zone_string, int &zone_id, int &colour, P int Zone::Load(Monitor *monitor, Zone **&zones) { static char sql[ZM_SQL_MED_BUFSIZ]; + MYSQL_RES *result; - db_mutex.lock(); - snprintf(sql, sizeof(sql), "SELECT Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0," - "MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels," - "FilterX,FilterY,MinFilterPixels,MaxFilterPixels," - "MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs," - "OverloadFrames,ExtendAlarmFrames" - " FROM Zones WHERE MonitorId = %d ORDER BY Type, Id", monitor->Id()); - if ( mysql_query(&dbconn, sql) ) { - db_mutex.unlock(); - Error("Can't run query: %s", mysql_error(&dbconn)); - return 0; + { // scope for lock + std::lock_guard lck(db_mutex); + snprintf(sql, sizeof(sql), "SELECT Id,Name,Type+0,Units,Coords,AlarmRGB,CheckMethod+0," + "MinPixelThreshold,MaxPixelThreshold,MinAlarmPixels,MaxAlarmPixels," + "FilterX,FilterY,MinFilterPixels,MaxFilterPixels," + "MinBlobPixels,MaxBlobPixels,MinBlobs,MaxBlobs," + "OverloadFrames,ExtendAlarmFrames" + " FROM Zones WHERE MonitorId = %d ORDER BY Type, Id", monitor->Id()); + if ( mysql_query(&dbconn, sql) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + return 0; + } + + result = mysql_store_result(&dbconn); } - - MYSQL_RES *result = mysql_store_result(&dbconn); - db_mutex.unlock(); - if ( !result ) { + if (!result) { Error("Can't use query result: %s", mysql_error(&dbconn)); return 0; } @@ -848,7 +844,7 @@ int Zone::Load(Monitor *monitor, Zone **&zones) { Debug(1, "Got %d zones for monitor %s", n_zones, monitor->Name()); delete[] zones; zones = new Zone *[n_zones]; - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { + for(int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) { int col = 0; int Id = atoi(dbrow[col++]); diff --git a/src/zmc.cpp b/src/zmc.cpp index adaf7116f..76d3b24ed 100644 --- a/src/zmc.cpp +++ b/src/zmc.cpp @@ -266,6 +266,7 @@ int main(int argc, char *argv[]) { monitor->Id()); zmDbDo(sql); } // end foreach monitor + if (zm_terminate) break; #if HAVE_RTSP_SERVER RTSPServerThread ** rtsp_server_threads = nullptr; @@ -418,9 +419,7 @@ int main(int argc, char *argv[]) { snprintf(sql, sizeof(sql), "INSERT INTO Monitor_Status (MonitorId,Status) VALUES (%d, 'Connected') ON DUPLICATE KEY UPDATE Status='NotRunning'", monitor->Id()); - if (mysql_query(&dbconn, sql)) { - Error("Can't run query: %s", mysql_error(&dbconn)); - } + zmDbDo(sql); } Image::Deinitialise(); From 550d302316c2fb4e51bacede23ab77c1fd7b7818 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 25 Feb 2021 14:18:23 -0500 Subject: [PATCH 57/57] Fix Crud version back to origin --- web/api/app/Plugin/Crud | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index 0bd63fb46..14292374c 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef +Subproject commit 14292374ccf1328f2d5db20897bd06f99ba4d938