📄 yuvscaler_bicubic.c
字号:
output_p+=output_offset; line_top+=local_padded_width; // BOTTOM LINE cspline_wp=cspline_w; in_col_p=in_col; for (out_col = 0; out_col < local_output_active_width; out_col++) { line = line_bot + *(in_col_p++); value1=*(line++)*(*(cspline_wp++)); for (w=1;w<width_neighbors-1;w++) value1+=*(line++)*(*(cspline_wp++)); value1+=*(line)*(*(cspline_wp++)); if (zero_width_neighbors) cspline_wp++; if (value1 < 0) *(output_p++) = 0; else { value = (value1 + FLOAT2INTOFFSET) >> FLOAT2INTEGERPOWER; if (value > 255) *(output_p++) = 255; else *(output_p++) = (uint8_t) value; } } // a bottom line on output is now finished. We jump to the beginning of the next top line output_p+=output_offset; line_bot+=local_padded_width; } } break; case 5: // We only scale on height, not width { cspline_hp0=cspline_h; in_line_p=in_line; for (out_line = 0; out_line < (local_output_active_height>>1); out_line++) { // TOP LINE line_begin=padded_top + *(in_line_p) * local_padded_width; for (out_col = 0; out_col < local_output_active_width; out_col++) { cspline_hp=cspline_hp0; value1 = *(line_begin)*(*(cspline_hp++)); for (h=1;h<height_neighbors-1;h++) value1 += (*(line_begin+h*local_padded_width))*(*(cspline_hp++)); value1 += (*((line_begin++)+h*local_padded_width))*(*(cspline_hp)); if (value1 < 0) *(output_p++) = 0; else { value = (value1 + FLOAT2INTOFFSET) >> FLOAT2INTEGERPOWER; if (value > 255) *(output_p++) = 255; else *(output_p++) = (uint8_t) value; } } // a top line on output is now finished. We jump to the beginning of the next bottom line output_p+=output_offset; // BOTTTOM LINE line_begin=padded_bottom + *(in_line_p++) * local_padded_width; for (out_col = 0; out_col < local_output_active_width-1; out_col++) { cspline_hp=cspline_hp0; value1 = *(line_begin)*(*(cspline_hp++)); for (h=1;h<height_neighbors-1;h++) value1 += (*(line_begin+h*local_padded_width))*(*(cspline_hp++)); value1 += (*((line_begin++)+h*local_padded_width))*(*(cspline_hp)); if (value1 < 0) *(output_p++) = 0; else { value = (value1 + FLOAT2INTOFFSET) >> FLOAT2INTEGERPOWER; if (value > 255) *(output_p++) = 255; else *(output_p++) = (uint8_t) value; } } // last out_col to be treated => cspline_hp0 incremented => we use the C "++" facility value1 = *(line_begin)*(*(cspline_hp0++)); for (h=1;h<height_neighbors;h++) value1 += (*(line_begin+h*local_padded_width))*(*(cspline_hp0++)); if (zero_height_neighbors) cspline_hp0++; if (value1 < 0) *(output_p++) = 0; else { value = (value1 + FLOAT2INTOFFSET) >> FLOAT2INTEGERPOWER; if (value > 255) *(output_p++) = 255; else *(output_p++) = (uint8_t) value; } // a bottom line on output is now finished. We jump to the beginning of the next top line output_p+=output_offset; } } break; } /* *INDENT-ON* */ // mjpeg_debug ("End of cubic_scale"); return (0); }// *************************************************************************************// // *************************************************************************************int16_tcubic_spline (float x, unsigned int multiplicative){ // Implementation of the Mitchell-Netravalli cubic spline, with recommended parameters B and C // [after Reconstruction filters in Computer Graphics by P. Mitchel and N. Netravali : Computer Graphics, Volume 22, Number 4, pp 221-228] // Normally, coefficiants are float, but they are transformed into integer with 1/FLOAT2INTEGER = 1/2"11 precision for speed reasons. // Please note that these coefficient may over and under shoot in the sense that they may be <0.0 and >1.0 // Given out values of B and C, maximum value is (x=0) 8/9 and undeshoot is bigger than -0.04 (x#1.5) const float B = 1.0 / 3.0; const float C = 1.0 / 3.0; if (fabs (x) < 1) return ((int16_t) floor (0.5 + (((12.0 - 9.0 * B - 6.0 * C) * fabs (x) * fabs (x) * fabs (x) + (-18.0 + 12.0 * B + 6.0 * C) * fabs (x) * fabs (x) + (6.0 - 2.0 * B)) / 6.0 ) * multiplicative)); if (fabs (x) <= 2) return ((int16_t) floor (0.5 + (((-B - 6.0 * C) * fabs (x) * fabs (x) * fabs (x) + (6.0 * B + 30.0 * C) * fabs (x) * fabs (x) + (-12.0 * B - 48.0 * C) * fabs (x) + (8.0 * B + 24.0 * C)) / 6.0) * multiplicative)); if (fabs (x) <= 3) return (0); mjpeg_info("In function cubic_spline: x=%f >3",x); return (0);}// *************************************************************************************// *************************************************************************************intpadding (uint8_t * padded_input, uint8_t * input, unsigned int half, uint16_t left_offset, uint16_t top_offset, uint16_t right_offset, uint16_t bottom_offset, uint16_t width_pad){ // In cubic interpolation, output pixel are evaluated from the 4*4 to 12*12 nearest neigbors. // For border pixels, this requires that input datas along the edge to be padded. // We choose to pad border pixel with black pixel, since border pixel along width are much of the time non-visible // (TV set for example) and along the height they are either non-visible or black borders are displayed // This padding functions requires output_interlaced==0 unsigned int local_input_useful_width = input_useful_width >> half; unsigned int local_input_useful_height = input_useful_height >> half; unsigned int local_padded_width = local_input_useful_width + width_pad; unsigned int local_input_width = input_width >> half; unsigned int line; uint8_t black,*uint8_pad,*uint8_inp; unsigned long int nb_top=top_offset*local_padded_width; // mjpeg_debug ("Start of padding, left_offset=%d,top_offset=%d,right_offset=%d,bottom_offset=%d,width_pad=%d",// left_offset,top_offset,right_offset,bottom_offset,width_pad); if (half) black=128; else black=16; // PADDING // vertical offset of top_offset lines // Black pixel on the left_offset left pixels // Content Copy with left_offset pixels offset on the left and right_offset pixels of the right // Black pixel on the right_offset right pixels // vertical offset of the last bottom_offset lines memset(padded_input,black,nb_top); uint8_inp=input; uint8_pad=padded_input+nb_top; for (line = 0; line < local_input_useful_height; line++) { memset(uint8_pad,black,left_offset); uint8_pad+=left_offset; memcpy (uint8_pad, uint8_inp, local_input_useful_width); uint8_pad+=local_input_useful_width; uint8_inp+=local_input_width; // it is local_input_width, not local_input_useful_width, see yuvscaler_implementation.txt memset(uint8_pad,black,right_offset); uint8_pad+=right_offset; } memset(uint8_pad,black,bottom_offset*local_padded_width); // mjpeg_debug ("End of padding"); return (0);}// *************************************************************************************// *************************************************************************************intpadding_interlaced (uint8_t * padded_top, uint8_t * padded_bottom, uint8_t * input, unsigned int half, uint16_t left_offset, uint16_t top_offset, uint16_t right_offset, uint16_t bottom_offset, uint16_t width_pad){ unsigned int local_input_useful_width = input_useful_width >> half; unsigned int local_input_useful_height = input_useful_height >> half; unsigned int local_padded_width = local_input_useful_width + width_pad; unsigned int local_input_width = input_width >> half; unsigned int line; uint8_t black, * uint8_ptop, * uint8_pbot, * uint8_inp; unsigned long int nb_top=top_offset*local_padded_width; unsigned long int nb_bot=bottom_offset*local_padded_width; // mjpeg_debug ("Start of padding_interlaced, left_offset=%d,top_offset=%d,right_offset=%d,bottom_offset=%d,width_pad=%d",// left_offset,top_offset,right_offset,bottom_offset,width_pad); if (half) black=128; else black=16; // PADDING // vertical offset of top_offset lines // Black pixel on the left_offset left pixels // Content Copy with left_offset pixels offset on the left and right_offset pixels of the right // Black pixel on the right_offset right pixels // vertical offset of the last bottom_offset lines memset(padded_top,black,nb_top); memset(padded_bottom,black,nb_top); uint8_inp=input; uint8_ptop=padded_top+nb_top; uint8_pbot=padded_bottom+nb_top; for (line = 0; line < (local_input_useful_height >> 1); line++) { memset(uint8_ptop,black,left_offset); uint8_ptop+=left_offset; memset(uint8_pbot,black,left_offset); uint8_pbot+=left_offset; memcpy (uint8_ptop, uint8_inp, local_input_useful_width); uint8_ptop+=local_input_useful_width; uint8_inp +=local_input_width; // it is local_input_width, not local_input_useful_width, see yuvscaler_implementation.txt memcpy (uint8_pbot, uint8_inp, local_input_useful_width); uint8_pbot+=local_input_useful_width; uint8_inp +=local_input_width; // it is local_input_width, not local_input_useful_width, see yuvscaler_implementation.txt memset(uint8_ptop,black,right_offset); uint8_ptop+=right_offset; memset(uint8_pbot,black,right_offset); uint8_pbot+=right_offset; } memset(uint8_ptop,black,nb_bot); memset(uint8_pbot,black,nb_bot); // mjpeg_debug ("End of padding_interlaced"); return (0);}// ************************************************************************************* // THE FOLLOWING LINE "if (!mmx) mmx=0;" DOES NO USEFUL CALCULATION BUT // it is necessary when gcc compilation with -O2 flag // to calculate correct values for value1+=(mmx_res[0]+mmx_res[1])*(*csplineh[h]); // I know this sounds incredible, but believe me, it is true ! // On the other hand, using only gcc -O1, this line is no more necessary. // And in both case, mmx_res[0],mmx_res[1] and *csplineh[h] have the same values // Indeed, the corresponding machine code is totally different with or without // this line with gcc -O2. // The line value1+=(mmx_res[0]+mmx_res[1])*(*csplineh[h]) is compiled into // (From DDD): // Right calculation, that is including the "if (!mmx) mmx=0;" line // --> 0x804f07f <cubic_scale+1615>:pmaddwd %mm0,%mm6 // --> 0x804f082 <cubic_scale+1618>:movq %mm6,(%ecx) // 0x804f085 <cubic_scale+1621>:mov (%ecx),%edx // 0x804f087 <cubic_scale+1623>:mov 0x4(%ecx),%eax // 0x804f08a <cubic_scale+1626>:mov 0xffffffbc(%ebp),%ebx // 0x804f08d <cubic_scale+1629>:add %edx,%eax // 0x804f08f <cubic_scale+1631>:mov (%ebx,%edi,4),%edx // --> 0x804f092 <cubic_scale+1634>:inc %edi // Wrong calculation, that is not including the "if (!mmx) mmx=0;" line // --> 0x804f062 <cubic_scale+1586>:pmaddwd %mm0,%mm6 // --> 0x804f065 <cubic_scale+1589>:movq %mm6,(%ecx) // 0x804f068 <cubic_scale+1592>:mov 0xffffffbc(%ebp),%ebx // 0x804f06b <cubic_scale+1595>:mov (%ecx),%eax // 0x804f06d <cubic_scale+1597>:mov (%ebx,%edi,4),%edx // 0x804f070 <cubic_scale+1600>:add %esi,%eax // --> 0x804f072 <cubic_scale+1602>:inc %edi // if (!mmx)// mmx=0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -