Merge branch 'release-1.34'
commit
a19990f4d7
|
@ -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
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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.'
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
textarea,
|
||||
input[name="newMonitor[Name]"],
|
||||
input[name="newMonitor[LabelFormat]"],
|
||||
input[name="newMonitor[ControlDevice]"],
|
||||
input[name="newMonitor[ControlAddress]"] {
|
||||
width: 100%;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 ?>;
|
||||
|
|
|
@ -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') ?> (<?php echo makePopupLink('?view=optionhelp&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 } ?>/>
|
||||
|
|
Loading…
Reference in New Issue