Merge branch 'release-1.34'

pull/3006/head
Isaac Connor 2020-08-06 11:57:35 -04:00
commit a19990f4d7
13 changed files with 103 additions and 41 deletions

View File

@ -213,9 +213,11 @@ Event::Event(
if ( monitor->GetOptVideoWriter() == Monitor::X264ENCODE ) {
#if ZM_HAVE_VIDEOWRITER_X264MP4
videowriter = new X264MP4Writer(video_file.c_str(),
monitor->Width(), monitor->Height(),
monitor->Colours(), monitor->SubpixelOrder(),
monitor->GetOptEncoderParams());
monitor->Width(),
monitor->Height(),
monitor->Colours(),
monitor->SubpixelOrder(),
monitor->GetOptEncoderParamsVec());
#else
Error("ZoneMinder was not compiled with the X264 MP4 video writer, check dependencies (x264 and mp4v2)");
#endif

View File

@ -383,6 +383,7 @@ Monitor::Monitor(
strncpy(event_prefix, p_event_prefix, sizeof(event_prefix)-1);
strncpy(label_format, p_label_format, sizeof(label_format)-1);
Debug(1, "encoder params %s", encoderparams.c_str());
// Change \n to actual line feeds
char *token_ptr = label_format;
@ -632,7 +633,7 @@ bool Monitor::connect() {
image_buffer = new Snapshot[image_buffer_count];
for ( int i = 0; i < image_buffer_count; i++ ) {
image_buffer[i].timestamp = &(shared_timestamps[i]);
image_buffer[i].image = new Image(width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]) );
image_buffer[i].image = new Image(width, height, camera->Colours(), camera->SubpixelOrder(), &(shared_images[i*camera->ImageSize()]));
image_buffer[i].image->HoldBuffer(true); /* Don't release the internal buffer or replace it with another */
}
if ( (deinterlacing & 0xff) == 4 ) {

View File

@ -473,7 +473,8 @@ public:
int GetOptSaveJPEGs() const { return savejpegs; }
VideoWriter GetOptVideoWriter() const { return videowriter; }
const std::vector<EncoderParameter_t>* GetOptEncoderParams() const { return &encoderparamsvec; }
const std::vector<EncoderParameter_t>* GetOptEncoderParamsVec() const { return &encoderparamsvec; }
const std::string GetOptEncoderParams() const { return encoderparams; }
uint64_t GetVideoWriterEventId() const { return video_store_data->current_event; }
void SetVideoWriterEventId( unsigned long long p_event_id ) { video_store_data->current_event = p_event_id; }
struct timeval GetVideoWriterStartTime() const { return video_store_data->recording; }

View File

@ -624,8 +624,8 @@ int RemoteCameraHttp::GetResponse() {
static char *content_type_header;
static char *boundary_header;
static char *authenticate_header;
static char subcontent_length_header[32];
static char subcontent_type_header[64];
static char subcontent_length_header[33];
static char subcontent_type_header[65];
static char http_version[16];
static char status_code[16];
@ -896,25 +896,37 @@ int RemoteCameraHttp::GetResponse() {
}
}
Debug( 6, "%d: %s", subheader_len, subheader_ptr );
Debug(6, "%d: %s", subheader_len, subheader_ptr);
if ( (crlf = mempbrk( subheader_ptr, "\r\n", subheader_len )) ) {
if ( (crlf = mempbrk(subheader_ptr, "\r\n", subheader_len)) ) {
//subheaders[n_subheaders++] = subheader_ptr;
n_subheaders++;
if ( !boundary_header && (strncasecmp( subheader_ptr, content_boundary, content_boundary_len ) == 0) ) {
if ( !boundary_header && (strncasecmp(subheader_ptr, content_boundary, content_boundary_len) == 0) ) {
boundary_header = subheader_ptr;
Debug( 4, "Got boundary subheader '%s'", subheader_ptr );
} else if ( !subcontent_length_header[0] && (strncasecmp( subheader_ptr, content_length_match, content_length_match_len) == 0) ) {
strncpy( subcontent_length_header, subheader_ptr+content_length_match_len, sizeof(subcontent_length_header) );
*(subcontent_length_header+strcspn( subcontent_length_header, "\r\n" )) = '\0';
Debug( 4, "Got content length subheader '%s'", subcontent_length_header );
Debug(4, "Got boundary subheader '%s'", subheader_ptr);
} else if (
!subcontent_length_header[0]
&&
(strncasecmp(subheader_ptr, content_length_match, content_length_match_len) == 0)
) {
strncpy(
subcontent_length_header,
subheader_ptr+content_length_match_len,
sizeof(subcontent_length_header)-1
);
*(subcontent_length_header+strcspn(subcontent_length_header, "\r\n")) = '\0';
Debug(4, "Got content length subheader '%s'", subcontent_length_header);
} else if ( !subcontent_type_header[0] && (strncasecmp( subheader_ptr, content_type_match, content_type_match_len) == 0) ) {
strncpy( subcontent_type_header, subheader_ptr+content_type_match_len, sizeof(subcontent_type_header) );
*(subcontent_type_header+strcspn( subcontent_type_header, "\r\n" )) = '\0';
Debug( 4, "Got content type subheader '%s'", subcontent_type_header );
strncpy(
subcontent_type_header,
subheader_ptr+content_type_match_len,
sizeof(subcontent_type_header)-1
);
*(subcontent_type_header+strcspn(subcontent_type_header, "\r\n")) = '\0';
Debug(4, "Got content type subheader '%s'", subcontent_type_header);
} else {
Debug( 6, "Got ignored subheader '%s' found", subheader_ptr );
Debug(6, "Got ignored subheader '%s' found", subheader_ptr);
}
subheader_ptr = crlf;
subheader_len -= buffer.consume( subheader_ptr-(char *)buffer );

View File

@ -37,11 +37,12 @@ VideoStore::VideoStore(
const char *format_in,
AVStream *p_video_in_stream,
AVStream *p_audio_in_stream,
Monitor *monitor
Monitor *p_monitor
) {
video_in_stream = p_video_in_stream;
audio_in_stream = p_audio_in_stream;
monitor = p_monitor;
#if LIBAVCODEC_VERSION_CHECK(57, 64, 0, 64, 0)
//video_in_ctx = avcodec_alloc_context3(NULL);
@ -213,11 +214,18 @@ VideoStore::VideoStore(
}
#if LIBAVCODEC_VERSION_CHECK(56, 35, 0, 64, 0)
#if 0
# This is commented out because we are only doing passthrough right now
/* I'm not entirely sure that this is a good idea. We may have to do it someday but really only when transcoding
* * think what I was trying to achieve here was to have zm_dump_codecpar output nice info
* */
#if 0
AVDictionary *opts = 0;
ret = av_dict_parse_string(&opts, monitor->GetOptEncoderParams().c_str(), "=", ",", 0);
if ( ret < 0 ) {
Warning("Could not parse ffmpeg encoder options '%s'", monitor->GetOptEncoderParams().c_str());
}
if ( (ret = avcodec_open2(video_out_ctx, video_out_codec, &opts)) < 0 ) {
Warning("Can't open video codec (%s) %s",
video_out_codec->name,
@ -404,21 +412,39 @@ bool VideoStore::open() {
}
zm_dump_stream_format(oc, 0, 0, 1);
if (audio_out_stream) zm_dump_stream_format(oc, 1, 0, 1);
if ( audio_out_stream ) zm_dump_stream_format(oc, 1, 0, 1);
AVDictionary *opts = NULL;
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
// Shiboleth reports that this may break seeking in mp4 before it downloads
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
// av_dict_set(&opts, "movflags",
// "frag_keyframe+empty_moov+default_base_moof", 0);
std::string option_string = monitor->GetOptEncoderParams();
ret = av_dict_parse_string(&opts, option_string.c_str(), "=", ",\n", 0);
if ( ret < 0 ) {
Warning("Could not parse ffmpeg output options '%s'", option_string.c_str());
}
const AVDictionaryEntry *movflags_entry = av_dict_get(opts, "movflags", NULL, AV_DICT_MATCH_CASE);
if ( !movflags_entry ) {
Debug(1, "setting movflags to frag_keyframe+empty_moov");
// av_dict_set(&opts, "movflags", "frag_custom+dash+delay_moov", 0);
// Shiboleth reports that this may break seeking in mp4 before it downloads
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
// av_dict_set(&opts, "movflags",
// "frag_keyframe+empty_moov+default_base_moof", 0);
} else {
Debug(1, "using movflags %s", movflags_entry->value);
}
if ( (ret = avformat_write_header(oc, &opts)) < 0 ) {
// if ((ret = avformat_write_header(oc, &opts)) < 0) {
Warning("Unable to set movflags to frag_custom+dash+delay_moov");
/* Write the stream header, if any. */
Warning("Unable to set movflags trying with defaults.");
ret = avformat_write_header(oc, NULL);
} else if (av_dict_count(opts) != 0) {
Warning("some options not set");
} else if ( av_dict_count(opts) != 0 ) {
Info("some options not used, turn on debugging for a list.");
AVDictionaryEntry *e = NULL;
while ( (e = av_dict_get(opts, "", e, AV_DICT_IGNORE_SUFFIX)) != NULL ) {
Debug(1, "Encoder Option %s=>%s", e->key, e->value);
if ( !e->value ) {
av_dict_set(&opts, e->key, NULL, 0);
}
}
}
if ( opts ) av_dict_free(&opts);
if ( ret < 0 ) {

View File

@ -19,7 +19,6 @@ extern "C" {
class VideoStore {
private:
AVOutputFormat *out_format;
AVFormatContext *oc;
@ -30,6 +29,7 @@ private:
AVStream *video_in_stream;
AVStream *audio_in_stream;
Monitor *monitor;
// Move this into the object so that we aren't constantly allocating/deallocating it on the stack
AVPacket opkt;

View File

@ -254,7 +254,7 @@ function collectData() {
if ( isset($elementData['sql']) )
$fieldSql[] = $elementData['sql'].' as '.$element;
else
$fieldSql[] = $element;
$fieldSql[] = '`'.$element.'`';
if ( isset($elementData['table']) && isset($elementData['join']) ) {
$joinSql[] = 'left join '.$elementData['table'].' on '.$elementData['join'];
}
@ -294,7 +294,7 @@ function collectData() {
preg_match('/^`?(\w+)`?\s*(ASC|DESC)?( NULLS FIRST)?$/i', $sort_field, $matches);
if ( count($matches) ) {
if ( in_array($matches[1], $fieldSql) ) {
if ( in_array($matches[1], $fieldSql) or in_array('`'.$matches[1].'`', $fieldSql) ) {
$sql .= $matches[1];
} else {
ZM\Error('Sort field '.$matches[1].' from ' .$sort_field.' not in SQL Fields: '.join(',', $sort_field));

View File

@ -993,6 +993,18 @@ $OLANG = array(
"loglevel=debug" Set verbosity of FFmpeg (quiet, panic, fatal, error, warning, info, verbose, debug)
'
),
'OPTIONS_ENCODER_PARAMETERS' => array(
'Help' => '
Parameters passed to the encoding codec. name=value separated by either , or newline.~~
For example to changing quality, use the crf option. 1 is best, 51 is worst 23 is default.~~
~~
crf=23~~
~~
You might want to alter the movflags value to support different behaviours. Some people have troubles viewing videos due to the frag_keyframe option, but that option is supposed to allow viewing of incomplete events. See
[https://ffmpeg.org/ffmpeg-formats.html](https://ffmpeg.org/ffmpeg-formats.html)
for more information. ZoneMinder\'s default is frag_keyframe,empty_moov~~
',
),
'OPTIONS_DECODERHWACCELNAME' => array(
'Help' => '
This is equivalent to the ffmpeg -hwaccel command line option. With intel graphics support, use "vaapi". For NVIDIA cuda support use "cuda". To check for support, run ffmpeg -hwaccels on the command line.'

View File

@ -11,6 +11,7 @@
textarea,
input[name="newMonitor[Name]"],
input[name="newMonitor[LabelFormat]"],
input[name="newMonitor[ControlDevice]"],
input[name="newMonitor[ControlAddress]"] {
width: 100%;

View File

@ -68,9 +68,9 @@ if ( !empty($page) ) {
$limitLeft = $limit - $limitStart;
$limitAmount = ($limitLeft>ZM_WEB_EVENTS_PER_PAGE)?ZM_WEB_EVENTS_PER_PAGE:$limitLeft;
}
$eventsSql .= " limit $limitStart, $limitAmount";
$eventsSql .= " LIMIT $limitStart, $limitAmount";
} elseif ( !empty($limit) ) {
$eventsSql .= ' limit 0, '.$limit;
$eventsSql .= ' LIMIT 0, '.$limit;
}
$maxShortcuts = 5;

View File

@ -297,8 +297,8 @@ function changeSize() {
console.log("Error finding frame for " + monitor.id);
continue;
}
monitor_frame.css('width', ( width ? width+'px' : 'auto') );
monitor_frame.css('height', ( height ? height+'px' : 'auto') );
monitor_frame.css('width', ( width ? width+'px' : 'auto'));
monitor_frame.css('height', ( height ? height+'px' : 'auto'));
/*Stream could be an applet so can't use moo tools*/
var streamImg = $('liveStream'+monitor.id);

View File

@ -1,3 +1,7 @@
<?php
global $connkey;
global $monitor;
?>
var connKey = '<?php echo $connkey ?>';
var monitorUrl = '<?php echo ( $monitor->UrlToIndex() ) ?>';
var CMD_QUIT = <?php echo CMD_QUIT ?>;

View File

@ -1060,8 +1060,11 @@ include('_monitor_source_nvsocket.php');
?>
</td></tr>
<tr>
<td><?php echo translate('OptionalEncoderParam') ?></td>
<td><textarea name="newMonitor[EncoderParameters]" rows="4" cols="36"><?php echo validHtmlStr($monitor->EncoderParameters()) ?></textarea></td></tr>
<td><?php echo translate('OptionalEncoderParam') ?>&nbsp;(<?php echo makePopupLink('?view=optionhelp&amp;option=OPTIONS_ENCODER_PARAMETERS', 'zmOptionHelp', 'optionhelp', '?' ) ?>)</td>
<td>
<textarea name="newMonitor[EncoderParameters]" rows="<?php echo count(explode("\n", $monitor->EncoderParameters())); ?>"><?php echo validHtmlStr($monitor->EncoderParameters()) ?></textarea>
</td>
</tr>
<tr><td><?php echo translate('RecordAudio') ?></td><td>
<?php if ( $monitor->Type() == 'Ffmpeg' ) { ?>
<input type="checkbox" name="newMonitor[RecordAudio]" value="1"<?php if ( $monitor->RecordAudio() ) { ?> checked="checked"<?php } ?>/>