diff --git a/db/zm_update-1.24.2.sql b/db/zm_update-1.24.2.sql index 3026bc53a..0d93185e6 100644 --- a/db/zm_update-1.24.2.sql +++ b/db/zm_update-1.24.2.sql @@ -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. -- diff --git a/src/zm_ffmpeg_camera.cpp b/src/zm_ffmpeg_camera.cpp index a217c32f6..8a820e0b6 100644 --- a/src/zm_ffmpeg_camera.cpp +++ b/src/zm_ffmpeg_camera.cpp @@ -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 diff --git a/src/zm_image.cpp b/src/zm_image.cpp index 16c528eee..bc51aade0 100644 --- a/src/zm_image.cpp +++ b/src/zm_image.cpp @@ -39,19 +39,19 @@ jpeg_decompress_struct *Image::jpg_dcinfo = 0; struct zm_error_mgr Image::jpg_err; /* Pointer to blend function. */ -blend_fptr_t fptr_blend; +static blend_fptr_t fptr_blend; /* Pointer to delta8 functions */ -delta_fptr_t fptr_delta8_rgb; -delta_fptr_t fptr_delta8_bgr; -delta_fptr_t fptr_delta8_rgba; -delta_fptr_t fptr_delta8_bgra; -delta_fptr_t fptr_delta8_argb; -delta_fptr_t fptr_delta8_abgr; -delta_fptr_t fptr_delta8_gray8; +static delta_fptr_t fptr_delta8_rgb; +static delta_fptr_t fptr_delta8_bgr; +static delta_fptr_t fptr_delta8_rgba; +static delta_fptr_t fptr_delta8_bgra; +static delta_fptr_t fptr_delta8_argb; +static delta_fptr_t fptr_delta8_abgr; +static delta_fptr_t fptr_delta8_gray8; -/* Pointer to big memory copy function */ -imgbufcpy_fptr_t fptr_imgbufcpy; +/* Pointer to image buffer memory copy function */ +static imgbufcpy_fptr_t fptr_imgbufcpy; Image::Image() { @@ -97,12 +97,11 @@ Image::Image( int p_width, int p_height, int p_colours, int p_subpixelorder, uin pixels = width*height; colours = p_colours; subpixelorder = p_subpixelorder; - size = width*height*colours; + size = (width*height)*colours; buffer = 0; holdbuffer = 0; if ( p_buffer ) { - /* Don't free the supplied buffer, but don't hold it either */ allocation = size; buffertype = ZM_BUFTYPE_DONTFREE; buffer = p_buffer; @@ -185,8 +184,9 @@ void Image::Initialise() fptr_delta8_bgra = &sse2_delta8_bgra; fptr_delta8_argb = &sse2_delta8_argb; fptr_delta8_abgr = &sse2_delta8_abgr; - /* On some systems, the 4 SSE2 algorithms above might be slower than - ** the standard algorithms, especially on early Pentium 4 processors + /* + ** On some systems, the 4 SSE2 algorithms above might be a little slower than + ** the standard algorithms, especially on early Pentium 4 processors. ** In that case, comment out the 4 lines above and uncomment the 4 lines below */ // fptr_delta8_rgba = &std_delta8_rgba; @@ -196,7 +196,7 @@ void Image::Initialise() fptr_delta8_gray8 = &sse2_delta8_gray8; Debug(2,"Delta: Using SSE2 delta functions"); } else { - /* No SSE available */ + /* No suitable SSE version available */ fptr_delta8_rgba = &std_delta8_rgba; fptr_delta8_bgra = &std_delta8_bgra; fptr_delta8_argb = &std_delta8_argb; @@ -269,7 +269,7 @@ void Image::Initialise() uint8_t* Image::WriteBuffer(const int p_width, const int p_height, const int p_colours, const int p_subpixelorder) { unsigned int newsize; - if(p_colours != 1 && p_colours != 3 && p_colours != 4) { + if(p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32) { Error("WriteBuffer called with unexpected colours: %d",p_colours); return NULL; } @@ -280,7 +280,7 @@ uint8_t* Image::WriteBuffer(const int p_width, const int p_height, const int p_c } if(p_width != width || p_height != height || p_colours != colours || p_subpixelorder != subpixelorder) { - newsize = p_width * p_height * p_colours; + newsize = (p_width * p_height) * p_colours; if(buffer == NULL) { AllocImgBuffer(newsize); @@ -316,7 +316,7 @@ void Image::AssignDirect( const int p_width, const int p_height, const int p_col return; } - if(buffer_size < (p_width*p_height*p_colours)) { + if(buffer_size < ((p_width*p_height)*p_colours)) { Error("Attempt to directly assign buffer from an undersized buffer of size: %u",buffer_size); return; } @@ -326,13 +326,13 @@ void Image::AssignDirect( const int p_width, const int p_height, const int p_col return; } - if(p_colours != 1 && p_colours != 3 && p_colours != 4) { + if(p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32) { Error("Attempt to directly assign buffer with unexpected colours per pixel: %d",p_colours); return; } if(holdbuffer && buffer) { - if((p_height * p_height * p_colours) > allocation) { + if(((p_height*p_width)*p_colours) > allocation) { Error("Held buffer is undersized for assigned buffer"); return; } else { @@ -369,7 +369,7 @@ void Image::AssignDirect( const int p_width, const int p_height, const int p_col } void Image::Assign(const int p_width, const int p_height, const int p_colours, const int p_subpixelorder, const uint8_t* new_buffer, const size_t buffer_size) { - unsigned int new_size = p_width * p_height * p_colours; + unsigned int new_size = (p_width * p_height) * p_colours; if(new_buffer == NULL) { Error("Attempt to assign buffer from a NULL pointer"); @@ -386,7 +386,7 @@ void Image::Assign(const int p_width, const int p_height, const int p_colours, c return; } - if(p_colours != 1 && p_colours != 3 && p_colours != 4) { + if(p_colours != ZM_COLOUR_GRAY8 && p_colours != ZM_COLOUR_RGB24 && p_colours != ZM_COLOUR_RGB32) { Error("Attempt to assign buffer with unexpected colours per pixel: %d",p_colours); return; } @@ -419,14 +419,14 @@ void Image::Assign(const int p_width, const int p_height, const int p_colours, c } void Image::Assign( const Image &image ) { - unsigned int new_size = image.width * image.height * image.colours; + unsigned int new_size = (image.width * image.height) * image.colours; if(image.buffer == NULL) { Error("Attempt to assign image with an empty buffer"); return; } - if(image.colours != 1 && image.colours != 3 && image.colours != 4) { + if(image.colours != ZM_COLOUR_GRAY8 && image.colours != ZM_COLOUR_RGB24 && image.colours != ZM_COLOUR_RGB32) { Error("Attempt to assign image with unexpected colours per pixel: %d",image.colours); return; } @@ -457,9 +457,10 @@ void Image::Assign( const Image &image ) { (*fptr_imgbufcpy)(buffer, image.buffer, size); } +/* RGB24 only */ Image *Image::HighlightEdges( Rgb colour, const Box *limits ) { - if ( colours != 1 ) + if ( colours != ZM_COLOUR_GRAY8 ) { Panic( "Attempt to highlight image edges when colours = %d", colours ); } @@ -636,12 +637,16 @@ bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder) subpixelorder = ZM_SUBPIX_ORDER_BGR; #else Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); - cinfo->out_color_space = JCS_EXT_RGB; + cinfo->out_color_space = JCS_RGB; subpixelorder = ZM_SUBPIX_ORDER_RGB; #endif } else { /* Assume RGB */ - cinfo->out_color_space = JCS_RGB; +#ifdef JCS_EXTENSIONS + cinfo->out_color_space = JCS_EXT_RGB; +#else + cinfo->out_color_space = JCS_RGB; +#endif subpixelorder = ZM_SUBPIX_ORDER_RGB; } break; @@ -683,7 +688,7 @@ bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder) bool Image::WriteJpeg( const char *filename, int quality_override ) const { - if ( config.colour_jpeg_files && colours == 1 ) + if ( config.colour_jpeg_files && colours == ZM_COLOUR_GRAY8 ) { Image temp_image( *this ); temp_image.Colourise( ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); @@ -758,7 +763,11 @@ bool Image::WriteJpeg( const char *filename, int quality_override ) const #endif } else { /* Assume RGB */ +#ifdef JCS_EXTENSIONS + cinfo->in_color_space = JCS_EXT_RGB; +#else cinfo->in_color_space = JCS_RGB; +#endif } break; } @@ -867,12 +876,16 @@ bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours subpixelorder = ZM_SUBPIX_ORDER_BGR; #else Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); - cinfo->out_color_space = JCS_EXT_RGB; + cinfo->out_color_space = JCS_RGB; subpixelorder = ZM_SUBPIX_ORDER_RGB; #endif } else { /* Assume RGB */ - cinfo->out_color_space = JCS_RGB; +#ifdef JCS_EXTENSIONS + cinfo->out_color_space = JCS_EXT_RGB; +#else + cinfo->out_color_space = JCS_RGB; +#endif subpixelorder = ZM_SUBPIX_ORDER_RGB; } break; @@ -912,7 +925,7 @@ bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours bool Image::EncodeJpeg( JOCTET *outbuffer, int *outbuffer_size, int quality_override ) const { - if ( config.colour_jpeg_files && colours == 1 ) + if ( config.colour_jpeg_files && colours == ZM_COLOUR_GRAY8 ) { Image temp_image( *this ); temp_image.Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); @@ -979,7 +992,11 @@ bool Image::EncodeJpeg( JOCTET *outbuffer, int *outbuffer_size, int quality_over #endif } else { /* Assume RGB */ +#ifdef JCS_EXTENSIONS + cinfo->in_color_space = JCS_EXT_RGB; +#else cinfo->in_color_space = JCS_RGB; +#endif } break; } @@ -1087,9 +1104,9 @@ void Image::Overlay( const Image &image ) unsigned char *pdest = buffer; unsigned char *psrc = image.buffer; - if ( colours == 1 ) + if ( colours == ZM_COLOUR_GRAY8 ) { - if ( image.colours == 1 ) + if ( image.colours == ZM_COLOUR_GRAY8 ) { while( pdest < (buffer+size) ) { @@ -1103,24 +1120,52 @@ void Image::Overlay( const Image &image ) } else { - Colourise(ZM_COLOUR_RGB24, ZM_SUBPIX_ORDER_RGB ); - pdest = buffer; - while( pdest < (buffer+size) ) - { - if ( RED_PTR_RGBA(psrc) || GREEN_PTR_RGBA(psrc) || BLUE_PTR_RGBA(psrc) ) - { - RED_PTR_RGBA(pdest) = RED_PTR_RGBA(psrc); - GREEN_PTR_RGBA(pdest) = GREEN_PTR_RGBA(psrc); - BLUE_PTR_RGBA(pdest) = BLUE_PTR_RGBA(psrc); + Colourise(image.colours, image.subpixelorder); + + if(colours == ZM_COLOUR_RGB32) { + Rgb* prdest = (Rgb*)buffer; + const Rgb* prsrc = (Rgb*)image.buffer; + const Rgb* const max_ptr = (Rgb*)(buffer+size); + if(subpixelorder == ZM_SUBPIX_ORDER_RGBA || subpixelorder == ZM_SUBPIX_ORDER_BGRA) { + /* RGB\BGR\RGBA\BGRA subpixel order - Alpha byte is last */ + while (prdest < max_ptr) { + if ( RED_PTR_RGBA(prsrc) || GREEN_PTR_RGBA(prsrc) || BLUE_PTR_RGBA(prsrc) ) + { + *prdest = *prsrc; + } + prdest++; + prsrc++; + } + } else { + /* ABGR\ARGB subpixel order - Alpha byte is first */ + while (prdest < max_ptr) { + if ( RED_PTR_ABGR(prsrc) || GREEN_PTR_ABGR(prsrc) || BLUE_PTR_ABGR(prsrc) ) + { + *prdest = *prsrc; + } + prdest++; + prsrc++; + } + } + } else { + /* Assume RGB24\BGR24 */ + while( pdest < (buffer+size) ) + { + if ( RED_PTR_RGBA(psrc) || GREEN_PTR_RGBA(psrc) || BLUE_PTR_RGBA(psrc) ) + { + RED_PTR_RGBA(pdest) = RED_PTR_RGBA(psrc); + GREEN_PTR_RGBA(pdest) = GREEN_PTR_RGBA(psrc); + BLUE_PTR_RGBA(pdest) = BLUE_PTR_RGBA(psrc); + } + psrc += 3; + pdest += 3; } - psrc += 3; - pdest += 3; } } } else { - if ( image.colours == 1 ) + if ( image.colours == ZM_COLOUR_GRAY8 ) { while( pdest < (buffer+size) ) { @@ -1128,11 +1173,14 @@ void Image::Overlay( const Image &image ) { RED_PTR_RGBA(pdest) = GREEN_PTR_RGBA(pdest) = BLUE_PTR_RGBA(pdest) = *psrc++; } - pdest += 3; + pdest += colours; } } else { + + + while( pdest < (buffer+size) ) { if ( RED_PTR_RGBA(psrc) || GREEN_PTR_RGBA(psrc) || BLUE_PTR_RGBA(psrc) ) @@ -1141,8 +1189,8 @@ void Image::Overlay( const Image &image ) GREEN_PTR_RGBA(pdest) = GREEN_PTR_RGBA(psrc); BLUE_PTR_RGBA(pdest) = BLUE_PTR_RGBA(psrc); } - psrc += 3; - pdest += 3; + psrc += colours; + pdest += colours; } } } @@ -1468,7 +1516,7 @@ void Image::Annotate( const char *p_text, const Coord &coord, const Rgb fg_colou if ( hi_line_y > height ) hi_line_y = height; - if ( colours == 1 ) + if ( colours == ZM_COLOUR_GRAY8 ) { unsigned char *ptr = &buffer[(lo_line_y*width)+lo_line_x]; for ( int y = lo_line_y, r = 0; y < hi_line_y && r < CHAR_HEIGHT; y++, r++, ptr += width ) @@ -1492,7 +1540,7 @@ void Image::Annotate( const char *p_text, const Coord &coord, const Rgb fg_colou } } } - else if ( colours == 3 ) + else if ( colours == ZM_COLOUR_RGB24 ) { int wc = width * colours; @@ -1524,7 +1572,7 @@ void Image::Annotate( const char *p_text, const Coord &coord, const Rgb fg_colou } } } - else if ( colours == 4) + else if ( colours == ZM_COLOUR_RGB32 ) { int wc = width * colours; @@ -1583,6 +1631,7 @@ void Image::Timestamp( const char *label, const time_t when, const Coord &coord } } +/* RGB32 compatible: complete */ void Image::Colourise(const int p_reqcolours, const int p_reqsubpixelorder) { Debug(9, "Colourise: Req colours: %u Req subpixel order: %u Current colours: %u Current subpixel order: %u",p_reqcolours,p_reqsubpixelorder,colours,subpixelorder); @@ -1643,45 +1692,49 @@ void Image::Colourise(const int p_reqcolours, const int p_reqsubpixelorder) } - +/* RGB32 compatible: complete */ void Image::DeColourise() { - colours = 1; + colours = ZM_COLOUR_GRAY8; + subpixelorder = ZM_SUBPIX_ORDER_NONE; size = width * height; - uint8_t *pdest = buffer; - unsigned int r,g,b; - - if ( colours == 3 ) + if ( colours == ZM_COLOUR_RGB32 ) { - const uint8_t *psrc = buffer; - while( pdest < (buffer+size) ) - { - //*pdest++ = (uint8_t)sqrt((RED(psrc) + GREEN(psrc) + BLUE(psrc))/3); - - /* Use fast algorithm for almost identical ITU-R BT.709 weighting */ - if(subpixelorder == ZM_SUBPIX_ORDER_BGR) { - /* BGR subpixel order */ - r = RED_PTR_BGRA(psrc); - g = GREEN_PTR_BGRA(psrc); - b = BLUE_PTR_BGRA(psrc); - *pdest++ = (r + r + b + g + g + g + g + g)>>3; - } else { - /* RGB subpixel order */ - r = RED_PTR_RGBA(psrc); - g = GREEN_PTR_RGBA(psrc); - b = BLUE_PTR_RGBA(psrc); - *pdest++ = (r + r + b + g + g + g + g + g)>>3; - } - psrc += 3; + switch(subpixelorder) { + case ZM_SUBPIX_ORDER_BGRA: + std_convert_bgra_gray8(buffer,buffer,pixels); + break; + case ZM_SUBPIX_ORDER_ARGB: + std_convert_argb_gray8(buffer,buffer,pixels); + break; + case ZM_SUBPIX_ORDER_ABGR: + std_convert_abgr_gray8(buffer,buffer,pixels); + break; + case ZM_SUBPIX_ORDER_RGBA: + default: + std_convert_rgba_gray8(buffer,buffer,pixels); + break; } + } else { + /* Assume RGB24 */ + switch(subpixelorder) { + case ZM_SUBPIX_ORDER_BGR: + std_convert_bgr_gray8(buffer,buffer,pixels); + break; + case ZM_SUBPIX_ORDER_RGB: + default: + std_convert_rgb_gray8(buffer,buffer,pixels); + break; + } + } } /* RGB32 compatible: complete */ void Image::Fill( Rgb colour, const Box *limits ) { - if ( !(colours == 1 || colours == 3 || colours == 4 ) ) + if ( !(colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB24 || colours == ZM_COLOUR_RGB32 ) ) { Panic( "Attempt to fill image with unexpected colours %d", colours ); } @@ -1693,7 +1746,7 @@ void Image::Fill( Rgb colour, const Box *limits ) int lo_y = limits?limits->Lo().Y():0; int hi_x = limits?limits->Hi().X():width-1; int hi_y = limits?limits->Hi().Y():height-1; - if ( colours == 1 ) + if ( colours == ZM_COLOUR_GRAY8 ) { for ( int y = lo_y; y <= hi_y; y++ ) { @@ -1704,7 +1757,7 @@ void Image::Fill( Rgb colour, const Box *limits ) } } } - else if ( colours == 3 ) + else if ( colours == ZM_COLOUR_RGB24 ) { for ( int y = lo_y; y <= hi_y; y++ ) { @@ -1717,12 +1770,11 @@ void Image::Fill( Rgb colour, const Box *limits ) } } } - else if ( colours == 4 ) /* RGB32 [R,G,B,A] */ + else if ( colours == ZM_COLOUR_RGB32 ) /* RGB32 */ { for ( unsigned int y = lo_y; y <= hi_y; y++ ) { Rgb *p = (Rgb*)&buffer[((y*width)+lo_x)<<2]; - // unsigned int count = (hi_x+1) - lo_x; for ( unsigned int x = lo_x; x <= hi_x; x++, p++) { @@ -1740,7 +1792,7 @@ void Image::Fill( Rgb colour, int density, const Box *limits ) if(density <= 1) return Fill(colour,limits); - if ( !(colours == 1 || colours == 3 || colours == 4 ) ) + if ( !(colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB24 || colours == ZM_COLOUR_RGB32 ) ) { Panic( "Attempt to fill image with unexpected colours %d", colours ); } @@ -1752,7 +1804,7 @@ void Image::Fill( Rgb colour, int density, const Box *limits ) int lo_y = limits?limits->Lo().Y():0; int hi_x = limits?limits->Hi().X():width-1; int hi_y = limits?limits->Hi().Y():height-1; - if ( colours == 1 ) + if ( colours == ZM_COLOUR_GRAY8 ) { for ( int y = lo_y; y <= hi_y; y++ ) { @@ -1764,7 +1816,7 @@ void Image::Fill( Rgb colour, int density, const Box *limits ) } } } - else if ( colours == 3 ) + else if ( colours == ZM_COLOUR_RGB24 ) { for ( int y = lo_y; y <= hi_y; y++ ) { @@ -1779,7 +1831,7 @@ void Image::Fill( Rgb colour, int density, const Box *limits ) } } } - else if ( colours == 4 ) /* RGB32 [R,G,B,A] */ + else if ( colours == ZM_COLOUR_RGB32 ) /* RGB32 */ { for ( int y = lo_y; y <= hi_y; y++ ) { @@ -1799,7 +1851,7 @@ void Image::Fill( Rgb colour, int density, const Box *limits ) /* RGB32 compatible: complete */ void Image::Outline( Rgb colour, const Polygon &polygon ) { - if ( !(colours == 1 || colours == 3 || colours == 4 ) ) + if ( !(colours == ZM_COLOUR_GRAY8 || colours == ZM_COLOUR_RGB24 || colours == ZM_COLOUR_RGB32 ) ) { Panic( "Attempt to outline image with unexpected colours %d", colours ); } @@ -1835,7 +1887,7 @@ void Image::Outline( Rgb colour, const Polygon &polygon ) double x; int y, yinc = (y1= 0; i-- ) + for ( int i = new_width-1; i >= 0; i-- ) { d_ptr = rotate_buffer+i; - for ( int j = height-1; j >= 0; j-- ) + for ( int j = new_height-1; j >= 0; j-- ) { *d_ptr = *s_ptr++; d_ptr += line_bytes; } } } - else + else if ( colours == ZM_COLOUR_RGB32 ) + { + Rgb* s_rptr = (Rgb*)s_ptr; + Rgb* d_rptr; + for ( int i = new_width-1; i >= 0; i-- ) + { + d_rptr = (Rgb*)(rotate_buffer+(i<<2)); + for ( int j = new_height-1; j >= 0; j-- ) + { + *d_rptr = *s_rptr++; + d_rptr += new_width; + } + } + } + else /* Assume RGB24 */ { unsigned char *d_ptr; - for ( int i = width-1; i >= 0; i-- ) + for ( int i = new_width-1; i >= 0; i-- ) { d_ptr = rotate_buffer+(3*i); - for ( int j = height-1; j >= 0; j-- ) + for ( int j = new_height-1; j >= 0; j-- ) { *d_ptr = *s_ptr++; *(d_ptr+1) = *s_ptr++; @@ -2116,7 +2185,7 @@ void Image::Rotate( int angle ) unsigned char *s_ptr = buffer+size; unsigned char *d_ptr = rotate_buffer; - if ( colours == 1 ) + if ( colours == ZM_COLOUR_GRAY8 ) { while( s_ptr > buffer ) { @@ -2124,7 +2193,17 @@ void Image::Rotate( int angle ) *d_ptr++ = *s_ptr; } } - else + else if ( colours == ZM_COLOUR_RGB32 ) + { + Rgb* s_rptr = (Rgb*)s_ptr; + Rgb* d_rptr = (Rgb*)d_ptr; + while( s_rptr > (Rgb*)buffer ) + { + s_rptr--; + *d_rptr++ = *s_rptr; + } + } + else /* Assume RGB24 */ { while( s_ptr > buffer ) { @@ -2138,20 +2217,19 @@ void Image::Rotate( int angle ) } case 270 : { - int temp = width; - width = height; - height = temp; + new_height = width; + new_width = height; - int line_bytes = width*colours; + int line_bytes = new_width*colours; unsigned char *s_ptr = buffer+size; - if ( colours == 1 ) + if ( colours == ZM_COLOUR_GRAY8 ) { unsigned char *d_ptr; - for ( int i = width-1; i >= 0; i-- ) + for ( int i = new_width-1; i >= 0; i-- ) { d_ptr = rotate_buffer+i; - for ( int j = height-1; j >= 0; j-- ) + for ( int j = new_height-1; j >= 0; j-- ) { s_ptr--; *d_ptr = *s_ptr; @@ -2159,13 +2237,28 @@ void Image::Rotate( int angle ) } } } - else + else if ( colours == ZM_COLOUR_RGB32 ) + { + Rgb* s_rptr = (Rgb*)s_ptr; + Rgb* d_rptr; + for ( int i = new_width-1; i >= 0; i-- ) + { + d_rptr = (Rgb*)(rotate_buffer+(i<<2)); + for ( int j = new_height-1; j >= 0; j-- ) + { + s_rptr--; + *d_rptr = *s_rptr; + d_rptr += new_width; + } + } + } + else /* Assume RGB24 */ { unsigned char *d_ptr; - for ( int i = width-1; i >= 0; i-- ) + for ( int i = new_width-1; i >= 0; i-- ) { d_ptr = rotate_buffer+(3*i); - for ( int j = height-1; j >= 0; j-- ) + for ( int j = new_height-1; j >= 0; j-- ) { *(d_ptr+2) = *(--s_ptr); *(d_ptr+1) = *(--s_ptr); @@ -2178,13 +2271,13 @@ void Image::Rotate( int angle ) } } - AssignDirect( width, height, colours, subpixelorder, rotate_buffer, size, ZM_BUFTYPE_ZM); + AssignDirect( new_width, new_height, colours, subpixelorder, rotate_buffer, size, ZM_BUFTYPE_ZM); } +/* RGB32 compatible: complete */ void Image::Flip( bool leftright ) { - uint8_t* flip_buffer = AllocBuffer(size); int line_bytes = width*colours; @@ -2196,7 +2289,7 @@ void Image::Flip( bool leftright ) unsigned char *d_ptr = flip_buffer; unsigned char *max_d_ptr = flip_buffer + size; - if ( colours == 1 ) + if ( colours == ZM_COLOUR_GRAY8 ) { while( d_ptr < max_d_ptr ) { @@ -2208,7 +2301,22 @@ void Image::Flip( bool leftright ) s_ptr += line_bytes2; } } - else + else if ( colours == ZM_COLOUR_RGB32 ) + { + Rgb* s_rptr = (Rgb*)s_ptr; + Rgb* d_rptr = (Rgb*)flip_buffer; + Rgb* max_d_rptr = (Rgb*)max_d_ptr; + while( d_rptr < max_d_rptr ) + { + for ( int j = 0; j < width; j++ ) + { + s_rptr--; + *d_rptr++ = *s_rptr; + } + s_rptr += width * 2; + } + } + else /* Assume RGB24 */ { while( d_ptr < max_d_ptr ) { @@ -2221,7 +2329,7 @@ void Image::Flip( bool leftright ) } s_ptr += line_bytes2; } - } + } } else { @@ -2411,7 +2519,11 @@ __attribute__ ((noinline)) void sse2_fastblend(const uint8_t* col1, const uint8_ "cmp %3, %4\n\t" "jb algo_sse2_blend\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i), "m" (clearmask), "m" (divider) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i), "m" (clearmask), "m" (divider) +#endif : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "cc", "memory" ); #else @@ -2422,6 +2534,7 @@ __attribute__ ((noinline)) void sse2_fastblend(const uint8_t* col1, const uint8_ __attribute__ ((noinline)) void std_fastblend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent) { static int divider = 0; static double current_blendpercent = 0.0; + const uint8_t* const max_ptr = result + count; if(current_blendpercent != blendpercent) { /* Attempt to match the blending percent to one of the possible values */ @@ -2448,7 +2561,7 @@ __attribute__ ((noinline)) void std_fastblend(const uint8_t* col1, const uint8_t } - for(register unsigned long i=0; i < count; i += 16, col1 += 16, col2 += 16, result += 16) { + while(result < max_ptr) { result[0] = ((col2[0] - col1[0])>>divider) + col1[0]; result[1] = ((col2[1] - col1[1])>>divider) + col1[1]; result[2] = ((col2[2] - col1[2])>>divider) + col1[2]; @@ -2465,26 +2578,32 @@ __attribute__ ((noinline)) void std_fastblend(const uint8_t* col1, const uint8_t result[13] = ((col2[13] - col1[13])>>divider) + col1[13]; result[14] = ((col2[14] - col1[14])>>divider) + col1[14]; result[15] = ((col2[15] - col1[15])>>divider) + col1[15]; + + col1 += 16; + col2 += 16; + result += 16; } } __attribute__ ((noinline)) void std_blend(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count, double blendpercent) { double divide = blendpercent / 100.0; double opacity = 1.0 - divide; - for(register unsigned long i=0; i < count; i++) { - result[i] = (col1[i] * opacity) + (col2[i] * divide); + const uint8_t* const max_ptr = result + count; + + while(result < max_ptr) { + *result++ = (*col1++ * opacity) + (*col2++ * divide); + } } - - - /************************************************* DELTA FUNCTIONS *************************************************/ /* Grayscale */ __attribute__ ((noinline)) void std_delta8_gray8(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) { /* Loop unrolling is used to work on 16 bytes (16 grayscale pixels) at a time */ - for(unsigned int i=0;i>3; + + col1 += 12; + col2 += 12; + result += 4; } } @@ -2532,7 +2661,9 @@ __attribute__ ((noinline)) void std_delta8_rgb(const uint8_t* col1, const uint8_ __attribute__ ((noinline)) void std_delta8_bgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) { /* Loop unrolling is used to work on 12 bytes (4 rgb24 pixels) at a time */ int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 12; + col2 += 12; + result += 4; } } @@ -2556,7 +2691,9 @@ __attribute__ ((noinline)) void std_delta8_bgr(const uint8_t* col1, const uint8_ __attribute__ ((noinline)) void std_delta8_rgba(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) { /* Loop unrolling is used to work on 16 bytes (4 rgb32 pixels) at a time */ int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + col2 += 16; + result += 4; } } @@ -2580,7 +2721,9 @@ __attribute__ ((noinline)) void std_delta8_rgba(const uint8_t* col1, const uint8 __attribute__ ((noinline)) void std_delta8_bgra(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) { /* Loop unrolling is used to work on 16 bytes (4 rgb32 pixels) at a time */ int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + col2 += 16; + result += 4; } } @@ -2604,7 +2751,9 @@ __attribute__ ((noinline)) void std_delta8_bgra(const uint8_t* col1, const uint8 __attribute__ ((noinline)) void std_delta8_argb(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) { /* Loop unrolling is used to work on 16 bytes (4 rgb32 pixels) at a time */ int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + col2 += 16; + result += 4; } } @@ -2628,7 +2781,9 @@ __attribute__ ((noinline)) void std_delta8_argb(const uint8_t* col1, const uint8 __attribute__ ((noinline)) void std_delta8_abgr(const uint8_t* col1, const uint8_t* col2, uint8_t* result, unsigned long count) { /* Loop unrolling is used to work on 16 bytes (4 rgb32 pixels) at a time */ int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + col2 += 16; + result += 4; } } @@ -2674,7 +2833,11 @@ __attribute__ ((noinline)) void sse2_delta8_gray8(const uint8_t* col1, const uin "cmp %3, %4\n\t" "jb algo_sse2_delta8_gray8\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i) +#endif : "%xmm1", "%xmm2", "%xmm3", "%xmm4", "cc", "memory" ); #else @@ -2749,7 +2912,11 @@ __attribute__ ((noinline)) void sse2_delta8_rgba(const uint8_t* col1, const uint "cmp %3, %4\n\t" "jb algo_sse2_delta8_rgba\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "cc", "memory" ); #else @@ -2824,7 +2991,11 @@ __attribute__ ((noinline)) void sse2_delta8_bgra(const uint8_t* col1, const uint "cmp %3, %4\n\t" "jb algo_sse2_delta8_bgra\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "cc", "memory" ); #else @@ -2900,7 +3071,11 @@ __attribute__ ((noinline)) void sse2_delta8_argb(const uint8_t* col1, const uint "cmp %3, %4\n\t" "jb algo_sse2_delta8_argb\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "cc", "memory" ); #else @@ -2976,7 +3151,11 @@ __attribute__ ((noinline)) void sse2_delta8_abgr(const uint8_t* col1, const uint "cmp %3, %4\n\t" "jb algo_sse2_delta8_abgr\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "cc", "memory" ); #else @@ -3034,7 +3213,11 @@ __attribute__ ((noinline)) void ssse3_delta8_rgba(const uint8_t* col1, const uin "cmp %3, %4\n\t" "jb algo_ssse3_delta8_rgba\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i), "m" (*movemask) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i), "m" (*movemask) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "cc", "memory" ); #else @@ -3092,7 +3275,11 @@ __attribute__ ((noinline)) void ssse3_delta8_bgra(const uint8_t* col1, const uin "cmp %3, %4\n\t" "jb algo_ssse3_delta8_bgra\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i), "m" (*movemask) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i), "m" (*movemask) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "cc", "memory" ); #else @@ -3151,7 +3338,11 @@ __attribute__ ((noinline)) void ssse3_delta8_argb(const uint8_t* col1, const uin "cmp %3, %4\n\t" "jb algo_ssse3_delta8_argb\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i), "m" (*movemask) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i), "m" (*movemask) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "cc", "memory" ); #else @@ -3210,7 +3401,11 @@ __attribute__ ((noinline)) void ssse3_delta8_abgr(const uint8_t* col1, const uin "cmp %3, %4\n\t" "jb algo_ssse3_delta8_abgr\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (col2), "r" (result), "m" (count), "r" (i), "m" (*movemask) +#else + : "r" (col1), "r" (col2), "r" (result), "r" (count), "r" (i), "m" (*movemask) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "cc", "memory" ); #else @@ -3221,10 +3416,68 @@ __attribute__ ((noinline)) void ssse3_delta8_abgr(const uint8_t* col1, const uin /************************************************* CONVERT FUNCTIONS *************************************************/ +/* RGB24 to grayscale */ +__attribute__ ((noinline)) void std_convert_rgb_gray8(const uint8_t* col1, uint8_t* result, unsigned long count) { + unsigned int r,g,b; + const uint8_t* const max_ptr = result + count; + + while(result < max_ptr) { + r = col1[0]; + g = col1[1]; + b = col1[2]; + result[0] = (r + r + b + g + g + g + g + g)>>3; + r = col1[3]; + g = col1[4]; + b = col1[5]; + result[1] = (r + r + b + g + g + g + g + g)>>3; + r = col1[6]; + g = col1[7]; + b = col1[8]; + result[2] = (r + r + b + g + g + g + g + g)>>3; + r = col1[9]; + g = col1[10]; + b = col1[11]; + result[3] = (r + r + b + g + g + g + g + g)>>3; + + col1 += 12; + result += 4; + } +} + +/* BGR24 to grayscale */ +__attribute__ ((noinline)) void std_convert_bgr_gray8(const uint8_t* col1, uint8_t* result, unsigned long count) { + unsigned int r,g,b; + const uint8_t* const max_ptr = result + count; + + while(result < max_ptr) { + b = col1[0]; + g = col1[1]; + r = col1[2]; + result[0] = (r + r + b + g + g + g + g + g)>>3; + b = col1[3]; + g = col1[4]; + r = col1[5]; + result[1] = (r + r + b + g + g + g + g + g)>>3; + b = col1[6]; + g = col1[7]; + r = col1[8]; + result[2] = (r + r + b + g + g + g + g + g)>>3; + b = col1[9]; + g = col1[10]; + r = col1[11]; + result[3] = (r + r + b + g + g + g + g + g)>>3; + + col1 += 12; + result += 4; + } +} + /* RGBA to grayscale */ __attribute__ ((noinline)) void std_convert_rgba_gray8(const uint8_t* col1, uint8_t* result, unsigned long count) { unsigned int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + result += 4; } } /* BGRA to grayscale */ __attribute__ ((noinline)) void std_convert_bgra_gray8(const uint8_t* col1, uint8_t* result, unsigned long count) { unsigned int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + result += 4; } } /* ARGB to grayscale */ __attribute__ ((noinline)) void std_convert_argb_gray8(const uint8_t* col1, uint8_t* result, unsigned long count) { unsigned int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + result += 4; } } /* ABGR to grayscale */ __attribute__ ((noinline)) void std_convert_abgr_gray8(const uint8_t* col1, uint8_t* result, unsigned long count) { unsigned int r,g,b; - for(unsigned int i=0; i>3; + + col1 += 16; + result += 4; } } @@ -3317,7 +3588,9 @@ __attribute__ ((noinline)) void std_convert_abgr_gray8(const uint8_t* col1, uint __attribute__ ((noinline)) void std_convert_yuyv_gray8(const uint8_t* col1, uint8_t* result, unsigned long count) { const uint16_t* yuvbuf = (const uint16_t*)col1; - for(register unsigned long i=0; i < count; i += 16, yuvbuf += 16, result += 16) { + const uint8_t* const max_ptr = result + count; + + while(result < max_ptr) { result[0] = (uint8_t)yuvbuf[0]; result[1] = (uint8_t)yuvbuf[1]; result[2] = (uint8_t)yuvbuf[2]; @@ -3334,7 +3607,10 @@ __attribute__ ((noinline)) void std_convert_yuyv_gray8(const uint8_t* col1, uint result[13] = (uint8_t)yuvbuf[13]; result[14] = (uint8_t)yuvbuf[14]; result[15] = (uint8_t)yuvbuf[15]; - } + + yuvbuf += 16; + result += 16; + } } /* RGBA to grayscale SSSE3 */ @@ -3382,7 +3658,11 @@ __attribute__ ((noinline)) void ssse3_convert_rgba_gray8(const uint8_t* col1, ui "cmp %2, %3\n\t" "jb algo_ssse3_convert_rgba_gray8\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (result), "m" (count), "r" (i), "m" (*movemask) +#else + : "r" (col1), "r" (result), "r" (count), "r" (i), "m" (*movemask) +#endif : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "cc", "memory" ); #else @@ -3423,7 +3703,11 @@ __attribute__ ((noinline)) void ssse3_convert_yuyv_gray8(const uint8_t* col1, ui "cmp %2, %3\n\t" "jb algo_ssse3_convert_yuyv_gray8\n\t" : +#if (defined(_DEBUG) && !defined(__x86_64__)) /* Use one less register to allow compilation to success on 32bit with omit frame pointer disabled */ : "r" (col1), "r" (result), "m" (count), "r" (i), "m" (*movemask1), "m" (*movemask2) +#else + : "r" (col1), "r" (result), "r" (count), "r" (i), "m" (*movemask1), "m" (*movemask2) +#endif : "%xmm3", "%xmm4", "cc", "memory" ); #else diff --git a/src/zm_image.h b/src/zm_image.h index 10173c03f..0da931a95 100644 --- a/src/zm_image.h +++ b/src/zm_image.h @@ -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); diff --git a/src/zm_local_camera.cpp b/src/zm_local_camera.cpp index 53ba9ce1f..78559ae55 100644 --- a/src/zm_local_camera.cpp +++ b/src/zm_local_camera.cpp @@ -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; diff --git a/src/zm_monitor.cpp b/src/zm_monitor.cpp index 4b143c279..7dc565b19 100644 --- a/src/zm_monitor.cpp +++ b/src/zm_monitor.cpp @@ -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 ) diff --git a/src/zm_monitor.h b/src/zm_monitor.h index 7b65265f2..a0674abd3 100644 --- a/src/zm_monitor.h +++ b/src/zm_monitor.h @@ -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; diff --git a/src/zm_remote_camera_rtsp.cpp b/src/zm_remote_camera_rtsp.cpp index 3b873e84e..ec4ce99cf 100644 --- a/src/zm_remote_camera_rtsp.cpp +++ b/src/zm_remote_camera_rtsp.cpp @@ -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) ; } diff --git a/src/zm_zone.cpp b/src/zm_zone.cpp index 95541b116..c66e6c517 100644 --- a/src/zm_zone.cpp +++ b/src/zm_zone.cpp @@ -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; diff --git a/web/skins/classic/views/monitor.php b/web/skins/classic/views/monitor.php index e38a1b9a6..23629e352 100644 --- a/web/skins/classic/views/monitor.php +++ b/web/skins/classic/views/monitor.php @@ -94,7 +94,7 @@ else 'MaxFPS' => "", 'AlarmMaxFPS' => "", 'FPSReportInterval' => 1000, - 'RefBlendPerc' => 7, + 'RefBlendPerc' => 12, 'DefaultView' => 'Events', 'DefaultRate' => '100', 'DefaultScale' => '100',