void y4munsharp(void) { int i, row, col, diff, value; u_char *i_ptr, *o_ptr; mjpeg_debug("Blurring Luma rows frame %d", frameno); for (row = 0; row < yheight; row++) { blur_line(ctable_y, cmatrix_y, cmatrix_y_len, &i_yuv[0][row * ywidth], &o_yuv[0][row * ywidth], ywidth); } if (uv_radius != -1.0) { mjpeg_debug("Blurring Chroma rows frame %d", frameno); for (row = 0; row < uvheight; row++) { blur_line(ctable_uv, cmatrix_uv, cmatrix_uv_len, &i_yuv[1][row * uvwidth], &o_yuv[1][row * uvwidth], uvwidth); blur_line(ctable_uv, cmatrix_uv, cmatrix_uv_len, &i_yuv[2][row * uvwidth], &o_yuv[2][row * uvwidth], uvwidth); } } else { memcpy(o_yuv[1], i_yuv[1], uvlen); memcpy(o_yuv[2], i_yuv[2], uvlen); } mjpeg_debug("Blurring Luma columns frame %d", frameno); for (col = 0; col < ywidth; col++) { /* * Do the entire frame if progressive, otherwise this does the only * the first field. */ get_column(&o_yuv[0][col], cur_col, interlaced ? 2 * ywidth : ywidth, interlaced ? yheight / 2 : yheight); blur_line(ctable_y, cmatrix_y, cmatrix_y_len, cur_col, dest_col, interlaced ? yheight / 2 : yheight); put_column(dest_col, &o_yuv[0][col], interlaced ? 2 * ywidth : ywidth, interlaced ? yheight / 2 : yheight); /* * If interlaced now process the second field (data source is offset * by 'ywidth'). */ if (interlaced) { get_column(&o_yuv[0][col + ywidth], cur_col, 2 * ywidth, yheight / 2); blur_line(ctable_y, cmatrix_y, cmatrix_y_len, cur_col, dest_col, interlaced ? yheight / 2 : yheight); put_column(dest_col, &o_yuv[0][col + ywidth], 2 * ywidth, yheight / 2); } } if (uv_radius == -1) goto merging; mjpeg_debug("Blurring chroma columns frame %d", frameno); for (col = 0; col < uvwidth; col++) { /* U */ get_column(&o_yuv[1][col], cur_col, interlaced ? 2 * uvwidth : uvwidth, interlaced ? uvheight / 2 : uvheight); blur_line(ctable_uv, cmatrix_uv, cmatrix_uv_len, cur_col, dest_col, interlaced ? uvheight / 2 : uvheight); put_column(dest_col, &o_yuv[1][col], interlaced ? 2 * uvwidth : uvwidth, interlaced ? uvheight / 2 : uvheight); if (interlaced) { get_column(&o_yuv[1][col + uvwidth], cur_col, 2 * uvwidth, uvheight / 2); blur_line(ctable_uv, cmatrix_uv, cmatrix_uv_len, cur_col, dest_col, interlaced ? uvheight / 2 : uvheight); put_column(dest_col, &o_yuv[1][col + uvwidth], 2 * uvwidth, uvheight / 2); } /* V */ get_column(&o_yuv[2][col], cur_col, interlaced ? 2 * uvwidth : uvwidth, interlaced ? uvheight / 2 : uvheight); blur_line(ctable_uv, cmatrix_uv, cmatrix_uv_len, cur_col, dest_col, interlaced ? uvheight / 2 : uvheight); put_column(dest_col, &o_yuv[2][col], interlaced ? 2 * uvwidth : uvwidth, interlaced ? uvheight / 2 : uvheight); if (interlaced) { get_column(&o_yuv[2][col + uvwidth], cur_col, 2 * uvwidth, uvheight / 2); blur_line(ctable_uv, cmatrix_uv, cmatrix_uv_len, cur_col, dest_col, interlaced ? uvheight / 2 : uvheight); put_column(dest_col, &o_yuv[2][col + uvwidth], 2 * uvwidth, uvheight / 2); } } merging: mjpeg_debug("Merging luma frame %d", frameno); for (row = 0, i_ptr = i_yuv[0], o_ptr = o_yuv[0]; row < yheight; row++) { for (i = 0; i < ywidth; i++, i_ptr++, o_ptr++) { diff = *i_ptr - *o_ptr; if (abs(2 * diff) < y_threshold) diff = 0; value = *i_ptr + (y_amount * diff); /* * For video the limits are 16 and 235 for the luma rather than 0 and 255! */ if (value < lowy) value = lowy; else if (value > highy) value = highy; *o_ptr = value; } } if (uv_radius == -1.0) goto done; mjpeg_debug("Merging chroma frame %d", frameno); for (row = 0, i_ptr = i_yuv[1], o_ptr = o_yuv[1]; row < uvheight; row++) { for (i = 0; i < uvwidth; i++, i_ptr++, o_ptr++) { diff = *i_ptr - *o_ptr; if (abs(2 * diff) < uv_threshold) diff = 0; value = *i_ptr + (uv_amount * diff); /* * For video the limits are 16 and 240 for the chroma rather than 0 and 255! */ if (value < lowuv) value = lowuv; else if (value > highuv) value = highuv; *o_ptr = value; } } for (row = 0, i_ptr = i_yuv[2], o_ptr = o_yuv[2]; row < uvheight; row++) { for (i = 0; i < uvwidth; i++, i_ptr++, o_ptr++) { diff = *i_ptr - *o_ptr; if (abs(2 * diff) < uv_threshold) diff = 0; value = *i_ptr + (uv_amount * diff); /* * For video the limits are 16 and 240 for the chroma rather than 0 and 255! */ if (value < 16) value = 16; else if (value > highuv) value = highuv; *o_ptr = value; } } done: return; }
void UnsharpUnit::process_package(LoadPackage *package) { UnsharpPackage *pkg = (UnsharpPackage*)package; // int w = server->src->get_w(); // int h = server->src->get_h(); int color_model = server->src->get_color_model(); int components = BC_CModels::components(color_model); double *cmatrix = 0; int cmatrix_length = 0; int padded_y1 = pkg->y1; int padded_y2 = pkg->y2; cmatrix_length = calculate_convolution_matrix( plugin->config.radius, &cmatrix); if(padded_y2 < server->src->get_h()) { padded_y2 += cmatrix_length / 2; padded_y2 = MIN(server->src->get_h(), padded_y2); } if(padded_y1 > 0) { padded_y1 -= cmatrix_length / 2; padded_y1 = MAX(0, padded_y1); } int padded_rows = padded_y2 - padded_y1; if(!temp || temp->get_h() != padded_rows) { delete temp; temp = 0; } if(!temp) { temp = new VFrame; temp->set_use_shm(0); temp->reallocate(0, -1, 0, 0, 0, server->src->get_w(), padded_rows, components == 3 ? BC_RGB_FLOAT : BC_RGBA_FLOAT, -1); } float *temp_in = new float[MAX(temp->get_w(), padded_rows) * components]; float *temp_out = new float[MAX(temp->get_w(), padded_rows) * components]; // Blur rows for(int i = padded_y1; i < padded_y2; i++) { get_row(temp_in, server->src, i); blur_pixels(cmatrix, cmatrix_length, temp_in, temp_out, temp->get_w(), components); // printf("UnsharpUnit::process_package %d %p %p %p %d %d\n", // __LINE__, // temp, // temp->get_rows()[0], // temp_out, // i - padded_y1, // temp->get_bytes_per_line()); memcpy(temp->get_rows()[i - padded_y1], temp_out, temp->get_bytes_per_line()); } //Now we're 100% floating point. Blur the columns for(int i = 0; i < temp->get_w(); i++) { get_column(temp_in, temp, i); blur_pixels(cmatrix, cmatrix_length, temp_in, temp_out, padded_rows, components); put_column(temp_out, temp, i); } //printf("%f %f %d\n", plugin->config.radius,plugin->config.amount, plugin->config.threshold); #define UNSHARPEN(type, components, max) \ { \ float threshold = (float)plugin->config.threshold * max / 0xff; \ float amount = plugin->config.amount; \ \ for(int i = pkg->y1; i < pkg->y2; i++) \ { \ float *blurry_row = (float*)temp->get_rows()[i - padded_y1]; \ type *orig_row = (type*)server->src->get_rows()[i]; \ for(int j = 0; j < server->src->get_w(); j++) \ { \ for(int k = 0; k < components; k++) \ { \ float diff = *orig_row - *blurry_row; \ if(fabsf(2 * diff) < threshold) \ diff = 0; \ float value = *orig_row + amount * diff; \ if(sizeof(type) == 4) \ *orig_row = (type)value; \ else \ *orig_row = (type)CLIP(value, 0, max); \ blurry_row++; \ orig_row++; \ } \ } \ } \ } // Apply unsharpening switch(color_model) { case BC_RGB888: case BC_YUV888: UNSHARPEN(unsigned char, 3, 0xff); break; case BC_RGBA8888: case BC_YUVA8888: UNSHARPEN(unsigned char, 4, 0xff); break; case BC_RGB_FLOAT: UNSHARPEN(float, 3, 1.0); break; case BC_RGBA_FLOAT: UNSHARPEN(float, 4, 1.0); break; case BC_YUV161616: UNSHARPEN(uint16_t, 3, 0xffff); break; case BC_YUVA16161616: UNSHARPEN(uint16_t, 4, 0xffff); break; } delete [] temp_in; delete [] temp_out; delete [] cmatrix; }