Fixed greyscale four field deinterlacing not processing last line, broken ssse3 color->greyscale conversion and improved error handling when reading\decoding jpegs

This commit is contained in:
mastertheknife 2013-09-10 18:37:56 +03:00
parent f8c4897031
commit 2b568906e5
1 changed files with 99 additions and 76 deletions

View File

@ -633,6 +633,7 @@ bool Image::WriteRaw( const char *filename ) const
bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder) bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder)
{ {
unsigned int new_width, new_height, new_colours, new_subpixelorder;
struct jpeg_decompress_struct *cinfo = jpg_dcinfo; struct jpeg_decompress_struct *cinfo = jpg_dcinfo;
if ( !cinfo ) if ( !cinfo )
@ -662,19 +663,6 @@ bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder)
jpeg_read_header( cinfo, TRUE ); jpeg_read_header( cinfo, TRUE );
/* Check if the image has at least one huffman table defined. If not, use the standard ones */
/* This is required for the MJPEG capture palette of USB devices */
if(cinfo->dc_huff_tbl_ptrs[0] == NULL) {
zm_use_std_huff_tables(cinfo);
}
if ( cinfo->image_width != (unsigned int)width || cinfo->image_height != (unsigned int)height)
{
width = cinfo->image_width;
height = cinfo->image_height;
pixels = width*height;
}
if ( cinfo->num_components != 1 && cinfo->num_components != 3 ) if ( cinfo->num_components != 1 && cinfo->num_components != 3 )
{ {
Error( "Unexpected colours when reading jpeg image: %d", colours ); Error( "Unexpected colours when reading jpeg image: %d", colours );
@ -683,31 +671,45 @@ bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder)
return( false ); return( false );
} }
/* Check if the image has at least one huffman table defined. If not, use the standard ones */
/* This is required for the MJPEG capture palette of USB devices */
if(cinfo->dc_huff_tbl_ptrs[0] == NULL) {
zm_use_std_huff_tables(cinfo);
}
new_width = cinfo->image_width;
new_height = cinfo->image_height;
if ( width != new_width || height != new_height )
{
Error("Image dimensions differ. Old: %ux%u New: %ux%u",width,height,new_width,new_height);
}
switch(p_colours) { switch(p_colours) {
case ZM_COLOUR_GRAY8: case ZM_COLOUR_GRAY8:
{ {
cinfo->out_color_space = JCS_GRAYSCALE; cinfo->out_color_space = JCS_GRAYSCALE;
colours = ZM_COLOUR_GRAY8; new_colours = ZM_COLOUR_GRAY8;
subpixelorder = ZM_SUBPIX_ORDER_NONE; new_subpixelorder = ZM_SUBPIX_ORDER_NONE;
break; break;
} }
case ZM_COLOUR_RGB32: case ZM_COLOUR_RGB32:
{ {
#ifdef JCS_EXTENSIONS #ifdef JCS_EXTENSIONS
colours = ZM_COLOUR_RGB32; new_colours = ZM_COLOUR_RGB32;
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) { if(p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
cinfo->out_color_space = JCS_EXT_BGRX; cinfo->out_color_space = JCS_EXT_BGRX;
subpixelorder = ZM_SUBPIX_ORDER_BGRA; new_subpixelorder = ZM_SUBPIX_ORDER_BGRA;
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) { } else if(p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
cinfo->out_color_space = JCS_EXT_XRGB; cinfo->out_color_space = JCS_EXT_XRGB;
subpixelorder = ZM_SUBPIX_ORDER_ARGB; new_subpixelorder = ZM_SUBPIX_ORDER_ARGB;
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) { } else if(p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
cinfo->out_color_space = JCS_EXT_XBGR; cinfo->out_color_space = JCS_EXT_XBGR;
subpixelorder = ZM_SUBPIX_ORDER_ABGR; new_subpixelorder = ZM_SUBPIX_ORDER_ABGR;
} else { } else {
/* Assume RGBA */ /* Assume RGBA */
cinfo->out_color_space = JCS_EXT_RGBX; cinfo->out_color_space = JCS_EXT_RGBX;
subpixelorder = ZM_SUBPIX_ORDER_RGBA; new_subpixelorder = ZM_SUBPIX_ORDER_RGBA;
} }
break; break;
#else #else
@ -717,15 +719,15 @@ bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder)
case ZM_COLOUR_RGB24: case ZM_COLOUR_RGB24:
default: default:
{ {
colours = ZM_COLOUR_RGB24; new_colours = ZM_COLOUR_RGB24;
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) { if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) {
#ifdef JCS_EXTENSIONS #ifdef JCS_EXTENSIONS
cinfo->out_color_space = JCS_EXT_BGR; cinfo->out_color_space = JCS_EXT_BGR;
subpixelorder = ZM_SUBPIX_ORDER_BGR; new_subpixelorder = ZM_SUBPIX_ORDER_BGR;
#else #else
Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); 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_RGB; cinfo->out_color_space = JCS_RGB;
subpixelorder = ZM_SUBPIX_ORDER_RGB; new_subpixelorder = ZM_SUBPIX_ORDER_RGB;
#endif #endif
} else { } else {
/* Assume RGB */ /* Assume RGB */
@ -737,26 +739,17 @@ bool Image::ReadJpeg( const char *filename, int p_colours, int p_subpixelorder)
#endif #endif
*/ */
cinfo->out_color_space = JCS_RGB; cinfo->out_color_space = JCS_RGB;
subpixelorder = ZM_SUBPIX_ORDER_RGB; new_subpixelorder = ZM_SUBPIX_ORDER_RGB;
} }
break; break;
} }
} }
size = pixels*colours; if(WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == NULL) {
Error("Failed requesting writeable buffer for reading JPEG image.");
if(buffer == NULL) { jpeg_abort_decompress( cinfo );
AllocImgBuffer(size); fclose( infile );
} else { return( false );
if(allocation < (unsigned int)size) {
if(holdbuffer) {
Error("Held buffer is undersized for the requested image");
return (false);
} else {
DumpImgBuffer();
AllocImgBuffer(size);
}
}
} }
jpeg_start_decompress( cinfo ); jpeg_start_decompress( cinfo );
@ -893,6 +886,7 @@ bool Image::WriteJpeg( const char *filename, int quality_override ) const
bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours, int p_subpixelorder) bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours, int p_subpixelorder)
{ {
unsigned int new_width, new_height, new_colours, new_subpixelorder;
struct jpeg_decompress_struct *cinfo = jpg_dcinfo; struct jpeg_decompress_struct *cinfo = jpg_dcinfo;
if ( !cinfo ) if ( !cinfo )
@ -914,19 +908,6 @@ bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours
jpeg_read_header( cinfo, TRUE ); jpeg_read_header( cinfo, TRUE );
/* Check if the image has at least one huffman table defined. If not, use the standard ones */
/* This is required for the MJPEG capture palette of USB devices */
if(cinfo->dc_huff_tbl_ptrs[0] == NULL) {
zm_use_std_huff_tables(cinfo);
}
if ( cinfo->image_width != (unsigned int)width || cinfo->image_height != (unsigned int)height)
{
width = cinfo->image_width;
height = cinfo->image_height;
pixels = width*height;
}
if ( cinfo->num_components != 1 && cinfo->num_components != 3 ) if ( cinfo->num_components != 1 && cinfo->num_components != 3 )
{ {
Error( "Unexpected colours when reading jpeg image: %d", colours ); Error( "Unexpected colours when reading jpeg image: %d", colours );
@ -934,31 +915,45 @@ bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours
return( false ); return( false );
} }
/* Check if the image has at least one huffman table defined. If not, use the standard ones */
/* This is required for the MJPEG capture palette of USB devices */
if(cinfo->dc_huff_tbl_ptrs[0] == NULL) {
zm_use_std_huff_tables(cinfo);
}
new_width = cinfo->image_width;
new_height = cinfo->image_height;
if ( width != new_width || height != new_height )
{
Error("Image dimensions differ. Old: %ux%u New: %ux%u",width,height,new_width,new_height);
}
switch(p_colours) { switch(p_colours) {
case ZM_COLOUR_GRAY8: case ZM_COLOUR_GRAY8:
{ {
cinfo->out_color_space = JCS_GRAYSCALE; cinfo->out_color_space = JCS_GRAYSCALE;
colours = ZM_COLOUR_GRAY8; new_colours = ZM_COLOUR_GRAY8;
subpixelorder = ZM_SUBPIX_ORDER_NONE; new_subpixelorder = ZM_SUBPIX_ORDER_NONE;
break; break;
} }
case ZM_COLOUR_RGB32: case ZM_COLOUR_RGB32:
{ {
#ifdef JCS_EXTENSIONS #ifdef JCS_EXTENSIONS
colours = ZM_COLOUR_RGB32; new_colours = ZM_COLOUR_RGB32;
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) { if(p_subpixelorder == ZM_SUBPIX_ORDER_BGRA) {
cinfo->out_color_space = JCS_EXT_BGRX; cinfo->out_color_space = JCS_EXT_BGRX;
subpixelorder = ZM_SUBPIX_ORDER_BGRA; new_subpixelorder = ZM_SUBPIX_ORDER_BGRA;
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) { } else if(p_subpixelorder == ZM_SUBPIX_ORDER_ARGB) {
cinfo->out_color_space = JCS_EXT_XRGB; cinfo->out_color_space = JCS_EXT_XRGB;
subpixelorder = ZM_SUBPIX_ORDER_ARGB; new_subpixelorder = ZM_SUBPIX_ORDER_ARGB;
} else if(p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) { } else if(p_subpixelorder == ZM_SUBPIX_ORDER_ABGR) {
cinfo->out_color_space = JCS_EXT_XBGR; cinfo->out_color_space = JCS_EXT_XBGR;
subpixelorder = ZM_SUBPIX_ORDER_ABGR; new_subpixelorder = ZM_SUBPIX_ORDER_ABGR;
} else { } else {
/* Assume RGBA */ /* Assume RGBA */
cinfo->out_color_space = JCS_EXT_RGBX; cinfo->out_color_space = JCS_EXT_RGBX;
subpixelorder = ZM_SUBPIX_ORDER_RGBA; new_subpixelorder = ZM_SUBPIX_ORDER_RGBA;
} }
break; break;
#else #else
@ -968,15 +963,15 @@ bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours
case ZM_COLOUR_RGB24: case ZM_COLOUR_RGB24:
default: default:
{ {
colours = ZM_COLOUR_RGB24; new_colours = ZM_COLOUR_RGB24;
if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) { if(p_subpixelorder == ZM_SUBPIX_ORDER_BGR) {
#ifdef JCS_EXTENSIONS #ifdef JCS_EXTENSIONS
cinfo->out_color_space = JCS_EXT_BGR; cinfo->out_color_space = JCS_EXT_BGR;
subpixelorder = ZM_SUBPIX_ORDER_BGR; new_subpixelorder = ZM_SUBPIX_ORDER_BGR;
#else #else
Warning("libjpeg-turbo is required for reading a JPEG directly into a BGR24 buffer, reading into a RGB24 buffer instead."); 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_RGB; cinfo->out_color_space = JCS_RGB;
subpixelorder = ZM_SUBPIX_ORDER_RGB; new_subpixelorder = ZM_SUBPIX_ORDER_RGB;
#endif #endif
} else { } else {
/* Assume RGB */ /* Assume RGB */
@ -988,26 +983,16 @@ bool Image::DecodeJpeg( const JOCTET *inbuffer, int inbuffer_size, int p_colours
#endif #endif
*/ */
cinfo->out_color_space = JCS_RGB; cinfo->out_color_space = JCS_RGB;
subpixelorder = ZM_SUBPIX_ORDER_RGB; new_subpixelorder = ZM_SUBPIX_ORDER_RGB;
} }
break; break;
} }
} }
size = pixels*colours; if(WriteBuffer(new_width, new_height, new_colours, new_subpixelorder) == NULL) {
Error("Failed requesting writeable buffer for reading JPEG image.");
if(buffer == NULL) { jpeg_abort_decompress( cinfo );
AllocImgBuffer(size); return( false );
} else {
if(allocation < (unsigned int)size) {
if(holdbuffer) {
Error("Held buffer is undersized for the requested image");
return (false);
} else {
DumpImgBuffer();
AllocImgBuffer(size);
}
}
} }
jpeg_start_decompress( cinfo ); jpeg_start_decompress( cinfo );
@ -4039,7 +4024,7 @@ __attribute__((noinline,__target__("ssse3"))) void ssse3_convert_rgba_gray8(cons
"movd %%xmm1, %%eax\n\t" "movd %%xmm1, %%eax\n\t"
"movnti %%eax, (%1,%2)\n\t" "movnti %%eax, (%1,%2)\n\t"
"sub $0x4, %2\n\t" "sub $0x4, %2\n\t"
"jnz ssse3_delta8_abgr_iter\n\t" "jnz ssse3_convert_rgba_gray8_iter\n\t"
: :
: "r" (col1), "r" (result), "r" (count), "m" (*movemask) : "r" (col1), "r" (result), "r" (count), "m" (*movemask)
: "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "cc", "memory" : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "cc", "memory"
@ -4751,6 +4736,44 @@ __attribute__((noinline,__target__("ssse3"))) void ssse3_deinterlace_4field_gray
/* Check if we reached the end */ /* Check if we reached the end */
"cmp %3, %0\n\t" "cmp %3, %0\n\t"
"jb algo_ssse3_deinterlace_4field_gray8\n\t" // Go for another iteration "jb algo_ssse3_deinterlace_4field_gray8\n\t" // Go for another iteration
/* Special case for the last line */
/* Load pabove into xmm1 and pnabove into xmm2 */
"movdqa (%0), %%xmm1\n\t"
"movdqa (%1), %%xmm2\n\t"
"movdqa %%xmm1, %%xmm5\n\t" /* Keep backup of pabove in xmm5 */
"pmaxub %%xmm2, %%xmm1\n\t"
"pminub %%xmm5, %%xmm2\n\t"
"psubb %%xmm2, %%xmm1\n\t"
"movdqa %%xmm1, %%xmm7\n\t" /* Backup of delta2 in xmm7 for now */
/* Next row */
"add %4, %0\n\t"
"add %4, %1\n\t"
/* Load pcurrent into xmm1 and pncurrent into xmm2 */
"movdqa (%0), %%xmm1\n\t"
"movdqa (%1), %%xmm2\n\t"
"movdqa %%xmm1, %%xmm6\n\t" /* Keep backup of pcurrent in xmm6 */
"pmaxub %%xmm2, %%xmm1\n\t"
"pminub %%xmm6, %%xmm2\n\t"
"psubb %%xmm2, %%xmm1\n\t"
"pavgb %%xmm7, %%xmm1\n\t" // Average the two deltas together
"movdqa %%xmm1, %%xmm2\n\t"
/* Do the comparison on words instead of bytes because we don't have unsigned comparison */
"punpcklbw %%xmm0, %%xmm1\n\t" // Expand pixels 0-7 into words into xmm1
"punpckhbw %%xmm0, %%xmm2\n\t" // Expand pixels 8-15 into words into xmm2
"pcmpgtw %%xmm4, %%xmm1\n\t" // Compare average delta with threshold for pixels 0-7
"pcmpgtw %%xmm4, %%xmm2\n\t" // Compare average delta with threshold for pixels 8-15
"packsswb %%xmm2, %%xmm1\n\t" // Pack the comparison results into xmm1
"pand %%xmm1, %%xmm5\n\t" // Filter out pixels in pabove that shouldn't be copied
"pandn %%xmm6, %%xmm1\n\t" // Filter out pixels in pcurrent that should be replaced
"por %%xmm5, %%xmm1\n\t" // Put the new values in pcurrent
"movntdq %%xmm1, (%0)\n\t" // Write pcurrent
: :
: "r" (col1), "r" (col2), "r" (max_ptr2), "r" (max_ptr), "r" (row_width), "m" (threshold_mask.int32) : "r" (col1), "r" (col2), "r" (max_ptr2), "r" (max_ptr), "r" (row_width), "m" (threshold_mask.int32)
: "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "cc", "memory" : "%eax", "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", "cc", "memory"