Some small changes

1) Fixed wrong size calculation in Image::AssignDirect.
2) Improved libjpeg subpixel order selection.
3) Finished adding support in the simple Overlay function.
4) Completed Flip and Rotate 32bit RGB support.
5) Allow ZM to compile on 32bit with omit frame pointer disabled by defining _DEBUG
   To use one less register in the SSE algorithms.
6) Removed the counter variable in some loops to reduce loop overhead.
7) Modified crop query error handling.
8) Most of the shared data now declared as volatile.
9) Small improvements to the AlarmedPixels motion detection.
10) Changed the default blend percent from 7% to 12%.
11) Fixed an earlier bug created by me: motion detection checking the wrong pixels.
This commit is contained in:
Kfir Itzhak
2011-06-07 23:14:01 +03:00
parent 1afe0bbf42
commit eeaed7ccd3
10 changed files with 575 additions and 265 deletions

View File

@@ -2,14 +2,6 @@
-- This updates a 1.24.2 database to the next version
--
--Add Colours colum. This is a harmless change for ZM 1.24.2 or ZM 1.24.3 without the patch, but is required to use the patch
ALTER TABLE `Monitors` ADD `Colours` TINYINT UNSIGNED NOT NULL DEFAULT '1' AFTER `Height`;
-- Replace now unused ZM_Y_IMAGE_DELTAS option with ZM_CPU_EXTENSIONS.
UPDATE `zm`.`Config` SET `Name` = 'ZM_CPU_EXTENSIONS',
`Prompt` = 'Use advanced CPU extensions to increase performance',
`Help` = 'When advanced processor extensions such as SSE2 or SSSE3 are available, ZoneMinder can use them, which should increase performance and reduce system load. Enabling this option on processors that do not support the advanced processors extensions used by ZoneMinder is harmless and will have no effect.' WHERE `Config`.`Id` = '27';
--
-- Add in remote ZoneMinder preset.
--

View File

@@ -157,18 +157,14 @@ int FfmpegCamera::PrimeCapture()
}
#if HAVE_LIBSWSCALE
if(!sws_isSupportedInput(mCodecContext->pix_fmt)) {
Fatal("swscale does not support the codec format");
}
if(!sws_isSupportedOutput(imagePixFormat)) {
Fatal("swscale does not support the target format");
}
if(config.cpu_extensions && sseversion >= 20) {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC | SWS_CPU_CAPS_SSE2, NULL, NULL, NULL );
} else {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
}
if(mConvertContext == NULL)
Fatal( "Unable to create conversion context for %s", mPath.c_str() );
#else // HAVE_LIBSWSCALE
Fatal( "You must compile ffmpeg with the --enable-swscale option to use ffmpeg cameras" );
#endif // HAVE_LIBSWSCALE
@@ -218,6 +214,16 @@ int FfmpegCamera::Capture( Image &image )
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
#if HAVE_LIBSWSCALE
if(mConvertContext == NULL) {
if(config.cpu_extensions && sseversion >= 20) {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC | SWS_CPU_CAPS_SSE2, NULL, NULL, NULL );
} else {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
}
if(mConvertContext == NULL)
Fatal( "Unable to create conversion context for %s", mPath.c_str() );
}
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
#else // HAVE_LIBSWSCALE

View File

File diff suppressed because it is too large Load Diff

View File

@@ -268,6 +268,8 @@ void ssse3_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result
void ssse3_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count);
/* Convert functions */
void std_convert_rgb_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void std_convert_bgr_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void std_convert_rgba_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void std_convert_bgra_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);
void std_convert_argb_gray8(const uint8_t* col1, uint8_t* result, unsigned long count);

View File

