From 4d6b69a4992636c29ab409d9b24826f61182329b Mon Sep 17 00:00:00 2001 From: stan Date: Mon, 15 Mar 2004 09:37:21 +0000 Subject: [PATCH] Sorted out monitor streaming and removed old config. git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@958 e3e1d417-86f3-4887-817a-d78f3d33393f --- src/zm_event.cpp | 6 +- src/zm_event.h | 4 +- src/zm_monitor.cpp | 117 ++++++++++++++++--------------- src/zm_monitor.h | 4 +- src/zms.cpp | 35 ++++----- web/zm_config.php.z | 6 -- web/zm_html_view_cycle.php | 2 +- web/zm_html_view_event.php | 4 +- web/zm_html_view_montagefeed.php | 2 +- web/zm_html_view_watchfeed.php | 2 +- zmconfig.pl.in | 48 ------------- 11 files changed, 87 insertions(+), 143 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index a50a2189d..8fbbd6e9e 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -358,7 +358,7 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * } } -void Event::StreamEvent( int event_id, int maxfps, int rate, int scale ) +void Event::StreamEvent( int event_id, int scale, int rate, int maxfps ) { static char sql[BUFSIZ]; static char eventpath[PATH_MAX]; @@ -504,7 +504,7 @@ void Event::StreamEvent( int event_id, int maxfps, int rate, int scale ) #if HAVE_LIBAVCODEC -void Event::StreamMpeg( int event_id, const char *format, int bitrate, int maxfps, int rate, int scale ) +void Event::StreamMpeg( int event_id, const char *format, int scale, int rate, int maxfps, int bitrate ) { static char sql[BUFSIZ]; static char eventpath[PATH_MAX]; @@ -639,7 +639,7 @@ void Event::StreamMpeg( int event_id, const char *format, int bitrate, int maxfp { last_id = db_id; last_delta = db_delta; - + } } if ( mysql_errno( &dbconn ) ) { diff --git a/src/zm_event.h b/src/zm_event.h index 1e2c16567..1195a3851 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -91,9 +91,9 @@ public: void AddFrames( int n_frames, Image **images, struct timeval **timestamps ); void AddFrame( Image *image, struct timeval timestamp, int score=0, Image *alarm_frame=NULL ); - static void StreamEvent( int event_id, int maxfps=10, int rate=100, int scale=100 ); + static void StreamEvent( int event_id, int scale=100, int rate=100, int maxfps=10 ); #if HAVE_LIBAVCODEC - static void StreamMpeg( int event_id, const char *format, int bitrate=100000, int maxfps=10, int rate=100, int scale=100 ); + static void StreamMpeg( int event_id, const char *format, int scale=100, int rate=100, int maxfps=10, int bitrate=100000 ); #endif // HAVE_LIBAVCODEC }; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 7785a8eda..b8bfc8b3e 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -1075,19 +1075,41 @@ Monitor *Monitor::Load( int id, bool load_zones, Purpose purpose ) return( monitor ); } -void Monitor::StreamImages( unsigned long idle, unsigned long refresh, time_t ttl, int scale ) +void Monitor::StreamImages( int scale, int maxfps, time_t ttl ) { fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); fprintf( stdout, "--ZoneMinderFrame\r\n" ); + int fps = int(GetFPS()); + if ( !fps ) + fps = 5; + + int min_fps = 1; + int max_fps = maxfps; + int base_fps = int(GetFPS()); + int effective_fps = base_fps; + + int frame_mod = 1; + // Min frame repeat? + while( effective_fps > max_fps ) + { + effective_fps /= 2; + frame_mod *= 2; + } + + Debug( 1, ( "BFPS:%d, EFPS:%d, FM:%d", base_fps, effective_fps, frame_mod )); + int last_read_index = image_buffer_count; - static JOCTET img_buffer[ZM_MAX_IMAGE_SIZE]; - int img_buffer_size = 0; - int loop_count = (idle/refresh)-1; time_t stream_start_time; time( &stream_start_time ); + int frame_count = 0; + struct timeval base_time; + struct DeltaTimeval delta_time; + int img_buffer_size = 0; + static JOCTET img_buffer[ZM_MAX_IMAGE_SIZE]; + Image scaled_image; while ( true ) { if ( feof( stdout ) || ferror( stdout ) ) @@ -1096,62 +1118,54 @@ void Monitor::StreamImages( unsigned long idle, unsigned long refresh, time_t tt } if ( last_read_index != shared_data->last_write_index ) { - // Send the next frame - last_read_index = shared_data->last_write_index; - int index = shared_data->last_write_index%image_buffer_count; - //Info(( "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer )); - Snapshot *snap = &image_buffer[index]; - Image *snap_image = snap->image; - - if ( scale == 100 ) + if ( (frame_mod == 1) || ((frame_count%frame_mod) == 0) ) { + // Send the next frame + last_read_index = shared_data->last_write_index; + int index = shared_data->last_write_index%image_buffer_count; + //Info(( "%d: %x - %x", index, image_buffer[index].image, image_buffer[index].image->buffer )); + Snapshot *snap = &image_buffer[index]; + Image *snap_image = snap->image; + + if ( scale != 100 ) + { + scaled_image.Assign( *snap_image ); + + scaled_image.Scale( scale ); + + snap_image = &scaled_image; + } if ( !timestamp_on_capture ) { TimestampImage( snap_image, snap->timestamp->tv_sec ); } - snap_image->EncodeJpeg( img_buffer, &img_buffer_size ); - } - else - { - Image scaled_image( *snap_image ); - scaled_image.Scale( scale ); + fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size ); + fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); + fwrite( img_buffer, img_buffer_size, 1, stdout ); + fprintf( stdout, "\r\n\r\n--ZoneMinderFrame\r\n" ); - if ( !timestamp_on_capture ) + if ( ttl ) { - TimestampImage( &scaled_image, snap->timestamp->tv_sec ); + time_t now; + time( &now ); + if ( (now - stream_start_time) > ttl ) + { + break; + } } - - scaled_image.EncodeJpeg( img_buffer, &img_buffer_size ); - } - - fprintf( stdout, "Content-Length: %d\r\n", img_buffer_size ); - fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); - fwrite( img_buffer, img_buffer_size, 1, stdout ); - fprintf( stdout, "\r\n\r\n--ZoneMinderFrame\r\n" ); - } - usleep( refresh*1000 ); - for ( int i = 0; shared_data->state == IDLE && i < loop_count; i++ ) - { - usleep( refresh*1000 ); - } - if ( ttl ) - { - time_t now; - time( &now ); - if ( (now - stream_start_time) > ttl ) - { - break; } + frame_count++; } + usleep( ZM_SAMPLE_RATE ); } } #if HAVE_LIBAVCODEC -void Monitor::StreamMpeg( const char *format, int bitrate, int maxfps, int scale, int buffer ) +void Monitor::StreamMpeg( const char *format, int scale, int maxfps, int bitrate ) { // Warning, most of these won't work for real-time streaming const char *mime_type = "video/mpeg"; @@ -1196,7 +1210,7 @@ void Monitor::StreamMpeg( const char *format, int bitrate, int maxfps, int scale frame_mod *= 2; } - Info(( "BFPS:%d, EFPS:%d, FM:%d", base_fps, effective_fps, frame_mod )); + Debug( 1, ( "BFPS:%d, EFPS:%d, FM:%d", base_fps, effective_fps, frame_mod )); VideoStream vid_stream( "pipe:", format, bitrate, fps, camera->Colours(), (width*scale)/ZM_SCALE_SCALE, (height*scale)/ZM_SCALE_SCALE ); @@ -1226,25 +1240,18 @@ void Monitor::StreamMpeg( const char *format, int bitrate, int maxfps, int scale Snapshot *snap = &image_buffer[index]; Image *snap_image = snap->image; - if ( scale == 100 ) - { - if ( !timestamp_on_capture ) - { - TimestampImage( snap_image, snap->timestamp->tv_sec ); - } - } - else + if ( scale != 100 ) { scaled_image.Assign( *snap_image ); scaled_image.Scale( scale ); - if ( !timestamp_on_capture ) - { - TimestampImage( &scaled_image, snap->timestamp->tv_sec ); - } snap_image = &scaled_image; } + if ( !timestamp_on_capture ) + { + TimestampImage( snap_image, snap->timestamp->tv_sec ); + } if ( !frame_count ) { diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 01ca5ecb4..c1d65c059 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -287,9 +287,9 @@ public: static int Load( int device, Monitor **&monitors, Purpose purpose=QUERY ); static int Load( const char *host, const char*port, const char*path, Monitor **&monitors, Purpose purpose=QUERY ); static Monitor *Load( int id, bool load_zones=false, Purpose purpose=QUERY ); - void StreamImages( unsigned long idle=5000, unsigned long refresh=50, time_t ttl=0, int scale=100 ); + void StreamImages( int scale=100, int maxfps=10, time_t ttl=0 ); #if HAVE_LIBAVCODEC - void StreamMpeg( const char *format, int bitrate=100000, int maxfps=10, int scale=100, int buffer=0 ); + void StreamMpeg( const char *format, int scale=100, int maxfps=10, int bitrate=100000 ); #endif // HAVE_LIBAVCODEC }; diff --git a/src/zms.cpp b/src/zms.cpp index bde7b743c..ff7320691 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -27,14 +27,11 @@ int main( int argc, const char *argv[] ) char format[32] = ""; int id = 1; int event = 0; - unsigned int bitrate = 100000; - unsigned int maxfps = 10; - unsigned int rate = 100; unsigned int scale = 100; - unsigned int buffer = 0; + unsigned int rate = 100; + unsigned int maxfps = 10; + unsigned int bitrate = 100000; unsigned int ttl = 0; - unsigned long idle = 5000; - unsigned long refresh = 50; zm_dbg_name = "zms"; @@ -77,22 +74,16 @@ int main( int argc, const char *argv[] ) event = strtoull( value, (char **)NULL, 10 ); else if ( !strcmp( name, "format" ) ) strncpy( format, value, sizeof(format) ); - else if ( !strcmp( name, "bitrate" ) ) - bitrate = atoi( value ); - else if ( !strcmp( name, "maxfps" ) ) - maxfps = atoi( value ); - else if ( !strcmp( name, "rate" ) ) - rate = atoi( value ); else if ( !strcmp( name, "scale" ) ) scale = atoi( value ); - else if ( !strcmp( name, "buffer" ) ) - buffer = atol( value ); + else if ( !strcmp( name, "rate" ) ) + rate = atoi( value ); + else if ( !strcmp( name, "maxfps" ) ) + maxfps = atoi( value ); + else if ( !strcmp( name, "bitrate" ) ) + bitrate = atoi( value ); else if ( !strcmp( name, "ttl" ) ) ttl = atoi(value); - else if ( !strcmp( name, "refresh" ) ) - refresh = atol( value ); - else if ( !strcmp( name, "idle" ) ) - idle = atol( value ); } } @@ -127,12 +118,12 @@ int main( int argc, const char *argv[] ) { if ( mode == ZMS_JPEG ) { - monitor->StreamImages( idle, refresh, ttl, scale ); + monitor->StreamImages( scale, maxfps, ttl ); } else { #if HAVE_LIBAVCODEC - monitor->StreamMpeg( format, bitrate, maxfps, scale, buffer ); + monitor->StreamMpeg( format, scale, maxfps, bitrate ); #else // HAVE_LIBAVCODEC Error(( "MPEG streaming of '%s' attempted while disabled", query )); fprintf( stderr, "MPEG streaming is disabled.\nYou should configure with the --with-ffmpeg option and rebuild to use this functionality.\n" ); @@ -145,12 +136,12 @@ int main( int argc, const char *argv[] ) { if ( mode == ZMS_JPEG ) { - Event::StreamEvent( event, maxfps, rate, scale ); + Event::StreamEvent( event, scale, rate, maxfps ); } else { #if HAVE_LIBAVCODEC - Event::StreamMpeg( event, format, bitrate, maxfps, rate, scale ); + Event::StreamMpeg( event, format, scale, rate, maxfps, bitrate ); #else // HAVE_LIBAVCODEC Error(( "MPEG streaming of '%s' attempted while disabled", query )); fprintf( stderr, "MPEG streaming is disabled.\nYou should configure with the --with-ffmpeg option and rebuild to use this functionality.\n" ); diff --git a/web/zm_config.php.z b/web/zm_config.php.z index 4a0ee5470..237da90ca 100644 --- a/web/zm_config.php.z +++ b/web/zm_config.php.z @@ -59,8 +59,6 @@ switch ( $bandwidth ) define( "REFRESH_EVENTS", ZM_WEB_H_REFRESH_EVENTS ); // How often the event listing is refreshed in the watch window, only for recent events define( "VIDEO_BITRATE", ZM_WEB_H_VIDEO_BITRATE ); // What the bitrate of any streamed video should be define( "VIDEO_MAXFPS", ZM_WEB_H_VIDEO_MAXFPS ); // What the maximum frame rate of any streamed video should be - define( "STREAM_IDLE_DELAY", ZM_WEB_H_STREAM_IDLE_DELAY ); // How long (in milliseconds) between streamed frames in the watch window - define( "STREAM_FRAME_DELAY", ZM_WEB_H_STREAM_FRAME_DELAY ); // How long (in milliseconds) to wait before looking for the next streamed frame define( "IMAGE_SCALING", ZM_WEB_H_IMAGE_SCALING ); // Image scaling for thumbnails, bandwidth versus cpu in rescaling break; } @@ -73,8 +71,6 @@ switch ( $bandwidth ) define( "REFRESH_EVENTS", ZM_WEB_M_REFRESH_EVENTS ); // How often the event listing is refreshed in the watch window, only for recent events define( "VIDEO_BITRATE", ZM_WEB_M_VIDEO_BITRATE ); // What the bitrate of any streamed video should be define( "VIDEO_MAXFPS", ZM_WEB_M_VIDEO_MAXFPS ); // What the maximum frame rate of any streamed video should be - define( "STREAM_IDLE_DELAY", ZM_WEB_M_STREAM_IDLE_DELAY ); // How long (in milliseconds) between streamed frames in the watch window - define( "STREAM_FRAME_DELAY", ZM_WEB_M_STREAM_FRAME_DELAY ); // How long (in milliseconds) to wait before looking for the next streamed frame define( "IMAGE_SCALING", ZM_WEB_M_IMAGE_SCALING ); // Image scaling for thumbnails, bandwidth versus cpu in rescaling break; } @@ -87,8 +83,6 @@ switch ( $bandwidth ) define( "REFRESH_EVENTS", ZM_WEB_L_REFRESH_EVENTS ); // How often the event listing is refreshed in the watch window, only for recent events define( "VIDEO_BITRATE", ZM_WEB_L_VIDEO_BITRATE ); // What the bitrate of any streamed video should be define( "VIDEO_MAXFPS", ZM_WEB_L_VIDEO_MAXFPS ); // What the maximum frame rate of any streamed video should be - define( "STREAM_IDLE_DELAY", ZM_WEB_L_STREAM_IDLE_DELAY ); // How long (in milliseconds) between streamed frames in the watch window - define( "STREAM_FRAME_DELAY", ZM_WEB_L_STREAM_FRAME_DELAY ); // How long (in milliseconds) to wait before looking for the next streamed frame define( "IMAGE_SCALING", ZM_WEB_L_IMAGE_SCALING ); // Image scaling for thumbnails, bandwidth versus cpu in rescaling break; } diff --git a/web/zm_html_view_cycle.php b/web/zm_html_view_cycle.php index 6363dc1bd..615b308c2 100644 --- a/web/zm_html_view_cycle.php +++ b/web/zm_html_view_cycle.php @@ -111,7 +111,7 @@ window.setTimeout( "window.location.replace( ' diff --git a/web/zm_html_view_event.php b/web/zm_html_view_event.php index b5805980a..b68506274 100644 --- a/web/zm_html_view_event.php +++ b/web/zm_html_view_event.php @@ -265,7 +265,7 @@ if ( $mode == "stream" ) } else { - $stream_src = ZM_PATH_ZMS."?mode=jpeg&event=$eid&rate=$rate&scale=$scale&maxfps=".VIDEO_MAXFPS; + $stream_src = ZM_PATH_ZMS."?mode=jpeg&event=$eid&scale=$scale&rate=$rate&maxfps=".VIDEO_MAXFPS; if ( canStreamNative() ) { ?> diff --git a/web/zm_html_view_montagefeed.php b/web/zm_html_view_montagefeed.php index da1a34db2..7685e0461 100644 --- a/web/zm_html_view_montagefeed.php +++ b/web/zm_html_view_montagefeed.php @@ -151,7 +151,7 @@ AutoStart=true> } else { - $stream_src = ZM_PATH_ZMS."?mode=jpeg&monitor=".$monitor['Id']."&idle=".STREAM_IDLE_DELAY."&refresh=".STREAM_FRAME_DELAY."&scale=$scale"; + $stream_src = ZM_PATH_ZMS."?mode=jpeg&monitor=".$monitor['Id']."&scale=$scale&maxfps=".VIDEO_MAXFPS; if ( canStreamNative() ) { ?> diff --git a/web/zm_html_view_watchfeed.php b/web/zm_html_view_watchfeed.php index 6ec46d472..39ede8322 100644 --- a/web/zm_html_view_watchfeed.php +++ b/web/zm_html_view_watchfeed.php @@ -148,7 +148,7 @@ AutoStart=true> } else { - $stream_src = ZM_PATH_ZMS."?mode=jpeg&monitor=".$monitor['Id']."&idle=".STREAM_IDLE_DELAY."&refresh=".STREAM_FRAME_DELAY."&scale=$scale"; + $stream_src = ZM_PATH_ZMS."?mode=jpeg&monitor=".$monitor['Id']."&scale=$scale&maxfps=".VIDEO_MAXFPS; if ( canStreamNative() ) { ?> diff --git a/zmconfig.pl.in b/zmconfig.pl.in index 5b86a23fa..75f52462f 100755 --- a/zmconfig.pl.in +++ b/zmconfig.pl.in @@ -993,22 +993,6 @@ my @options = type => $types{integer}, category => 'highband', }, - { - name => "ZM_WEB_H_STREAM_IDLE_DELAY", - default => "250", - description => "How long (in milliseconds) between streamed frames in the watch window", - help => "The top frame of the monitor window when monitoring a live feed in streaming mode contains a continuous stream of images. This option controls how often a new frame is sent to the browser when the monitor is idle, ie. not in alarm state. It makes little sense to set this too small as if it results in frames being sent much faster than they are being captured you will just get the same ones over and over. It should be set to be less or equal to the capture rate of the cameras you are using which will normally be between 2 and 25 Frames Per Second which maps to values between 500 and 40 being used here though your bandwidth may well limit how much can actually be sent. Note also that this is the update rate when no alarms are being generated, if an alarm situation occurs then the rate speeds up as per the next option so this can be set to a longer delay without you missing anything.", - type => $types{integer}, - category => 'highband', - }, - { - name => "ZM_WEB_H_STREAM_FRAME_DELAY", - default => "50", - description => "How long (in milliseconds) to wait before looking for the next streamed frame", - help => "The top frame of the monitor window when monitoring a live feed in streaming mode contains a continuous stream of images. This option controls how often a new frame is sent to the browser when an alarm is being generated. It makes little sense to set this too small as if it results in frames being sent much faster than they are being captured you will just get the same ones over and over. It should be set to roughly match the capture rate of the cameras you are using which will normally be between 2 and 25 Frames Per Second which maps to values between 500 and 40 being used here though your bandwidth may well limit how much can actually be sent.", - type => $types{integer}, - category => 'highband', - }, { name => "ZM_WEB_H_IMAGE_SCALING", default => "1", @@ -1075,22 +1059,6 @@ my @options = type => $types{integer}, category => 'medband', }, - { - name => "ZM_WEB_M_STREAM_IDLE_DELAY", - default => "2500", - description => "How long (in milliseconds) between streamed frames in the watch window", - help => "The top frame of the monitor window when monitoring a live feed in streaming mode contains a continuous stream of images. This option controls how often a new frame is sent to the browser when the monitor is idle, ie. not in alarm state. It makes little sense to set this too small as if it exceeds the available bandwidth and results in frames being sent much faster than they are able to be displayed. In medium bandwidth mode it should be set to be rather less than the capture rate of the cameras you are using. Note also that this is the update rate when no alarms are being generated, if an alarm situation occurs then the rate speeds up as per the next option so this can be set to a longer delay without you missing anything.", - type => $types{integer}, - category => 'medband', - }, - { - name => "ZM_WEB_M_STREAM_FRAME_DELAY", - default => "100", - description => "How long (in milliseconds) to wait before looking for the next streamed frame", - help => "The top frame of the monitor window when monitoring a live feed in streaming mode contains a continuous stream of images. This option controls how often a new frame is sent to the browser when an alarm is being generated. It makes little sense to set this too small as if it exceeds the available bandwidth and results in frames being sent much faster than they are able to be displayed though as should be only for a short period it may be possible to catch up. In medium bandwidth mode it should be set to maybe half the capture rate of the cameras you are using.", - type => $types{integer}, - category => 'medband', - }, { name => "ZM_WEB_M_IMAGE_SCALING", default => "4", @@ -1157,22 +1125,6 @@ my @options = type => $types{integer}, category => 'lowband', }, - { - name => "ZM_WEB_L_STREAM_IDLE_DELAY", - default => "10000", - description => "How long (in milliseconds) between streamed frames in the watch window", - help => "The top frame of the monitor window when monitoring a live feed in streaming mode contains a continuous stream of images. This option controls how often a new frame is sent to the browser when the monitor is idle, ie. not in alarm state. It makes little sense to set this too small as if it exceeds the available bandwidth and results in frames being sent much faster than they are able to be displayed. In low bandwidth mode it should be set to be far less than the capture rate of the cameras you are using. Note also that this is the update rate when no alarms are being generated, if an alarm situation occurs then the rate speeds up as per the next option so this can be set to a longer delay without you missing anything.", - type => $types{integer}, - category => 'lowband', - }, - { - name => "ZM_WEB_L_STREAM_FRAME_DELAY", - default => "250", - description => "How long (in milliseconds) to wait before looking for the next streamed frame", - help => "The top frame of the monitor window when monitoring a live feed in streaming mode contains a continuous stream of images. This option controls how often a new frame is sent to the browser when an alarm is being generated. It makes little sense to set this too small as if it exceeds the available bandwidth and results in frames being sent much faster than they are able to be displayed though as should be only for a short period it may be possible to catch up. In low bandwidth mode it should be set to maybe a quarter the capture rate of the cameras you are using.", - type => $types{integer}, - category => 'lowband', - }, { name => "ZM_WEB_L_IMAGE_SCALING", default => "4",