From 0022dbfb765a5b862253bbc92dab008b0e5a72c9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 5 Mar 2019 14:31:39 -0500 Subject: [PATCH 01/40] add a newline to improve readability --- web/includes/csrf/csrf-magic.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/web/includes/csrf/csrf-magic.php b/web/includes/csrf/csrf-magic.php index 584432ef7..01122fed7 100644 --- a/web/includes/csrf/csrf-magic.php +++ b/web/includes/csrf/csrf-magic.php @@ -157,7 +157,8 @@ function csrf_ob_handler($buffer, $flags) { $input = ""; $buffer = preg_replace('#(]*method\s*=\s*["\']post["\'][^>]*>)#i', '$1' . $input, $buffer); if ($GLOBALS['csrf']['frame-breaker']) { - $buffer = str_ireplace('', '', $buffer); + $buffer = str_ireplace('', ' +', $buffer); } if ($js = $GLOBALS['csrf']['rewrite-js']) { $buffer = str_ireplace( @@ -165,7 +166,8 @@ function csrf_ob_handler($buffer, $flags) { ''. - '', + ' + ', $buffer ); $script = ''; From 7b7a58b2f1f7b35636a8e0876e48bedc8df760e4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 5 Mar 2019 14:33:03 -0500 Subject: [PATCH 02/40] remove old xhtml-isms --- web/skins/classic/includes/functions.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/web/skins/classic/includes/functions.php b/web/skins/classic/includes/functions.php index 201bebe21..b7ae819de 100644 --- a/web/skins/classic/includes/functions.php +++ b/web/skins/classic/includes/functions.php @@ -149,26 +149,18 @@ echo output_link_if_exists( array( if ( $skinJsPhpFile ) { ?> - + - + From 5a66969fd1e2a23d3349ba237be94722c72c1980 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 5 Mar 2019 14:34:34 -0500 Subject: [PATCH 03/40] change buttons from inputs to buttons. Add submit to montagereview. get rid of onclick handlers --- web/skins/classic/views/filter.php | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 9f95d8c58..2b9d495cd 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -293,8 +293,8 @@ for ( $i=0; $i < count($terms); $i++ ) { ?> 2 ) { echo htmlSelect("filter[Query][terms][$i][cbr]", $cbracketTypes, $term['cbr']); } else { ?>  - - /> + + AutoDelete() ) { ?> checked="checked" data-on-click-this="updateButtons"/>

- AutoMove() ) { ?> checked="checked" onclick="updateButtons(this);if(this.checked){$j(this.form.elements['filter[AutoMoveTo]']).css('display','inline');}else{this.form.elements['filter[AutoMoveTo]'].hide();};"/> - AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;' )); ?> + AutoMove() ) { ?> checked="checked" data-on-click-this="click_automove"/> + AutoMoveTo(), $filter->AutoMove() ? null : array('style'=>'display:none;')); ?>

@@ -406,7 +406,8 @@ if ( ZM_OPT_MESSAGE ) {


- + + Date: Tue, 5 Mar 2019 14:35:02 -0500 Subject: [PATCH 04/40] implement click_automove and submitToMontrageReview for onclick handlers --- web/skins/classic/views/js/filter.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index 3c2b561d6..bd9095763 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -63,6 +63,15 @@ function updateButtons(element) { } } +function click_automove(element) { + updateButtons(this); + if ( this.checked ) { + $j(this.form.elements['filter[AutoMoveTo]']).css('display','inline'); + } else { + this.form.elements['filter[AutoMoveTo]'].hide(); + } +} + function checkValue( element ) { var rows = $j(element).closest('tbody').children(); parseRows(rows); @@ -83,6 +92,11 @@ function submitToEvents( element ) { form.action = thisUrl + '?view=events'; history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); } +function submitToMontageReview( element ) { + var form = element.form; + form.action = thisUrl + '?view=montagereview'; + history.replaceState(null, null, '?view=filter&' + $j(form).serialize()); +} function executeFilter( element ) { var form = element.form; From c9985107ee45fac584a4be0e1414396a50e4c75e Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 1 Apr 2019 13:38:13 -0400 Subject: [PATCH 05/40] Add a deinit function to handle avformat_network_deinit --- src/zm_ffmpeg.cpp | 8 +++++++- src/zm_ffmpeg.h | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index b22ca6df5..5efbdb07a 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -65,8 +65,9 @@ void log_libav_callback( void *ptr, int level, const char *fmt, va_list vargs ) } } +static bool bInit = false; + void FFMPEGInit() { - static bool bInit = false; if ( !bInit ) { if ( logDebugging() ) @@ -86,6 +87,11 @@ void FFMPEGInit() { } } +void FFMPEGDeInit() { + avformat_network_deinit(); + bInit = false; +} + #if HAVE_LIBAVUTIL enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder) { enum _AVPIXELFORMAT pf; diff --git a/src/zm_ffmpeg.h b/src/zm_ffmpeg.h index 383de6af3..a4d984dec 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -199,6 +199,7 @@ extern "C" { /* A single function to initialize ffmpeg, to avoid multiple initializations */ void FFMPEGInit(); +void FFMPEGDeInit(); #if HAVE_LIBAVUTIL enum _AVPIXELFORMAT GetFFMPEGPixelFormat(unsigned int p_colours, unsigned p_subpixelorder); From a6998cbc9ebe4fff07484c0b60033446a708d8b4 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 1 Apr 2019 13:39:11 -0400 Subject: [PATCH 06/40] Use FFMPEGDeInit instead of avformat_network_deinit --- 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 5da4c0dc4..18ef7da12 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -168,7 +168,7 @@ FfmpegCamera::~FfmpegCamera() { if ( capture ) { Terminate(); } - avformat_network_deinit(); + FFMPEGDeInit(); } void FfmpegCamera::Initialise() { @@ -1034,7 +1034,7 @@ int FfmpegCamera::CaptureAndRecord( Image &image, timeval recording, char* event int FfmpegCamera::FfmpegInterruptCallback(void *ctx) { //FfmpegCamera* camera = reinterpret_cast(ctx); - Debug(4, "FfmpegInterruptCallback"); + //Debug(4, "FfmpegInterruptCallback"); return zm_terminate; } From cb33318c4ac53ee472a07d2847731da640cab64d Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 1 Apr 2019 14:02:39 -0400 Subject: [PATCH 07/40] fix invalid memory access due to incorrect opening/closing/copying of contexts --- src/zm_videostore.cpp | 59 +++++++++++++++++++++++++++---------------- src/zm_videostore.h | 17 ++++++++----- 2 files changed, 47 insertions(+), 29 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 5ae3404b7..4e0ee2eee 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -81,7 +81,7 @@ VideoStore::VideoStore( filename, format); return; } else { - Debug(4, "Success alocateing out ctx"); + Debug(4, "Success allocating out ctx"); } } // end if ! oc @@ -94,7 +94,7 @@ VideoStore::VideoStore( out_format = oc->oformat; - AVCodec *video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id); + video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id); if ( !video_out_codec ) { #if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) Fatal("Could not find encoder for '%s'", avcodec_get_name(video_out_ctx->codec_id)); @@ -112,9 +112,8 @@ VideoStore::VideoStore( } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - //video_out_stream->codec = avcodec_alloc_context3(video_out_codec); - // Since we are not re-encoding, all we have to do is copy the parameters video_out_ctx = avcodec_alloc_context3(video_out_codec); + // Since we are not re-encoding, all we have to do is copy the parameters // Copy params from instream to ctx ret = avcodec_parameters_to_context(video_out_ctx, video_in_stream->codecpar); if ( ret < 0 ) { @@ -230,7 +229,6 @@ VideoStore::VideoStore( #endif } - AVDictionary *opts = 0; if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { Warning("Can't open video codec (%s) %s", @@ -278,16 +276,14 @@ VideoStore::VideoStore( if ( audio_in_stream ) { Debug(3, "Have audio stream"); -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_in_ctx = avcodec_alloc_context3(NULL); - ret = avcodec_parameters_to_context(audio_in_ctx, - audio_in_stream->codecpar); - audio_in_ctx->time_base = audio_in_stream->time_base; -#else - audio_in_ctx = audio_in_stream->codec; -#endif - if ( audio_in_ctx->codec_id != AV_CODEC_ID_AAC ) { + if ( +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + audio_in_stream->codecpar->codec_id +#else + audio_in_stream->codec->codec_id +#endif + != AV_CODEC_ID_AAC ) { static char error_buffer[256]; avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); Debug(2, "Got something other than AAC (%s)", error_buffer); @@ -298,6 +294,15 @@ VideoStore::VideoStore( } else { Debug(2, "Got AAC"); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + audio_in_ctx = avcodec_alloc_context3(NULL); + ret = avcodec_parameters_to_context(audio_in_ctx, + audio_in_stream->codecpar); + audio_in_ctx->time_base = audio_in_stream->time_base; +#else + audio_in_ctx = audio_in_stream->codec; +#endif + audio_out_stream = #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec)); @@ -506,30 +511,39 @@ VideoStore::~VideoStore() { #endif video_in_ctx = NULL; + if ( video_out_codec ) { + avcodec_close(video_out_ctx); + Debug(4, "Success closing video_out_ctx"); + video_out_codec = NULL; + } // end if video_out_codec avcodec_close(video_out_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - //avcodec_free_context(&video_out_ctx); + avcodec_free_context(&video_out_ctx); #endif video_out_ctx = NULL; - Debug(4, "Success freeing video_out_ctx"); } // end if video_out_stream if ( audio_out_stream ) { if ( audio_in_codec ) { avcodec_close(audio_in_ctx); + Debug(4, "Success closing audio_in_ctx"); audio_in_codec = NULL; } // end if audio_in_codec #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it avcodec_free_context(&audio_in_ctx); + Debug(4, "Success freeing audio_in_ctx"); #endif audio_in_ctx = NULL; - avcodec_close(audio_out_ctx); + if ( audio_out_ctx ) { + avcodec_close(audio_out_ctx); + Debug(4, "Success closing audio_out_ctx"); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context(&audio_out_ctx); + avcodec_free_context(&audio_out_ctx); #endif + } audio_out_ctx = NULL; #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE) if ( resample_ctx ) { @@ -579,8 +593,11 @@ bool VideoStore::setup_resampler() { audio_in_codec = avcodec_find_decoder(audio_in_stream->codecpar->codec_id); #else - audio_in_codec = avcodec_find_decoder(audio_in_ctx->codec_id); +// codec is already open in ffmpeg_camera + audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id); #endif + audio_in_ctx = avcodec_alloc_context3(audio_in_codec); + if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { Error("Can't open in codec!"); return false; @@ -592,6 +609,7 @@ bool VideoStore::setup_resampler() { return false; } + audio_out_stream = avformat_new_stream(oc, audio_out_codec); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // audio_out_ctx = audio_out_stream->codec; audio_out_ctx = avcodec_alloc_context3(audio_out_codec); @@ -600,10 +618,7 @@ bool VideoStore::setup_resampler() { audio_out_stream = NULL; return false; } - - audio_out_stream = avformat_new_stream(oc, audio_out_codec); #else - audio_out_stream = avformat_new_stream(oc, NULL); audio_out_ctx = audio_out_stream->codec; #endif // Some formats (i.e. WAV) do not produce the proper channel layout diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 08cf01a42..1fe3fe81b 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -20,14 +20,16 @@ extern "C" { class VideoStore { private: - AVOutputFormat *out_format; - AVFormatContext *oc; - AVStream *video_out_stream; - AVStream *audio_out_stream; - AVCodecContext *video_out_ctx; + AVOutputFormat *out_format; + AVFormatContext *oc; - AVStream *video_in_stream; - AVStream *audio_in_stream; + AVCodec *video_out_codec; + AVCodecContext *video_out_ctx; + AVStream *video_out_stream; + + AVStream *video_in_stream; + + AVStream *audio_in_stream; // Move this into the object so that we aren't constantly allocating/deallocating it on the stack AVPacket opkt; @@ -41,6 +43,7 @@ private: int ret; // The following are used when encoding the audio stream to AAC + AVStream *audio_out_stream; AVCodec *audio_out_codec; AVCodecContext *audio_out_ctx; #ifdef HAVE_LIBSWRESAMPLE From f78e95f5d4dde01fa0fb1c83400fcde8e08b07ba Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 13:21:52 -0400 Subject: [PATCH 08/40] add is_video_context and is_audio_context and use them in zm_revceive_frame to add audio decoding support --- src/zm_ffmpeg.cpp | 36 ++++++++++++++++++++++++++++++------ src/zm_ffmpeg.h | 7 +++++-- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 5efbdb07a..011def0ee 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -285,7 +285,8 @@ static void zm_log_fps(double d, const char *postfix) { } void zm_dump_frame(const AVFrame *frame,const char *text) { - Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d layout %d pts %" PRId64, + Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d layout %d pts %" PRId64 + " duration %" PRId64, text, frame->format, av_get_sample_fmt_name((AVSampleFormat)frame->format), @@ -297,7 +298,8 @@ void zm_dump_frame(const AVFrame *frame,const char *text) { 0, #endif frame->channel_layout, - frame->pts + frame->pts, + frame->pkt_duration ); } @@ -450,6 +452,14 @@ bool is_video_stream( AVStream * stream ) { return false; } +bool is_video_context( AVCodecContext *codec_context ) { + return + #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) + ( codec_context->codec_type == AVMEDIA_TYPE_VIDEO ); + #else + ( codec_context->codec_type == CODEC_TYPE_VIDEO ); + #endif +} bool is_audio_stream( AVStream * stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -466,6 +476,15 @@ bool is_audio_stream( AVStream * stream ) { return false; } +bool is_audio_context( AVCodecContext *codec_context ) { + return + #if (LIBAVCODEC_VERSION_CHECK(52, 64, 0, 64, 0) || LIBAVUTIL_VERSION_CHECK(50, 14, 0, 14, 0)) + ( codec_context->codec_type == AVMEDIA_TYPE_AUDIO ); + #else + ( codec_context->codec_type == CODEC_TYPE_AUDIO ); + #endif +} + int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) { int ret; #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -500,15 +519,20 @@ int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet # else int frameComplete = 0; while ( !frameComplete ) { - if ( (ret = zm_avcodec_decode_video( context, frame, &frameComplete, &packet )) < 0 ) { - Error( "Unable to decode frame at frame: %s, continuing", - av_make_error_string(ret).c_str() ); + if ( is_video_context(context) ) { + ret = zm_avcodec_decode_video(context, frame, &frameComplete, &packet); + } else { + ret = avcodec_decode_audio4(context, frame, &frameComplete, &packet); + } + if ( ret < 0 ) { + Error("Unable to decode frame: %s", av_make_error_string(ret).c_str()); return 0; } - } + } // end while !frameComplete #endif return 1; } // end int zm_receive_frame( AVCodecContext *context, AVFrame *frame, AVPacket &packet ) + 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 a4d984dec..37a239509 100644 --- a/src/zm_ffmpeg.h +++ b/src/zm_ffmpeg.h @@ -326,8 +326,11 @@ void zm_dump_frame(const AVFrame *frame, const char *text="Frame"); int check_sample_fmt(AVCodec *codec, enum AVSampleFormat sample_fmt); -bool is_video_stream( AVStream * stream ); -bool is_audio_stream( AVStream * stream ); +bool is_video_stream(AVStream *); +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 ); void dumpPacket(AVStream *, AVPacket *,const char *text=""); #endif // ZM_FFMPEG_H From aece64049f7f91038f4a647fd849c630a82c2138 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 13:23:00 -0400 Subject: [PATCH 09/40] We cannot avcodec_open2 a context that has been duped. This code currently works without crashes and leaks on ffmpeg 2.8 --- src/zm_videostore.cpp | 457 ++++++++++++++++++++++-------------------- src/zm_videostore.h | 1 + 2 files changed, 237 insertions(+), 221 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 7d3c4b256..0d0c88765 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -103,6 +103,7 @@ VideoStore::VideoStore( #endif } +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) video_out_stream = avformat_new_stream(oc, video_out_codec); if ( !video_out_stream ) { Error("Unable to create video out stream"); @@ -111,7 +112,7 @@ VideoStore::VideoStore( Debug(2, "Success creating video out stream"); } -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // by allocating our own copy, we don't run into the problems when we free the streams video_out_ctx = avcodec_alloc_context3(video_out_codec); // Since we are not re-encoding, all we have to do is copy the parameters // Copy params from instream to ctx @@ -123,8 +124,21 @@ VideoStore::VideoStore( zm_dump_codec(video_out_ctx); } #else + video_out_stream = avformat_new_stream(oc, NULL); + if ( !video_out_stream ) { + Error("Unable to create video out stream"); + return; + } else { + Debug(2, "Success creating video out stream"); + } video_out_ctx = video_out_stream->codec; + // This will wipe out the codec defaults ret = avcodec_copy_context(video_out_ctx, video_in_ctx); + //video_out_ctx->width = video_in_ctx->width; + //video_out_ctx->height = video_in_ctx->height; + //video_out_ctx->pix_fmt = video_in_ctx->pix_fmt; + //video_out_ctx->max_b_frames = video_in_ctx->max_b_frames; + //video_out_ctx->has_b_frames = video_in_ctx->has_b_frames; if ( ret < 0 ) { Fatal("Unable to copy in video ctx to out video ctx %s", av_make_error_string(ret).c_str()); @@ -142,8 +156,7 @@ VideoStore::VideoStore( zm_dump_codec(video_out_ctx); - //video_out_ctx->bit_rate = 400*1024; - //video_out_ctx->thread_count = 0; +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) //// Fix deprecated formats switch ( video_out_ctx->pix_fmt ) { case AV_PIX_FMT_YUVJ422P : @@ -162,15 +175,6 @@ VideoStore::VideoStore( break; } - if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { - video_out_ctx->max_b_frames = 1; - if ( video_out_ctx->priv_data ) { - av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); - //av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); - } else { - Debug(2, "Not setting priv_data"); - } - } if ( !video_out_ctx->codec_tag ) { Debug(2, "No codec_tag"); @@ -185,6 +189,7 @@ VideoStore::VideoStore( video_out_ctx->codec_tag = video_in_ctx->codec_tag; } } +#endif video_out_stream->time_base = video_in_stream->time_base; if ( video_in_stream->avg_frame_rate.num ) { @@ -195,13 +200,26 @@ VideoStore::VideoStore( video_out_stream->avg_frame_rate = video_in_stream->avg_frame_rate; } if ( video_in_stream->r_frame_rate.num ) { - Debug(3,"Copying r_frame_rate (%d/%d)", + Debug(3,"Copying r_frame_rate (%d/%d) to out (%d/%d)", video_in_stream->r_frame_rate.num, - video_in_stream->r_frame_rate.den + video_in_stream->r_frame_rate.den , + video_out_stream->r_frame_rate.num, + video_out_stream->r_frame_rate.den ); video_out_stream->r_frame_rate = video_in_stream->r_frame_rate; } #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) + if ( video_out_ctx->codec_id == AV_CODEC_ID_H264 ) { + //video_out_ctx->level = 32;I// + video_out_ctx->bit_rate = 400*1024; + video_out_ctx->max_b_frames = 1; + if ( video_out_ctx->priv_data ) { + av_opt_set(video_out_ctx->priv_data, "crf", "1", AV_OPT_SEARCH_CHILDREN); + av_opt_set(video_out_ctx->priv_data, "preset", "ultrafast", 0); + } else { + Debug(2, "Not setting priv_data"); + } + } ret = avcodec_parameters_from_context(video_out_stream->codecpar, video_out_ctx); if ( ret < 0 ) { Error("Could not initialize video_out_ctx parameters"); @@ -229,6 +247,7 @@ VideoStore::VideoStore( #endif } +#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) AVDictionary *opts = 0; if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) { Warning("Can't open video codec (%s) %s", @@ -242,6 +261,7 @@ VideoStore::VideoStore( while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { Warning("Encoder Option %s not recognized by ffmpeg codec", e->key); } +#endif Monitor::Orientation orientation = monitor->getOrientation(); if ( orientation ) { @@ -273,6 +293,15 @@ VideoStore::VideoStore( fifo = NULL; #endif #endif + video_first_pts = 0; + video_first_dts = 0; + video_last_pts = 0; + video_last_dts = 0; + + audio_first_pts = 0; + audio_first_dts = 0; + audio_next_pts = 0; + audio_next_dts = 0; if ( audio_in_stream ) { Debug(3, "Have audio stream"); @@ -284,9 +313,27 @@ VideoStore::VideoStore( audio_in_stream->codec->codec_id #endif != AV_CODEC_ID_AAC ) { - static char error_buffer[256]; - avcodec_string(error_buffer, sizeof(error_buffer), audio_in_ctx, 0); - Debug(2, "Got something other than AAC (%s)", error_buffer); + + audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); + if ( !audio_out_codec ) { + Error("Could not find codec for AAC"); + return; + } + +#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"); + audio_out_stream = NULL; + return; + } +#else + audio_out_stream = avformat_new_stream(oc, audio_out_codec); + audio_out_ctx = audio_out_stream->codec; +#endif + audio_out_stream->time_base = audio_in_stream->time_base; if ( !setup_resampler() ) { return; @@ -294,90 +341,66 @@ VideoStore::VideoStore( } else { Debug(2, "Got AAC"); -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_in_ctx = avcodec_alloc_context3(NULL); - ret = avcodec_parameters_to_context(audio_in_ctx, - audio_in_stream->codecpar); - audio_in_ctx->time_base = audio_in_stream->time_base; -#else - audio_in_ctx = audio_in_stream->codec; -#endif - - audio_out_stream = -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avformat_new_stream(oc, (const AVCodec *)(audio_in_ctx->codec)); -#else - avformat_new_stream(oc, (AVCodec *)audio_in_ctx->codec); -#endif + audio_out_stream = avformat_new_stream(oc, NULL); if ( !audio_out_stream ) { - Error("Unable to create audio out stream"); - audio_out_stream = NULL; - } else { -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - audio_out_ctx = avcodec_alloc_context3(audio_out_codec); - // Copy params from instream to ctx - ret = avcodec_parameters_to_context( - audio_out_ctx, audio_in_stream->codecpar); - if ( ret < 0 ) { - Error("Unable to copy audio params to ctx %s", - av_make_error_string(ret).c_str()); - } - ret = avcodec_parameters_from_context( - audio_out_stream->codecpar, audio_out_ctx); - if ( ret < 0 ) { - Error("Unable to copy audio params to stream %s", - av_make_error_string(ret).c_str()); - } + Error("Could not allocate new stream"); + return; + } + audio_out_stream->time_base = audio_in_stream->time_base; - if ( !audio_out_ctx->codec_tag ) { - audio_out_ctx->codec_tag = av_codec_get_tag( - oc->oformat->codec_tag, audio_in_ctx->codec_id); - Debug(2, "Setting audio codec tag to %d", - audio_out_ctx->codec_tag); - } +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + // Just use the ctx to copy the parameters over + audio_out_ctx = avcodec_alloc_context3(NULL); + if ( !audio_out_ctx ) { + Error("Could not allocate new output_context"); + return; + } + + // We don't actually care what the time_base is.. + audio_out_ctx->time_base = audio_in_stream->time_base; + + // Copy params from instream to ctx + ret = avcodec_parameters_to_context( + audio_out_ctx, audio_in_stream->codecpar); + if ( ret < 0 ) { + Error("Unable to copy audio params to ctx %s", + av_make_error_string(ret).c_str()); + } + ret = avcodec_parameters_from_context( + audio_out_stream->codecpar, audio_out_ctx); + if ( ret < 0 ) { + Error("Unable to copy audio params to stream %s", + av_make_error_string(ret).c_str()); + } + avcodec_free_context(&audio_out_ctx); #else - audio_out_ctx = audio_out_stream->codec; - ret = avcodec_copy_context(audio_out_ctx, audio_in_ctx); - audio_out_ctx->codec_tag = 0; + audio_out_ctx = audio_out_stream->codec; + ret = avcodec_copy_context(audio_out_ctx, audio_in_stream->codec); + if ( ret < 0 ) { + Error("Unable to copy audio ctx %s", + av_make_error_string(ret).c_str()); + audio_out_stream = NULL; + return; + } // end if + audio_out_ctx->codec_tag = 0; #endif - if ( ret < 0 ) { - Error("Unable to copy audio ctx %s", - av_make_error_string(ret).c_str()); - audio_out_stream = NULL; - } else { - if ( audio_out_ctx->channels > 1 ) { - Warning("Audio isn't mono, changing it."); - audio_out_ctx->channels = 1; - } else { - Debug(3, "Audio is mono"); - } - } - } // end if audio_out_stream + + if ( audio_out_ctx->channels > 1 ) { + Warning("Audio isn't mono, changing it."); + audio_out_ctx->channels = 1; + } else { + Debug(3, "Audio is mono"); + } } // end if is AAC - if ( audio_out_stream ) { - if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { + if ( oc->oformat->flags & AVFMT_GLOBALHEADER ) { #if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0) - audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; + audio_out_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; #else - audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; + audio_out_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; #endif - } } } // end if audio_in_stream - - video_first_pts = 0; - video_first_dts = 0; - video_last_pts = 0; - video_last_dts = 0; - - audio_first_pts = 0; - audio_first_dts = 0; - audio_last_pts = 0; - audio_last_dts = 0; - audio_next_pts = 0; - audio_next_dts = 0; - } // VideoStore::VideoStore bool VideoStore::open() { @@ -500,6 +523,7 @@ VideoStore::~VideoStore() { } } // end if ( oc->pb ) +#if 0 // I wonder if we should be closing the file first. // I also wonder if we really need to be doing all the ctx // allocation/de-allocation constantly, or whether we can just re-use it. @@ -508,7 +532,7 @@ VideoStore::~VideoStore() { if ( video_out_stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it - //avcodec_free_context(&video_in_ctx); + avcodec_free_context(&video_in_ctx); #endif video_in_ctx = NULL; @@ -517,14 +541,15 @@ VideoStore::~VideoStore() { Debug(4, "Success closing video_out_ctx"); video_out_codec = NULL; } // end if video_out_codec - avcodec_close(video_out_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - avcodec_free_context(&video_out_ctx); #endif + avcodec_free_context(&video_out_ctx); video_out_ctx = NULL; } // end if video_out_stream +#endif if ( audio_out_stream ) { +#if 0 if ( audio_in_codec ) { avcodec_close(audio_in_ctx); Debug(4, "Success closing audio_in_ctx"); @@ -533,33 +558,35 @@ VideoStore::~VideoStore() { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it +#endif avcodec_free_context(&audio_in_ctx); Debug(4, "Success freeing audio_in_ctx"); -#endif audio_in_ctx = NULL; if ( audio_out_ctx ) { avcodec_close(audio_out_ctx); Debug(4, "Success closing audio_out_ctx"); -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) avcodec_free_context(&audio_out_ctx); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) #endif } audio_out_ctx = NULL; +#endif + #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE) if ( resample_ctx ) { -#if defined(HAVE_LIBSWRESAMPLE) + #if defined(HAVE_LIBSWRESAMPLE) if ( fifo ) { av_audio_fifo_free(fifo); fifo = NULL; } swr_free(&resample_ctx); -#else -#if defined(HAVE_LIBAVRESAMPLE) + #else + #if defined(HAVE_LIBAVRESAMPLE) avresample_close(resample_ctx); avresample_free(&resample_ctx); -#endif -#endif + #endif + #endif } if ( in_frame ) { av_frame_free(&in_frame); @@ -576,7 +603,7 @@ VideoStore::~VideoStore() { #endif } // end if audio_out_stream - /* free the stream */ + /* free the streams */ avformat_free_context(oc); } // VideoStore::~VideoStore() @@ -593,35 +620,35 @@ bool VideoStore::setup_resampler() { // decoder, can't reuse the one from the camera. audio_in_codec = avcodec_find_decoder(audio_in_stream->codecpar->codec_id); + audio_in_ctx = avcodec_alloc_context3(audio_in_codec); #else // codec is already open in ffmpeg_camera - audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id); + audio_in_ctx = audio_in_stream->codec; + audio_in_codec = (AVCodec *)audio_in_ctx->codec; + //audio_in_codec = avcodec_find_decoder(audio_in_stream->codec->codec_id); #endif - audio_in_ctx = avcodec_alloc_context3(audio_in_codec); +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) +#else +#if 0 + ret = avcodec_copy_context(audio_in_ctx, audio_in_stream->codec); + if ( ret < 0 ) { + Fatal("Unable to copy in video ctx to out video ctx %s", + av_make_error_string(ret).c_str()); + } else { + Debug(3, "Success copying ctx"); + } +#endif +#endif + + // if the codec is already open, nothing is done. if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { Error("Can't open in codec!"); return false; } - audio_out_codec = avcodec_find_encoder(AV_CODEC_ID_AAC); - if ( !audio_out_codec ) { - Error("Could not find codec for AAC"); - return false; - } + Debug(2, "Got something other than AAC (%s)", audio_in_codec->name); - audio_out_stream = avformat_new_stream(oc, audio_out_codec); -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - // audio_out_ctx = audio_out_stream->codec; - audio_out_ctx = avcodec_alloc_context3(audio_out_codec); - if ( !audio_out_ctx ) { - Error("could not allocate codec ctx for AAC"); - audio_out_stream = NULL; - return false; - } -#else - audio_out_ctx = audio_out_stream->codec; -#endif // Some formats (i.e. WAV) do not produce the proper channel layout if ( audio_in_ctx->channel_layout == 0 ) { Debug(2, "Setting input channel layout to mono"); @@ -930,7 +957,6 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { opkt.dts = 0; } - opkt.flags = ipkt->flags; opkt.pos = -1; opkt.data = ipkt->data; @@ -969,46 +995,21 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { return 0; // FIXME -ve return codes do not free packet in ffmpeg_camera at // the moment } + dumpPacket(audio_in_stream, ipkt, "input packet"); if ( audio_out_codec ) { -#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE) - - #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - if ( (ret = avcodec_send_packet(audio_in_ctx, ipkt)) < 0 ) { - Error("avcodec_send_packet fail %s", av_make_error_string(ret).c_str()); + Debug(2, "Have output codec"); + if ( ! zm_receive_frame(audio_in_ctx, in_frame, *ipkt) ) { return 0; } - if ( (ret = avcodec_receive_frame(audio_in_ctx, in_frame)) < 0 ) { - Error("avcodec_receive_frame fail %s", av_make_error_string(ret).c_str()); - return 0; - } - - #else - int data_present; - if ( (ret = avcodec_decode_audio4( - audio_in_ctx, in_frame, &data_present, ipkt)) < 0 ) { - Error("Could not decode frame (error '%s')", - av_make_error_string(ret).c_str()); - dumpPacket(video_in_stream, ipkt); - // I'm not sure if we should be freeing the frame. - av_frame_free(&in_frame); - return 0; - } - if ( !data_present ) { - Debug(2, "Not ready to transcode a frame yet."); - return 0; - } - #endif zm_dump_frame(in_frame, "In frame from decode"); - int frame_size = in_frame->nb_samples; - // Resample the in into the audioSampleBuffer until we proceed the whole - // decoded data. Note: pts does not survive resampling or converting - #if defined(HAVE_LIBSWRESAMPLE) - Debug(2, "Converting %d to %d samples using swresample", in_frame->nb_samples, out_frame->nb_samples); - ret = swr_convert_frame(resample_ctx, out_frame, in_frame); - zm_dump_frame(out_frame, "Out frame after convert"); + if ( ! resample_audio() ) { + av_frame_unref(in_frame); + return 0; + } + zm_dump_frame(out_frame, "Out frame after resample"); out_frame->pts = in_frame->pts; // out_frame pts is in the input pkt pts... needs to be adjusted before sending to the encoder @@ -1020,64 +1021,12 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } else { out_frame->pts = out_frame->pts - audio_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; } - av_frame_unref(in_frame); - if ( ret < 0 ) { - Error("Could not resample frame (error '%s')", - av_make_error_string(ret).c_str()); - return 0; - } - if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples)) < 0) { - Error("Could not reallocate FIFO"); - return 0; - } - /** Store the new samples in the FIFO buffer. */ - ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples); - if ( ret < frame_size ) { - Error("Could not write data to FIFO on %d written", ret); - return 0; - } - - // Reset frame_size to output_frame_size - frame_size = audio_out_ctx->frame_size; - - // AAC requires 1024 samples per encode. Our input tends to be 160, so need to buffer them. - if ( frame_size > av_audio_fifo_size(fifo) ) { - return 0; - } - - if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) < frame_size ) { - Error("Could not read data from FIFO"); - return 0; - } - out_frame->nb_samples = frame_size; - /// FIXME this is not the correct pts - #else - #if defined(HAVE_LIBAVRESAMPLE) - (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, in_frame->nb_samples)) - av_frame_unref(in_frame); - if ( ret < 0 ) { - Error("Could not resample frame (error '%s')", - av_make_error_string(ret).c_str()); - return 0; - } - - int samples_available = avresample_available(resample_ctx); - if ( samples_available < frame_size ) { - Debug(1, "Not enough samples yet (%d)", samples_available); - return 0; - } - - // Read a frame audio data from the resample fifo - if ( avresample_read(resample_ctx, out_frame->data, frame_size) != - frame_size) { - Warning("Error reading resampled audio."); - return 0; - } - #endif - #endif - zm_dump_frame(out_frame, "Out frame after resample"); + audio_next_pts = out_frame->pts + out_frame->nb_samples; av_init_packet(&opkt); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) @@ -1102,6 +1051,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { 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')", @@ -1115,11 +1065,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { return 0; } #endif -#else - Error("Have audio codec but no resampler?!"); -#endif - //if ( out_frame ) { - //opkt.duration = out_frame->nb_samples; opkt.duration = av_rescale_q(opkt.duration, audio_in_stream->time_base, audio_out_stream->time_base); @@ -1129,12 +1074,15 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { opkt.dts = av_rescale_q(opkt.dts, audio_in_stream->time_base, audio_out_stream->time_base); + dumpPacket(audio_out_stream, &opkt, "raw opkt"); + } else { + Debug(2,"copying"); av_init_packet(&opkt); opkt.data = ipkt->data; opkt.size = ipkt->size; - if ( ipkt->duration != AV_NOPTS_VALUE ) { + if ( ipkt->duration && (ipkt->duration != AV_NOPTS_VALUE) ) { opkt.duration = av_rescale_q( ipkt->duration, audio_in_stream->time_base, @@ -1154,7 +1102,6 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { Debug(2, "audio opkt.pts = %" PRId64 " from ipkt->pts(%" PRId64 ") - first_pts(%" PRId64 ")", opkt.pts, ipkt->pts, audio_first_pts); } - audio_last_pts = ipkt->pts; } else { Debug(2, "opkt.pts = undef"); opkt.pts = AV_NOPTS_VALUE; @@ -1186,13 +1133,11 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { } else { opkt.dts = AV_NOPTS_VALUE; } - } + } // end if encoding or copying opkt.pos = -1; opkt.stream_index = audio_out_stream->index; - dumpPacket(audio_out_stream, &opkt, "raw opkt"); - if ( opkt.dts > opkt.pts ) { Debug(1, "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 ")." @@ -1213,3 +1158,73 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { zm_av_packet_unref(&opkt); return 0; } // end int VideoStore::writeAudioFramePacket(AVPacket *ipkt) + +int VideoStore::resample_audio() { + // Resample the in into the audioSampleBuffer until we process the whole + // decoded data. Note: pts does not survive resampling or converting +#if defined(HAVE_LIBSWRESAMPLE) || defined(HAVE_LIBAVRESAMPLE) +#if defined(HAVE_LIBSWRESAMPLE) + Debug(2, "Converting %d to %d samples using swresample", + in_frame->nb_samples, out_frame->nb_samples); + ret = swr_convert_frame(resample_ctx, out_frame, in_frame); + zm_dump_frame(out_frame, "Out frame after convert"); + + if ( ret < 0 ) { + Error("Could not resample frame (error '%s')", + av_make_error_string(ret).c_str()); + return 0; + } + if ((ret = av_audio_fifo_realloc(fifo, av_audio_fifo_size(fifo) + out_frame->nb_samples)) < 0) { + Error("Could not reallocate FIFO"); + return 0; + } + /** Store the new samples in the FIFO buffer. */ + ret = av_audio_fifo_write(fifo, (void **)out_frame->data, out_frame->nb_samples); + if ( ret < in_frame->nb_samples ) { + Error("Could not write data to FIFO on %d written", ret); + return 0; + } + + // 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. + if ( frame_size > av_audio_fifo_size(fifo) ) { + return 0; + } + + if ( av_audio_fifo_read(fifo, (void **)out_frame->data, frame_size) < frame_size ) { + Error("Could not read data from FIFO"); + return 0; + } + out_frame->nb_samples = frame_size; +#else +#if defined(HAVE_LIBAVRESAMPLE) + (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + 0, in_frame->nb_samples)) + if ( ret < 0 ) { + Error("Could not resample frame (error '%s')", + av_make_error_string(ret).c_str()); + return 0; + } + + int samples_available = avresample_available(resample_ctx); + if ( samples_available < frame_size ) { + Debug(1, "Not enough samples yet (%d)", samples_available); + return 0; + } + + // Read a frame audio data from the resample fifo + if ( avresample_read(resample_ctx, out_frame->data, frame_size) != + frame_size) { + Warning("Error reading resampled audio."); + return 0; + } +#endif +#endif +#else + Error("Have audio codec but no resampler?!"); + return 0; +#endif + return 1; +} // end int VideoStore::resample_audio diff --git a/src/zm_videostore.h b/src/zm_videostore.h index 1fe3fe81b..8e7308e69 100644 --- a/src/zm_videostore.h +++ b/src/zm_videostore.h @@ -77,6 +77,7 @@ private: int64_t audio_next_dts; bool setup_resampler(); + int resample_audio(); public: VideoStore( From b6f35db4defaa0c2a934bc15787567d6d8c254db Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 14:25:18 -0400 Subject: [PATCH 10/40] put back codec closing in destructure, testing with bionic --- src/zm_videostore.cpp | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 0d0c88765..d2804de90 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -104,7 +104,7 @@ VideoStore::VideoStore( } #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - video_out_stream = avformat_new_stream(oc, video_out_codec); + video_out_stream = avformat_new_stream(oc, NULL); if ( !video_out_stream ) { Error("Unable to create video out stream"); return; @@ -523,7 +523,6 @@ VideoStore::~VideoStore() { } } // end if ( oc->pb ) -#if 0 // I wonder if we should be closing the file first. // I also wonder if we really need to be doing all the ctx // allocation/de-allocation constantly, or whether we can just re-use it. @@ -532,7 +531,7 @@ VideoStore::~VideoStore() { if ( video_out_stream ) { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it - avcodec_free_context(&video_in_ctx); + //avcodec_free_context(&video_in_ctx); #endif video_in_ctx = NULL; @@ -542,14 +541,12 @@ VideoStore::~VideoStore() { video_out_codec = NULL; } // end if video_out_codec #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) -#endif avcodec_free_context(&video_out_ctx); +#endif video_out_ctx = NULL; } // end if video_out_stream -#endif if ( audio_out_stream ) { -#if 0 if ( audio_in_codec ) { avcodec_close(audio_in_ctx); Debug(4, "Success closing audio_in_ctx"); @@ -558,20 +555,19 @@ VideoStore::~VideoStore() { #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // We allocate and copy in newer ffmpeg, so need to free it -#endif avcodec_free_context(&audio_in_ctx); +#endif Debug(4, "Success freeing audio_in_ctx"); audio_in_ctx = NULL; if ( audio_out_ctx ) { avcodec_close(audio_out_ctx); Debug(4, "Success closing audio_out_ctx"); - avcodec_free_context(&audio_out_ctx); #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + avcodec_free_context(&audio_out_ctx); #endif } audio_out_ctx = NULL; -#endif #if defined(HAVE_LIBAVRESAMPLE) || defined(HAVE_LIBSWRESAMPLE) if ( resample_ctx ) { @@ -621,6 +617,14 @@ bool VideoStore::setup_resampler() { audio_in_codec = avcodec_find_decoder(audio_in_stream->codecpar->codec_id); audio_in_ctx = avcodec_alloc_context3(audio_in_codec); + // Copy params from instream to ctx + ret = avcodec_parameters_to_context( + audio_in_ctx, audio_in_stream->codecpar); + if ( ret < 0 ) { + Error("Unable to copy audio params to ctx %s", + av_make_error_string(ret).c_str()); + } + #else // codec is already open in ffmpeg_camera audio_in_ctx = audio_in_stream->codec; @@ -643,7 +647,7 @@ bool VideoStore::setup_resampler() { // if the codec is already open, nothing is done. if ( (ret = avcodec_open2(audio_in_ctx, audio_in_codec, NULL)) < 0 ) { - Error("Can't open in codec!"); + Error("Can't open audio in codec!"); return false; } From b53e4aa803f45c1f33af5d9045d09c4770e711de Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 14:51:10 -0400 Subject: [PATCH 11/40] fix segfault --- src/zm_videostore.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index d2804de90..993136e27 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -350,7 +350,7 @@ VideoStore::VideoStore( #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) // Just use the ctx to copy the parameters over - audio_out_ctx = avcodec_alloc_context3(NULL); + audio_out_ctx = avcodec_alloc_context3(audio_out_codec); if ( !audio_out_ctx ) { Error("Could not allocate new output_context"); return; @@ -372,7 +372,6 @@ VideoStore::VideoStore( Error("Unable to copy audio params to stream %s", av_make_error_string(ret).c_str()); } - avcodec_free_context(&audio_out_ctx); #else audio_out_ctx = audio_out_stream->codec; ret = avcodec_copy_context(audio_out_ctx, audio_in_stream->codec); From 2e7fd7c9a24907a0b7f0ef8fb63969176f63ca75 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 14:55:29 -0400 Subject: [PATCH 12/40] handle really old ffmpeg not having pkt_duration --- src/zm_ffmpeg.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 011def0ee..22d680260 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -285,8 +285,9 @@ static void zm_log_fps(double d, const char *postfix) { } void zm_dump_frame(const AVFrame *frame,const char *text) { - Debug(1, "%s: format %d %s sample_rate %" PRIu32 " nb_samples %d channels %d layout %d pts %" PRId64 - " duration %" PRId64, + 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), @@ -294,12 +295,12 @@ void zm_dump_frame(const AVFrame *frame,const char *text) { frame->nb_samples, #if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) frame->channels, + frame->pkt_duration, #else -0, +0, 0, #endif frame->channel_layout, - frame->pts, - frame->pkt_duration + frame->pts ); } From bd9b5afe46db7e9f9c590891bfb0417a21f446b1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 14:56:14 -0400 Subject: [PATCH 13/40] old ffmpeg doesn't have av_frame_unref and it doesn't seem to be needed --- src/zm_videostore.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 0d0c88765..0586532fa 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -1006,7 +1006,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { zm_dump_frame(in_frame, "In frame from decode"); if ( ! resample_audio() ) { - av_frame_unref(in_frame); + //av_frame_unref(in_frame); return 0; } zm_dump_frame(out_frame, "Out frame after resample"); From 94479fc850afe605e0c5e8b7a9f040914932f875 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 16:03:21 -0400 Subject: [PATCH 14/40] copy pkt flags as well. When pts is NOPTS_VALUE set it to zero --- src/zm_videostore.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index f6e38ee2c..0f51358f1 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -871,7 +871,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { dumpPacket(video_in_stream, ipkt, "input packet"); int64_t duration; - if ( ipkt->duration ) { + if ( ipkt->duration && ( ipkt->duration != AV_NOPTS_VALUE ) ) { duration = av_rescale_q( ipkt->duration, video_in_stream->time_base, @@ -925,7 +925,8 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { video_last_pts = ipkt->pts; } else { Debug(3, "opkt.pts = undef"); - opkt.pts = AV_NOPTS_VALUE; + opkt.pts = 0; + //AV_NOPTS_VALUE; } // Just because the in stream wraps, doesn't mean the out needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out. So need to handle in wrap, without causing out wrap. if ( ipkt->dts != AV_NOPTS_VALUE ) { @@ -1140,6 +1141,7 @@ int VideoStore::writeAudioFramePacket(AVPacket *ipkt) { opkt.pos = -1; opkt.stream_index = audio_out_stream->index; + opkt.flags = ipkt->flags; if ( opkt.dts > opkt.pts ) { Debug(1, From 12631abd46d664e9cf4389ec001cb34bf2de06a9 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 16:51:27 -0400 Subject: [PATCH 15/40] when copying a packet (for old ffmpeg) copy pts, dts and duration too --- src/zm_ffmpeg.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 22d680260..578e12e6b 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -434,6 +434,9 @@ unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src ) { av_new_packet(dst,src->size); memcpy(dst->data, src->data, src->size); dst->flags = src->flags; + dst->pts = src->pts; + dst->dts = src->dts; + dst->duration = src->duration; return 0; } #endif From 8d3fa807e2ad2ee2abdd9dabf5795eeb912d1278 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Wed, 3 Apr 2019 16:51:41 -0400 Subject: [PATCH 16/40] compilation fixes for old ffmpeg --- src/zm_videostore.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 0f51358f1..8b307ed7e 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -665,10 +665,7 @@ bool VideoStore::setup_resampler() { audio_out_ctx->channels = audio_in_ctx->channels; audio_out_ctx->channel_layout = audio_in_ctx->channel_layout; audio_out_ctx->sample_fmt = audio_in_ctx->sample_fmt; -#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) -#else - audio_out_ctx->refcounted_frames = 1; -#endif +#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) if ( !audio_out_ctx->channel_layout ) { Debug(3, "Correcting channel layout from (%d) to (%d)", audio_out_ctx->channel_layout, @@ -676,7 +673,7 @@ bool VideoStore::setup_resampler() { ); audio_out_ctx->channel_layout = av_get_default_channel_layout(audio_out_ctx->channels); } - +#endif if ( audio_out_codec->supported_samplerates ) { int found = 0; for ( unsigned int i = 0; audio_out_codec->supported_samplerates[i]; i++ ) { @@ -832,7 +829,9 @@ bool VideoStore::setup_resampler() { out_frame->nb_samples = audio_out_ctx->frame_size; out_frame->format = audio_out_ctx->sample_fmt; +#if LIBAVCODEC_VERSION_CHECK(56, 8, 0, 60, 100) out_frame->channels = audio_out_ctx->channels; +#endif out_frame->channel_layout = audio_out_ctx->channel_layout; out_frame->sample_rate = audio_out_ctx->sample_rate; @@ -1205,14 +1204,16 @@ int VideoStore::resample_audio() { out_frame->nb_samples = frame_size; #else #if defined(HAVE_LIBAVRESAMPLE) - (ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, - 0, in_frame->nb_samples)) + ret = avresample_convert(resample_ctx, NULL, 0, 0, in_frame->data, + 0, in_frame->nb_samples); if ( ret < 0 ) { Error("Could not resample frame (error '%s')", av_make_error_string(ret).c_str()); return 0; } + int frame_size = audio_out_ctx->frame_size; + int samples_available = avresample_available(resample_ctx); if ( samples_available < frame_size ) { Debug(1, "Not enough samples yet (%d)", samples_available); From 8de7d576a590556f9272e3477f537c30543d315b Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 09:35:37 -0400 Subject: [PATCH 17/40] spacing and use Error instead of fprintf(stderr) so that things get logged. --- src/zmu.cpp | 202 +++++++++++++++++++++++++--------------------------- 1 file changed, 99 insertions(+), 103 deletions(-) diff --git a/src/zmu.cpp b/src/zmu.cpp index a8ee61273..479bbd973 100644 --- a/src/zmu.cpp +++ b/src/zmu.cpp @@ -426,11 +426,11 @@ int main(int argc, char *argv[]) { if ( config.opt_use_auth ) { if ( strcmp(config.auth_relay, "none") == 0 ) { if ( !checkUser(username)) { - fprintf(stderr, "Error, username greater than allowed 32 characters\n"); + Error("Username greater than allowed 32 characters"); exit_zmu(-1); } if ( !username ) { - fprintf(stderr, "Error, username must be supplied\n"); + Error("Username must be supplied"); exit_zmu(-1); } @@ -439,36 +439,32 @@ int main(int argc, char *argv[]) { } } else { if ( !(username && password) && !auth ) { - fprintf(stderr, "Error, username and password or auth string must be supplied\n"); + Error("Username and password or auth string must be supplied"); exit_zmu(-1); } if ( !checkUser(username)) { - fprintf(stderr, "Error, username greater than allowed 32 characters\n"); + Error("Username greater than allowed 32 characters"); exit_zmu(-1); } if ( !checkPass(password)) { - fprintf(stderr, "Error, password greater than allowed 64 characters\n"); + Error("Password greater than allowed 64 characters"); exit_zmu(-1); } - //if ( strcmp( config.auth_relay, "hashed" ) == 0 ) - { - if ( auth ) { - user = zmLoadAuthUser(auth, false); - } + + if ( auth ) { + user = zmLoadAuthUser(auth, false); } - //else if ( strcmp( config.auth_relay, "plain" ) == 0 ) - { - if ( username && password ) { - user = zmLoadUser(username, password); - } + if ( username && password ) { + user = zmLoadUser(username, password); } - } + } // auth relay == none or not + if ( !user ) { - fprintf(stderr, "Error, unable to authenticate user\n"); - return exit_zmu(-1); + Error("Unable to authenticate user"); + exit_zmu(-1); } if ( !ValidateAccess(user, mon_id, function) ) { - fprintf(stderr, "Error, insufficient privileges for requested action\n"); + Error("Insufficient privileges for requested action"); exit_zmu(-1); } } // end if auth @@ -503,201 +499,201 @@ int main(int argc, char *argv[]) { if ( verbose ) { char timestamp_str[64] = "None"; if ( timestamp.tv_sec ) - strftime( timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime( ×tamp.tv_sec ) ); + strftime(timestamp_str, sizeof(timestamp_str), "%Y-%m-%d %H:%M:%S", localtime(×tamp.tv_sec)); if ( image_idx == -1 ) - printf( "Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000 ); + printf("Time of last image capture: %s.%02ld\n", timestamp_str, timestamp.tv_usec/10000); else - printf( "Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000 ); + printf("Time of image %d capture: %s.%02ld\n", image_idx, timestamp_str, timestamp.tv_usec/10000); } else { - if ( have_output ) printf( "%c", separator ); - printf( "%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000 ); + if ( have_output ) printf("%c", separator); + printf("%ld.%02ld", timestamp.tv_sec, timestamp.tv_usec/10000); have_output = true; } } if ( function & ZMU_READ_IDX ) { if ( verbose ) - printf( "Last read index: %d\n", monitor->GetLastReadIndex() ); + printf("Last read index: %d\n", monitor->GetLastReadIndex()); else { - if ( have_output ) printf( "%c", separator ); - printf( "%d", monitor->GetLastReadIndex() ); + if ( have_output ) printf("%c", separator); + printf("%d", monitor->GetLastReadIndex()); have_output = true; } } if ( function & ZMU_WRITE_IDX ) { - if ( verbose ) - printf( "Last write index: %d\n", monitor->GetLastWriteIndex() ); - else { - if ( have_output ) printf( "%c", separator ); - printf( "%d", monitor->GetLastWriteIndex() ); + if ( verbose ) { + printf("Last write index: %d\n", monitor->GetLastWriteIndex()); + } else { + if ( have_output ) printf("%c", separator); + printf("%d", monitor->GetLastWriteIndex()); have_output = true; } } if ( function & ZMU_EVENT ) { - if ( verbose ) - printf( "Last event id: %" PRIu64 "\n", monitor->GetLastEventId() ); - else { - if ( have_output ) printf( "%c", separator ); - printf( "%" PRIu64, monitor->GetLastEventId() ); + if ( verbose ) { + printf("Last event id: %" PRIu64 "\n", monitor->GetLastEventId()); + } else { + if ( have_output ) printf("%c", separator); + printf("%" PRIu64, monitor->GetLastEventId()); have_output = true; } } if ( function & ZMU_FPS ) { if ( verbose ) - printf( "Current capture rate: %.2f frames per second\n", monitor->GetFPS() ); + printf("Current capture rate: %.2f frames per second\n", monitor->GetFPS()); else { - if ( have_output ) printf( "%c", separator ); - printf( "%.2f", monitor->GetFPS() ); + if ( have_output ) printf("%c", separator); + printf("%.2f", monitor->GetFPS()); have_output = true; } } if ( function & ZMU_IMAGE ) { if ( verbose ) { if ( image_idx == -1 ) - printf( "Dumping last image captured to Monitor%d.jpg", monitor->Id() ); + printf("Dumping last image captured to Monitor%d.jpg", monitor->Id()); else - printf( "Dumping buffer image %d to Monitor%d.jpg", image_idx, monitor->Id() ); + printf("Dumping buffer image %d to Monitor%d.jpg", image_idx, monitor->Id()); if ( scale != -1 ) - printf( ", scaling by %d%%", scale ); - printf( "\n" ); + printf(", scaling by %d%%", scale); + printf("\n"); } - monitor->GetImage( image_idx, scale>0?scale:100 ); + monitor->GetImage(image_idx, scale>0?scale:100); } if ( function & ZMU_ZONES ) { if ( verbose ) - printf( "Dumping zone image to Zones%d.jpg\n", monitor->Id() ); - monitor->DumpZoneImage( zoneString ); + printf("Dumping zone image to Zones%d.jpg\n", monitor->Id()); + monitor->DumpZoneImage(zoneString); } if ( function & ZMU_ALARM ) { if ( verbose ) - printf( "Forcing alarm on\n" ); - monitor->ForceAlarmOn( config.forced_alarm_score, "Forced Web" ); + printf("Forcing alarm on\n"); + monitor->ForceAlarmOn(config.forced_alarm_score, "Forced Web"); while ( monitor->GetState() != Monitor::ALARM ) { // Wait for monitor to notice. usleep(1000); } - printf( "Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId() ); + printf("Alarmed event id: %" PRIu64 "\n", monitor->GetLastEventId()); } if ( function & ZMU_NOALARM ) { if ( verbose ) - printf( "Forcing alarm off\n" ); + printf("Forcing alarm off\n"); monitor->ForceAlarmOff(); } if ( function & ZMU_CANCEL ) { if ( verbose ) - printf( "Cancelling forced alarm on/off\n" ); + printf("Cancelling forced alarm on/off\n"); monitor->CancelForced(); } if ( function & ZMU_RELOAD ) { if ( verbose ) - printf( "Reloading monitor settings\n" ); + printf("Reloading monitor settings\n"); monitor->actionReload(); } if ( function & ZMU_ENABLE ) { if ( verbose ) - printf( "Enabling event generation\n" ); + printf("Enabling event generation\n"); monitor->actionEnable(); } if ( function & ZMU_DISABLE ) { if ( verbose ) - printf( "Disabling event generation\n" ); + printf("Disabling event generation\n"); monitor->actionDisable(); } if ( function & ZMU_SUSPEND ) { if ( verbose ) - printf( "Suspending event generation\n" ); + printf("Suspending event generation\n"); monitor->actionSuspend(); } if ( function & ZMU_RESUME ) { if ( verbose ) - printf( "Resuming event generation\n" ); + printf("Resuming event generation\n"); monitor->actionResume(); } if ( function & ZMU_QUERY ) { char monString[16382] = ""; - monitor->DumpSettings( monString, verbose ); - printf( "%s\n", monString ); + monitor->DumpSettings(monString, verbose); + printf("%s\n", monString); } if ( function & ZMU_BRIGHTNESS ) { if ( verbose ) { if ( brightness >= 0 ) - printf( "New brightness: %d\n", monitor->actionBrightness( brightness ) ); + printf("New brightness: %d\n", monitor->actionBrightness(brightness)); else - printf( "Current brightness: %d\n", monitor->actionBrightness() ); + printf("Current brightness: %d\n", monitor->actionBrightness()); } else { - if ( have_output ) printf( "%c", separator ); + if ( have_output ) printf("%c", separator); if ( brightness >= 0 ) - printf( "%d", monitor->actionBrightness( brightness ) ); + printf("%d", monitor->actionBrightness(brightness)); else - printf( "%d", monitor->actionBrightness() ); + printf("%d", monitor->actionBrightness()); have_output = true; } } if ( function & ZMU_CONTRAST ) { if ( verbose ) { if ( contrast >= 0 ) - printf( "New brightness: %d\n", monitor->actionContrast( contrast ) ); + printf("New brightness: %d\n", monitor->actionContrast(contrast)); else - printf( "Current contrast: %d\n", monitor->actionContrast() ); + printf("Current contrast: %d\n", monitor->actionContrast()); } else { - if ( have_output ) printf( "%c", separator ); + if ( have_output ) printf("%c", separator); if ( contrast >= 0 ) - printf( "%d", monitor->actionContrast( contrast ) ); + printf("%d", monitor->actionContrast(contrast)); else - printf( "%d", monitor->actionContrast() ); + printf("%d", monitor->actionContrast()); have_output = true; } } if ( function & ZMU_HUE ) { if ( verbose ) { if ( hue >= 0 ) - printf( "New hue: %d\n", monitor->actionHue( hue ) ); + printf("New hue: %d\n", monitor->actionHue(hue)); else - printf( "Current hue: %d\n", monitor->actionHue() ); + printf("Current hue: %d\n", monitor->actionHue()); } else { - if ( have_output ) printf( "%c", separator ); + if ( have_output ) printf("%c", separator); if ( hue >= 0 ) - printf( "%d", monitor->actionHue( hue ) ); + printf("%d", monitor->actionHue(hue)); else - printf( "%d", monitor->actionHue() ); + printf("%d", monitor->actionHue()); have_output = true; } } if ( function & ZMU_COLOUR ) { if ( verbose ) { if ( colour >= 0 ) - printf( "New colour: %d\n", monitor->actionColour( colour ) ); + printf("New colour: %d\n", monitor->actionColour(colour)); else - printf( "Current colour: %d\n", monitor->actionColour() ); + printf("Current colour: %d\n", monitor->actionColour()); } else { - if ( have_output ) printf( "%c", separator ); + if ( have_output ) printf("%c", separator); if ( colour >= 0 ) - printf( "%d", monitor->actionColour( colour ) ); + printf("%d", monitor->actionColour(colour)); else - printf( "%d", monitor->actionColour() ); + printf("%d", monitor->actionColour()); have_output = true; } } if ( have_output ) { - printf( "\n" ); + printf("\n"); } if ( !function ) { Usage(); } delete monitor; } else { - fprintf(stderr, "Error, invalid monitor id %d\n", mon_id); + Error("Invalid monitor id %d", mon_id); exit_zmu(-1); } } else { if ( function & ZMU_QUERY ) { #if ZM_HAS_V4L char vidString[0x10000] = ""; - bool ok = LocalCamera::GetCurrentSettings( device, vidString, v4lVersion, verbose ); - printf( "%s", vidString ); - exit_zmu( ok?0:-1 ); + bool ok = LocalCamera::GetCurrentSettings(device, vidString, v4lVersion, verbose); + printf("%s", vidString); + exit_zmu(ok ? 0 : -1); #else // ZM_HAS_V4L - fprintf( stderr, "Error, video4linux is required for device querying\n" ); - exit_zmu( -1 ); + Error("Video4linux is required for device querying"); + exit_zmu(-1); #endif // ZM_HAS_V4L } @@ -708,25 +704,25 @@ int main(int argc, char *argv[]) { } sql += " order by Id asc"; - if ( mysql_query( &dbconn, sql.c_str() ) ) { - Error( "Can't run query: %s", mysql_error( &dbconn ) ); - exit_zmu( mysql_errno( &dbconn ) ); + if ( mysql_query(&dbconn, sql.c_str()) ) { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit_zmu(mysql_errno(&dbconn)); } - MYSQL_RES *result = mysql_store_result( &dbconn ); + MYSQL_RES *result = mysql_store_result(&dbconn); if ( !result ) { - Error( "Can't use query result: %s", mysql_error( &dbconn ) ); - exit_zmu( mysql_errno( &dbconn ) ); + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit_zmu(mysql_errno(&dbconn)); } - Debug( 1, "Got %d monitors", mysql_num_rows( result ) ); + Debug(1, "Got %d monitors", mysql_num_rows(result)); - printf( "%4s%5s%6s%9s%14s%6s%6s%8s%8s\n", "Id", "Func", "State", "TrgState", "LastImgTim", "RdIdx", "WrIdx", "LastEvt", "FrmRate" ); - for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row( result ); i++ ) { + printf("%4s%5s%6s%9s%14s%6s%6s%8s%8s\n", "Id", "Func", "State", "TrgState", "LastImgTim", "RdIdx", "WrIdx", "LastEvt", "FrmRate"); + for( int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++ ) { int mon_id = atoi(dbrow[0]); int function = atoi(dbrow[1]); - if ( !user || user->canAccess( mon_id ) ) { + if ( !user || user->canAccess(mon_id) ) { if ( function > 1 ) { - Monitor *monitor = Monitor::Load( mon_id, false, Monitor::QUERY ); + Monitor *monitor = Monitor::Load(mon_id, false, Monitor::QUERY); if ( monitor && monitor->connect() ) { struct timeval tv = monitor->GetTimestamp(); printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8" PRIu64 "%8.2f\n", @@ -744,7 +740,7 @@ int main(int argc, char *argv[]) { } } else { struct timeval tv = { 0, 0 }; - printf( "%4d%5d%6d%9d%11ld.%02ld%6d%6d%8d%8.2f\n", + printf("%4d%5d%6d%9d%11ld.%02ld%6d%6d%8d%8.2f\n", mon_id, function, 0, @@ -755,11 +751,11 @@ int main(int argc, char *argv[]) { 0, 0.0 ); - } - } - } - mysql_free_result( result ); - } + } // end if function filter + } // endif !user || canAccess(mon_id) + } // end foreach row + mysql_free_result(result); + } // end if function && ZMU_LIST } delete user; From 79de2b65cde72927932f5c4152ec7fae0acb3bb5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 12:18:46 -0400 Subject: [PATCH 18/40] If we are saving jpegs we don't save a snapshot image, and since we may delay writing frame info to the db, we have to default to frame 0 instead of snapshot --- web/views/image.php | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/web/views/image.php b/web/views/image.php index 672baf3f5..5959982d8 100644 --- a/web/views/image.php +++ b/web/views/image.php @@ -87,8 +87,9 @@ if ( empty($_REQUEST['path']) ) { $Frame->Id('objdetect'); } else if ( $_REQUEST['fid'] == 'alarm' ) { # look for first alarmed frame - $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), - array('order'=>'FrameId ASC')); + $Frame = ZM\Frame::find_one( + array('EventId'=>$_REQUEST['eid'], 'Type'=>'Alarm'), + array('order'=>'FrameId ASC')); if ( !$Frame ) { # no alarms, get first one I find $Frame = ZM\Frame::find_one(array('EventId'=>$_REQUEST['eid'])); if ( !$Frame ) { @@ -101,7 +102,7 @@ if ( empty($_REQUEST['path']) ) { $Monitor = $Event->Monitor(); if ( $Monitor->SaveJPEGs() & 1 ) { # If we store Frames as jpgs, then we don't store an alarmed snapshot - $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg'; + $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg'; } else { $path = $Event->Path().'/alarm.jpg'; } @@ -113,12 +114,16 @@ if ( empty($_REQUEST['path']) ) { ZM\Warning('No frame found for event ' . $_REQUEST['eid']); $Frame = new ZM\Frame(); $Frame->Delta(1); - $Frame->FrameId('snapshot'); + if ( $Monitor->SaveJPEGs() & 1 ) { + $Frame->FrameId(0); + } else { + $Frame->FrameId('snapshot'); + } } $Monitor = $Event->Monitor(); if ( $Monitor->SaveJPEGs() & 1 ) { # If we store Frames as jpgs, then we don't store a snapshot - $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d',$Frame->FrameId()).'-'.$show.'.jpg'; + $path = $Event->Path().'/'.sprintf('%0'.ZM_EVENT_IMAGE_DIGITS.'d', $Frame->FrameId()).'-'.$show.'.jpg'; } else { $path = $Event->Path().'/snapshot.jpg'; } From 271937f005e3dc84662a5668d7b946972d285cd3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 12:28:08 -0400 Subject: [PATCH 19/40] store the snapshot_file and alarm_file strings in the boject during construction so that we don't have to do it everytime we write out an image --- src/zm_event.cpp | 9 +++------ src/zm_event.h | 2 ++ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 876a031d4..c44f8ee93 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -193,6 +193,9 @@ Event::Event( video_name[0] = 0; + snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path); + snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path); + /* Save as video */ if ( monitor->GetOptVideoWriter() != 0 ) { @@ -464,8 +467,6 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st // neccessarily be of the motion. But some events are less than 10 frames, // so I am changing this to 1, but we should overwrite it later with a better snapshot. if ( frames == 1 ) { - char snapshot_file[PATH_MAX]; - snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path); WriteFrameImage(images[i], *(timestamps[i]), snapshot_file); } } @@ -549,15 +550,11 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a } else { //If this is the first frame, we should add a thumbnail to the event directory if ( frames == 1 || score > (int)max_score ) { - char snapshot_file[PATH_MAX]; - snprintf(snapshot_file, sizeof(snapshot_file), "%s/snapshot.jpg", path); WriteFrameImage(image, timestamp, snapshot_file); } // The first frame with a score will be the frame that alarmed the event if (!alarm_frame_written && score > 0) { alarm_frame_written = true; - char alarm_file[PATH_MAX]; - snprintf(alarm_file, sizeof(alarm_file), "%s/alarm.jpg", path); WriteFrameImage(image, timestamp, alarm_file); } } diff --git a/src/zm_event.h b/src/zm_event.h index 1d31addcc..2035b6af6 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -90,6 +90,8 @@ class Event { unsigned int tot_score; unsigned int max_score; char path[PATH_MAX]; + char snapshot_file[PATH_MAX]; + char alarm_file[PATH_MAX]; VideoWriter* videowriter; FILE* timecodes_fd; char video_name[PATH_MAX]; From f6d5038586f524bb3331f5e2ebb4b2ca69084692 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 12:37:25 -0400 Subject: [PATCH 20/40] we only use event_file if we are writing out a jpg, so only generate the event_file string if we are writing out jpgs --- src/zm_event.cpp | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index c44f8ee93..3fda77e11 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -456,9 +456,9 @@ void Event::AddFramesInternal( int n_frames, int start_frame, Image **images, st frames++; - static char event_file[PATH_MAX]; - snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); if ( monitor->GetOptSaveJPEGs() & 1 ) { + static char event_file[PATH_MAX]; + snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); Debug(1, "Writing pre-capture frame %d", frames); WriteFrameImage(images[i], *(timestamps[i]), event_file); } else { @@ -539,27 +539,25 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a frames++; - static char event_file[PATH_MAX]; - snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); - if ( monitor->GetOptSaveJPEGs() & 1 ) { + static char event_file[PATH_MAX]; + snprintf(event_file, sizeof(event_file), staticConfig.capture_file_format, path, frames); Debug(1, "Writing capture frame %d to %s", frames, event_file); if ( ! WriteFrameImage(image, timestamp, event_file) ) { Error("Failed to write frame image"); } } else { //If this is the first frame, we should add a thumbnail to the event directory - if ( frames == 1 || score > (int)max_score ) { + if ( (frames == 1) || (score > (int)max_score) ) { WriteFrameImage(image, timestamp, snapshot_file); } // The first frame with a score will be the frame that alarmed the event - if (!alarm_frame_written && score > 0) { + if ( (!alarm_frame_written) && (score > 0) ) { alarm_frame_written = true; WriteFrameImage(image, timestamp, alarm_file); } } if ( videowriter != NULL ) { -Debug(3, "Writing video"); WriteFrameVideo(image, timestamp, videowriter); } @@ -625,7 +623,7 @@ Debug(3, "Writing video"); } } } - } + } // end if frame_type == ALARM /* This makes viewing the diagnostic images impossible because it keeps deleting them if ( config.record_diag_images ) { From bc6249309699fb865f191e16acd9beb68be748a5 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 12:55:35 -0400 Subject: [PATCH 21/40] Increase sql buffer space because we are using path strings that are PATH_MAX size. --- src/zm_event.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 3fda77e11..7b8b446d4 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -254,7 +254,7 @@ Event::~Event() { WriteDbFrames(); // Should not be static because we might be multi-threaded - char sql[ZM_SQL_MED_BUFSIZ]; + char sql[ZM_SQL_LGE_BUFSIZ]; snprintf(sql, sizeof(sql), "UPDATE Events SET Name='%s %" PRIu64 "', EndTime = from_unixtime( %ld ), Length = %s%ld.%02ld, Frames = %d, AlarmFrames = %d, TotScore = %d, AvgScore = %d, MaxScore = %d, DefaultVideo = '%s' WHERE Id = %" PRIu64, monitor->EventPrefix(), id, end_time.tv_sec, @@ -616,6 +616,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a if ( alarm_image ) { if ( monitor->GetOptSaveJPEGs() & 2 ) { + static char event_file[PATH_MAX]; snprintf(event_file, sizeof(event_file), staticConfig.analyse_file_format, path, frames); Debug(1, "Writing analysis frame %d", frames); if ( ! WriteFrameImage(alarm_image, timestamp, event_file, true) ) { From 7955a1c9b2d85c39e8ca831f009d9a3978e89fc1 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 12:56:00 -0400 Subject: [PATCH 22/40] fix version check to get rid of deprecated av_register_all --- src/zm_ffmpeg.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 578e12e6b..c5bc1b471 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -78,7 +78,7 @@ void FFMPEGInit() { av_log_set_callback(log_libav_callback); else Info("Not enabling ffmpeg logs, as LOG_FFMPEG is disabled in options"); -#if LIBAVCODEC_VERSION_CHECK(58, 18, 0, 64, 0) +#if LIBAVFORMAT_VERSION_CHECK(58, 9, 0, 64, 0) #else av_register_all(); #endif From d97dd6cdd97438de87c97cbfd69599ef99ad3dde Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 14:11:56 -0400 Subject: [PATCH 23/40] Should close videostore before closing input codecs/streams. --- src/zm_ffmpeg_camera.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 04b4588d9..c07c9312e 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -675,6 +675,11 @@ int FfmpegCamera::Close() { } #endif + if ( videoStore ) { + delete videoStore; + videoStore = NULL; + } + if ( mVideoCodecContext ) { avcodec_close(mVideoCodecContext); Debug(1,"After codec close"); @@ -700,10 +705,6 @@ int FfmpegCamera::Close() { mFormatContext = NULL; } - if ( videoStore ) { - delete videoStore; - videoStore = NULL; - } if ( packetqueue ) { delete packetqueue; packetqueue = NULL; From 9ae6acf532f4bc471adc61a4ed417a15ddd34fde Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Thu, 4 Apr 2019 17:20:21 -0400 Subject: [PATCH 24/40] Fix for opening audio_in_codec --- src/zm_ffmpeg.cpp | 1 + src/zm_ffmpeg_camera.cpp | 18 +++++++++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index c5bc1b471..63c0c9aa3 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -437,6 +437,7 @@ unsigned int zm_av_packet_ref( AVPacket *dst, AVPacket *src ) { dst->pts = src->pts; dst->dts = src->dts; dst->duration = src->duration; + dst->stream_index = src->stream_index; return 0; } #endif diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index 04b4588d9..ae04e0bc9 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -565,15 +565,23 @@ int FfmpegCamera::OpenFfmpeg() { Debug(1, "HWACCEL not in use"); } if ( mAudioStreamId >= 0 ) { + if ( (mAudioCodec = avcodec_find_decoder( #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - mAudioCodecContext = avcodec_alloc_context3( NULL ); - avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar ); + mFormatContext->streams[mAudioStreamId]->codecpar->codec_id #else - mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec; + mFormatContext->streams[mAudioStreamId]->codec->codec_id #endif - if ( (mAudioCodec = avcodec_find_decoder(mAudioCodecContext->codec_id)) == NULL ) { + )) == NULL ) { Debug(1, "Can't find codec for audio stream from %s", mPath.c_str()); } else { +#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) + mAudioCodecContext = avcodec_alloc_context3(mAudioCodec); + avcodec_parameters_to_context( mAudioCodecContext, mFormatContext->streams[mAudioStreamId]->codecpar ); +#else + mAudioCodecContext = mFormatContext->streams[mAudioStreamId]->codec; + // = avcodec_alloc_context3(mAudioCodec); +#endif + Debug(1, "Audio Found decoder"); zm_dump_stream_format(mFormatContext, mAudioStreamId, 0, 0); // Open the codec @@ -584,7 +592,7 @@ int FfmpegCamera::OpenFfmpeg() { Debug ( 1, "Calling avcodec_open2" ); if ( avcodec_open2(mAudioCodecContext, mAudioCodec, 0) < 0 ) { #endif - Error( "Unable to open codec for video stream from %s", mPath.c_str() ); + Error( "Unable to open codec for audio stream from %s", mPath.c_str() ); return -1; } Debug(2, "Opened audio codec"); From aaef151815a1909dfba7153aaf7fa7cbf0a72193 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 5 Apr 2019 13:18:06 -0400 Subject: [PATCH 25/40] ZM_VERSION is a constant not a scalar variable --- scripts/ZoneMinder/lib/ZoneMinder/Control/Dahua.pm | 2 +- scripts/ZoneMinder/lib/ZoneMinder/Control/PSIA.pm | 2 +- scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Dahua.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Dahua.pm index e274aaaf7..e55a6da1c 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Dahua.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Dahua.pm @@ -84,7 +84,7 @@ sub open use LWP::UserAgent; $self->{ua} = LWP::UserAgent->new(keep_alive => 1); - $self->{ua}->agent("ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION); + $self->{ua}->agent("ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION); $self->{state} = 'closed'; # credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string) $self->{ua}->credentials($ADDRESS, $REALM, $USERNAME, $PASSWORD); diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/PSIA.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/PSIA.pm index fe067fe1f..438c5cff5 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/PSIA.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/PSIA.pm @@ -40,7 +40,7 @@ sub open use LWP::UserAgent; $self->{ua} = LWP::UserAgent->new; - $self->{ua}->agent( "ZoneMinder Control Agent/".$ZoneMinder::Base::ZM_VERSION ); + $self->{ua}->agent( "ZoneMinder Control Agent/".ZoneMinder::Base::ZM_VERSION ); $self->{state} = 'closed'; Debug( "sendCmd credentials control address:'".$ADDRESS ."' realm:'" . $REALM diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm index 4ee710297..c57fc5c62 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm @@ -45,7 +45,7 @@ sub open { use LWP::UserAgent; $self->{ua} = LWP::UserAgent->new; - $self->{ua}->agent('ZoneMinder Control Agent/'.$ZoneMinder::Base::ZM_VERSION); + $self->{ua}->agent('ZoneMinder Control Agent/'.ZoneMinder::Base::ZM_VERSION); $self->{state} = 'closed'; # credentials: ("ip:port" (no prefix!), realm (string), username (string), password (string) Debug ( "sendCmd credentials control address:'".$ADDRESS From e1873b1693b4b15b6df184f729538c69515f6975 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 5 Apr 2019 15:17:13 -0400 Subject: [PATCH 26/40] debug response content --- scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm index c57fc5c62..4afba372c 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control/Trendnet.pm @@ -120,6 +120,7 @@ sub sendCmd { Debug('sendCmd command: ' . $url); if ( $res->is_success ) { + Debug($res->content); return !undef; } Error("Error check failed: '".$res->status_line()."' cmd:'".$cmd."'"); @@ -155,6 +156,7 @@ sub sendCmdPost { Debug("sendCmdPost credentials control to: $PROTOCOL$ADDRESS$url realm:'" . $REALM . "' username:'" . $USERNAME . "' password:'".$PASSWORD."'"); if ( $res->is_success ) { + Debug($res->content); return !undef; } Error("sendCmdPost Error check failed: '".$res->status_line()."' cmd:"); From aa83239069431ad387c43fa659a4204709832dd8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 5 Apr 2019 15:18:03 -0400 Subject: [PATCH 27/40] rework zmcontrol.pl. If command is given and server is not up, use zmdc.pl to start it. Give up after 10 seconds. --- scripts/zmcontrol.pl.in | 185 ++++++++++++++++++++-------------------- 1 file changed, 91 insertions(+), 94 deletions(-) diff --git a/scripts/zmcontrol.pl.in b/scripts/zmcontrol.pl.in index b0388bcf3..f83bc82d4 100644 --- a/scripts/zmcontrol.pl.in +++ b/scripts/zmcontrol.pl.in @@ -30,7 +30,7 @@ use autouse 'Pod::Usage'=>qw(pod2usage); use POSIX qw/strftime EPIPE/; use Socket; #use Data::Dumper; -use Module::Load::Conditional qw{can_load};; +use Module::Load::Conditional qw{can_load}; use constant MAX_CONNECT_DELAY => 15; use constant MAX_COMMAND_WAIT => 1800; @@ -43,7 +43,7 @@ delete @ENV{qw(IFS CDPATH ENV BASH_ENV)}; logInit(); -my $arg_string = join( " ", @ARGV ); +my $arg_string = join(' ', @ARGV); my $id; my %options; @@ -64,22 +64,46 @@ GetOptions( ) or pod2usage(-exitstatus => -1); if ( !$id ) { - print( STDERR "Please give a valid monitor id\n" ); + print(STDERR "Please give a valid monitor id\n"); pod2usage(-exitstatus => -1); } ( $id ) = $id =~ /^(\w+)$/; -Debug("zmcontrol: arg string: $arg_string"); my $sock_file = $Config{ZM_PATH_SOCKS}.'/zmcontrol-'.$id.'.sock'; +Debug("zmcontrol: arg string: $arg_string sock file $sock_file"); -socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) - or Fatal("Can't open socket: $!"); +socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); my $saddr = sockaddr_un($sock_file); -my $server_up = connect(CLIENT, $saddr); -if ( !$server_up ) { + +if ( $options{command} ) { + # Have a command, so we are the client, connect to the server and send it. + + my $tries = 10; + my $server_up; + while ( $tries and ! ( $server_up = connect(CLIENT, $saddr) ) ) { + Debug("Failed to connect to $server_up at $sock_file"); + runCommand("zmdc.pl start zmcontrol.pl --id=$id"); + sleep 1; + $tries -= 1; + } + if ( $server_up ) { + # The server is there, connect to it + #print( "Writing commands\n" ); + CLIENT->autoflush(); + + if ( $options{command} ) { + my $message = jsonEncode(\%options); + print(CLIENT $message); + } + shutdown(CLIENT, 1); + } else { + Error("Unable to connect to zmcontrol server at $sock_file"); + } +} else { + # The server isn't there my $monitor = zmDbGetMonitorAndControl($id); if ( !$monitor ) { @@ -113,99 +137,72 @@ if ( !$server_up ) { Fatal("Can't load ZoneMinder::Control::$protocol\n$Module::Load::Conditional::ERROR"); } - if ( my $cpid = fork() ) { - logReinit(); + Info("Control server $id/$protocol starting at " + .strftime('%y/%m/%d %H:%M:%S', localtime()) + ); - # Parent process just sleep and fall through - socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) - or die("Can't open socket: $!"); - my $attempts = 0; - while ( !connect(CLIENT, $saddr) ) { - $attempts++; - Fatal("Can't connect: $! after $attempts attempts to $sock_file") if $attempts > MAX_CONNECT_DELAY; - sleep(1); - } - } elsif ( defined($cpid) ) { - close(STDOUT); - close(STDERR); + $0 = $0." --id=$id"; - setpgrp(); + my $control = "ZoneMinder::Control::$protocol"->new($id); + my $control_key = $control->getKey(); + $control->loadMonitor(); - logReinit(); + $control->open(); - Info("Control server $id/$protocol starting at " - .strftime('%y/%m/%d %H:%M:%S', localtime()) - ); - - $0 = $0." --id $id"; - - my $control = "ZoneMinder::Control::$protocol"->new($id); - my $control_key = $control->getKey(); - $control->loadMonitor(); - - $control->open(); - - socket(SERVER, PF_UNIX, SOCK_STREAM, 0) - or Fatal("Can't open socket: $!"); - unlink($sock_file); - bind(SERVER, $saddr) or Fatal("Can't bind: $!"); - listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); - - my $rin = ''; - vec( $rin, fileno(SERVER), 1 ) = 1; - my $win = $rin; - my $ein = $win; - my $timeout = MAX_COMMAND_WAIT; - while( 1 ) { - my $nfound = select(my $rout = $rin, undef, undef, $timeout); - if ( $nfound > 0 ) { - if ( vec( $rout, fileno(SERVER), 1 ) ) { - my $paddr = accept(CLIENT, SERVER); - my $message = ; - - next if !$message; - - my $params = jsonDecode($message); - #Debug( Dumper( $params ) ); - - my $command = $params->{command}; - close( CLIENT ); - if ( $command eq 'quit' ) { - last; - } - $control->$command($params); - } else { - Fatal('Bogus descriptor'); - } - } elsif ( $nfound < 0 ) { - if ( $! == EPIPE ) { - Error("Can't select: $!"); - } else { - Fatal("Can't select: $!"); - } - } else { - #print( "Select timed out\n" ); - last; - } - } # end while forever - Info("Control server $id/$protocol exiting"); - unlink($sock_file); - $control->close(); - exit(0); - } else { - Fatal("Can't fork: $!"); + # If we have a command when starting up, then do it. + if ( $options{command} ) { + my $command = $options{command}; + $control->$command(\%options); } + + socket(SERVER, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!"); + unlink($sock_file); + bind(SERVER, $saddr) or Fatal("Can't bind: $!"); + listen(SERVER, SOMAXCONN) or Fatal("Can't listen: $!"); + + my $rin = ''; + vec( $rin, fileno(SERVER), 1 ) = 1; + my $win = $rin; + my $ein = $win; + my $timeout = MAX_COMMAND_WAIT; + while( 1 ) { + my $nfound = select(my $rout = $rin, undef, undef, $timeout); + if ( $nfound > 0 ) { + if ( vec( $rout, fileno(SERVER), 1 ) ) { + my $paddr = accept(CLIENT, SERVER); + my $message = ; + + next if !$message; + + my $params = jsonDecode($message); + #Debug( Dumper( $params ) ); + + my $command = $params->{command}; + close( CLIENT ); + if ( $command eq 'quit' ) { + last; + } + $control->$command($params); + } else { + Fatal('Bogus descriptor'); + } + } elsif ( $nfound < 0 ) { + if ( $! == EPIPE ) { + Error("Can't select: $!"); + } else { + Fatal("Can't select: $!"); + } + } else { + #print( "Select timed out\n" ); + last; + } + } # end while forever + Info("Control server $id/$protocol exiting"); + unlink($sock_file); + $control->close(); + exit(0); } # end if !server up -# The server is there, connect to it -#print( "Writing commands\n" ); -CLIENT->autoflush(); - -if ( $options{command} ) { - my $message = jsonEncode(\%options); - print(CLIENT $message); -} -shutdown(CLIENT, 1); exit(0); From 381f526d66874703b877a315e108a6d4c82cb4a8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Fri, 5 Apr 2019 15:18:20 -0400 Subject: [PATCH 28/40] spacing --- web/includes/control_functions.php | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/web/includes/control_functions.php b/web/includes/control_functions.php index bea235668..77240df49 100644 --- a/web/includes/control_functions.php +++ b/web/includes/control_functions.php @@ -735,29 +735,29 @@ function buildControlCommand( $monitor ) { return( $ctrlCommand ); } -function sendControlCommand($mid,$command) { +function sendControlCommand($mid, $command) { // Either connects to running zmcontrol.pl or runs zmcontrol.pl to send the command. - $socket = socket_create( AF_UNIX, SOCK_STREAM, 0 ); + $socket = socket_create(AF_UNIX, SOCK_STREAM, 0); if ( $socket < 0 ) { - Fatal( 'socket_create() failed: '.socket_strerror($socket) ); + Fatal('socket_create() failed: '.socket_strerror($socket)); } $sockFile = ZM_PATH_SOCKS.'/zmcontrol-'.$mid.'.sock'; - if ( @socket_connect( $socket, $sockFile ) ) { + if ( @socket_connect($socket, $sockFile) ) { $options = array(); - foreach ( explode( ' ', $command ) as $option ) { - if ( preg_match( '/--([^=]+)(?:=(.+))?/', $option, $matches ) ) { + foreach ( explode(' ', $command) as $option ) { + if ( preg_match('/--([^=]+)(?:=(.+))?/', $option, $matches) ) { $options[$matches[1]] = $matches[2]?$matches[2]:1; } } - $optionString = jsonEncode( $options ); - if ( !socket_write( $socket, $optionString ) ) { - Fatal( "Can't write to control socket: ".socket_strerror(socket_last_error($socket)) ); + $optionString = jsonEncode($options); + if ( !socket_write($socket, $optionString) ) { + Fatal("Can't write to control socket: ".socket_strerror(socket_last_error($socket))); } - socket_close( $socket ); + socket_close($socket); } else if ( $command != 'quit' ) { $command .= ' --id='.$mid; // Can't connect so use script - $ctrlOutput = exec( escapeshellcmd( $command ) ); + $ctrlOutput = exec(escapeshellcmd($command)); } -} // end function sendControlCommand( $mid, $command ) +} // end function sendControlCommand($mid, $command) From f719dd9acc4b042be9b56999be179fabbe166b83 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Apr 2019 10:29:02 -0400 Subject: [PATCH 29/40] always commit buffered db_frames when we have a new max score image or alarm cause image --- src/zm_event.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 7b8b446d4..330f421eb 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -538,6 +538,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a } frames++; + bool write_to_db = false; if ( monitor->GetOptSaveJPEGs() & 1 ) { static char event_file[PATH_MAX]; @@ -549,10 +550,12 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a } else { //If this is the first frame, we should add a thumbnail to the event directory if ( (frames == 1) || (score > (int)max_score) ) { + write_to_db = true; // web ui might show this as thumbnail, so db needs to know about it. WriteFrameImage(image, timestamp, snapshot_file); } // The first frame with a score will be the frame that alarmed the event if ( (!alarm_frame_written) && (score > 0) ) { + write_to_db = true; // OD processing will need it, so the db needs to know about it alarm_frame_written = true; WriteFrameImage(image, timestamp, alarm_file); } @@ -574,7 +577,7 @@ void Event::AddFrame(Image *image, struct timeval timestamp, int score, Image *a static char sql[ZM_SQL_MED_BUFSIZ]; frame_data.push(new Frame(id, frames, frame_type, timestamp, delta_time, score)); - if ( frame_data.size() > 20 ) { + if ( write_to_db || ( frame_data.size() > 20 ) ) { WriteDbFrames(); Debug(1, "Adding 20 frames to DB"); last_db_frame = frames; From d776f63bd85bc8a56f29115dcaafb2815072d260 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Sun, 7 Apr 2019 17:23:39 -0400 Subject: [PATCH 30/40] Change MonitorIds from TinyText to TEXT. Fixes #2569 --- db/zm_create.sql.in | 2 +- db/zm_update-1.33.6.sql | 1 + version | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 db/zm_update-1.33.6.sql diff --git a/db/zm_create.sql.in b/db/zm_create.sql.in index 1eaca832b..c197d09ab 100644 --- a/db/zm_create.sql.in +++ b/db/zm_create.sql.in @@ -639,7 +639,7 @@ CREATE TABLE `Users` ( `Devices` enum('None','View','Edit') NOT NULL default 'None', `System` enum('None','View','Edit') NOT NULL default 'None', `MaxBandwidth` varchar(16), - `MonitorIds` tinytext, + `MonitorIds` text, PRIMARY KEY (`Id`), UNIQUE KEY `UC_Username` (`Username`) ) ENGINE=@ZM_MYSQL_ENGINE@; diff --git a/db/zm_update-1.33.6.sql b/db/zm_update-1.33.6.sql new file mode 100644 index 000000000..159f80ac6 --- /dev/null +++ b/db/zm_update-1.33.6.sql @@ -0,0 +1 @@ +ALTER TABLE Users MODIFY MonitorIds text; diff --git a/version b/version index ad5831d4d..170749774 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.33.5 +1.33.6 From 4b2fe5c3c7fb50d590e354afe7642e301d024c5e Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Sun, 7 Apr 2019 18:21:52 -0500 Subject: [PATCH 31/40] Update zoneminder.spec --- distros/redhat/zoneminder.spec | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/distros/redhat/zoneminder.spec b/distros/redhat/zoneminder.spec index 1f0352fc4..440b05acc 100644 --- a/distros/redhat/zoneminder.spec +++ b/distros/redhat/zoneminder.spec @@ -23,7 +23,7 @@ %global _hardened_build 1 Name: zoneminder -Version: 1.33.4 +Version: 1.33.6 Release: 1%{?dist} Summary: A camera monitoring and analysis tool Group: System Environment/Daemons @@ -410,11 +410,14 @@ EOF %dir %attr(755,nginx,nginx) %{_localstatedir}/spool/zoneminder-upload %changelog +* Sun Apr 07 2019 Andrew Bauer - 1.33.6-1 +- Bump to 1.33.6 Development + * Sat Mar 30 2019 Andrew Bauer - 1.33.4-1 -- Bump tp 1.33.4 Development +- Bump to 1.33.4 Development * Tue Dec 11 2018 Andrew Bauer - 1.33.0-1 -- Bump tp 1.33.0 Development +- Bump to 1.33.0 Development * Sat Dec 08 2018 Andrew Bauer - 1.32.3-1 - 1.32.3 Release From 3c57d79669ecd33086c0c886f5381488e0cd47fc Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Apr 2019 10:04:26 -0400 Subject: [PATCH 32/40] Go back to using video_first_dts --- src/zm_videostore.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 8b307ed7e..51e4805ef 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -93,7 +93,6 @@ VideoStore::VideoStore( oc->metadata = pmetadata; out_format = oc->oformat; - video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id); if ( !video_out_codec ) { #if (LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 11, 0) && (LIBAVFORMAT_VERSION_MICRO >= 100)) @@ -870,7 +869,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { dumpPacket(video_in_stream, ipkt, "input packet"); int64_t duration; - if ( ipkt->duration && ( ipkt->duration != AV_NOPTS_VALUE ) ) { + if ( ipkt->duration != AV_NOPTS_VALUE ) { duration = av_rescale_q( ipkt->duration, video_in_stream->time_base, @@ -929,8 +928,9 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { } // Just because the in stream wraps, doesn't mean the out needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out. So need to handle in wrap, without causing out wrap. if ( ipkt->dts != AV_NOPTS_VALUE ) { -#if 0 - if ( (!video_first_dts) && ( ipkt->dts >= 0 ) ) { +#if 1 + if ( (!video_first_dts) ) { + // && ( ipkt->dts >= 0 ) ) { // This is the first packet. opkt.dts = 0; Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts); @@ -938,14 +938,14 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { } else { #endif opkt.dts = av_rescale_q( - ipkt->dts - video_first_pts, + ipkt->dts - video_first_dts, video_in_stream->time_base, video_out_stream->time_base ); Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")", - opkt.dts, ipkt->dts, video_first_pts); + opkt.dts, ipkt->dts, video_first_dts); video_last_dts = ipkt->dts; -#if 0 +#if 1 } #endif if ( opkt.dts > opkt.pts ) { From e81c216b4a8d64670f68affc9d6bd12689e23fac Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Apr 2019 13:51:13 -0400 Subject: [PATCH 33/40] add more fields in dump_codec. --- src/zm_ffmpeg.cpp | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/zm_ffmpeg.cpp b/src/zm_ffmpeg.cpp index 63c0c9aa3..d49210cbf 100644 --- a/src/zm_ffmpeg.cpp +++ b/src/zm_ffmpeg.cpp @@ -320,7 +320,8 @@ void zm_dump_codecpar ( const AVCodecParameters *par ) { #endif void zm_dump_codec(const AVCodecContext *codec) { - Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d) format(%s)", + Debug(1, "Dumping codec_context codec_type(%d) codec_id(%d) width(%d) height(%d) timebase(%d/%d) format(%s)\n" + "gop_size %d max_b_frames %d me_cmp %d me_range %d qmin %d qmax %d", codec->codec_type, codec->codec_id, codec->width, @@ -328,11 +329,17 @@ void zm_dump_codec(const AVCodecContext *codec) { codec->time_base.num, codec->time_base.den, #if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0) - (codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt)) + (codec->pix_fmt == AV_PIX_FMT_NONE ? "none" : av_get_pix_fmt_name(codec->pix_fmt)), #else - "unsupported on avconv" + "unsupported on avconv", #endif -); + codec->gop_size, + codec->max_b_frames, + codec->me_cmp, + codec->me_range, + codec->qmin, + codec->qmax + ); } /* "user interface" functions */ @@ -356,9 +363,9 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) Debug(1, "ids [0x%x]", st->id); if (lang) Debug(1, "language (%s)", lang->value); - Debug(1, "frames:%d, frame_size:%d stream timebase: %d/%d codec timebase: %d/%d", - st->codec_info_nb_frames, codec->frame_size, st->time_base.num, st->time_base.den, - st->codec->time_base.num, st->codec->time_base.den + Debug(1, "frames:%d, frame_size:%d stream timebase: %d/%d", + st->codec_info_nb_frames, codec->frame_size, + st->time_base.num, st->time_base.den ); avcodec_string(buf, sizeof(buf), st->codec, is_output); Debug(1, "codec: %s", buf); @@ -377,17 +384,14 @@ void zm_dump_stream_format(AVFormatContext *ic, int i, int index, int is_output) display_aspect_ratio.num, display_aspect_ratio.den); } - if ( st->codec->codec_type == AVMEDIA_TYPE_VIDEO ) { + if ( codec->codec_type == AVMEDIA_TYPE_VIDEO ) { int fps = st->avg_frame_rate.den && st->avg_frame_rate.num; int tbn = st->time_base.den && st->time_base.num; - int tbc = st->codec->time_base.den && st->codec->time_base.num; if (fps) zm_log_fps(av_q2d(st->avg_frame_rate), "fps"); if (tbn) zm_log_fps(1 / av_q2d(st->time_base), "stream tb numerator"); - if (tbc) - zm_log_fps(1 / av_q2d(st->codec->time_base), "codec time base:"); } if (st->disposition & AV_DISPOSITION_DEFAULT) From accaeadb188aaabd9ea07ea4bf2c705f33a59ae8 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Apr 2019 13:51:41 -0400 Subject: [PATCH 34/40] code cleanup. dump_codecs --- src/zm_ffmpeg_camera.cpp | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index da25b5f62..152f426f2 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -535,31 +535,23 @@ int FfmpegCamera::OpenFfmpeg() { zm_dump_stream_format(mFormatContext, mVideoStreamId, 0, 0); // Open the codec #if !LIBAVFORMAT_VERSION_CHECK(53, 8, 0, 8, 0) - Debug(1, "Calling avcodec_open"); - if ( avcodec_open(mVideoCodecContext, mVideoCodec) < 0 ) + ret = avcodec_open(mVideoCodecContext, mVideoCodec); #else - Debug(1, "Calling avcodec_open2"); - if ( avcodec_open2(mVideoCodecContext, mVideoCodec, &opts) < 0 ) + ret = avcodec_open2(mVideoCodecContext, mVideoCodec, &opts); #endif - { - AVDictionaryEntry *e = NULL; - while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Option %s not recognized by ffmpeg", e->key); - } - Error( "Unable to open codec for video stream from %s", mPath.c_str() ); + AVDictionaryEntry *e = NULL; + while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { + Warning( "Option %s not recognized by ffmpeg", e->key); + } + if ( ret < 0 ) { + Error("Unable to open codec for video stream from %s", mPath.c_str()); av_dict_free(&opts); return -1; - } else { - - AVDictionaryEntry *e = NULL; - if ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) { - Warning( "Option %s not recognized by ffmpeg", e->key); - } - av_dict_free(&opts); } + zm_dump_codec(mVideoCodecContext); } - if (mVideoCodecContext->hwaccel != NULL) { + if ( mVideoCodecContext->hwaccel != NULL ) { Debug(1, "HWACCEL in use"); } else { Debug(1, "HWACCEL not in use"); @@ -595,7 +587,7 @@ int FfmpegCamera::OpenFfmpeg() { Error( "Unable to open codec for audio stream from %s", mPath.c_str() ); return -1; } - Debug(2, "Opened audio codec"); + zm_dump_codec(mAudioCodecContext); } // end if find decoder } // end if have audio_context From 7f2440177b2f9f5752809a140e4dc3b91c6228ba Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Apr 2019 13:51:55 -0400 Subject: [PATCH 35/40] remove duplicate dump_codec --- src/zm_videostore.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 51e4805ef..997b27cd2 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -119,8 +119,6 @@ VideoStore::VideoStore( if ( ret < 0 ) { Error("Could not initialize video_out_ctx parameters"); return; - } else { - zm_dump_codec(video_out_ctx); } #else video_out_stream = avformat_new_stream(oc, NULL); From 1b98f3529f7b60dd55e5e6860ac21bf503a9edf3 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Apr 2019 14:18:59 -0400 Subject: [PATCH 36/40] allow non-increasing dts in muxer --- src/zm_videostore.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/zm_videostore.cpp b/src/zm_videostore.cpp index 51e4805ef..da245b14c 100644 --- a/src/zm_videostore.cpp +++ b/src/zm_videostore.cpp @@ -92,6 +92,7 @@ VideoStore::VideoStore( oc->metadata = pmetadata; out_format = oc->oformat; + out_format->flags |= AVFMT_TS_NONSTRICT; // allow non increasing dts video_out_codec = avcodec_find_encoder(video_in_ctx->codec_id); if ( !video_out_codec ) { @@ -926,17 +927,18 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { opkt.pts = 0; //AV_NOPTS_VALUE; } - // Just because the in stream wraps, doesn't mean the out needs to. Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out. So need to handle in wrap, without causing out wrap. + // Just because the in stream wraps, doesn't mean the out needs to. + // Really, if we are limiting ourselves to 10min segments I can't imagine every wrapping in the out. + // So need to handle in wrap, without causing out wrap. + if ( ipkt->dts != AV_NOPTS_VALUE ) { -#if 1 - if ( (!video_first_dts) ) { + if ( !video_first_dts ) { // && ( ipkt->dts >= 0 ) ) { // This is the first packet. opkt.dts = 0; Debug(1, "Starting video first_dts will become (%" PRId64 ")", ipkt->dts); video_first_dts = ipkt->dts; } else { -#endif opkt.dts = av_rescale_q( ipkt->dts - video_first_dts, video_in_stream->time_base, @@ -944,10 +946,7 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { ); Debug(3, "opkt.dts = %" PRId64 " from ipkt->dts(%" PRId64 ") - first_pts(%" PRId64 ")", opkt.dts, ipkt->dts, video_first_dts); - video_last_dts = ipkt->dts; -#if 1 } -#endif if ( opkt.dts > opkt.pts ) { Debug(1, "opkt.dts(%" PRId64 ") must be <= opkt.pts(%" PRId64 "). Decompression must happen " @@ -960,6 +959,17 @@ int VideoStore::writeVideoFramePacket(AVPacket *ipkt) { opkt.dts = 0; } +# if 0 + if ( opkt.dts <= video_out_stream->cur_dts ) { + Warning("Fixing non-monotonic dts/pts dts %" PRId64 " pts %" PRId64 " stream %" PRId64, + opkt.dts, opkt.pts, video_out_stream->cur_dts); + opkt.dts = video_out_stream->cur_dts + 1; + if ( opkt.dts > opkt.pts ) { + opkt.pts = opkt.dts; + } + } +#endif + opkt.flags = ipkt->flags; opkt.pos = -1; opkt.data = ipkt->data; From 3abf263e7a9bf206644d3576afbdcb73c416139f Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 8 Apr 2019 16:57:41 -0400 Subject: [PATCH 37/40] fixup half-merged changes to filter to view in montagereview --- scripts/ZoneMinder/lib/ZoneMinder/Control.pm | 2 +- web/api/app/Plugin/Crud | 2 +- web/lang/en_gb.php | 1 + web/skins/classic/views/filter.php | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm index efd17abcd..bbc06a884 100644 --- a/scripts/ZoneMinder/lib/ZoneMinder/Control.pm +++ b/scripts/ZoneMinder/lib/ZoneMinder/Control.pm @@ -67,7 +67,7 @@ sub AUTOLOAD { if ( exists($self->{$name}) ) { return $self->{$name}; } - Error("Can't access $name member of object of class $class"); + Error("Can't access $name $AUTOLOAD member of object of class $class"); } sub getKey { diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index c3976f147..0bd63fb46 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5 +Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef diff --git a/web/lang/en_gb.php b/web/lang/en_gb.php index bb5e59a88..4eb493630 100644 --- a/web/lang/en_gb.php +++ b/web/lang/en_gb.php @@ -782,6 +782,7 @@ $SLANG = array( 'VersionRemindNever' => 'Don\'t remind about new versions', 'VersionRemindWeek' => 'Remind again in 1 week', 'Version' => 'Version', + 'ViewMatches' => 'View Matches', 'VideoFormat' => 'Video Format', 'VideoGenFailed' => 'Video Generation Failed!', 'VideoGenFiles' => 'Existing Video Files', diff --git a/web/skins/classic/views/filter.php b/web/skins/classic/views/filter.php index 20218cb07..da965b4e9 100644 --- a/web/skins/classic/views/filter.php +++ b/web/skins/classic/views/filter.php @@ -406,8 +406,8 @@ if ( ZM_OPT_MESSAGE ) {

- - + + Date: Mon, 8 Apr 2019 18:40:52 -0500 Subject: [PATCH 38/40] fix eslint errors --- web/api/app/Plugin/Crud | 2 +- web/skins/classic/views/js/filter.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/web/api/app/Plugin/Crud b/web/api/app/Plugin/Crud index c3976f147..0bd63fb46 160000 --- a/web/api/app/Plugin/Crud +++ b/web/api/app/Plugin/Crud @@ -1 +1 @@ -Subproject commit c3976f1478c681b0bbc132ec3a3e82c3984eeed5 +Subproject commit 0bd63fb464957080ead342db58ca9e01532cf1ef diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index 7de029ff6..29e4dfe82 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -64,12 +64,12 @@ function updateButtons(element) { } function click_automove(element) { - updateButtons(this); - if ( this.checked ) { - $j(this.form.elements['filter[AutoMoveTo]']).css('display','inline'); - } else { - this.form.elements['filter[AutoMoveTo]'].hide(); - } + updateButtons(this); + if ( this.checked ) { + $j(this.form.elements['filter[AutoMoveTo]']).css('display', 'inline'); + } else { + this.form.elements['filter[AutoMoveTo]'].hide(); + } } function checkValue( element ) { From 50dd63c21dfbc05f347784ce2d8728a928632234 Mon Sep 17 00:00:00 2001 From: Andrew Bauer Date: Mon, 8 Apr 2019 19:58:18 -0500 Subject: [PATCH 39/40] fix eslint --- web/skins/classic/views/js/filter.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/web/skins/classic/views/js/filter.js b/web/skins/classic/views/js/filter.js index 29e4dfe82..8b6968668 100644 --- a/web/skins/classic/views/js/filter.js +++ b/web/skins/classic/views/js/filter.js @@ -67,9 +67,9 @@ function click_automove(element) { updateButtons(this); if ( this.checked ) { $j(this.form.elements['filter[AutoMoveTo]']).css('display', 'inline'); - } else { - this.form.elements['filter[AutoMoveTo]'].hide(); - } + } else { + this.form.elements['filter[AutoMoveTo]'].hide(); + } } function checkValue( element ) { From 37b7c32465ea85a1005d3eb120edf6fc7cfdaa80 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Tue, 9 Apr 2019 09:45:28 -0400 Subject: [PATCH 40/40] fix errors when no filter specified --- web/skins/classic/views/montagereview.php | 49 ++++++++++++----------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/web/skins/classic/views/montagereview.php b/web/skins/classic/views/montagereview.php index 61cf95b21..1d05d597e 100644 --- a/web/skins/classic/views/montagereview.php +++ b/web/skins/classic/views/montagereview.php @@ -59,34 +59,35 @@ include('_monitor_filters.php'); $filter_bar = ob_get_contents(); ob_end_clean(); +$filter = array(); if ( isset($_REQUEST['filter']) ) { $filter = $_REQUEST['filter']; } else { - if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) { - $filter = array( - 'Query' => array( - 'terms' => array( - array('attr' => 'StartDateTime', 'op' => '>=', 'val' => $_REQUEST['minTime'], 'obr' => '1'), - array('attr' => 'StartDateTime', 'op' => '<=', 'val' => $_REQUEST['maxTime'], 'cnj' => 'and', 'cbr' => '1'), - ) - ), - ); - if ( count($selected_monitor_ids) ) { - $filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => 'IN', 'val' => implode(',',$selected_monitor_ids), 'cnj' => 'and')); - } else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) { - # this should be redundant - for ($i=0; $i < count($displayMonitors); $i++) { - if ($i == '0') { - $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1'); - } else if ($i == (count($displayMonitors)-1)) { - $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1'); - } else { - $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or'); - } - } - } -} # end if REQUEST[Filter] + if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($displayMonitors) != 0) { + $filter = array( + 'Query' => array( + 'terms' => array( + array('attr' => 'StartDateTime', 'op' => '>=', 'val' => $_REQUEST['minTime'], 'obr' => '1'), + array('attr' => 'StartDateTime', 'op' => '<=', 'val' => $_REQUEST['maxTime'], 'cnj' => 'and', 'cbr' => '1'), + ) + ), + ); + if ( count($selected_monitor_ids) ) { + $filter['Query']['terms'][] = (array('attr' => 'MonitorId', 'op' => 'IN', 'val' => implode(',',$selected_monitor_ids), 'cnj' => 'and')); + } else if ( ( $group_id != 0 || isset($_SESSION['ServerFilter']) || isset($_SESSION['StorageFilter']) || isset($_SESSION['StatusFilter']) ) ) { + # this should be redundant + for ($i=0; $i < count($displayMonitors); $i++) { + if ($i == '0') { + $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'and', 'obr' => '1'); + } else if ($i == (count($displayMonitors)-1)) { + $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or', 'cbr' => '1'); + } else { + $filter['Query']['terms'][] = array('attr' => 'MonitorId', 'op' => '=', 'val' => $displayMonitors[$i]['Id'], 'cnj' => 'or'); + } + } + } + } # end if REQUEST[Filter] parseFilter($filter); # This is to enable the download button session_start();