@@ -418,10 +418,10 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel,
Debug(2,"Using ZM for image conversion");
if(palette == V4L2_PIX_FMT_RGB32 && colours == ZM_COLOUR_GRAY8) {
conversion_fptr = &std_convert_argb_gray8;
subpixelorder = ZM_SUBPIX_ORDER_ARGB;
subpixelorder = ZM_SUBPIX_ORDER_NONE;
} else if(palette == V4L2_PIX_FMT_BGR32 && colours == ZM_COLOUR_GRAY8) {
conversion_fptr = &std_convert_bgra_gray8;
subpixelorder = ZM_SUBPIX_ORDER_BGRA;
subpixelorder = ZM_SUBPIX_ORDER_NONE;
} else if(palette == V4L2_PIX_FMT_YUYV && colours == ZM_COLOUR_GRAY8) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
if(config.cpu_extensions && sseversion >= 35) {
@@ -529,10 +529,10 @@ LocalCamera::LocalCamera( int p_id, const std::string &p_device, int p_channel,
if(palette == VIDEO_PALETTE_RGB32 && colours == ZM_COLOUR_GRAY8) {
if(BigEndian) {
conversion_fptr = &std_convert_argb_gray8;
subpixelorder = ZM_SUBPIX_ORDER_ARGB;
subpixelorder = ZM_SUBPIX_ORDER_NONE;
} else {
conversion_fptr = &std_convert_bgra_gray8;
subpixelorder = ZM_SUBPIX_ORDER_BGRA;
subpixelorder = ZM_SUBPIX_ORDER_NONE;
}
} else if((palette == VIDEO_PALETTE_YUYV || palette == VIDEO_PALETTE_YUV422) && colours == ZM_COLOUR_GRAY8) {
/* Fast YUYV->Grayscale conversion by extracting the Y channel */
@@ -1185,55 +1185,53 @@ bool LocalCamera::GetCurrentSettings( const char *device, char *output, int vers
if ( !verbose )
output[strlen(output)-1] = '|';
struct v4l2_cropcap cropcap;
memset( &cropcap, 0, sizeof(cropcap) );
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( vidioctl( vid_fd, VIDIOC_CROPCAP, &cropcap ) < 0 )
{
Error( "Failed to query crop capabilities: %s", strerror(errno) );
if ( verbose )
sprintf( output, "Error, failed to query crop capabilities %s: %s\n", queryDevice, strerror(errno) );
else
sprintf( output, "error%d\n", errno );
return( false );
}
if ( verbose )
{
sprintf( output+strlen(output), "Crop Capabilities\n" );
sprintf( output+strlen(output), " Bounds: %d x %d\n", cropcap.bounds.width, cropcap.bounds.height );
sprintf( output+strlen(output), " Default: %d x %d\n", cropcap.defrect.width, cropcap.defrect.height );
}
else
{
sprintf( output+strlen(output), "B:%dx%d|", cropcap.bounds.width, cropcap.bounds.height );
}
struct v4l2_crop crop;
memset( &crop, 0, sizeof(crop) );
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( vidioctl( vid_fd, VIDIOC_G_CROP, &crop ) < 0 )
{
if ( errno != EINVAL )
{
Error( "Failed to query crop: %s", strerror(errno) );
if ( verbose )
sprintf( output, "Error, failed to query crop %s: %s\n", queryDevice, strerror(errno) );
else
sprintf( output, "error%d\n", errno );
/* Crop detection failure is not fatal and cropping is not used anyway, so no reason not to continue */
/* return( false ); */
}
else if ( verbose )
{
Info( "Does not support VIDIOC_G_CROP");
}
}
else
{
if ( verbose )
sprintf( output+strlen(output), " Current: %d x %d\n", crop.c.width, crop.c.height );
}
struct v4l2_cropcap cropcap;
memset( &cropcap, 0, sizeof(cropcap) );
cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( vidioctl( vid_fd, VIDIOC_CROPCAP, &cropcap ) < 0 )
{
if(errno != EINVAL) {
/* Failed querying crop capability, write error to the log and continue as if crop is not supported */
Error( "Failed to query crop capabilities: %s", strerror(errno) );
}
if(verbose) {
sprintf( output+strlen(output), "Cropping is not supported");
} else {
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
sprintf( output+strlen(output), "B:%dx%d|",0,0);
}
} else {
struct v4l2_crop crop;
memset( &crop, 0, sizeof(crop) );
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ( vidioctl( vid_fd, VIDIOC_G_CROP, &crop ) < 0 )
{
if ( errno != EINVAL )
{
/* Failed querying crop sizes, write error to the log and continue as if crop is not supported */
Error( "Failed to query crop: %s", strerror(errno) );
}
if ( verbose ) {
sprintf( output+strlen(output), "Cropping is not supported");
} else {
/* Send fake crop bounds to not confuse things parsing this, such as monitor probe */
sprintf( output+strlen(output), "B:%dx%d|",0,0);
}
} else {
/* Cropping supported */
if ( verbose ) {
sprintf( output+strlen(output), "Crop Capabilities\n" );
sprintf( output+strlen(output), " Bounds: %d x %d\n", cropcap.bounds.width, cropcap.bounds.height );
sprintf( output+strlen(output), " Default: %d x %d\n", cropcap.defrect.width, cropcap.defrect.height );
sprintf( output+strlen(output), " Current: %d x %d\n", crop.c.width, crop.c.height );
} else {
sprintf( output+strlen(output), "B:%dx%d|", cropcap.bounds.width, cropcap.bounds.height );
}
}
} /* Crop code */
struct v4l2_input input;
int inputIndex = 0;

View File

@@ -394,7 +394,6 @@ Monitor::Monitor(
struct timeval *shared_timestamps = (struct timeval *)((char *)trigger_data + sizeof(TriggerData));
unsigned char *shared_images = (unsigned char *)((char *)shared_timestamps + (image_buffer_count*sizeof(struct timeval)));
/* This shouldn't be needed if the shared memory start address is multiple of 16, but just in case */
if(((unsigned long)shared_images % 16) != 0) {
/* Align images buffer to nearest 16 byte boundary */
Debug(3,"Aligning shared memory images to the next 16 byte boundary");
@@ -405,7 +404,6 @@ Monitor::Monitor(
{
memset( mem_ptr, 0, mem_size );
shared_data->size = sizeof(SharedData);
shared_data->valid = true;
shared_data->active = enabled;
shared_data->signal = false;
shared_data->state = IDLE;
@@ -426,6 +424,7 @@ Monitor::Monitor(
trigger_data->trigger_cause[0] = 0;
trigger_data->trigger_text[0] = 0;
trigger_data->trigger_showtext[0] = 0;
shared_data->valid = true;
}
else if ( purpose == ANALYSIS )
{
@@ -507,7 +506,7 @@ Monitor::Monitor(
Fatal( "Can't change to parent directory: %s", strerror(errno) );
}
while( shared_data->last_write_index == image_buffer_count )
while( shared_data->last_write_index == image_buffer_count && shared_data->last_write_time == 0)
{
Warning( "Waiting for capture daemon" );
sleep( 1 );
@@ -941,7 +940,10 @@ void Monitor::DumpZoneImage( const char *zone_string )
Image *snap_image = snap->image;
Image zone_image( *snap_image );
zone_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB );
if(zone_image.Colours() == ZM_COLOUR_GRAY8) {
zone_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB );
}
for( int i = 0; i < n_zones; i++ )
{
if ( exclude_id && (!extra_colour || extra_zone.getNumCoords()) && zones[i]->Id() == exclude_id )

View File

@@ -165,8 +165,8 @@ protected:
int mem_size;
unsigned char *mem_ptr;
SharedData *shared_data;
TriggerData *trigger_data;
volatile SharedData *shared_data;
volatile TriggerData *trigger_data;
int last_state;
int last_event;

View File

@@ -201,18 +201,14 @@ int RemoteCameraRtsp::PrimeCapture()
}
#if HAVE_LIBSWSCALE
if(!sws_isSupportedInput(mCodecContext->pix_fmt)) {
Fatal("swscale does not support the codec format");
}
if(!sws_isSupportedOutput(imagePixFormat)) {
Fatal("swscale does not support the target format");
}
if(config.cpu_extensions && sseversion >= 20) {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC | SWS_CPU_CAPS_SSE2, NULL, NULL, NULL );
} else {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
}
if(mConvertContext == NULL)
Fatal( "Unable to create conversion context");
#else // HAVE_LIBSWSCALE
Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" );
#endif // HAVE_LIBSWSCALE
@@ -237,6 +233,7 @@ int RemoteCameraRtsp::Capture( Image &image )
{
AVPacket packet;
uint8_t* directbuffer;
int frameComplete = false;
/* Request a writeable buffer of the target image */
directbuffer = image.WriteBuffer(width, height, colours, subpixelorder);
@@ -261,8 +258,8 @@ int RemoteCameraRtsp::Capture( Image &image )
return( -1 );
av_init_packet( &packet );
int frameComplete = false;
<<<<<<< HEAD
while ( !frameComplete )
{
packet.data = buffer.head();
@@ -282,22 +279,60 @@ int RemoteCameraRtsp::Capture( Image &image )
if ( frameComplete )
{
Debug( 3, "Got frame %d", frameCount );
=======
while ( !frameComplete && buffer.size() > 0 )
{
packet.data = buffer.head();
packet.size = buffer.size();
int len = avcodec_decode_video2( mCodecContext, mRawFrame, &frameComplete, &packet );
if ( len < 0 )
{
Error( "Error while decoding frame %d", frameCount );
Hexdump( ZM_DBG_ERR, buffer.head(), buffer.size()>256?256:buffer.size() );
buffer.clear();
continue;
}
Debug( 2, "Frame: %d - %d/%d", frameCount, len, buffer.size() );
//if ( buffer.size() < 400 )
//Hexdump( 0, buffer.head(), buffer.size() );
buffer -= len;
}
if ( frameComplete ) {
Debug( 3, "Got frame %d", frameCount );
>>>>>>> Some small changes
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
avpicture_fill( (AVPicture *)mFrame, directbuffer, imagePixFormat, width, height);
#if HAVE_LIBSWSCALE
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
if(mConvertContext == NULL) {
if(config.cpu_extensions && sseversion >= 20) {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC | SWS_CPU_CAPS_SSE2, NULL, NULL, NULL );
} else {
mConvertContext = sws_getContext( mCodecContext->width, mCodecContext->height, mCodecContext->pix_fmt, width, height, imagePixFormat, SWS_BICUBIC, NULL, NULL, NULL );
}
if(mConvertContext == NULL)
Fatal( "Unable to create conversion context");
}
if ( sws_scale( mConvertContext, mRawFrame->data, mRawFrame->linesize, 0, mCodecContext->height, mFrame->data, mFrame->linesize ) < 0 )
Fatal( "Unable to convert raw format %u to target format %u at frame %d", mCodecContext->pix_fmt, imagePixFormat, frameCount );
#else // HAVE_LIBSWSCALE
Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" );
Fatal( "You must compile ffmpeg with the --enable-swscale option to use RTSP cameras" );
#endif // HAVE_LIBSWSCALE
frameCount++;
}
buffer -= len;
}
av_free_packet( &packet );
}
frameCount++;
} /* frame complete */
av_free_packet( &packet );
} /* getFrame() */
if(frameComplete)
return (0);
}
return (0) ;
}

View File

@@ -153,30 +153,22 @@ bool Zone::CheckAlarms( const Image *delta_image )
Debug( 5, "Checking for alarmed pixels" );
uint8_t *pdiff;
const uint8_t *ppoly;
// Create an upper margin
if ( lo_y > 0 )
{
lo_x = ranges[0].lo_x;
if ( lo_x > 0 )
lo_x--;
hi_x = ranges[0].hi_x;
if ( hi_x < (diff_width-1) )
hi_x++;
pdiff = diff_buff + ( lo_x * (lo_y-1) );
memset( pdiff, BLACK, (hi_x-lo_x)+1 );
}
uint8_t calc_max_pixel_threshold = 255; /* To be able to remove one check from the loop below */
if(max_pixel_threshold)
calc_max_pixel_threshold = max_pixel_threshold;
for ( int y = lo_y, py = 0; y <= hi_y; y++, py++ )
{
lo_x = ranges[py].lo_x;
hi_x = ranges[py].hi_x;
Debug( 7, "Checking line %d from %d -> %d", y, lo_x, hi_x );
pdiff = diff_buff + (diff_width * y);
pdiff = diff_buff + ((diff_width * y) + lo_x);
ppoly = pg_image->Buffer( ranges[py].off_x, py );
pdiff += lo_x;
for ( int x = lo_x; x <= hi_x; x++, pdiff++, ppoly++ )
{
if ( *ppoly && (*pdiff > min_pixel_threshold) && (!max_pixel_threshold || (*pdiff < max_pixel_threshold)) )
if ( *ppoly && (*pdiff > min_pixel_threshold) && (*pdiff <= calc_max_pixel_threshold) )
{
alarm_pixels++;
pixel_diff_count += *pdiff;
@@ -228,16 +220,15 @@ bool Zone::CheckAlarms( const Image *delta_image )
if ( bx > 1 || by > 1 )
{
// Now remove any pixels smaller than our filter size
unsigned char *pdiff;
unsigned char *cpdiff;
int ldx, hdx, ldy, hdy;
bool block;
for ( int y = lo_y, py = 0; y <= hi_y; y++, py++ )
{
int lo_x = ranges[py].lo_x;
int hi_x = ranges[py].hi_x;
lo_x = ranges[py].lo_x;
hi_x = ranges[py].hi_x;
pdiff = diff_buff + (lo_x * y);
pdiff = diff_buff + ((diff_width * y) + lo_x);
for ( int x = lo_x; x <= hi_x; x++, pdiff++ )
{
@@ -258,7 +249,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
{
for ( int dx2 = 0; block && dx2 < bx; dx2++ )
{
cpdiff = diff_buff + ( (x+dx+dx2) * (y+dy+dy2) );
cpdiff = diff_buff + (((y+dy+dy2)*diff_width) + (x+dx+dx2));
if ( !*cpdiff )
{
block = false;
@@ -315,7 +306,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
typedef struct { unsigned char tag; int count; int lo_x; int hi_x; int lo_y; int hi_y; } BlobStats;
BlobStats blob_stats[256];
memset( blob_stats, 0, sizeof(BlobStats)*256 );
unsigned char *pdiff, *spdiff;
uint8_t *spdiff;
int last_x, last_y;
BlobStats *bsx, *bsy;
BlobStats *bsm, *bss;
@@ -324,7 +315,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
int lo_x = ranges[py].lo_x;
int hi_x = ranges[py].hi_x;
pdiff = diff_buff + ( lo_x * y );
pdiff = diff_buff + ((diff_width * y) + lo_x);
for ( int x = lo_x; x <= hi_x; x++, pdiff++ )
{
if ( *pdiff == WHITE )
@@ -370,7 +361,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
Debug( 9, "Changing %d(%d), %d->%d", sy, psy, lo_sx, hi_sx );
Debug( 9, "Range %d(%d), %d->%d", sy, psy, ranges[psy].lo_x, ranges[psy].hi_x );
spdiff = diff_buff + ( lo_sx * sy );
spdiff = diff_buff + ((diff_width * sy) + lo_sx);
for ( int sx = lo_sx; sx <= hi_sx; sx++, spdiff++ )
{
Debug( 9, "Pixel at %d,%d (%p) is %d", sx, sy, spdiff, *spdiff );
@@ -453,7 +444,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
{
for ( int sy = bs->lo_y; sy <= bs->hi_y; sy++ )
{
unsigned char *spdiff = diff_buff + ( bs->lo_x * sy );
spdiff = diff_buff + ((diff_width * sy) + bs->lo_x);
for ( int sx = bs->lo_x; sx <= bs->hi_x; sx++, spdiff++ )
{
if ( *spdiff == bs->tag )
@@ -530,7 +521,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
{
for ( int sy = bs->lo_y; sy <= bs->hi_y; sy++ )
{
unsigned char *spdiff = diff_buff + ( bs->lo_x * sy );
spdiff = diff_buff + ((diff_width * sy) + bs->lo_x);
for ( int sx = bs->lo_x; sx <= bs->hi_x; sx++, spdiff++ )
{
if ( *spdiff == bs->tag )
@@ -603,7 +594,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
for ( int sy = bs->lo_y; sy <= bs->hi_y; sy++ )
{
unsigned char *spdiff = diff_buff + ( bs->lo_x * sy );
spdiff = diff_buff + ((diff_width * sy) + bs->lo_x);
for ( int sx = bs->lo_x; sx <= bs->hi_x; sx++, spdiff++ )
{
if ( *spdiff == bs->tag )
@@ -676,7 +667,7 @@ bool Zone::CheckAlarms( const Image *delta_image )
// First mask out anything we don't want
for ( int y = lo_y, py = 0; y <= hi_y; y++, py++ )
{
pdiff = diff_buff + ( lo_x * y );
pdiff = diff_buff + ((diff_width * y) + lo_x);
int lo_x2 = ranges[py].lo_x;
int hi_x2 = ranges[py].hi_x;

View File

@@ -94,7 +94,7 @@ else
'MaxFPS' => "",
'AlarmMaxFPS' => "",
'FPSReportInterval' => 1000,
'RefBlendPerc' => 7,
'RefBlendPerc' => 12,
'DefaultView' => 'Events',
'DefaultRate' => '100',
'DefaultScale' => '100',