From 0a9ae1d4f9b35f53c1e7c52b80f3f0ccffc3c174 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 11 Jun 2019 13:55:57 -0400 Subject: [PATCH 01/34] Include pixdesc.h to get av_get_pix_fmt_name(AVPixelFormat) --- src/zm_ffmpeg.cpp | 3 +++ src/zm_ffmpeg_camera.cpp | 1 + 2 files changed, 4 insertions(+) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 029492f90..139ab5838 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -21,6 +21,9 @@ #include "zm_ffmpeg.h" #include "zm_image.h" #include "zm_rgb.h" +extern "C" { +#include "libavutil/pixdesc.h" +} #if HAVE_LIBAVCODEC || HAVE_LIBAVUTIL || HAVE_LIBSWSCALE diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 9cf2d93ef..31ce90f1e 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -29,6 +29,7 @@ extern "C" { #if HAVE_LIBAVUTIL_HWCONTEXT_H #include "libavutil/hwcontext.h" #endif +#include "libavutil/pixdesc.h" } #ifndef AV_ERROR_MAX_STRING_SIZE #define AV_ERROR_MAX_STRING_SIZE 64 From 1815bf18a988adfe0279a687ac84379b9cf81a3d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 24 Jun 2019 11:50:58 -0400 Subject: [PATCH 02/34] Add support for specifying PPA --- utils/do_debian_package.sh | 48 +++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index a825d0b62..ba6bd198b 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -23,6 +23,10 @@ case $i in INTERACTIVE="${i#*=}" shift # past argument=value ;; + -p=*|--ppa=*) + PPA="${i#*=}" + shift # past argument=value + ;; -r=*|--release=*) RELEASE="${i#*=}" shift @@ -108,6 +112,23 @@ else fi; fi +if [ "$PPA" == "" ]; then + if [ "$RELEASE" != "" ]; then + # We need to use our official tarball for the original source, so grab it and overwrite our generated one. + IFS='.' read -r -a VERSION <<< "$RELEASE" + if [ "${VERSION[0]}.${VERSION[1]}" == "1.30" ]; then + PPA="ppa:iconnor/zoneminder-stable" + else + PPA="ppa:iconnor/zoneminder-${VERSION[0]}.${VERSION[1]}" + fi; + else + if [ "$BRANCH" == "" ]; then + PPA="ppa:iconnor/zoneminder-master"; + else + PPA="ppa:iconnor/zoneminder-$BRANCH"; + fi; + fi; +fi; # Instead of cloning from github each time, if we have a fork lying around, update it and pull from there instead. if [ ! -d "${GITHUB_FORK}_zoneminder_release" ]; then @@ -261,9 +282,9 @@ if [ $TYPE == "binary" ]; then if [ "$INTERACTIVE" != "no" ]; then read -p "Not doing dput since it's a binary release. Do you want to install it? (Y/N)" if [[ $REPLY == [yY] ]]; then - sudo dpkg -i $DIRECTORY*.deb + sudo dpkg -i $DIRECTORY*.deb else - echo $REPLY; + echo $REPLY; fi; if [ "$DISTRO" == "jessie" ]; then read -p "Do you want to upload this binary to zmrepo? (y/N)" @@ -282,25 +303,14 @@ if [ $TYPE == "binary" ]; then fi; else SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes"; - PPA=""; - if [ "$RELEASE" != "" ]; then - PPA="ppa:iconnor/zoneminder"; - else - if [ "$BRANCH" == "" ]; then - PPA="ppa:iconnor/zoneminder-master"; - else - PPA="ppa:iconnor/zoneminder-$BRANCH"; - fi; - fi; - dput="Y"; if [ "$INTERACTIVE" != "no" ]; then - echo "Ready to dput $SC to $PPA ? Y/N..."; - read dput - fi - if [ "$dput" == [Yy] ]; then + read -p "Ready to dput $SC to $PPA ? Y/N..."; + if [[ "$REPLY" == [yY] ]]; then + dput $PPA $SC + fi; + else + echo "dputting to $PPA"; dput $PPA $SC fi; fi; - - From ee19322e11fdb89ed83cb9121c70a6dfe51d01e9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 24 Jun 2019 11:57:52 -0400 Subject: [PATCH 03/34] update do_debian_package from storageareas --- utils/do_debian_package.sh | 277 +++++++++++++++++++++---------------- 1 file changed, 155 insertions(+), 122 deletions(-) diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index ba6bd198b..fc1eaaeff 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -8,6 +8,13 @@ exit; fi +DEBUILD=`which debuild`; + +if [ "$DEBUILD" == "" ]; then + echo "You must install the devscripts package. Try sudo apt-get install devscripts"; + exit; +fi + for i in "$@" do case $i in @@ -16,7 +23,7 @@ case $i in shift # past argument=value ;; -d=*|--distro=*) - DISTRO="${i#*=}" + DISTROS="${i#*=}" shift # past argument=value ;; -i=*|--interactive=*) @@ -71,11 +78,15 @@ else echo "Doing $TYPE build" fi; -if [ "$DISTRO" == "" ]; then - DISTRO=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`; - echo "Defaulting to $DISTRO for distribution"; +if [ "$DISTROS" == "" ]; then + if [ "$RELEASE" != "" ]; then + DISTROS="xenial,bionic,cosmic,disco,trusty" + else + DISTROS=`lsb_release -a 2>/dev/null | grep Codename | awk '{print $2}'`; + fi; + echo "Defaulting to $DISTROS for distribution"; else - echo "Building for $DISTRO"; + echo "Building for $DISTROS"; fi; # Release is a special mode... it uploads to the release ppa and cannot have a snapshot @@ -90,7 +101,8 @@ if [ "$RELEASE" != "" ]; then else GITHUB_FORK="ZoneMinder"; fi - BRANCH="release-$RELEASE" + # We use a tag instead of a branch atm. + BRANCH=$RELEASE else if [ "$GITHUB_FORK" == "" ]; then echo "Defaulting to ZoneMinder upstream git" @@ -167,6 +179,11 @@ if [ "$SNAPSHOT" != "stable" ] && [ "$SNAPSHOT" != "" ]; then fi; DIRECTORY="zoneminder_$VERSION"; +if [ -d "$DIRECTORY.orig" ]; then + echo "$DIRECTORY.orig already exists. Please delete it." + exit 0; +fi; + echo "Doing $TYPE release $DIRECTORY"; mv "${GITHUB_FORK}_zoneminder_release" "$DIRECTORY.orig"; if [ $? -ne 0 ]; then @@ -174,102 +191,153 @@ if [ $? -ne 0 ]; then echo "Setting up build dir failed."; exit $?; fi; + cd "$DIRECTORY.orig"; +# Init submodules git submodule init git submodule update --init --recursive -if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]; then - mv distros/ubuntu1204 debian -else - if [ "$DISTRO" == "wheezy" ]; then - mv distros/debian debian - else - mv distros/ubuntu1604 debian - fi; -fi; - -if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then - AUTHOR="$DEBFULLNAME <$DEBEMAIL>" -else - if [ -z `hostname -d` ] ; then - AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`.local>" - else - AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`>" - fi -fi - -if [ "$URGENCY" = "" ]; then - URGENCY="medium" -fi; - -if [ "$SNAPSHOT" == "stable" ]; then -cat < debian/changelog -zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY - - * Release $VERSION - - -- $AUTHOR $DATE - -EOF -cat < debian/NEWS -zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY - - * Release $VERSION - - -- $AUTHOR $DATE -EOF -else -cat < debian/changelog -zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY - - * - - -- $AUTHOR $DATE -EOF -cat < debian/changelog -zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY - - * - - -- $AUTHOR $DATE -EOF -fi; +# Cleanup rm -rf .git rm .gitignore cd ../ -tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig -cd $DIRECTORY.orig -if [ $TYPE == "binary" ]; then - # Auto-install all ZoneMinder's depedencies using the Debian control file - sudo apt-get install devscripts equivs - sudo mk-build-deps -ir ./debian/control - echo "Status: $?" - DEBUILD=debuild -else - if [ $TYPE == "local" ]; then +if [ ! -e "$DIRECTORY.orig.tar.gz" ]; then + tar zcf $DIRECTORY.orig.tar.gz $DIRECTORY.orig +fi; + +IFS=',' ;for DISTRO in `echo "$DISTROS"`; do + echo "Generating package for $DISTRO"; + cd $DIRECTORY.orig + + if [ -e "debian" ]; then + rm -rf debian + fi; + + # Generate Changlog + if [ "$DISTRO" == "trusty" ] || [ "$DISTRO" == "precise" ]; then + cp -Rpd distros/ubuntu1204 debian + else + if [ "$DISTRO" == "wheezy" ]; then + cp -Rpd distros/debian debian + else + cp -Rpd distros/ubuntu1604 debian + fi; + fi; + + if [ "$DEBEMAIL" != "" ] && [ "$DEBFULLNAME" != "" ]; then + AUTHOR="$DEBFULLNAME <$DEBEMAIL>" + else + if [ -z `hostname -d` ] ; then + AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`.local>" + else + AUTHOR="`getent passwd $USER | cut -d ':' -f 5 | cut -d ',' -f 1` <`whoami`@`hostname`>" + fi + fi + + if [ "$URGENCY" = "" ]; then + URGENCY="medium" + fi; + + if [ "$SNAPSHOT" == "stable" ]; then + cat < debian/changelog +zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY + + * Release $VERSION + + -- $AUTHOR $DATE + +EOF + cat < debian/NEWS +zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY + + * Release $VERSION + + -- $AUTHOR $DATE +EOF + else + cat < debian/changelog +zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY + + * + + -- $AUTHOR $DATE +EOF + cat < debian/changelog +zoneminder ($VERSION-$DISTRO${PACKAGE_VERSION}) $DISTRO; urgency=$URGENCY + + * + + -- $AUTHOR $DATE +EOF + fi; + + if [ $TYPE == "binary" ]; then # Auto-install all ZoneMinder's depedencies using the Debian control file sudo apt-get install devscripts equivs sudo mk-build-deps -ir ./debian/control echo "Status: $?" - DEBUILD="debuild -i -us -uc -b" - else - # Source build, don't need build depends. - DEBUILD="debuild -S -sa" + DEBUILD=debuild + else + if [ $TYPE == "local" ]; then + # Auto-install all ZoneMinder's depedencies using the Debian control file + sudo apt-get install devscripts equivs + sudo mk-build-deps -ir ./debian/control + echo "Status: $?" + DEBUILD="debuild -i -us -uc -b" + else + # Source build, don't need build depends. + DEBUILD="debuild -S -sa" + fi; + fi; + if [ "$DEBSIGN_KEYID" != "" ]; then + DEBUILD="$DEBUILD -k$DEBSIGN_KEYID" + fi + eval $DEBUILD + if [ $? -ne 0 ]; then + echo "Error status code is: $?" + echo "Build failed."; + exit $?; fi; -fi; -if [ "$DEBSIGN_KEYID" != "" ]; then - DEBUILD="$DEBUILD -k$DEBSIGN_KEYID" -fi -$DEBUILD -if [ $? -ne 0 ]; then -echo "Error status code is: $?" - echo "Build failed."; - exit $?; -fi; -cd ../ + cd ../ + + if [ $TYPE == "binary" ]; then + if [ "$INTERACTIVE" != "no" ]; then + read -p "Not doing dput since it's a binary release. Do you want to install it? (y/N)" + if [[ $REPLY == [yY] ]]; then + sudo dpkg -i $DIRECTORY*.deb + fi; + read -p "Do you want to upload this binary to zmrepo? (y/N)" + if [[ $REPLY == [yY] ]]; then + if [ "$RELEASE" != "" ]; then + scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/" + else + if [ "$BRANCH" == "" ]; then + scp "zoneminder_${VERSION}-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/" + else + scp "$DIRECTORY-${DISTRO}"* "zoneminder-doc_${VERSION}-${DISTRO}"* "zoneminder-dbg_${VERSION}-${DISTRO}"* "zoneminder_${VERSION}.orig.tar.gz" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/" + fi; + fi; + fi; + fi; + else + SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes"; + + dput="Y"; + if [ "$INTERACTIVE" != "no" ]; then + read -p "Ready to dput $SC to $PPA ? Y/N..."; + if [[ "$REPLY" == [yY] ]]; then + dput $PPA $SC + fi; + else + echo "dputting to $PPA"; + dput $PPA $SC + fi; + fi; +done; # foreach distro + if [ "$INTERACTIVE" != "no" ]; then read -p "Do you want to keep the checked out version of Zoneminder (incase you want to modify it later) [y/N]" [[ $REPLY == [yY] ]] && { mv "$DIRECTORY.orig" zoneminder_release; echo "The checked out copy is preserved in zoneminder_release"; } || { rm -fr "$DIRECTORY.orig"; echo "The checked out copy has been deleted"; } @@ -278,39 +346,4 @@ else rm -fr "$DIRECTORY.orig"; echo "The checked out copy has been deleted"; fi -if [ $TYPE == "binary" ]; then - if [ "$INTERACTIVE" != "no" ]; then - read -p "Not doing dput since it's a binary release. Do you want to install it? (Y/N)" - if [[ $REPLY == [yY] ]]; then - sudo dpkg -i $DIRECTORY*.deb - else - echo $REPLY; - fi; - if [ "$DISTRO" == "jessie" ]; then - read -p "Do you want to upload this binary to zmrepo? (y/N)" - if [[ $REPLY == [yY] ]]; then - if [ "$RELEASE" != "" ]; then - scp "zoneminder_${VERSION}-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/stable/mini-dinstall/incoming/" - else - if [ "$BRANCH" == "" ]; then - scp "zoneminder_${VERSION}-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/master/mini-dinstall/incoming/" - else - scp "$DIRECTORY-${DISTRO}*" "zmrepo@zmrepo.connortechnology.com:debian/${BRANCH}/mini-dinstall/incoming/" - fi; - fi; - fi; - fi; - fi; -else - SC="zoneminder_${VERSION}-${DISTRO}${PACKAGE_VERSION}_source.changes"; - if [ "$INTERACTIVE" != "no" ]; then - read -p "Ready to dput $SC to $PPA ? Y/N..."; - if [[ "$REPLY" == [yY] ]]; then - dput $PPA $SC - fi; - else - echo "dputting to $PPA"; - dput $PPA $SC - fi; -fi; From 8cf7563ce4abbcf88dc5ebeb2c3910c76aa0b4e2 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 24 Jun 2019 12:00:19 -0400 Subject: [PATCH 04/34] fix merge --- utils/do_debian_package.sh | 24 +----------------------- 1 file changed, 1 insertion(+), 23 deletions(-) diff --git a/utils/do_debian_package.sh b/utils/do_debian_package.sh index ae09f98a8..7addf8362 100755 --- a/utils/do_debian_package.sh +++ b/utils/do_debian_package.sh @@ -124,7 +124,6 @@ else fi; fi -<<<<<<< HEAD if [ "$PPA" == "" ]; then if [ "$RELEASE" != "" ]; then # We need to use our official tarball for the original source, so grab it and overwrite our generated one. @@ -140,22 +139,6 @@ if [ "$PPA" == "" ]; then else PPA="ppa:iconnor/zoneminder-$BRANCH"; fi; -======= -PPA=""; -if [ "$RELEASE" != "" ]; then - # We need to use our official tarball for the original source, so grab it and overwrite our generated one. - IFS='.' read -r -a VERSION <<< "$RELEASE" - if [ "${VERSION[0]}.${VERSION[1]}" == "1.30" ]; then - PPA="ppa:iconnor/zoneminder-stable" - else - PPA="ppa:iconnor/zoneminder-${VERSION[0]}.${VERSION[1]}" - fi; -else - if [ "$BRANCH" == "" ]; then - PPA="ppa:iconnor/zoneminder-master"; - else - PPA="ppa:iconnor/zoneminder-$BRANCH"; ->>>>>>> acb95709e6cd8fdb9e76b3d58bc6f546fc6b1447 fi; fi; @@ -349,11 +332,8 @@ EOF dput $PPA $SC fi; else -<<<<<<< HEAD echo "dputting to $PPA"; -======= ->>>>>>> acb95709e6cd8fdb9e76b3d58bc6f546fc6b1447 - dput $PPA $SC + dput $PPA $SC fi; fi; done; # foreach distro @@ -365,5 +345,3 @@ if [ "$INTERACTIVE" != "no" ]; then else rm -fr "$DIRECTORY.orig"; echo "The checked out copy has been deleted"; fi - - From a9579484b8700af47fd7dd9f0a1e55d6770b993f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Jul 2019 09:49:53 -0400 Subject: [PATCH 05/34] gracefully handle failure to config hw pix fmt and debug a bit more --- src/zm_ffmpeg_camera.cpp | 42 +++++++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 9cf2d93ef..3399e4e80 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -455,36 +455,46 @@ int FfmpegCamera::OpenFfmpeg() { if ( !config ) { Debug(1, "Decoder %s does not support device type %s.", mVideoCodec->name, av_hwdevice_get_type_name(type)); - return -1; + break; } if ( (config->methods & AV_CODEC_HW_CONFIG_METHOD_HW_DEVICE_CTX) && (config->device_type == type) ) { hw_pix_fmt = config->pix_fmt; break; + } else { + Debug(1, "decoder %s hwConfig doesn't match our type: %s, pix_fmt %s.", + mVideoCodec->name, + av_hwdevice_get_type_name(config-device_type), + av_get_pix_fmt_name(config->pix_fmt); + ); } } // end foreach hwconfig #else hw_pix_fmt = find_fmt_by_hw_type(type); #endif -Debug(1, "Selected gw_pix_fmt %d %s", - hw_pix_fmt, - av_get_pix_fmt_name(hw_pix_fmt)); + if ( hw_pix_fmt != AV_PIX_FMT_NONE ) { + Debug(1, "Selected gw_pix_fmt %d %s", + hw_pix_fmt, + av_get_pix_fmt_name(hw_pix_fmt)); - mVideoCodecContext->get_format = get_hw_format; + mVideoCodecContext->get_format = get_hw_format; - Debug(1, "Creating hwdevice for %s", - (hwaccel_device != "" ? hwaccel_device.c_str() : "")); - ret = av_hwdevice_ctx_create(&hw_device_ctx, type, - (hwaccel_device != "" ? hwaccel_device.c_str(): NULL), NULL, 0); - if ( ret < 0 ) { - Error("Failed to create specified HW device."); - return -1; + Debug(1, "Creating hwdevice for %s", + (hwaccel_device != "" ? hwaccel_device.c_str() : "")); + ret = av_hwdevice_ctx_create(&hw_device_ctx, type, + (hwaccel_device != "" ? hwaccel_device.c_str(): NULL), NULL, 0); + if ( ret < 0 ) { + Error("Failed to create specified HW device."); + return -1; + } + Debug(1, "Created hwdevice"); + mVideoCodecContext->hw_device_ctx = av_buffer_ref(hw_device_ctx); + hwaccel = true; + hwFrame = zm_av_frame_alloc(); + } else { + Debug(1, "Failed to setup hwaccel."); } - Debug(1, "Created hwdevice"); - mVideoCodecContext->hw_device_ctx = av_buffer_ref(hw_device_ctx); - hwaccel = true; - hwFrame = zm_av_frame_alloc(); #else Warning("HWAccel support not compiled in."); #endif From 2470c09b20f82b05aa0515da1b0e5c44bef32523 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Jul 2019 17:19:10 -0400 Subject: [PATCH 06/34] Honour thumbnail width when bringing up frames popup for frames and alarm frames --- web/skins/classic/views/events.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/web/skins/classic/views/events.php b/web/skins/classic/views/events.php index 703e67153..fc692169b 100644 --- a/web/skins/classic/views/events.php +++ b/web/skins/classic/views/events.php @@ -215,8 +215,12 @@ while ( $event_row = dbFetchNext($results) ) { ( $event->EndTime() ? ' until ' . strftime(STRF_FMT_DATETIME_SHORTER, strtotime($event->EndTime()) ) : '' ) ?> Length() ) ?> - Id(), 'zmFrames', 'frames', $event->Frames() ) ?> - Id(), 'zmFrames', 'frames', $event->AlarmFrames() ) ?> + Id(), 'zmFrames', + ( ZM_WEB_LIST_THUMBS ? array('frames', ZM_WEB_LIST_THUMB_WIDTH, ZM_WEB_LIST_THUMB_HEIGHT) : 'frames'), + $event->Frames() ) ?> + Id(), 'zmFrames', + ( ZM_WEB_LIST_THUMBS ? array('frames', ZM_WEB_LIST_THUMB_WIDTH, ZM_WEB_LIST_THUMB_HEIGHT) : 'frames'), + $event->AlarmFrames() ) ?> TotScore() ?> AvgScore() ?> Date: Thu, 4 Jul 2019 09:04:43 -0400 Subject: [PATCH 07/34] google code style --- web/skins/classic/js/skin.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index a14c63bfc..d39062087 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -51,51 +51,51 @@ function newWindow( url, name, width, height ) { function getPopupSize( tag, width, height ) { if ( typeof popupSizes == 'undefined' ) { - Error( "Can't find any window sizes" ); - return ( {'width': 0, 'height': 0} ); + Error("Can't find any window sizes"); + return {'width': 0, 'height': 0}; } - var popupSize = Object.clone( popupSizes[tag] ); + var popupSize = Object.clone(popupSizes[tag]); if ( !popupSize ) { - Error( "Can't find window size for tag '"+tag+"'" ); - return ( {'width': 0, 'height': 0} ); + Error("Can't find window size for tag '"+tag+"'"); + return {'width': 0, 'height': 0}; } if ( popupSize.width && popupSize.height ) { if ( width || height ) { - Warning( "Ignoring passed dimensions "+width+"x"+height+" when getting popup size for tag '"+tag+"'" ); + Warning("Ignoring passed dimensions "+width+"x"+height+" when getting popup size for tag '"+tag+"'"); } - return ( popupSize ); + return popupSize; } if ( popupSize.addWidth ) { popupSize.width = popupSize.addWidth; if ( !width ) { - Error( "Got addWidth but no passed width when getting popup size for tag '"+tag+"'" ); + Error("Got addWidth but no passed width when getting popup size for tag '"+tag+"'"); } else { popupSize.width += parseInt(width); } } else if ( width ) { popupSize.width = width; - Error( "Got passed width but no addWidth when getting popup size for tag '"+tag+"'" ); + Error("Got passed width but no addWidth when getting popup size for tag '"+tag+"'"); } if ( popupSize.minWidth && popupSize.width < popupSize.minWidth ) { - Warning( "Adjusting to minimum width when getting popup size for tag '"+tag+"'" ); + Warning("Adjusting to minimum width when getting popup size for tag '"+tag+"'"); popupSize.width = popupSize.minWidth; } if ( popupSize.addHeight ) { popupSize.height = popupSize.addHeight; if ( !height ) { - Error( "Got addHeight but no passed height when getting popup size for tag '"+tag+"'" ); + Error("Got addHeight but no passed height when getting popup size for tag '"+tag+"'"); } else { popupSize.height += parseInt(height); } } else if ( height ) { popupSize.height = height; - Error( "Got passed height but no addHeight when getting popup size for tag '"+tag+"'" ); + Error("Got passed height but no addHeight when getting popup size for tag '"+tag+"'"); } if ( popupSize.minHeight && ( popupSize.height < popupSize.minHeight ) ) { - Warning( "Adjusting to minimum height ("+popupSize.minHeight+") when getting popup size for tag '"+tag+"' because calculated height is " + popupSize.height ); + Warning("Adjusting to minimum height ("+popupSize.minHeight+") when getting popup size for tag '"+tag+"' because calculated height is " + popupSize.height); popupSize.height = popupSize.minHeight; } - return ( popupSize ); + return popupSize; } function zmWindow() { From aa817adbeda64c497ab59b595860bb459d3ad82b Mon Sep 17 00:00:00 2001 From: bluikko <14869000+bluikko@users.noreply.github.com> Date: Sun, 7 Jul 2019 19:26:06 +0700 Subject: [PATCH 08/34] Add primary keys to Logs and Stats tables (#2653) * Add primary keys to Logs and Stats tables Adds an auto_increment int(10) Id as PRIMARY KEY to Logs and Stats tables. Closes ZoneMinder#2550 and makes ZoneMinder compatible with Galera writeset replication for InnoDB (Galera Cluster, Percona XtraDB Cluster). * Do ALTER TABLE only if columns do not exist * Add forgotten prepare/execute --- db/zm_create.sql.in | 4 ++++ db/zm_update-1.33.12.sql | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 db/zm_update-1.33.12.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index f8fb8673b..261a4368c 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -351,6 +351,7 @@ CREATE INDEX `Groups_Monitors_MonitorId_idx` ON `Groups_Monitors` (`MonitorId`); DROP TABLE IF EXISTS `Logs`; CREATE TABLE `Logs` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, `TimeKey` decimal(16,6) NOT NULL, `Component` varchar(32) NOT NULL, `ServerId` int(10) unsigned, @@ -360,6 +361,7 @@ CREATE TABLE `Logs` ( `Message` text NOT NULL, `File` varchar(255) DEFAULT NULL, `Line` smallint(5) unsigned DEFAULT NULL, + PRIMARY KEY (`Id`), KEY `TimeKey` (`TimeKey`) ) ENGINE=@ZM_MYSQL_ENGINE@; @@ -589,6 +591,7 @@ CREATE INDEX `Servers_Name_idx` ON `Servers` (`Name`); DROP TABLE IF EXISTS `Stats`; CREATE TABLE `Stats` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT, `MonitorId` int(10) unsigned NOT NULL default '0', `ZoneId` int(10) unsigned NOT NULL default '0', `EventId` BIGINT UNSIGNED NOT NULL, @@ -605,6 +608,7 @@ CREATE TABLE `Stats` ( `MinY` smallint(5) unsigned NOT NULL default '0', `MaxY` smallint(5) unsigned NOT NULL default '0', `Score` smallint(5) unsigned NOT NULL default '0', + PRIMARY KEY (`Id`), KEY `EventId` (`EventId`), KEY `MonitorId` (`MonitorId`), KEY `ZoneId` (`ZoneId`) diff --git a/db/zm_update-1.33.12.sql b/db/zm_update-1.33.12.sql new file mode 100644 index 000000000..8188ad841 --- /dev/null +++ b/db/zm_update-1.33.12.sql @@ -0,0 +1,27 @@ +-- +-- Add primary keys for Logs and Stats tables +-- + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Logs' + AND column_name = 'Id' + ) > 0, +"SELECT 'Column Id already exists in Logs'", +"ALTER TABLE `Logs` ADD COLUMN `Id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`Id`)" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; + +SET @s = (SELECT IF( + (SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE() + AND table_name = 'Stats' + AND column_name = 'Id' + ) > 0, +"SELECT 'Column Id already exists in Stats'", +"ALTER TABLE `Stats` ADD COLUMN `Id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT FIRST, ADD PRIMARY KEY (`Id`)" +)); + +PREPARE stmt FROM @s; +EXECUTE stmt; From 8c735856f80ca38d83584c803814951275e8fe36 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 7 Jul 2019 07:32:12 -0500 Subject: [PATCH 09/34] bump version required by #2653 --- version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version b/version index ca7a1ec9c..325da8275 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.33.11 +1.33.12 From 255f606ebf77f6885d420cdc80a04c8409e37ec4 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 7 Jul 2019 07:33:50 -0500 Subject: [PATCH 10/34] bump rpm specfile --- distros/redhat/zoneminder.spec | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index c8413d6a0..d064c3b94 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -23,7 +23,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.33.9 +Version: 1.33.12 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons @@ -411,6 +411,9 @@ EOF %dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload %changelog +* Sun Jul 07 2019 Andrew Bauer - 1.33.12-1 +- Bump to 1.33.12 Development + * Sun Jun 23 2019 Andrew Bauer - 1.33.9-1 - Bump to 1.33.9 Development From 0f35d86efbdec059eda5ccb1f1b12c59cb51af72 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Jul 2019 08:56:39 -0400 Subject: [PATCH 11/34] implement zm_send_frame which sends a frame and receives a packet --- src/zm_ffmpeg.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/zm_ffmpeg.h | 4 +++- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 139ab5838..4ee6e6707 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -539,6 +539,45 @@ int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet) return 0; } // end int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet) +int zm_send_frame(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) { + int ret; + #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + if ( (ret = avcodec_send_frame(ctx, frame)) < 0 ) { + Error("Could not send frame (error '%s')", + av_make_error_string(ret).c_str()); + zm_av_packet_unref(&packet); + return 0; + } + + if ( (ret = avcodec_receive_packet(ctx, &packet)) < 0 ) { + if ( AVERROR(EAGAIN) == ret ) { + // The codec may need more samples than it has, perfectly valid + Debug(2, "Codec not ready to give us a packet"); + } else { + Error("Could not recieve packet (error %d = '%s')", ret, + av_make_error_string(ret).c_str()); + } + zm_av_packet_unref(&packet); + return 0; + } + #else + int data_present; + if ( (ret = avcodec_encode_audio2( + ctx, &packet, frame, &data_present)) < 0 ) { + Error("Could not encode frame (error '%s')", + av_make_error_string(ret).c_str()); + zm_av_packet_unref(&packet); + return 0; + } + if ( !data_present ) { + Debug(2, "Not ready to out a frame yet."); + zm_av_packet_unref(&packet); + return 0; + } + #endif + return 1; +} // wend zm_send_frame + void dumpPacket(AVStream *stream, AVPacket *pkt, const char *text) { char b[10240]; diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index e3b8314f8..18e018e26 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -332,7 +332,9 @@ bool is_audio_stream(AVStream *); bool is_video_context(AVCodec *); bool is_audio_context(AVCodec *); -int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ); +int zm_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet); +int zm_send_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet); + void dumpPacket(AVStream *, AVPacket *,const char *text=""); void dumpPacket(AVPacket *,const char *text=""); #endif // ZM_FFMPEG_H From 94cc85aa36908d42f2cd2faa7038cf0a5fda4819 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Jul 2019 08:57:22 -0400 Subject: [PATCH 12/34] Sorta fix pts on encoded audio packets. Sync is off, but at least it is close --- src/zm_ffmpeg_camera.cpp | 4 +- src/zm_videostore.cpp | 110 ++++++++++++++++++--------------------- 2 files changed, 54 insertions(+), 60 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 0eac0e49d..b96142aab 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -466,8 +466,8 @@ int FfmpegCamera::OpenFfmpeg() { } else { Debug(1, "decoder %s hwConfig doesn't match our type: %s, pix_fmt %s.", mVideoCodec->name, - av_hwdevice_get_type_name(config-device_type), - av_get_pix_fmt_name(config->pix_fmt); + av_hwdevice_get_type_name(config->device_type), + av_get_pix_fmt_name(config->pix_fmt) ); } } // end foreach hwconfig diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index bd4f47a2f..5ffec165b 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -1030,13 +1030,15 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } zm_dump_frame(out_frame, "Out frame after resample"); +#if 0 // out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder if ( out_frame->pts != AV_NOPTS_VALUE ) { if ( !audio_first_pts ) { audio_first_pts = out_frame->pts; - Debug(1, "No video_first_pts setting to %" PRId64, audio_first_pts); + Debug(1, "No audio_first_pts setting to %" PRId64, audio_first_pts); out_frame->pts = 0; } else { + // out_frame_pts is in codec->timebase, audio_first_pts is in packet timebase. out_frame->pts = out_frame->pts - audio_first_pts; zm_dump_frame(out_frame, "Out frame after pts adjustment"); } @@ -1046,55 +1048,55 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { out_frame->pts = audio_next_pts; } audio_next_pts = out_frame->pts + out_frame->nb_samples; +#endif av_init_packet(&opkt); - #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( (ret = avcodec_send_frame(audio_out_ctx, out_frame)) < 0 ) { - Error("Could not send frame (error '%s')", - av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); + if ( !zm_send_frame(audio_out_ctx, out_frame, opkt) ) { return 0; } - if ( (ret = avcodec_receive_packet(audio_out_ctx, &opkt)) < 0 ) { - if ( AVERROR(EAGAIN) == ret ) { - // The codec may need more samples than it has, perfectly valid - Debug(2, "Codec not ready to give us a packet"); - } else { - Error("Could not recieve packet (error %d = '%s')", ret, - av_make_error_string(ret).c_str()); - } - zm_av_packet_unref(&opkt); - return 0; - } - #else - int data_present; - if ( (ret = avcodec_encode_audio2( - audio_out_ctx, &opkt, out_frame, &data_present)) < 0 ) { - Error("Could not encode frame (error '%s')", - av_make_error_string(ret).c_str()); - zm_av_packet_unref(&opkt); - return 0; - } - if ( !data_present ) { - Debug(2, "Not ready to out a frame yet."); - zm_av_packet_unref(&opkt); - return 0; - } - #endif -#if 0 - // These should be set by encoder. They may not directly relate to ipkt due to buffering in codec. - opkt.duration = av_rescale_q(opkt.duration, - audio_in_stream->time_base, - audio_out_stream->time_base); - opkt.pts = av_rescale_q(opkt.pts, - audio_in_stream->time_base, - audio_out_stream->time_base); - opkt.dts = av_rescale_q(opkt.dts, - audio_in_stream->time_base, - audio_out_stream->time_base); -#endif dumpPacket(audio_out_stream, &opkt, "raw opkt"); + opkt.duration = av_rescale_q( + opkt.duration, + audio_out_ctx->time_base, + audio_out_stream->time_base); + // Scale the PTS of the outgoing packet to be the correct time base + if ( ipkt->pts != AV_NOPTS_VALUE ) { + if ( !audio_first_pts ) { + opkt.pts = 0; + audio_first_pts = ipkt->pts; + Debug(1, "No audio_first_pts"); + } else { + opkt.pts = av_rescale_q( + opkt.pts, + audio_out_ctx->time_base, + audio_out_stream->time_base); + opkt.pts -= audio_first_pts; + Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")", + opkt.pts, ipkt->pts, audio_first_pts); + } + } else { + Debug(2, "opkt.pts = undef"); + opkt.pts = AV_NOPTS_VALUE; + } + + if ( opkt.dts != AV_NOPTS_VALUE ) { + if ( !audio_first_dts ) { + opkt.dts = 0; + audio_first_dts = opkt.dts; + } else { + opkt.dts = av_rescale_q( + opkt.dts, + audio_out_ctx->time_base, + audio_out_stream->time_base); + opkt.dts -= audio_first_dts; + Debug(2, "opkt.dts = %" PRId64 " from ipkt.dts(%" PRId64 ") - first_dts(%" PRId64 ")", + opkt.dts, ipkt->dts, audio_first_dts); + } + audio_last_dts = opkt.dts; + } else { + opkt.dts = AV_NOPTS_VALUE; + } } else { Debug(2,"copying"); @@ -1128,16 +1130,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } if ( ipkt->dts != AV_NOPTS_VALUE ) { - // So if the in has no dts assigned... still need an out dts... so we use cur_dts? - -#if 0 - if ( audio_last_dts >= audio_in_stream->cur_dts ) { - Debug(1, "Resetting audio_last_dts from (%d) to cur_dts (%d)", audio_last_dts, audio_in_stream->cur_dts); - opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); - } else { - opkt.dts = audio_next_dts + av_rescale_q( audio_in_stream->cur_dts - audio_last_dts, AV_TIME_BASE_Q, audio_out_stream->time_base); - } -#endif if ( !audio_first_dts ) { opkt.dts = 0; audio_first_dts = ipkt->dts; @@ -1251,15 +1243,17 @@ int VideoStore::resample_audio() { } out_frame->nb_samples = frame_size; // resampling changes the duration because the timebase is 1/samples + // I think we should be dealing in codec timebases not stream if ( in_frame->pts != AV_NOPTS_VALUE ) { out_frame->pkt_duration = av_rescale_q( in_frame->pkt_duration, - audio_in_stream->time_base, - audio_out_stream->time_base); + audio_in_ctx->time_base, + audio_out_ctx->time_base); out_frame->pts = av_rescale_q( in_frame->pts, - audio_in_stream->time_base, - audio_out_stream->time_base); + audio_in_ctx->time_base, + audio_out_ctx->time_base); + zm_dump_frame(out_frame, "Out frame after timestamp conversion"); } #else #if defined(HAVE_LIBAVRESAMPLE) From 3c1cd1e7501caa40fbaf6949c710a9c0c70c2c63 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Jul 2019 16:03:54 -0400 Subject: [PATCH 13/34] rename var from nevents to nFrames because that's what they are. Fix an error when page=0 --- web/skins/classic/views/frames.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index 9a877ae3b..ea8b181a1 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -28,7 +28,6 @@ require_once('includes/Frame.php'); $countSql = 'SELECT COUNT(*) AS FrameCount FROM Frames AS F WHERE 1 '; $frameSql = 'SELECT *, unix_timestamp( TimeStamp ) AS UnixTimeStamp FROM Frames AS F WHERE 1 '; -$eid = $_REQUEST['eid']; // override the sort_field handling in parseSort for frames if ( empty($_REQUEST['sort_field']) ) @@ -59,6 +58,7 @@ if ( $_REQUEST['filter']['sql'] ) { $frameSql .= " ORDER BY $sortColumn $sortOrder,Id $sortOrder"; +$eid = validInt($_REQUEST['eid']); $Event = new ZM\Event($eid); $Monitor = $Event->Monitor(); @@ -75,22 +75,22 @@ if ( isset( $_REQUEST['scale'] ) ) { $page = isset($_REQUEST['page']) ? validInt($_REQUEST['page']) : 1; $limit = isset($_REQUEST['limit']) ? validInt($_REQUEST['limit']) : 0; -$nEvents = dbFetchOne($countSql, 'FrameCount' ); +$nFrames = dbFetchOne($countSql, 'FrameCount' ); -if ( !empty($limit) && $nEvents > $limit ) { - $nEvents = $limit; +if ( !empty($limit) && ($nFrames > $limit) ) { + $nFrames = $limit; } -$pages = (int)ceil($nEvents/ZM_WEB_EVENTS_PER_PAGE); +$pages = (int)ceil($nFrames/ZM_WEB_EVENTS_PER_PAGE); if ( !empty($page) ) { - if ( $page < 0 ) + if ( $page <= 0 ) $page = 1; else if ( $pages and ( $page > $pages ) ) $page = $pages; $limitStart = (($page-1)*ZM_WEB_EVENTS_PER_PAGE); - if ( empty( $limit ) ) { + if ( empty($limit) ) { $limitAmount = ZM_WEB_EVENTS_PER_PAGE; } else { $limitLeft = $limit - $limitStart; @@ -104,7 +104,7 @@ if ( !empty($page) ) { $maxShortcuts = 5; $pagination = getPagination($pages, $page, $maxShortcuts, $sortQuery.'&eid='.$eid.$limitQuery.$filterQuery); -$frames = dbFetchAll( $frameSql ); +$frames = dbFetchAll($frameSql); $focusWindow = true; From 4b41655dc5cf96475c85a7773a0ed26c50ae6fce Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Jul 2019 16:10:53 -0400 Subject: [PATCH 14/34] fix --- web/skins/classic/views/frames.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/frames.php b/web/skins/classic/views/frames.php index ea8b181a1..80d99fe3c 100644 --- a/web/skins/classic/views/frames.php +++ b/web/skins/classic/views/frames.php @@ -24,6 +24,9 @@ if ( !canView('Events') ) { } require_once('includes/Frame.php'); +$eid = validInt($_REQUEST['eid']); +$Event = new ZM\Event($eid); +$Monitor = $Event->Monitor(); $countSql = 'SELECT COUNT(*) AS FrameCount FROM Frames AS F WHERE 1 '; $frameSql = 'SELECT *, unix_timestamp( TimeStamp ) AS UnixTimeStamp FROM Frames AS F WHERE 1 '; @@ -58,9 +61,6 @@ if ( $_REQUEST['filter']['sql'] ) { $frameSql .= " ORDER BY $sortColumn $sortOrder,Id $sortOrder"; -$eid = validInt($_REQUEST['eid']); -$Event = new ZM\Event($eid); -$Monitor = $Event->Monitor(); if ( isset( $_REQUEST['scale'] ) ) { $scale = validNum($_REQUEST['scale']); From b84e3499f4598e86c80b213543db71802266c548 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Jul 2019 17:25:49 -0400 Subject: [PATCH 15/34] Implement code to auto-load monitor status info if not already loaded. Check for Connected instead of Capturing in watch to display warning message --- web/includes/Monitor.php | 25 ++++++++++++++++++------- web/skins/classic/views/watch.php | 2 +- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/web/includes/Monitor.php b/web/includes/Monitor.php index 75c432c09..c46048716 100644 --- a/web/includes/Monitor.php +++ b/web/includes/Monitor.php @@ -105,6 +105,7 @@ private $defaults = array( 'DefaultCodec' => 'auto', ); private $status_fields = array( + 'Status' => null, 'AnalysisFPS' => null, 'CaptureFPS' => null, 'CaptureBandwidth' => null, @@ -271,17 +272,27 @@ private $control_fields = array( return $this->{$fn}; #array_unshift($args, $this); #call_user_func_array( $this->{$fn}, $args); - } else { - if ( array_key_exists($fn, $this->control_fields) ) { + } else if ( array_key_exists($fn, $this->control_fields) ) { return $this->control_fields{$fn}; - } else if ( array_key_exists( $fn, $this->defaults ) ) { + } else if ( array_key_exists( $fn, $this->defaults ) ) { return $this->defaults{$fn}; + } else if ( array_key_exists( $fn, $this->status_fields) ) { + $sql = 'SELECT Status,CaptureFPS,AnalysisFPS,CaptureBandwidth + FROM Monitor_Status WHERE MonitorId=?'; + $row = dbFetchOne($sql, NULL, array($this->{'Id'})); + if ( !$row ) { + Error("Unable to load Monitor record for Id=" . $this->{'Id'}); } else { - $backTrace = debug_backtrace(); - $file = $backTrace[1]['file']; - $line = $backTrace[1]['line']; - Warning( "Unknown function call Monitor->$fn from $file:$line" ); + foreach ($row as $k => $v) { + $this->{$k} = $v; + } } + return $this->{$fn}; + } else { + $backTrace = debug_backtrace(); + $file = $backTrace[1]['file']; + $line = $backTrace[1]['line']; + Warning( "Unknown function call Monitor->$fn from $file:$line" ); } } diff --git a/web/skins/classic/views/watch.php b/web/skins/classic/views/watch.php index 0038f3016..4d2fa93d5 100644 --- a/web/skins/classic/views/watch.php +++ b/web/skins/classic/views/watch.php @@ -78,7 +78,7 @@ if ( canView('Control') && $monitor->Type() == 'Local' ) {
Status() != 'Capturing' ) { +if ( $monitor->Status() != 'Connected' ) { echo '
Monitor is not capturing. We will be unable to provide an image
'; } ?> From da5e8d19b8f5eb4f5c7241030b869a38bdf29267 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Jul 2019 17:54:45 -0400 Subject: [PATCH 16/34] Fix #2656 --- web/skins/classic/views/report_event_audit.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index c7517728e..b378dc43d 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -192,9 +192,8 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { ) ) ); + parseFilter($ZeroSize_filter); } - - ?> From 5b896b5e5ca57fe9780e852d570a31c7a5b2ecfb Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Jul 2019 14:16:57 -0400 Subject: [PATCH 17/34] Replace password('admin') with the resulting string because use of password is deprecated --- db/zm_create.sql.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 261a4368c..d1952f66a 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -749,7 +749,7 @@ insert into Storage VALUES (NULL, '@ZM_DIR_EVENTS@', 'Default', 'local', NULL, N -- -- Create a default admin user. -- -insert into Users VALUES (NULL,'admin',password('admin'),'',1,'View','Edit','Edit','Edit','Edit','Edit','Edit','','',0,1); +insert into Users VALUES (NULL,'admin','$2b$12$NHZsm6AM2f2LQVROriz79ul3D6DnmFiZC.ZK5eqbF.ZWfwH9bqUJ6','',1,'View','Edit','Edit','Edit','Edit','Edit','Edit','','',0,1); -- -- Add a sample filter to purge the oldest 100 events when the disk is 95% full From df8c46f0f0a26ae8b7a574533d6822835b9e9230 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Jul 2019 14:22:46 -0400 Subject: [PATCH 18/34] Fix #2657 --- web/skins/classic/views/report_event_audit.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/skins/classic/views/report_event_audit.php b/web/skins/classic/views/report_event_audit.php index b378dc43d..f3f508623 100644 --- a/web/skins/classic/views/report_event_audit.php +++ b/web/skins/classic/views/report_event_audit.php @@ -218,7 +218,7 @@ for( $monitor_i = 0; $monitor_i < count($displayMonitors); $monitor_i += 1 ) { '.count($FileMissing).'' : '0' ?> - '.count($FileMissing).'' : '0' ?> + '.count($ZeroSize).'' : '0' ?> Date: Mon, 8 Jul 2019 14:27:49 -0400 Subject: [PATCH 19/34] Fix #2655 --- web/includes/Event.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/web/includes/Event.php b/web/includes/Event.php index 07460a7ec..1b996a839 100644 --- a/web/includes/Event.php +++ b/web/includes/Event.php @@ -580,6 +580,9 @@ class Event { if ( file_exists( $this->Path().'/'.$this->DefaultVideo() ) ) { return true; } + if ( !defined('ZM_SERVER_ID') ) { + return false; + } $Storage= $this->Storage(); $Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server(); if ( $Server->Id() != ZM_SERVER_ID ) { @@ -624,6 +627,9 @@ class Event { if ( file_exists($this->Path().'/'.$this->DefaultVideo()) ) { return filesize($this->Path().'/'.$this->DefaultVideo()); } + if ( !defined('ZM_SERVER_ID') ) { + return false; + } $Storage= $this->Storage(); $Server = $Storage->ServerId() ? $Storage->Server() : $this->Monitor()->Server(); if ( $Server->Id() != ZM_SERVER_ID ) { From 288f2f3e8f1f91bfaec70c6597d4d0c06d078fae Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Jul 2019 17:56:22 -0400 Subject: [PATCH 20/34] Convert zm_dump_frame from a function to a define, this way we get line #'s from where we call zm_dump_frame instead of from the line in zm_ffmpeg where the function was. --- src/zm_ffmpeg.cpp | 19 ------------------- src/zm_ffmpeg.h | 31 ++++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 4ee6e6707..2ea1142bf 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -298,25 +298,6 @@ void zm_dump_video_frame(const AVFrame *frame, const char *text) { frame->pts ); } -void zm_dump_frame(const AVFrame *frame,const char *text) { - Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" - " duration %" PRId64 - " layout %d pts %" PRId64, - text, - frame->format, - av_get_sample_fmt_name((AVSampleFormat)frame->format), - frame->sample_rate, - frame->nb_samples, -#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) - frame->channels, - frame->pkt_duration, -#else -0, 0, -#endif - frame->channel_layout, - frame->pts - ); -} #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) void zm_dump_codecpar ( const AVCodecParameters *par ) { diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 18e018e26..7618a461b 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -299,7 +299,36 @@ void zm_dump_codec(const AVCodecContext *codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) void zm_dump_codecpar(const AVCodecParameters *par); #endif -void zm_dump_frame(const AVFrame *frame, const char *text="Frame"); +#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) +#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \ + " duration %" PRId64 \ + " layout %d pts %" PRId64,\ + text, \ + frame->format, \ + av_get_sample_fmt_name((AVSampleFormat)frame->format), \ + frame->sample_rate, \ + frame->nb_samples, \ + frame->channels, \ + frame->pkt_duration, \ + frame->channel_layout, \ + frame->pts \ + ); +#else +#define zm_dump_frame(frame, text) Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d" \ + " duration %" PRId64 \ + " layout %d pts %" PRId64, \ + text, \ + frame->format, \ + av_get_sample_fmt_name((AVSampleFormat)frame->format), \ + frame->sample_rate, \ + frame->nb_samples, \ + 0, 0, \ + frame->channel_layout, \ + frame->pts \ + ); + +#endif + void zm_dump_video_frame(const AVFrame *frame, const char *text="Frame"); #if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) From 13c91bdf606568ae4b3ad1887c528c19c00329a9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Jul 2019 17:56:53 -0400 Subject: [PATCH 21/34] Add pts adjustment to the delayed flushed encoder packets --- src/zm_videostore.cpp | 74 +++++++++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 5ffec165b..355578ffc 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -476,7 +476,51 @@ VideoStore::~VideoStore() { break; } #endif + + // Need to adjust pts and dts and duration + pkt.stream_index = audio_out_stream->index; + + pkt.duration = av_rescale_q( + pkt.duration, + audio_out_ctx->time_base, + audio_out_stream->time_base); + // Scale the PTS of the outgoing packet to be the correct time base + if ( pkt.pts != AV_NOPTS_VALUE ) { + pkt.pts = av_rescale_q( + pkt.pts, + audio_out_ctx->time_base, + audio_in_stream->time_base); + // audio_first_pts is in audio_in_stream time base + pkt.pts -= audio_first_pts; + pkt.pts = av_rescale_q( + pkt.pts, + audio_in_stream->time_base, + audio_out_stream->time_base); + + Debug(2, "audio pkt.pts = %" PRId64 " from first_pts(%" PRId64 ")", + pkt.pts, audio_first_pts); + } else { + Debug(2, "pkt.pts = undef"); + pkt.pts = AV_NOPTS_VALUE; + } + + if ( pkt.dts != AV_NOPTS_VALUE ) { + pkt.dts = av_rescale_q( + pkt.dts, + audio_out_ctx->time_base, + audio_in_stream->time_base); + pkt.dts -= audio_first_dts; + pkt.dts = av_rescale_q( + pkt.dts, + audio_in_ctx->time_base, + audio_out_stream->time_base); + Debug(2, "pkt.dts = %" PRId64 " - first_dts(%" PRId64 ")", + pkt.dts, audio_first_dts); + } else { + pkt.dts = AV_NOPTS_VALUE; + } + dumpPacket(audio_out_stream, &pkt, "writing flushed packet"); av_interleaved_write_frame(oc, &pkt); zm_av_packet_unref(&pkt); @@ -1196,28 +1240,9 @@ int VideoStore::resample_audio() { av_make_error_string(ret).c_str()); return 0; } - zm_dump_frame(out_frame, "Out frame after convert"); - -#if 0 - // out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder - if ( out_frame->pts != AV_NOPTS_VALUE ) { - if ( !video_first_pts ) { - video_first_pts = out_frame->pts; - Debug(1, "No video_first_pts setting to %" PRId64, video_first_pts); - out_frame->pts = 0; - } else { - out_frame->pts = out_frame->pts - video_first_pts; - } - // - } else { - // sending AV_NOPTS_VALUE doesn't really work but we seem to get it in ffmpeg 2.8 - out_frame->pts = audio_next_pts; - } - audio_next_pts = out_frame->pts + out_frame->nb_samples; -#endif - - if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples)) < 0) { + ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples); + if ( ret < 0 ) { Error("Could not reallocate FIFO"); return 0; } @@ -1232,7 +1257,7 @@ int VideoStore::resample_audio() { // Reset frame_size to output_frame_size int frame_size = audio_out_ctx->frame_size; - // AAC requires 1024 samples per encode. Our input tends to be 160, so need to buffer them. + // AAC requires 1024 samples per encode. Our input tends to be something else, so need to buffer them. if ( frame_size > av_audio_fifo_size(fifo) ) { return 0; } @@ -1245,10 +1270,11 @@ int VideoStore::resample_audio() { // resampling changes the duration because the timebase is 1/samples // I think we should be dealing in codec timebases not stream if ( in_frame->pts != AV_NOPTS_VALUE ) { + // pkt_duration is in avstream timebase units out_frame->pkt_duration = av_rescale_q( in_frame->pkt_duration, - audio_in_ctx->time_base, - audio_out_ctx->time_base); + audio_in_stream->time_base, + audio_out_stream->time_base); out_frame->pts = av_rescale_q( in_frame->pts, audio_in_ctx->time_base, From 05be9008c76553cee28be56927c5250ad8f0b87d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Jul 2019 17:57:11 -0400 Subject: [PATCH 22/34] use FFMPEGInit to initialise ffmpeg instead of doing it ourselves --- src/zm_ffmpeg_input.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zm_ffmpeg_input.cpp b/src/zm_ffmpeg_input.cpp index 5cca6b35b..03d89348d 100644 --- a/src/zm_ffmpeg_input.cpp +++ b/src/zm_ffmpeg_input.cpp @@ -7,8 +7,7 @@ FFmpeg_Input::FFmpeg_Input() { input_format_context = NULL; video_stream_id = -1; audio_stream_id = -1; - av_register_all(); - avcodec_register_all(); + FFMPEGInit(); streams = NULL; frame = NULL; } From 52e7cde66d3802fd46d5afc611768444ab44e913 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 11 Jul 2019 19:04:51 -0400 Subject: [PATCH 23/34] If Email has EIMOD, not only attach the image if it exists, but replace %EIMOD% with the link to it --- scripts/zmfilter.pl.in | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/zmfilter.pl.in b/scripts/zmfilter.pl.in index 6527742c8..b572d40fa 100644 --- a/scripts/zmfilter.pl.in +++ b/scripts/zmfilter.pl.in @@ -728,6 +728,7 @@ sub substituteTags { } if ( $text =~ s/%EIMOD%//g ) { + $text =~ s/%EIMOD%/$url?view=frame&mid=$Event->{MonitorId}&eid=$Event->{Id}&fid=objdetect/g; my $path = $Event->Path().'/objdetect.jpg'; if ( -e $path ) { push @$attachments_ref, { type=>'image/jpeg', path=>$path }; From 67168a23870ea1e9749640ec6b30f8fc6aea963e Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Fri, 12 Jul 2019 14:31:39 -0400 Subject: [PATCH 24/34] demote token log (#2663) --- src/zm_user.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 35f25f7c9..0c8142374 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -193,7 +193,7 @@ User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { } Debug (1,"Got stored expiry time of %u",stored_iat); - Info ("Authenticated user '%s' via token", username.c_str()); + Debug (1,"Authenticated user '%s' via token", username.c_str()); mysql_free_result(result); return user; From ef9fe2dbd62b68ec190e9882c11ec2a0e3b43214 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 17 Jul 2019 10:06:30 -0400 Subject: [PATCH 25/34] Free up hwFrame, preventing memleak --- src/zm_ffmpeg_camera.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index b96142aab..87b53c1d6 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -137,6 +137,7 @@ FfmpegCamera::FfmpegCamera( hwaccel = false; hwFrame = NULL; + hw_device_ctx = NULL; mFormatContext = NULL; mVideoStreamId = -1; @@ -648,6 +649,10 @@ int FfmpegCamera::Close() { av_frame_free(&mRawFrame); mRawFrame = NULL; } + if ( hwFrame ) { + av_frame_free(&hwFrame); + hwFrame = NULL; + } #if HAVE_LIBSWSCALE if ( mConvertContext ) { @@ -675,6 +680,12 @@ int FfmpegCamera::Close() { #endif mAudioCodecContext = NULL; // Freed by av_close_input_file } +#if 0 + if ( hw_device_ctx ) { + hwdevice_ctx_free + } +#endif + if ( mFormatContext ) { #if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) From 75af3972239f746ffca58ea185e47e341e68083f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 17 Jul 2019 20:33:23 -0400 Subject: [PATCH 26/34] hwFrame isn't defined unless we have HWCONTEXT_H --- src/zm_ffmpeg_camera.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 87b53c1d6..d5a02ddb7 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -649,10 +649,12 @@ int FfmpegCamera::Close() { av_frame_free(&mRawFrame); mRawFrame = NULL; } +#if HAVE_LIBAVUTIL_HWCONTEXT_H if ( hwFrame ) { av_frame_free(&hwFrame); hwFrame = NULL; } +#endif #if HAVE_LIBSWSCALE if ( mConvertContext ) { From 2b7610a5acf1588c54affbda7bf8364b3dbf45d5 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Wed, 17 Jul 2019 20:37:27 -0400 Subject: [PATCH 27/34] fixed ffmpeg log association to zm log levels (#2664) --- src/zm_ffmpeg.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 2ea1142bf..1df9b7718 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -73,14 +73,14 @@ static bool bInit = false; void FFMPEGInit() { if ( !bInit ) { - if ( logDebugging() ) + if ( logDebugging() && config.log_ffmpeg ) { av_log_set_level( AV_LOG_DEBUG ); - else + av_log_set_callback(log_libav_callback); + Info("Enabling ffmpeg logs, as LOG_DEBUG+LOG_FFMPEG are enabled in options"); + } else { + Info("Not enabling ffmpeg logs, as LOG_FFMPEG and/or LOG_DEBUG is disabled in options, or this monitor not part of your debug targets"); av_log_set_level( AV_LOG_QUIET ); - if ( config.log_ffmpeg ) - av_log_set_callback(log_libav_callback); - else - Info("Not enabling ffmpeg logs, as LOG_FFMPEG is disabled in options"); + } #if LIBAVFORMAT_VERSION_CHECK(58, 9, 0, 64, 0) #else av_register_all(); From a9d01ba3d2035fd2032fcc2311025c19f3a90685 Mon Sep 17 00:00:00 2001 From: Pliable Pixels Date: Wed, 17 Jul 2019 20:38:58 -0400 Subject: [PATCH 28/34] Alarm api (#2665) * fixed alarm api to use tokens if present * clearer debug logs for tokens * space --- src/zm_user.cpp | 5 +++-- web/api/app/Controller/MonitorsController.php | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/zm_user.cpp b/src/zm_user.cpp index 0c8142374..b873b8547 100644 --- a/src/zm_user.cpp +++ b/src/zm_user.cpp @@ -157,6 +157,7 @@ User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { std::pair ans = verifyToken(jwt_token_str, key); std::string username = ans.first; unsigned int iat = ans.second; + Debug (1,"retrieved user '%s' from token", username.c_str()); if (username != "") { char sql[ZM_SQL_MED_BUFSIZ] = ""; @@ -178,7 +179,7 @@ User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { if ( n_users != 1 ) { mysql_free_result(result); - Error("Unable to authenticate user %s", username.c_str()); + Error("Unable to authenticate user '%s'", username.c_str()); return NULL; } @@ -188,7 +189,7 @@ User *zmLoadTokenUser (std::string jwt_token_str, bool use_remote_addr ) { if (stored_iat > iat ) { // admin revoked tokens mysql_free_result(result); - Error("Token was revoked for %s", username.c_str()); + Error("Token was revoked for '%s'", username.c_str()); return NULL; } diff --git a/web/api/app/Controller/MonitorsController.php b/web/api/app/Controller/MonitorsController.php index f83aecf97..0686232df 100644 --- a/web/api/app/Controller/MonitorsController.php +++ b/web/api/app/Controller/MonitorsController.php @@ -254,6 +254,7 @@ class MonitorsController extends AppController { throw new BadRequestException(__('Invalid command')); } $zm_path_bin = Configure::read('ZM_PATH_BIN'); + $mToken = $this->request->query('token') ? $this->request->query('token') : null; switch ($cmd) { case 'on': @@ -281,8 +282,12 @@ class MonitorsController extends AppController { $zmAuthRelay = $config['Config']['Value']; $auth = ''; + if ( $zmOptAuth ) { - if ( $zmAuthRelay == 'hashed' ) { + if ($mToken) { + $auth = ' -T '.$mToken; + } + elseif ( $zmAuthRelay == 'hashed' ) { $options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_SECRET')); $config = $this->Config->find('first', $options); $zmAuthHashSecret = $config['Config']['Value']; From 542d88b6a4abf4955e2540615d07a97adb2198d6 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 17 Jul 2019 21:10:24 -0400 Subject: [PATCH 29/34] fix compile without HWCONTEXT --- src/zm_ffmpeg_camera.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index d5a02ddb7..f0f6a3b1d 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -136,8 +136,6 @@ FfmpegCamera::FfmpegCamera( } hwaccel = false; - hwFrame = NULL; - hw_device_ctx = NULL; mFormatContext = NULL; mVideoStreamId = -1; @@ -155,6 +153,8 @@ FfmpegCamera::FfmpegCamera( packetqueue = NULL; error_count = 0; #if HAVE_LIBAVUTIL_HWCONTEXT_H + hwFrame = NULL; + hw_device_ctx = NULL; hw_pix_fmt = AV_PIX_FMT_NONE; #endif From f3166663a5eb0a224e46f7a638c295f8f591da53 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Jul 2019 12:51:31 -0400 Subject: [PATCH 30/34] unref hw_device_ctx on Close. I think this should release all the other hwaccel related stuff --- src/zm_ffmpeg_camera.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index f0f6a3b1d..8c61dfcff 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -682,13 +682,13 @@ int FfmpegCamera::Close() { #endif mAudioCodecContext = NULL; // Freed by av_close_input_file } -#if 0 + +#if HAVE_LIBAVUTIL_HWCONTEXT_H if ( hw_device_ctx ) { - hwdevice_ctx_free + av_buffer_unref(&hw_device_ctx); } #endif - if ( mFormatContext ) { #if !LIBAVFORMAT_VERSION_CHECK(53, 17, 0, 25, 0) av_close_input_file(mFormatContext); From 9a31f8792cdf546e588f8af9ef6f809699dd4066 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Jul 2019 13:55:35 -0400 Subject: [PATCH 31/34] return proper error codes when failed auth or fail permissions --- src/zms.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/zms.cpp b/src/zms.cpp index 5e6e4c2d6..c78dba1d2 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -43,9 +43,8 @@ bool ValidateAccess( User *user, int mon_id ) { allowed = false; } if ( !allowed ) { - Error( "Error, insufficient privileges for requested action user %d %s for monitor %d", - user->Id(), user->getUsername(), mon_id ); - exit( -1 ); + Error("Error, insufficient privileges for requested action user %d %s for monitor %d", + user->Id(), user->getUsername(), mon_id); } return allowed; } @@ -164,8 +163,7 @@ int main( int argc, const char *argv[] ) { strncpy( auth, value, sizeof(auth)-1 ); } else if ( !strcmp( name, "token" ) ) { jwt_token_str = value; - Debug(1,"ZMS: JWT token found: %s", jwt_token_str.c_str()); - + Debug(1, "ZMS: JWT token found: %s", jwt_token_str.c_str()); } else if ( !strcmp( name, "user" ) ) { username = UriDecode( value ); } else if ( !strcmp( name, "pass" ) ) { @@ -184,17 +182,15 @@ int main( int argc, const char *argv[] ) { } else { snprintf(log_id_string, sizeof(log_id_string), "zms_e%" PRIu64, event_id); } - logInit( log_id_string ); + logInit(log_id_string); if ( config.opt_use_auth ) { User *user = 0; - if (jwt_token_str != "") { + if ( jwt_token_str != "" ) { //user = zmLoadTokenUser(jwt_token_str, config.auth_hash_ips); user = zmLoadTokenUser(jwt_token_str, false); - - } - else if ( strcmp(config.auth_relay, "none") == 0 ) { + } else if ( strcmp(config.auth_relay, "none") == 0 ) { if ( checkUser(username.c_str()) ) { user = zmLoadUser(username.c_str()); } else { @@ -216,21 +212,27 @@ int main( int argc, const char *argv[] ) { } } if ( !user ) { + fprintf(stdout, "HTTP/1.0 401 Unauthorized\r\n"); Error("Unable to authenticate user"); logTerm(); zmDbClose(); return -1; } - ValidateAccess(user, monitor_id); + if ( !ValidateAccess(user, monitor_id) ) { + fprintf(stdout, "HTTP/1.0 403 Forbidden\r\n"); + logTerm(); + zmDbClose(); + return -1; + } } // end if config.opt_use_auth hwcaps_detect(); zmSetDefaultTermHandler(); zmSetDefaultDieHandler(); - setbuf( stdout, 0 ); + setbuf(stdout, 0); if ( nph ) { - fprintf( stdout, "HTTP/1.0 200 OK\r\n" ); + fprintf(stdout, "HTTP/1.0 200 OK\r\n"); } fprintf( stdout, "Server: ZoneMinder Video Server/%s\r\n", ZM_VERSION ); From 1e0c39c632e390c2d49ea965dc7f41176f0c27f0 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Jul 2019 16:28:18 -0400 Subject: [PATCH 32/34] mostly spacing cleanups. Don't bother setting pkt_duration on resampled frame --- src/zm_videostore.cpp | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 355578ffc..563c06be8 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -308,7 +308,6 @@ VideoStore::VideoStore( #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) audio_out_stream = avformat_new_stream(oc, NULL); - audio_out_stream->time_base = audio_in_stream->time_base; audio_out_ctx = avcodec_alloc_context3(audio_out_codec); if ( !audio_out_ctx ) { Error("could not allocate codec ctx for AAC"); @@ -1061,8 +1060,8 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { dumpPacket(audio_in_stream, ipkt, "input packet"); if ( audio_out_codec ) { - Debug(2, "Have output codec"); if ( ( ret = zm_receive_frame(audio_in_ctx, in_frame, *ipkt) ) < 0 ) { + Debug(3, "Not ready to receive frame"); return 0; } @@ -1100,10 +1099,11 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } dumpPacket(audio_out_stream, &opkt, "raw opkt"); - opkt.duration = av_rescale_q( - opkt.duration, - audio_out_ctx->time_base, - audio_out_stream->time_base); + + opkt.duration = av_rescale_q( + opkt.duration, + audio_out_ctx->time_base, + audio_out_stream->time_base); // Scale the PTS of the outgoing packet to be the correct time base if ( ipkt->pts != AV_NOPTS_VALUE ) { if ( !audio_first_pts ) { @@ -1116,8 +1116,8 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { audio_out_ctx->time_base, audio_out_stream->time_base); opkt.pts -= audio_first_pts; - Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")", - opkt.pts, ipkt->pts, audio_first_pts); + Debug(2, "audio opkt.pts = %" PRId64 " from first_pts %" PRId64, + opkt.pts, audio_first_pts); } } else { Debug(2, "opkt.pts = undef"); @@ -1134,8 +1134,8 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { audio_out_ctx->time_base, audio_out_stream->time_base); opkt.dts -= audio_first_dts; - Debug(2, "opkt.dts = %" PRId64 " from ipkt.dts(%" PRId64 ") - first_dts(%" PRId64 ")", - opkt.dts, ipkt->dts, audio_first_dts); + Debug(2, "opkt.dts = %" PRId64 " from first_dts %" PRId64, + opkt.dts, audio_first_dts); } audio_last_dts = opkt.dts; } else { @@ -1270,17 +1270,12 @@ int VideoStore::resample_audio() { // resampling changes the duration because the timebase is 1/samples // I think we should be dealing in codec timebases not stream if ( in_frame->pts != AV_NOPTS_VALUE ) { - // pkt_duration is in avstream timebase units - out_frame->pkt_duration = av_rescale_q( - in_frame->pkt_duration, - audio_in_stream->time_base, - audio_out_stream->time_base); out_frame->pts = av_rescale_q( in_frame->pts, audio_in_ctx->time_base, audio_out_ctx->time_base); - zm_dump_frame(out_frame, "Out frame after timestamp conversion"); } + zm_dump_frame(out_frame, "Out frame after timestamp conversion"); #else #if defined(HAVE_LIBAVRESAMPLE) ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, From fe71a9abaa97af6d005a9d492b2b2b1c023fd970 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 19 Jul 2019 16:32:40 -0400 Subject: [PATCH 33/34] php_errormsg is deprecated --- web/includes/functions.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/includes/functions.php b/web/includes/functions.php index e1016bb82..867861ffe 100644 --- a/web/includes/functions.php +++ b/web/includes/functions.php @@ -2459,11 +2459,13 @@ function do_post_request($url, $data, $optional_headers = null) { $ctx = stream_context_create($params); $fp = @fopen($url, 'rb', false, $ctx); if ( !$fp ) { - throw new Exception("Problem with $url, $php_errormsg"); + throw new Exception("Problem with $url, " + .print_r(error_get_last(),true)); } $response = @stream_get_contents($fp); if ( $response === false ) { - throw new Exception("Problem reading data from $url, $php_errormsg"); + throw new Exception("Problem reading data from $url, data: ".print_r($params,true) + .print_r(error_get_last(),true)); } return $response; } From df0aef89affbc8a0cb6e31bf5395a3f03892f255 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 23 Jul 2019 10:03:28 -0400 Subject: [PATCH 34/34] gracefully handle when window[fnName] doesn't exist --- web/skins/classic/js/skin.js | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/web/skins/classic/js/skin.js b/web/skins/classic/js/skin.js index d39062087..c29ef4a84 100644 --- a/web/skins/classic/js/skin.js +++ b/web/skins/classic/js/skin.js @@ -144,7 +144,7 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() { el.addEventListener("click", function onClick(evt) { var el = this; var url; - if (el.hasAttribute("href")) { + if ( el.hasAttribute("href") ) { // url = el.getAttribute("href"); } else { @@ -167,12 +167,20 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() { // 'data-on-click-this' calls the global function in the attribute value with the element when a click happens. document.querySelectorAll("a[data-on-click-this], button[data-on-click-this], input[data-on-click-this]").forEach(function attachOnClick(el) { var fnName = el.getAttribute("data-on-click-this"); + if ( !window[fnName] ) { + console.error("Nothing found to bind to " + fnName); + return; + } el.onclick = window[fnName].bind(el, el); }); // 'data-on-click' calls the global function in the attribute value with no arguments when a click happens. document.querySelectorAll("a[data-on-click], button[data-on-click], input[data-on-click]").forEach(function attachOnClick(el) { var fnName = el.getAttribute("data-on-click"); + if ( !window[fnName] ) { + console.error("Nothing found to bind to " + fnName); + return; + } el.onclick = function() { window[fnName](); }; @@ -181,6 +189,10 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() { // 'data-on-click-true' calls the global function in the attribute value with no arguments when a click happens. document.querySelectorAll("a[data-on-click-true], button[data-on-click-true], input[data-on-click-true]").forEach(function attachOnClick(el) { var fnName = el.getAttribute("data-on-click-true"); + if ( !window[fnName] ) { + console.error("Nothing found to bind to " + fnName); + return; + } el.onclick = function() { window[fnName](true); }; @@ -189,12 +201,20 @@ window.addEventListener("DOMContentLoaded", function onSkinDCL() { // 'data-on-change-this' calls the global function in the attribute value with the element when a change happens. document.querySelectorAll("select[data-on-change-this], input[data-on-change-this]").forEach(function attachOnChangeThis(el) { var fnName = el.getAttribute("data-on-change-this"); + if ( !window[fnName] ) { + console.error("Nothing found to bind to " + fnName); + return; + } el.onchange = window[fnName].bind(el, el); }); // 'data-on-change' adds an event listener for the global function in the attribute value when a change happens. document.querySelectorAll("select[data-on-change], input[data-on-change]").forEach(function attachOnChange(el) { var fnName = el.getAttribute("data-on-change"); + if ( !window[fnName] ) { + console.error("Nothing found to bind to " + fnName); + return; + } el.onchange = window[fnName]; }); });