📄 yuvscaler.c
字号:
} // END OF RESAMPLE RESAMPLE RESAMPLE // BICUBIC BICUBIC BICUBIC if (algorithm == 1) { // SPECIFIC // Is a specific downscaling speed enhanced treatment available? // We only downscale on height, not width. // Ex: 16/9 to 4/3 conversion if ((output_width_slice == 1) && (input_width_slice == 1)) specific = 5; // We only downscale on width, not height // Ex: Full size to SVCD if ((output_height_slice == 1) && (input_height_slice == 1)) specific = 1; if (specific) mjpeg_info ("Specific downscaling routing number %u", specific); // specific=0; // Let us tabulate several values which are explained below: // // Given the scaling factor "height_scale" on height and "width_scale" on width, to an output pixel of coordinates (out_col,out_line) // corresponds an input pixel of coordinates (in_col,in_line), where in_col = out_col/width_scale and in_line = out_line/height_scale. // As pixel coordinates are integer values, we take for in_col and out_col the nearest smaller integer // value: in_col = floor(out_col/width_scale) and in_line = floor(out_line/height_scale). // The input pixel of coordinates (in_col,in_line) is called the base input pixel // Thus, we make an error conventionnally named "b" for columns and "a" for lines // with b = out_col/width_scale - floor(out_col/width_scale) and a = out_line/height_scale - floor(out_line/height_scale). // Please note that a and b are inside range [0,1[. // // For upscaling along w (resp. h), we need to take into account the 4 nearest neighbors along w (resp. h) of the base input pixel. // For downscaling along w (resp. h), we need to take into account AT LEAST 6 nearest neighbors of the base input p顇el. // And the real number of neighbors pixel from the base input pixel to be taken into account depends on the scaling ratios. // We have to take into account "width_neighbors" neighbors on the width and "height_neighbors" on the height; // with width_neighbors = 2*nearest_higher_integer(2/width_scale), or 4 if upscaling (output_width_slice>input_width_slice) // and width_offset=(width_neighbors/2)-1; // with height_neighbors = 2*nearest_higher_integer(2/height_scale), or 4 if upscaling (output_height_slice>input_height_slice) // and height_offset=(height_neighbors/2)-1; // // ***************** // The general formula giving the value of the output pixel as a function of the input pixels is: // OutputPixel(out_col,out_line)= // Sum(h=-height_offset,...(height_neigbors-height_offset-1))Sum(w=-width_offset,...(width_neigbors-width_offset-1)) // InputPixel(in_col+w,in_line+h)*BicubicCoefficient((b-w)*scale_width)*BicubicCoefficient((a-h)*scale_height)*scale_height*scale_width // ***************** // Please note that [theoretically] (a-h)*scale_height is [-2:2], as well as (b-w)*scale_width. // But, as height_neigbors is the nearest higher integer, the practical range for "(a-h)*scale_height" and "(b-w)*scale_width" is // extended from theorital [-2:2] to [-3:3] => "(a-h)*scale_height" and "(b-w)*scale_width" are considered 0 outside of [-2:2]. // Please note also that for upscaling only, scale_height and scale_width are artifially taken as 1.0 in the formula. // // For an easier implementation, it is preferable that h and w start from 0. Therefore, in the general formula, we will replace // "h" by "h-height_offset" and "w" by "w-width_offset". // // Moreover, the output pixel value depends on at least the 4x4 nearest neighbors from the base input pixel in the input image. // As a consequence, if the base input pixel is at on the border of the image, the bicubic algorithm will try to find values // outside the input image => to avoid this, we will pad the input image height_offset pixel on the top, width_offset pixels on the left, // (and right_offset pixels on the right and bottom_offset pixels at the bottom). // Therefore, in the general formula, we will replace InputPixel(x,y) by PaddedInputPixel(x+width_offset,y+height_offset). // // ***************** // Finally, the general formula may be rewritten as: // OutputPixel(out_col,out_line)= // Sum(h=0,...(height_neigbors-1))Sum(w=0...(width_neigbors-1)) // PaddedInputPixel(in_col+w,in_line+h)*BicubicCoefficient((b-w+width_offset)*scale_width)*BicubicCoefficient((a-h+height_offset)*scale_height)*scale_height*scale_width // ***************** // // // ***************** // IMPLEMENTATION // ***************** // To insure a fast implementation of the general formula, we will pre-calculate all possible values of // BicubicCoefficient((b-w+width_offset)*scale_width)*scale_width, and tabulate them as cspline_w: // cspline_w[w,out_col]=BicubicCoefficient((b[out_col]-w+width_offset)*scale_width)*scale_width. // And the same stands for height: // cspline_h[h,out_line]=BicubicCoefficient((a[out_line]-h+height_offset)*scale_height)*scale_height // // To be continued ... height_scale=(float)output_height_slice/(float)input_height_slice; if (height_scale>1.0) height_scale=1.0; width_scale=(float)output_width_slice/(float)input_width_slice; if (width_scale>1.0) width_scale=1.0; width_neighbors = (2 * input_width_slice ) / output_width_slice; if (((2 * input_width_slice ) % output_width_slice)!=0) width_neighbors++; width_neighbors*=2; if (width_neighbors < 4) width_neighbors = 4; width_offset = left_offset = width_neighbors/2-1; width_pad=width_neighbors - 1; right_offset=width_neighbors/2; height_neighbors = (2 * input_height_slice ) / output_height_slice; if (((2 * input_height_slice ) % output_height_slice)!=0) height_neighbors++; height_neighbors*=2; if (height_neighbors < 4) height_neighbors = 4; height_offset = top_offset = height_neighbors/2-1; height_pad=height_neighbors - 1; bottom_offset=height_neighbors/2; mjpeg_debug("height_scale=%f, width_scale=%f, width_neighbors=%d, height_neighbors=%d",height_scale,width_scale,width_neighbors,height_neighbors); // Memory allocations #ifdef HAVE_ASM_MMX if (!(mmx_res = (int32_t *) malloc (2 * sizeof (int32_t) + ALIGNEMENT))) mjpeg_error_exit1 ("Could not allocate memory for mmx registers. STOP!"); // alignement instructions if (((unsigned long int) mmx_res % ALIGNEMENT) != 0) mmx_res = (int32_t *) ((((unsigned long int) mmx_res / ALIGNEMENT) + 1) * ALIGNEMENT); if (mmx==1) { if (width_neighbors <= MAXWIDTHNEIGHBORS) { mjpeg_info("MMX accelerated treatment activated"); mmx = 1; } else { mmx=0; mjpeg_warn("MMX accelerated treatment not available for downscaling ratio larger than 4 to 1"); mjpeg_warn("If you still want to use an MMX treatment (not really useful for such a large downscaling ratio"); mjpeg_warn("please use multiple yuvscaler downscaling to achieve the desired downscaling ratio"); } }#endif// Il faudrait peut-阾re aligner correctement tous ces pointeurs, en particulier cspline_w_neighbors et cspline_h_neighbors// qui sont amplement utilis閟 dans les routines de scaling => il faut aussi aligner cspline_w et cspline_h if ( !(cspline_w = (int16_t *) malloc ( width_neighbors * output_active_width * sizeof (int16_t))) || !(cspline_h = (int16_t *) malloc ( height_neighbors * output_active_height * sizeof (int16_t))) || !(in_col = (unsigned int *) malloc ( output_active_width * sizeof (unsigned int))) || !(b = (float *) malloc ( output_active_width * sizeof (float))) || !(in_line = (unsigned int *) malloc ( output_active_height * sizeof (unsigned int))) || !(a = (float *) malloc ( output_active_height * sizeof (float))) ) mjpeg_error_exit1 ("Could not allocate memory for bicubic tables. STOP!"); // Initialisation of bicubic tables pointer=cspline_h; for (out_line = 0; out_line < output_active_height; out_line++) { in_line[out_line] = (out_line * input_height_slice) / output_height_slice; // mjpeg_debug("in_line[%u]=%u",out_line,in_line[out_line]); a[out_line] = (float) ((out_line * input_height_slice) % output_height_slice) / (float) output_height_slice; somme=0; for (h=0;h<height_neighbors;h++) { cspline_value=cubic_spline ((a[out_line] + height_offset -h)*height_scale, bicubic_div_height)*height_scale; mjpeg_debug("cspline_value=%d,cspline=%d,a[%u]=%g,height_offset=%d,height_scale=%g,h=%lu",cspline_value,cubic_spline ((a[out_line] + height_offset -h)*height_scale, bicubic_div_height),out_line,a[out_line],height_offset,height_scale,h); somme+=cspline_value; *(pointer++)=cspline_value; } if (cspline_value!=0) zero_height_neighbors=0; // Normalisation test and normalisation of cspline if (somme != bicubic_div_height) *(pointer-2) += bicubic_div_height-somme; } pointer=cspline_w; for (out_col = 0; out_col < output_active_width; out_col++) { in_col[out_col] = (out_col * input_width_slice) / output_width_slice; b[out_col] = (float) ((out_col * input_width_slice) % output_width_slice) / (float) output_width_slice; somme=0; for (w=0;w<width_neighbors;w++) {// mjpeg_debug("b[%u]=%g,width_offset=%d,width_scale=%g,w=%lu",out_col,b[out_col],width_offset,width_scale,w); cspline_value=cubic_spline ((b[out_col] + width_offset -w)*width_scale, bicubic_div_width)*width_scale; mjpeg_debug("cspline_value=%d,b[%u]=%g,height_offset=%d,height_scale=%g,w=%lu",cspline_value,out_col,b[out_col],height_offset,height_scale,w); somme+=cspline_value; *(pointer++)=cspline_value; } if (cspline_value!=0) zero_width_neighbors=0; // Normalisation test and normalisation of cspline if (somme != bicubic_div_width) *(pointer-2) += bicubic_div_width-somme; } // Added +2*ALIGNEMENT for MMX scaling routines that loads a higher number of pixels than necessary (memory overflow) if (interlaced == Y4M_ILACE_NONE) { if (!(padded_input = (uint8_t *) malloc ((input_useful_width + width_neighbors) * (input_useful_height + height_neighbors)+2*ALIGNEMENT))) mjpeg_error_exit1 ("Could not allocate memory for padded_input table. STOP!"); } else { if (!(padded_top = (uint8_t *) malloc ((input_useful_width + width_neighbors) * (input_useful_height / 2 + height_neighbors)+2*ALIGNEMENT)) || !(padded_bottom = (uint8_t *) malloc ((input_useful_width + width_neighbors) * (input_useful_height / 2 + height_neighbors)+2*ALIGNEMENT))) mjpeg_error_exit1 ("Could not allocate memory for padded_top|bottom tables. STOP!"); } if (!(intermediate = (int32_t *) malloc(output_active_width*(input_useful_height + height_neighbors)*sizeof(int32_t)))) mjpeg_error_exit1 ("Could not allocate memory for intermediate. STOP!"); } // END OF BICUBIC BICUBIC BICUBIC // Pointers allocations if (!(input = malloc (((input_width * input_height * 3) / 2) + ALIGNEMENT)) || !(output = malloc (((output_width * output_height * 3) / 2) + ALIGNEMENT)) ) mjpeg_error_exit1 ("Could not allocate memory for input or output tables. STOP!"); // input and output pointers alignement mjpeg_debug ("before alignement: input=%p output=%p", input, output); if (((unsigned long) input % ALIGNEMENT) != 0) input = (uint8_t *) ((((unsigned long) input / ALIGNEMENT) + 1) * ALIGNEMENT); if (((unsigned long) output % ALIGNEMENT) != 0) output = (uint8_t *) ((((unsigned long) output / ALIGNEMENT) + 1) * ALIGNEMENT); mjpeg_debug ("after alignement: input=%p output=%p", input, output); // if skip_col==1 if (!(frame_y_p = (uint8_t **) malloc (display_height * sizeof (uint8_t *))) || !(frame_u_p = (uint8_t **) malloc (display_height / 2 * sizeof (uint8_t *))) || !(frame_v_p = (uint8_t **) malloc (display_height / 2 * sizeof (uint8_t *)))) mjpeg_error_exit1 ("Could not allocate memory for frame_y_p, frame_u_p or frame_v_p tables. STOP!"); // Incorporate blacks lines and columns directly into output matrix since this will never change. // BLACK pixel in YUV = (16,128,128) if (black == 1) { u_c_p = output; // Y component for (i = 0; i < output_black_line_above * output_width; i++) *(u_c_p++) = blacky; if (black_col == 0) u_c_p += output_active_height * output_width; else { for (i = 0; i < output_active_height; i++) { for (j = 0; j < output_black_col_left; j++) *(u_c_p++) = blacky; u_c_p += output_active_width; for (j = 0; j < output_black_col_right; j++) *(u_c_p++) = blacky; } } for (i = 0; i < output_black_line_under * output_width; i++) *(u_c_p++) = blacky; // U component // u_c_p=output+output_width*output_height; for (i = 0; i < output_black_line_above / 2 * output_width / 2; i++) *(u_c_p++) = blackuv; if (black_col == 0) u_c_p += output_active_height / 2 * output_width / 2; else { for (i = 0; i < output_active_height / 2; i++) { for (j = 0; j < output_black_col_left / 2; j++) *(u_c_p++) = blackuv; u_c_p += output_active_width / 2; for (j = 0; j < output_black_col_right / 2; j++) *(u_c_p++) = blackuv; } } for (i = 0; i < output_black_line_under / 2 * output_width / 2; i++) *(u_c_p++) = blackuv; // V component // u_c_p=output+(output_width*output_height*5)/4; for (i = 0; i < output_black_line_above / 2 * output_width / 2; i++) *(u_c_p++) = blackuv; if (black_col == 0) u_c_p += output_active_height / 2 * output_width / 2; else { for (i = 0; i < output_active_height / 2; i++) { for (j = 0; j < output_black_col_left / 2; j++) *(u_c_p++) = blackuv; u_c_p += output_active_width / 2; for (j = 0; j < output_black_col_right / 2; j++) *(u_c_p++) = blackuv; } } for (i = 0; i < output_black_line_under / 2 * output_width / 2; i++) *(u_c_p++) = blackuv; } // MONOCHROME FRAMES if (mono == 1) { // the U and V components of output frame will always be 128 u_c_p = output + output_width * output_height; for (i = 0; i < 2 * output_width / 2 * output_height / 2; i++) *(u_c_p++) = blackuv; } // Various initialisatiosn for variables concerning input and output out_nb_col_slice = output_active_width / output_width_slice; out_nb_line_slice = output_active_height / output_height_slice; input_y = input + input_discard_line_above * input_width + input_discard_col_left; input_u = input + input_width * input_height + input_discard_line_above / 2 * input_width / 2 + input_discard_col_left / 2; input_v = input + (input_height * input_width * 5) / 4 + input_discard_line_above / 2 * input_width / 2 + input_discard_col_left / 2; output_y = output + output_black_line_above * output_width + output_black_col_left; output_u = output + output_width * output_
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -