From eb2363747b0947421a2b1192ae2ef3b57eb53869 Mon Sep 17 00:00:00 2001 From: stan Date: Mon, 15 Mar 2004 08:48:52 +0000 Subject: [PATCH] Implemented frame rates better on events. git-svn-id: http://svn.zoneminder.com/svn/zm/trunk@957 e3e1d417-86f3-4887-817a-d78f3d33393f --- src/zm_event.cpp | 139 ++++++++++++++++++++++--------------- src/zm_event.h | 2 +- src/zms.cpp | 4 +- web/zm_html.php | 37 +++------- web/zm_html_view_event.php | 2 +- zmconfig.pl.in | 2 +- 6 files changed, 99 insertions(+), 87 deletions(-) diff --git a/src/zm_event.cpp b/src/zm_event.cpp index 17e4d170a..a50a2189d 100644 --- a/src/zm_event.cpp +++ b/src/zm_event.cpp @@ -358,12 +358,12 @@ void Event::AddFrame( Image *image, struct timeval timestamp, int score, Image * } } -void Event::StreamEvent( int event_id, int rate, int scale ) +void Event::StreamEvent( int event_id, int maxfps, int rate, int scale ) { static char sql[BUFSIZ]; static char eventpath[PATH_MAX]; - sprintf( sql, "select M.Id, M.Name, E.Frames from Events as E inner join Monitors as M on E.MonitorId = M.Id where E.Id = %d", event_id ); + sprintf( sql, "select M.Id, M.Name, E.Length, E.Frames from Events as E inner join Monitors as M on E.MonitorId = M.Id where E.Id = %d", event_id ); if ( mysql_query( &dbconn, sql ) ) { Error(( "Can't run query: %s", mysql_error( &dbconn ) )); @@ -385,7 +385,23 @@ void Event::StreamEvent( int event_id, int rate, int scale ) } sprintf( eventpath, "%s/%s/%s/%d", ZM_PATH_WEB, (const char *)config.Item( ZM_DIR_EVENTS ), dbrow[1], event_id ); - int frames = atoi(dbrow[2] ); + int duration = atoi(dbrow[2]); + int frames = atoi(dbrow[3]); + + int min_fps = 1; + int max_fps = maxfps; + int base_fps = frames/duration; + int effective_fps = (base_fps*rate)/ZM_RATE_SCALE; + + int frame_mod = 1; + // Min frame repeat? + while( effective_fps > max_fps ) + { + effective_fps /= 2; + frame_mod *= 2; + } + + Debug( 1, ( "Duration:%d, Frames:%d, BFPS:%d, EFPS:%d, FM:%d", atoi(dbrow[2]), atoi(dbrow[3]), base_fps, effective_fps, frame_mod )); mysql_free_result( result ); @@ -406,71 +422,76 @@ void Event::StreamEvent( int event_id, int rate, int scale ) fprintf( stdout, "Content-Type: multipart/x-mixed-replace;boundary=ZoneMinderFrame\r\n\r\n" ); fprintf( stdout, "--ZoneMinderFrame\r\n" ); - //int n_frames = mysql_num_rows( result ); - //Info(( "Got %d frames, at rate %d, scale %d", n_frames, rate, scale )); FILE *fdj = NULL; int n_bytes = 0; + int id = 1, db_id, last_db_id = 0; + double base_delta, last_delta = 0.0L; + double db_delta, last_db_delta = 0.0L; + unsigned int delta_us =0; static unsigned char buffer[ZM_MAX_IMAGE_SIZE]; - double last_delta = 0; - struct timeval now, last_now; - struct DeltaTimeval delta_time; - - gettimeofday( &now, &dummy_tz ); - for( int i = 0; dbrow = mysql_fetch_row( result ); i++ ) + while( (id <= frames) && (dbrow = mysql_fetch_row( result )) ) { - if ( rate ) + if ( id == 1 ) { - double this_delta = atof(dbrow[2]); - if ( i ) - { - gettimeofday( &now, &dummy_tz ); - - double frame_delta = this_delta-last_delta; - DELTA_TIMEVAL( delta_time, now, last_now, DT_PREC_6 ); - - int delay = (int)((DT_GRAN_1000000*frame_delta))-delta_time.delta; - - delay = (delay * ZM_RATE_SCALE) / rate; - - //Info(( "FD:%lf, DDT:%d, D:%d, N:%d.%d, LN:%d.%d", frame_delta, delta_time.delta, delay, now.tv_sec, now.tv_usec, last_now.tv_sec, last_now.tv_usec )); - if ( delay > 0 ) - usleep( delay ); - } - last_delta = this_delta; - gettimeofday( &last_now, &dummy_tz ); + base_delta = atof(dbrow[2]); } - static char filepath[PATH_MAX]; - sprintf( filepath, "%s/%03d-capture.jpg", eventpath, atoi(dbrow[0]) ); - fprintf( stdout, "Content-Length: %d\r\n", n_bytes ); - fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); - if ( scale == 100 ) + db_id = atoi( dbrow[0] ); + db_delta = atof( dbrow[2] )-base_delta; + bool db_written = false; + while( db_id >= id ) { - if ( (fdj = fopen( filepath, "r" )) ) + if ( (frame_mod == 1) || (((id-1)%frame_mod) == 0) ) { - while ( (n_bytes = fread( buffer, 1, sizeof(buffer), fdj )) ) + double this_delta = last_db_delta+(((id-last_db_id)*(db_delta-last_db_delta))/(db_id-last_db_id)); + delta_us = (unsigned int)((this_delta-last_delta) * 1000000); + if ( rate != ZM_RATE_SCALE ) + delta_us = (delta_us*ZM_RATE_SCALE)/rate; + Debug( 2, ( "I:%d, DI:%d, LDBI:%d, DD:%lf, LD:%lf, LDBD:%lf, TD:%lf, DU:%d", id, db_id, last_db_id, db_delta, last_delta, last_db_delta, this_delta, delta_us )); + + static char filepath[PATH_MAX]; + sprintf( filepath, "%s/%03d-capture.jpg", eventpath, id ); + + fprintf( stdout, "Content-Length: %d\r\n", n_bytes ); + fprintf( stdout, "Content-Type: image/jpeg\r\n\r\n" ); + if ( scale == 100 ) { + if ( (fdj = fopen( filepath, "r" )) ) + { + while ( (n_bytes = fread( buffer, 1, sizeof(buffer), fdj )) ) + { + write( fileno(stdout), buffer, n_bytes ); + } + fclose( fdj ); + } + else + { + Error(( "Can't open %s: %s", filepath, strerror(errno) )); + } + } + else + { + Image image( filepath ); + + image.Scale( scale ); + + image.EncodeJpeg( buffer, &n_bytes ); + write( fileno(stdout), buffer, n_bytes ); } - fclose( fdj ); - } - else - { - Error(( "Can't open %s: %s", filepath, strerror(errno) )); + fprintf( stdout, "\r\n\r\n--ZoneMinderFrame\r\n" ); + fflush( stdout ); + last_delta = this_delta; + db_written = true; + usleep( delta_us ); } + id++; } - else + if ( db_written ) { - Image image( filepath ); - - image.Scale( scale ); - - image.EncodeJpeg( buffer, &n_bytes ); - - write( fileno(stdout), buffer, n_bytes ); + last_db_id = db_id; + last_db_delta = db_delta; } - fprintf( stdout, "\r\n\r\n--ZoneMinderFrame\r\n" ); - fflush( stdout ); } if ( mysql_errno( &dbconn ) ) { @@ -528,7 +549,7 @@ void Event::StreamMpeg( int event_id, const char *format, int bitrate, int maxfp frame_mod *= 2; } - //Info(( "Duration:%d, Frames:%d, BFPS:%d, EFPS:%d, FM:%d", atoi(dbrow[2]), atoi(dbrow[3]), base_fps, effective_fps, frame_mod )); + Debug( 1, ( "Duration:%d, Frames:%d, BFPS:%d, EFPS:%d, FM:%d", atoi(dbrow[2]), atoi(dbrow[3]), base_fps, effective_fps, frame_mod )); mysql_free_result( result ); @@ -582,6 +603,7 @@ void Event::StreamMpeg( int event_id, const char *format, int bitrate, int maxfp int db_id = atoi( dbrow[0] ); double db_delta = atof( dbrow[2] )-base_delta; + bool db_written = false; while( db_id >= id ) { if ( (frame_mod == 1) || (((id-1)%frame_mod) == 0) ) @@ -607,12 +629,17 @@ void Event::StreamMpeg( int event_id, const char *format, int bitrate, int maxfp delta_ms = (delta_ms*ZM_RATE_SCALE)/rate; double pts = vid_stream->EncodeFrame( image.Buffer(), image.Size(), timed_frames, delta_ms ); - //Info(( "I:%d, DI:%d, LI:%d, DD:%lf, LD:%lf, TD:%lf, DM:%d, PTS:%lf", id, db_id, last_id, db_delta, last_delta, temp_delta, delta_ms, pts )); + Debug( 2, ( "I:%d, DI:%d, LI:%d, DD:%lf, LD:%lf, TD:%lf, DM:%d, PTS:%lf", id, db_id, last_id, db_delta, last_delta, temp_delta, delta_ms, pts )); + + db_written = true; } id++; } - last_id = db_id; - last_delta = db_delta; + if ( db_written ) + { + 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 05aa64f31..1e2c16567 100644 --- a/src/zm_event.h +++ b/src/zm_event.h @@ -91,7 +91,7 @@ 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 rate=100, int scale=100 ); + static void StreamEvent( int event_id, int maxfps=10, int rate=100, int scale=100 ); #if HAVE_LIBAVCODEC static void StreamMpeg( int event_id, const char *format, int bitrate=100000, int maxfps=10, int rate=100, int scale=100 ); #endif // HAVE_LIBAVCODEC diff --git a/src/zms.cpp b/src/zms.cpp index 6a837aca2..bde7b743c 100644 --- a/src/zms.cpp +++ b/src/zms.cpp @@ -28,7 +28,7 @@ int main( int argc, const char *argv[] ) int id = 1; int event = 0; unsigned int bitrate = 100000; - unsigned int maxfps = 100000; + unsigned int maxfps = 10; unsigned int rate = 100; unsigned int scale = 100; unsigned int buffer = 0; @@ -145,7 +145,7 @@ int main( int argc, const char *argv[] ) { if ( mode == ZMS_JPEG ) { - Event::StreamEvent( event, rate, scale ); + Event::StreamEvent( event, maxfps, rate, scale ); } else { diff --git a/web/zm_html.php b/web/zm_html.php index a6e125d42..7aa57acae 100644 --- a/web/zm_html.php +++ b/web/zm_html.php @@ -67,32 +67,17 @@ $bw_array = array( "low"=>$zmSlangLow ); -if ( ZM_VIDEO_STREAM_METHOD == 'mpeg' ) -{ - $rates = array( - "10000" => "100x", - "5000" => "50x", - "2500" => "25x", - "1000" => "10x", - "400" => "4x", - "200" => "2x", - "100" => $zmSlangReal, - "50" => "1/2x", - "25" => "1/4x", - ); -} -else -{ - $rates = array( - "0" => $zmSlangMax, - "1000" => "10x", - "400" => "4x", - "200" => "2x", - "100" => $zmSlangReal, - "50" => "1/2x", - "25" => "1/4x", - ); -} +$rates = array( + "10000" => "100x", + "5000" => "50x", + "2500" => "25x", + "1000" => "10x", + "400" => "4x", + "200" => "2x", + "100" => $zmSlangReal, + "50" => "1/2x", + "25" => "1/4x", +); $scales = array( "400" => "4x", diff --git a/web/zm_html_view_event.php b/web/zm_html_view_event.php index 7143bd954..b5805980a 100644 --- a/web/zm_html_view_event.php +++ b/web/zm_html_view_event.php @@ -312,7 +312,7 @@ AutoStart=true> } else { - $stream_src = ZM_PATH_ZMS."?mode=jpeg&event=$eid&rate=$rate&scale=$scale"; + $stream_src = ZM_PATH_ZMS."?mode=jpeg&event=$eid&rate=$rate&scale=$scale&maxfps=".VIDEO_MAXFPS; if ( canStreamNative() ) { ?> diff --git a/zmconfig.pl.in b/zmconfig.pl.in index 9171d1bd8..5b86a23fa 100755 --- a/zmconfig.pl.in +++ b/zmconfig.pl.in @@ -987,7 +987,7 @@ my @options = }, { name => "ZM_WEB_H_VIDEO_MAXFPS", - default => "10", + default => "15", description => "What the maximum frame rate for streamed video should be", help => "When using streamed video the main control is the bitrate which determines how much data can be transmitted. However a lower bitrate at high frame rates results in a lower quality image. This option allows you to limit the maximum frame rate to ensure that video quality is maintained. An additional advantage is that encoding video at high frame rates is a processor intensive task when for the most part a very high frame rate offers little perceptible improvement over one that has a more manageable resource requirement. Note, this option is implemented as a cap beyond which binary reduction takes place. So if you have a device capturing at 15fps and set this option to 10fps then the video is not produced at 10fps, but rather at 7.5fps (15 divided by 2) as the final frame rate must be the original divided by a power of 2.", type => $types{integer},