/***************************************************************************** * PostprocPict *****************************************************************************/ static picture_t *PostprocPict( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; const uint8_t *src[3]; uint8_t *dst[3]; int i_plane; int i_src_stride[3], i_dst_stride[3]; picture_t *p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } /* Lock to prevent issues if pp_mode is changed */ vlc_mutex_lock( &p_sys->lock ); if( !p_sys->pp_mode ) { vlc_mutex_unlock( &p_sys->lock ); picture_CopyPixels( p_outpic, p_pic ); return CopyInfoAndRelease( p_outpic, p_pic ); } for( i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) { src[i_plane] = p_pic->p[i_plane].p_pixels; dst[i_plane] = p_outpic->p[i_plane].p_pixels; /* I'm not sure what happens if i_pitch != i_visible_pitch ... * at least it shouldn't crash. */ i_src_stride[i_plane] = p_pic->p[i_plane].i_pitch; i_dst_stride[i_plane] = p_outpic->p[i_plane].i_pitch; } if( !p_pic->p_q && p_sys->b_had_matrix ) { msg_Warn( p_filter, "Quantification table was not set by video decoder. Postprocessing won't look good." ); p_sys->b_had_matrix = false; } else if( p_pic->p_q ) { p_sys->b_had_matrix = true; } pp_postprocess( src, i_src_stride, dst, i_dst_stride, p_filter->fmt_in.video.i_width, p_filter->fmt_in.video.i_height, p_pic->p_q, p_pic->i_qstride, p_sys->pp_mode, p_sys->pp_context, p_pic->i_qtype == QTYPE_MPEG2 ? PP_PICT_TYPE_QP2 : 0 ); vlc_mutex_unlock( &p_sys->lock ); return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Filter *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t * p_outpic; filter_sys_t *p_sys = p_filter->p_sys; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } if( p_sys->b_first ) { picture_CopyPixels( p_sys->p_tmp, p_pic ); p_sys->b_first = false; } /* Get a new picture */ RenderBlur( p_sys, p_pic, p_outpic ); picture_CopyPixels( p_sys->p_tmp, p_outpic ); return CopyInfoAndRelease( p_outpic, p_pic ); }
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; const int v1 = -1; const int v2 = 3; /* 2^3 = 8 */ const unsigned i_visible_lines = p_pic->p[Y_PLANE].i_visible_lines; const unsigned i_visible_pitch = p_pic->p[Y_PLANE].i_visible_pitch; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } if (!IS_YUV_420_10BITS(p_pic->format.i_chroma)) SHARPEN_FRAME(255, uint8_t); else SHARPEN_FRAME(1023, uint16_t); plane_CopyPixels( &p_outpic->p[U_PLANE], &p_pic->p[U_PLANE] ); plane_CopyPixels( &p_outpic->p[V_PLANE], &p_pic->p[V_PLANE] ); return CopyInfoAndRelease( p_outpic, p_pic ); }
static picture_t *Filter(filter_t *p_filter, picture_t *p_pic) { filter_sys_t *p_sys = p_filter->p_sys; if (!p_pic) return NULL; picture_t *p_outpic = filter_NewPicture(p_filter); if (!p_outpic) { picture_Release(p_pic); return NULL; } switch (p_pic->format.i_chroma) { case VLC_CODEC_I420: case VLC_CODEC_J420: case VLC_CODEC_YV12: combine_side_by_side_yuv420(p_pic, p_outpic, p_sys->left, p_sys->right); break; default: msg_Warn(p_filter, "Unsupported input chroma (%4.4s)", (char*)&(p_pic->format.i_chroma)); picture_Release(p_pic); return NULL; } return CopyInfoAndRelease(p_outpic, p_pic); }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to adjust modified image, * waits until it is displayed and switch the two rendering buffers, preparing * next frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; filter_sys_t *p_sys = p_filter->p_sys; vlc_mutex_lock( &p_sys->lock ); int i_simthres = p_sys->i_simthres; int i_satthres = p_sys->i_satthres; int i_color = p_sys->i_color; vlc_mutex_unlock( &p_sys->lock ); if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } /* Copy the Y plane */ plane_CopyPixels( &p_outpic->p[Y_PLANE], &p_pic->p[Y_PLANE] ); /* * Do the U and V planes */ int refu, refv, reflength; GetReference( &refu, &refv, &reflength, i_color ); for( int y = 0; y < p_pic->p[U_PLANE].i_visible_lines; y++ ) { uint8_t *p_src_u = &p_pic->p[U_PLANE].p_pixels[y * p_pic->p[U_PLANE].i_pitch]; uint8_t *p_src_v = &p_pic->p[V_PLANE].p_pixels[y * p_pic->p[V_PLANE].i_pitch]; uint8_t *p_dst_u = &p_outpic->p[U_PLANE].p_pixels[y * p_outpic->p[U_PLANE].i_pitch]; uint8_t *p_dst_v = &p_outpic->p[V_PLANE].p_pixels[y * p_outpic->p[V_PLANE].i_pitch]; for( int x = 0; x < p_pic->p[U_PLANE].i_visible_pitch; x++ ) { if( IsSimilar( *p_src_u - 0x80, *p_src_v - 0x80, refu, refv, reflength, i_satthres, i_simthres ) ) { *p_dst_u++ = *p_src_u; *p_dst_v++ = *p_src_v; } else { *p_dst_u++ = 0x80; *p_dst_v++ = 0x80; } p_src_u++; p_src_v++; } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Filter: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to the internal opencv * filter for processing. *****************************************************************************/ static picture_t* Filter( filter_t* p_filter, picture_t* p_pic ) { picture_t* p_outpic = filter_NewPicture( p_filter ); if( p_outpic == NULL ) { msg_Err( p_filter, "couldn't get a p_outpic!" ); picture_Release( p_pic ); return NULL; } video_format_t fmt_out; // Make a copy if we want to show the original input if (p_filter->p_sys->i_wrapper_output == VINPUT) picture_Copy( p_outpic, p_pic ); VlcPictureToIplImage( p_filter, p_pic ); // Pass the image (as a pointer to the first IplImage*) to the // internal OpenCV filter for processing. p_filter->p_sys->p_opencv->pf_video_filter( p_filter->p_sys->p_opencv, (picture_t*)&(p_filter->p_sys->p_cv_image[0]) ); if(p_filter->p_sys->i_wrapper_output == PROCESSED) { // Processed video if( (p_filter->p_sys->p_proc_image) && (p_filter->p_sys->p_proc_image->i_planes > 0) && (p_filter->p_sys->i_internal_chroma != CINPUT) ) { //p_filter->p_sys->p_proc_image->format.i_chroma = VLC_CODEC_RGB24; memset( &fmt_out, 0, sizeof(video_format_t) ); fmt_out = p_pic->format; //picture_Release( p_outpic ); /* * We have to copy out the image from image_Convert(), otherwise * you leak pictures for some reason: * main video output error: pictures leaked, trying to workaround */ picture_t* p_outpic_tmp = image_Convert( p_filter->p_sys->p_image, p_filter->p_sys->p_proc_image, &(p_filter->p_sys->p_proc_image->format), &fmt_out ); picture_CopyPixels( p_outpic, p_outpic_tmp ); CopyInfoAndRelease( p_outpic, p_outpic_tmp ); } else if( p_filter->p_sys->i_internal_chroma == CINPUT ) { picture_CopyPixels( p_outpic, p_filter->p_sys->p_proc_image ); picture_CopyProperties( p_outpic, p_filter->p_sys->p_proc_image ); } } ReleaseImages( p_filter ); picture_Release( p_pic ); #ifndef NDEBUG msg_Dbg( p_filter, "Filter() done" ); #endif if( p_filter->p_sys->i_wrapper_output != NONE ) { return p_outpic; } else { // NONE picture_Release( p_outpic ); return NULL; } }
static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; filter_sys_t *p_sys = p_filter->p_sys; const int i_dim = p_sys->i_dim; type_t *pt_buffer; type_t *pt_scale; const type_t *pt_distribution = p_sys->pt_distribution; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } if( !p_sys->pt_buffer ) { p_sys->pt_buffer = realloc_or_free( p_sys->pt_buffer, p_pic->p[Y_PLANE].i_visible_lines * p_pic->p[Y_PLANE].i_pitch * sizeof( type_t ) ); } pt_buffer = p_sys->pt_buffer; if( !p_sys->pt_scale ) { const int i_visible_lines = p_pic->p[Y_PLANE].i_visible_lines; const int i_visible_pitch = p_pic->p[Y_PLANE].i_visible_pitch; const int i_pitch = p_pic->p[Y_PLANE].i_pitch; p_sys->pt_scale = xmalloc( i_visible_lines * i_pitch * sizeof( type_t ) ); pt_scale = p_sys->pt_scale; for( int i_line = 0; i_line < i_visible_lines; i_line++ ) { for( int i_col = 0; i_col < i_visible_pitch; i_col++ ) { type_t t_value = 0; for( int y = __MAX( -i_dim, -i_line ); y <= __MIN( i_dim, i_visible_lines - i_line - 1 ); y++ ) { for( int x = __MAX( -i_dim, -i_col ); x <= __MIN( i_dim, i_visible_pitch - i_col + 1 ); x++ ) { t_value += pt_distribution[y+i_dim] * pt_distribution[x+i_dim]; } } pt_scale[i_line*i_pitch+i_col] = t_value; } } } pt_scale = p_sys->pt_scale; for( int i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) { uint8_t *p_in = p_pic->p[i_plane].p_pixels; uint8_t *p_out = p_outpic->p[i_plane].p_pixels; const int i_visible_lines = p_pic->p[i_plane].i_visible_lines; const int i_visible_pitch = p_pic->p[i_plane].i_visible_pitch; const int i_in_pitch = p_pic->p[i_plane].i_pitch; const int x_factor = p_pic->p[Y_PLANE].i_visible_pitch/i_visible_pitch-1; const int y_factor = p_pic->p[Y_PLANE].i_visible_lines/i_visible_lines-1; for( int i_line = 0; i_line < i_visible_lines; i_line++ ) { for( int i_col = 0; i_col < i_visible_pitch; i_col++ ) { type_t t_value = 0; const int c = i_line*i_in_pitch+i_col; for( int x = __MAX( -i_dim, -i_col*(x_factor+1) ); x <= __MIN( i_dim, (i_visible_pitch - i_col)*(x_factor+1) + 1 ); x++ ) { t_value += pt_distribution[x+i_dim] * p_in[c+(x>>x_factor)]; } pt_buffer[c] = t_value; } } for( int i_line = 0; i_line < i_visible_lines; i_line++ ) { for( int i_col = 0; i_col < i_visible_pitch; i_col++ ) { type_t t_value = 0; const int c = i_line*i_in_pitch+i_col; for( int y = __MAX( -i_dim, (-i_line)*(y_factor+1) ); y <= __MIN( i_dim, (i_visible_lines - i_line)*(y_factor+1) - 1 ); y++ ) { t_value += pt_distribution[y+i_dim] * pt_buffer[c+(y>>y_factor)*i_in_pitch]; } const type_t t_scale = pt_scale[(i_line<<y_factor)*(i_in_pitch<<x_factor)+(i_col<<x_factor)]; p_out[i_line * p_outpic->p[i_plane].i_pitch + i_col] = (uint8_t)(t_value / t_scale); // FIXME wouldn't it be better to round instead of trunc ? } } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/**************************************************************************** * Filter: the whole thing ****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_outpic; int i_width, i_height, i_xcrop, i_ycrop, i_outwidth, i_outheight, i_xpadd, i_ypadd; const int p_padd_color[] = { 0x00, 0x80, 0x80, 0xff }; if( !p_pic ) return NULL; /* Request output picture */ p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } for( int i_plane = 0; i_plane < p_pic->i_planes; i_plane++ ) /* p_pic and p_outpic have the same chroma/number of planes but that's * about it. */ { plane_t *p_plane = p_pic->p+i_plane; plane_t *p_outplane = p_outpic->p+i_plane; uint8_t *p_in = p_plane->p_pixels; uint8_t *p_out = p_outplane->p_pixels; int i_pixel_pitch = p_plane->i_pixel_pitch; int i_padd_color = i_plane > 3 ? p_padd_color[0] : p_padd_color[i_plane]; /* These assignments assume that the first plane always has * a width and height equal to the picture's */ i_width = ( ( p_filter->fmt_in.video.i_visible_width - p_sys->i_cropleft - p_sys->i_cropright ) * p_plane->i_visible_pitch ) / p_pic->p->i_visible_pitch; i_height = ( ( p_filter->fmt_in.video.i_visible_height - p_sys->i_croptop - p_sys->i_cropbottom ) * p_plane->i_visible_lines ) / p_pic->p->i_visible_lines; i_xcrop = ( p_sys->i_cropleft * p_plane->i_visible_pitch) / p_pic->p->i_visible_pitch; i_ycrop = ( p_sys->i_croptop * p_plane->i_visible_lines) / p_pic->p->i_visible_lines; i_outwidth = ( p_filter->fmt_out.video.i_visible_width * p_outplane->i_visible_pitch ) / p_outpic->p->i_visible_pitch; i_outheight = ( p_filter->fmt_out.video.i_visible_height * p_outplane->i_visible_lines ) / p_outpic->p->i_visible_lines; i_xpadd = ( p_sys->i_paddleft * p_outplane->i_visible_pitch ) / p_outpic->p->i_visible_pitch; i_ypadd = ( p_sys->i_paddtop * p_outplane->i_visible_lines ) / p_outpic->p->i_visible_lines; /* Crop the top */ p_in += i_ycrop * p_plane->i_pitch; /* Padd on the top */ memset( p_out, i_padd_color, i_ypadd * p_outplane->i_pitch ); p_out += i_ypadd * p_outplane->i_pitch; for( int i_line = 0; i_line < i_height; i_line++ ) { uint8_t *p_in_next = p_in + p_plane->i_pitch; uint8_t *p_out_next = p_out + p_outplane->i_pitch; /* Crop on the left */ p_in += i_xcrop * i_pixel_pitch; /* Padd on the left */ memset( p_out, i_padd_color, i_xpadd * i_pixel_pitch ); p_out += i_xpadd * i_pixel_pitch; /* Copy the image and crop on the right */ memcpy( p_out, p_in, i_width * i_pixel_pitch ); p_out += i_width * i_pixel_pitch; p_in += i_width * i_pixel_pitch; /* Padd on the right */ memset( p_out, i_padd_color, ( i_outwidth - i_xpadd - i_width ) * i_pixel_pitch ); /* Got to begining of the next line */ p_in = p_in_next; p_out = p_out_next; } /* Padd on the bottom */ memset( p_out, i_padd_color, ( i_outheight - i_ypadd - i_height ) * p_outplane->i_pitch ); } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Run the filter on a Packed YUV picture *****************************************************************************/ static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic ) { int pi_luma[256]; int pi_gamma[256]; picture_t *p_outpic; uint8_t *p_in, *p_in_end, *p_line_end; uint8_t *p_out; int i_y_offset, i_u_offset, i_v_offset; int i_pitch, i_visible_pitch; bool b_thres; double f_hue; double f_gamma; int32_t i_cont, i_lum; int i_sat, i_sin, i_cos, i_x, i_y; int i; filter_sys_t *p_sys = p_filter->p_sys; if( !p_pic ) return NULL; i_pitch = p_pic->p->i_pitch; i_visible_pitch = p_pic->p->i_visible_pitch; if( GetPackedYuvOffsets( p_pic->format.i_chroma, &i_y_offset, &i_u_offset, &i_v_offset ) != VLC_SUCCESS ) { msg_Warn( p_filter, "Unsupported input chroma (%4.4s)", (char*)&(p_pic->format.i_chroma) ); picture_Release( p_pic ); return NULL; } p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { msg_Warn( p_filter, "can't get output picture" ); picture_Release( p_pic ); return NULL; } /* Get variables */ vlc_mutex_lock( &p_sys->lock ); i_cont = (int)( p_sys->f_contrast * 255 ); i_lum = (int)( (p_sys->f_brightness - 1.0)*255 ); f_hue = (float)( p_sys->i_hue * M_PI / 180 ); i_sat = (int)( p_sys->f_saturation * 256 ); f_gamma = 1.0 / p_sys->f_gamma; b_thres = p_sys->b_brightness_threshold; vlc_mutex_unlock( &p_sys->lock ); /* * Threshold mode drops out everything about luma, contrast and gamma. */ if( !b_thres ) { /* Contrast is a fast but kludged function, so I put this gap to be * cleaner :) */ i_lum += 128 - i_cont / 2; /* Fill the gamma lookup table */ for( i = 0 ; i < 256 ; i++ ) { pi_gamma[ i ] = clip_uint8_vlc( pow(i / 255.0, f_gamma) * 255.0); } /* Fill the luma lookup table */ for( i = 0 ; i < 256 ; i++ ) { pi_luma[ i ] = pi_gamma[clip_uint8_vlc( i_lum + i_cont * i / 256)]; } } else { /* * We get luma as threshold value: the higher it is, the darker is * the image. Should I reverse this? */ for( i = 0 ; i < 256 ; i++ ) { pi_luma[ i ] = (i < i_lum) ? 0 : 255; } /* * Desaturates image to avoid that strange yellow halo... */ i_sat = 0; } /* * Do the Y plane */ p_in = p_pic->p->p_pixels + i_y_offset; p_in_end = p_in + p_pic->p->i_visible_lines * p_pic->p->i_pitch - 8 * 4; p_out = p_outpic->p->p_pixels + i_y_offset; for( ; p_in < p_in_end ; ) { p_line_end = p_in + i_visible_pitch - 8 * 4; for( ; p_in < p_line_end ; ) { /* Do 8 pixels at a time */ *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; } p_line_end += 8 * 4; for( ; p_in < p_line_end ; ) { *p_out = pi_luma[ *p_in ]; p_in += 2; p_out += 2; } p_in += i_pitch - p_pic->p->i_visible_pitch; p_out += i_pitch - p_outpic->p->i_visible_pitch; } /* * Do the U and V planes */ i_sin = sin(f_hue) * 256; i_cos = cos(f_hue) * 256; i_x = ( cos(f_hue) + sin(f_hue) ) * 32768; i_y = ( cos(f_hue) - sin(f_hue) ) * 32768; if ( i_sat > 256 ) { if ( p_sys->pf_process_sat_hue_clip( p_pic, p_outpic, i_sin, i_cos, i_sat, i_x, i_y ) != VLC_SUCCESS ) { /* Currently only one error can happen in the function, but if there * will be more of them, this message must go away */ msg_Warn( p_filter, "Unsupported input chroma (%4.4s)", (char*)&(p_pic->format.i_chroma) ); picture_Release( p_pic ); return NULL; } } else { if ( p_sys->pf_process_sat_hue( p_pic, p_outpic, i_sin, i_cos, i_sat, i_x, i_y ) != VLC_SUCCESS ) { /* Currently only one error can happen in the function, but if there * will be more of them, this message must go away */ msg_Warn( p_filter, "Unsupported input chroma (%4.4s)", (char*)&(p_pic->format.i_chroma) ); picture_Release( p_pic ); return NULL; } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Run the filter on a Planar YUV picture *****************************************************************************/ static picture_t *FilterPlanar( filter_t *p_filter, picture_t *p_pic ) { int pi_luma[256]; int pi_gamma[256]; picture_t *p_outpic; uint8_t *p_in, *p_in_end, *p_line_end; uint8_t *p_out; bool b_thres; double f_hue; double f_gamma; int32_t i_cont, i_lum; int i_sat, i_sin, i_cos, i_x, i_y; int i; filter_sys_t *p_sys = p_filter->p_sys; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } /* Get variables */ vlc_mutex_lock( &p_sys->lock ); i_cont = (int)( p_sys->f_contrast * 255 ); i_lum = (int)( (p_sys->f_brightness - 1.0)*255 ); f_hue = (float)( p_sys->i_hue * M_PI / 180 ); i_sat = (int)( p_sys->f_saturation * 256 ); f_gamma = 1.0 / p_sys->f_gamma; b_thres = p_sys->b_brightness_threshold; vlc_mutex_unlock( &p_sys->lock ); /* * Threshold mode drops out everything about luma, contrast and gamma. */ if( !b_thres ) { /* Contrast is a fast but kludged function, so I put this gap to be * cleaner :) */ i_lum += 128 - i_cont / 2; /* Fill the gamma lookup table */ for( i = 0 ; i < 256 ; i++ ) { pi_gamma[ i ] = clip_uint8_vlc( pow(i / 255.0, f_gamma) * 255.0); } /* Fill the luma lookup table */ for( i = 0 ; i < 256 ; i++ ) { pi_luma[ i ] = pi_gamma[clip_uint8_vlc( i_lum + i_cont * i / 256)]; } } else { /* * We get luma as threshold value: the higher it is, the darker is * the image. Should I reverse this? */ for( i = 0 ; i < 256 ; i++ ) { pi_luma[ i ] = (i < i_lum) ? 0 : 255; } /* * Desaturates image to avoid that strange yellow halo... */ i_sat = 0; } /* * Do the Y plane */ p_in = p_pic->p[Y_PLANE].p_pixels; p_in_end = p_in + p_pic->p[Y_PLANE].i_visible_lines * p_pic->p[Y_PLANE].i_pitch - 8; p_out = p_outpic->p[Y_PLANE].p_pixels; for( ; p_in < p_in_end ; ) { p_line_end = p_in + p_pic->p[Y_PLANE].i_visible_pitch - 8; for( ; p_in < p_line_end ; ) { /* Do 8 pixels at a time */ *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ]; *p_out++ = pi_luma[ *p_in++ ]; } p_line_end += 8; for( ; p_in < p_line_end ; ) { *p_out++ = pi_luma[ *p_in++ ]; } p_in += p_pic->p[Y_PLANE].i_pitch - p_pic->p[Y_PLANE].i_visible_pitch; p_out += p_outpic->p[Y_PLANE].i_pitch - p_outpic->p[Y_PLANE].i_visible_pitch; } /* * Do the U and V planes */ i_sin = sin(f_hue) * 256; i_cos = cos(f_hue) * 256; i_x = ( cos(f_hue) + sin(f_hue) ) * 32768; i_y = ( cos(f_hue) - sin(f_hue) ) * 32768; if ( i_sat > 256 ) { /* Currently no errors are implemented in the function, if any are added * check them here */ p_sys->pf_process_sat_hue_clip( p_pic, p_outpic, i_sin, i_cos, i_sat, i_x, i_y ); } else { /* Currently no errors are implemented in the function, if any are added * check them here */ p_sys->pf_process_sat_hue( p_pic, p_outpic, i_sin, i_cos, i_sat, i_x, i_y ); } return CopyInfoAndRelease( p_outpic, p_pic ); }
static picture_t *FilterPacked( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; filter_sys_t *p_sys = p_filter->p_sys; int i_simthres = atomic_load( &p_sys->i_simthres ); int i_satthres = atomic_load( &p_sys->i_satthres ); int i_color = atomic_load( &p_sys->i_color ); if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } int i_y_offset, i_u_offset, i_v_offset; int i_ret = GetPackedYuvOffsets( p_filter->fmt_in.video.i_chroma, &i_y_offset, &i_u_offset, &i_v_offset ); if( i_ret == VLC_EGENERIC ) { picture_Release( p_pic ); return NULL; } /* * Copy Y and do the U and V planes */ int refu, refv, reflength; GetReference( &refu, &refv, &reflength, i_color ); for( int y = 0; y < p_pic->p->i_visible_lines; y++ ) { uint8_t *p_src = &p_pic->p->p_pixels[y * p_pic->p->i_pitch]; uint8_t *p_dst = &p_outpic->p->p_pixels[y * p_outpic->p->i_pitch]; for( int x = 0; x < p_pic->p->i_visible_pitch / 4; x++ ) { p_dst[i_y_offset + 0] = p_src[i_y_offset + 0]; p_dst[i_y_offset + 2] = p_src[i_y_offset + 2]; if( IsSimilar( p_src[i_u_offset] - 0x80, p_src[i_v_offset] - 0x80, refu, refv, reflength, i_satthres, i_simthres ) ) { p_dst[i_u_offset] = p_src[i_u_offset]; p_dst[i_v_offset] = p_src[i_v_offset]; } else { p_dst[i_u_offset] = 0x80; p_dst[i_v_offset] = 0x80; } p_dst += 4; p_src += 4; } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Distort image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; unsigned int w, h; int x,y; uint8_t u,v; picture_t *p_converted; video_format_t fmt_out; memset( &fmt_out, 0, sizeof(video_format_t) ); fmt_out.p_palette = NULL; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } if( !p_filter->p_sys->p_image ) p_filter->p_sys->p_image = image_HandlerCreate( p_filter ); /* chrominance */ u = p_filter->p_sys->u; v = p_filter->p_sys->v; for( y = 0; y<p_outpic->p[U_PLANE].i_lines; y++) { vlc_memset( p_outpic->p[U_PLANE].p_pixels+y*p_outpic->p[U_PLANE].i_pitch, u, p_outpic->p[U_PLANE].i_pitch ); vlc_memset( p_outpic->p[V_PLANE].p_pixels+y*p_outpic->p[V_PLANE].i_pitch, v, p_outpic->p[V_PLANE].i_pitch ); if( v == 0 && u != 0 ) u --; else if( u == 0xff ) v --; else if( v == 0xff ) u ++; else if( u == 0 ) v ++; } /* luminance */ vlc_memcpy( p_outpic->p[Y_PLANE].p_pixels, p_pic->p[Y_PLANE].p_pixels, p_outpic->p[Y_PLANE].i_lines * p_outpic->p[Y_PLANE].i_pitch ); /* image visualization */ fmt_out = p_filter->fmt_out.video; fmt_out.i_width = p_filter->fmt_out.video.i_width*p_filter->p_sys->scale/150; fmt_out.i_height = p_filter->fmt_out.video.i_height*p_filter->p_sys->scale/150; p_converted = image_Convert( p_filter->p_sys->p_image, p_pic, &(p_pic->format), &fmt_out ); if( p_converted ) { #define copyimage( plane, b ) \ for( y=0; y<p_converted->p[plane].i_visible_lines; y++) { \ for( x=0; x<p_converted->p[plane].i_visible_pitch; x++) { \ int nx, ny; \ if( p_filter->p_sys->yinc == 1 ) \ ny= y; \ else \ ny = p_converted->p[plane].i_visible_lines-y; \ if( p_filter->p_sys->xinc == 1 ) \ nx = x; \ else \ nx = p_converted->p[plane].i_visible_pitch-x; \ p_outpic->p[plane].p_pixels[(p_filter->p_sys->x*b+nx)+(ny+p_filter->p_sys->y*b)*p_outpic->p[plane].i_pitch ] = p_converted->p[plane].p_pixels[y*p_converted->p[plane].i_pitch+x]; \ } } copyimage( Y_PLANE, 2 ); copyimage( U_PLANE, 1 ); copyimage( V_PLANE, 1 ); #undef copyimage picture_Release( p_converted ); } else { msg_Err( p_filter, "Image scaling failed miserably." ); } p_filter->p_sys->x += p_filter->p_sys->xinc; p_filter->p_sys->y += p_filter->p_sys->yinc; p_filter->p_sys->scale += p_filter->p_sys->scaleinc; if( p_filter->p_sys->scale >= 50 ) p_filter->p_sys->scaleinc = -1; if( p_filter->p_sys->scale <= 1 ) p_filter->p_sys->scaleinc = 1; w = p_filter->fmt_out.video.i_width*p_filter->p_sys->scale/150; h = p_filter->fmt_out.video.i_height*p_filter->p_sys->scale/150; if( p_filter->p_sys->x*2 + w >= p_filter->fmt_out.video.i_width ) p_filter->p_sys->xinc = -1; if( p_filter->p_sys->x <= 0 ) p_filter->p_sys->xinc = 1; if( p_filter->p_sys->x*2 + w >= p_filter->fmt_out.video.i_width ) p_filter->p_sys->x = (p_filter->fmt_out.video.i_width-w)/2; if( p_filter->p_sys->y*2 + h >= p_filter->fmt_out.video.i_height ) p_filter->p_sys->y = (p_filter->fmt_out.video.i_height-h)/2; if( p_filter->p_sys->y*2 + h >= p_filter->fmt_out.video.i_height ) p_filter->p_sys->yinc = -1; if( p_filter->p_sys->y <= 0 ) p_filter->p_sys->yinc = 1; for( y = 0; y< 16; y++ ) { if( p_filter->p_sys->v == 0 && p_filter->p_sys->u != 0 ) p_filter->p_sys->u -= 1; else if( p_filter->p_sys->u == 0xff ) p_filter->p_sys->v -= 1; else if( p_filter->p_sys->v == 0xff ) p_filter->p_sys->u += 1; else if( p_filter->p_sys->u == 0 ) p_filter->p_sys->v += 1; } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Invert image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; int i_planes; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { msg_Warn( p_filter, "can't get output picture" ); picture_Release( p_pic ); return NULL; } if( p_pic->format.i_chroma == VLC_CODEC_YUVA ) { /* We don't want to invert the alpha plane */ i_planes = p_pic->i_planes - 1; memcpy( p_outpic->p[A_PLANE].p_pixels, p_pic->p[A_PLANE].p_pixels, p_pic->p[A_PLANE].i_pitch * p_pic->p[A_PLANE].i_lines ); } else { i_planes = p_pic->i_planes; } for( int i_index = 0 ; i_index < i_planes ; i_index++ ) { uint8_t *p_in, *p_in_end, *p_line_end, *p_out; p_in = p_pic->p[i_index].p_pixels; p_in_end = p_in + p_pic->p[i_index].i_visible_lines * p_pic->p[i_index].i_pitch; p_out = p_outpic->p[i_index].p_pixels; while( p_in < p_in_end ) { uint64_t *p_in64, *p_out64; p_line_end = p_in + p_pic->p[i_index].i_visible_pitch - 64; p_in64 = (uint64_t*)p_in; p_out64 = (uint64_t*)p_out; while( p_in64 < (uint64_t *)p_line_end ) { /* Do 64 pixels at a time */ *p_out64++ = ~*p_in64++; *p_out64++ = ~*p_in64++; *p_out64++ = ~*p_in64++; *p_out64++ = ~*p_in64++; *p_out64++ = ~*p_in64++; *p_out64++ = ~*p_in64++; *p_out64++ = ~*p_in64++; *p_out64++ = ~*p_in64++; } p_in = (uint8_t*)p_in64; p_out = (uint8_t*)p_out64; p_line_end += 64; while( p_in < p_line_end ) { *p_out++ = ~( *p_in++ ); } p_in += p_pic->p[i_index].i_pitch - p_pic->p[i_index].i_visible_pitch; p_out += p_outpic->p[i_index].i_pitch - p_outpic->p[i_index].i_visible_pitch; } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/** * Filter a picture */ picture_t *Filter( filter_t *p_filter, picture_t *p_pic_in ) { if( !p_pic_in || !p_filter) return NULL; const video_format_t *p_fmt_in = &p_filter->fmt_in.video; filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_pic_out = filter_NewPicture( p_filter ); if( !p_pic_out ) { picture_Release( p_pic_in ); return NULL; } int i_ret = 0; p_sys->b_bake_request = false; if ((p_sys->pi_order == NULL) || (p_sys->ps_desk_planes == NULL) || (p_sys->ps_pict_planes == NULL) || (p_sys->ps_puzzle_array == NULL) || (p_sys->ps_pieces == NULL)) p_sys->b_init = false; if ((p_sys->ps_pieces_shapes == NULL) && p_sys->s_current_param.b_advanced && (p_sys->s_current_param.i_shape_size != 0)) p_sys->b_init = false; /* assert initialized & allocated data match with current frame characteristics */ if ( p_sys->s_allocated.i_planes != p_pic_out->i_planes) p_sys->b_init = false; p_sys->s_current_param.i_planes = p_pic_out->i_planes; if (p_sys->ps_pict_planes != NULL) { for (uint8_t i_plane = 0; i_plane < p_sys->s_allocated.i_planes; i_plane++) { if ( (p_sys->ps_pict_planes[i_plane].i_lines != p_pic_in->p[i_plane].i_visible_lines) || (p_sys->ps_pict_planes[i_plane].i_width != p_pic_in->p[i_plane].i_visible_pitch / p_pic_in->p[i_plane].i_pixel_pitch) || (p_sys->ps_desk_planes[i_plane].i_lines != p_pic_out->p[i_plane].i_visible_lines) || (p_sys->ps_desk_planes[i_plane].i_width != p_pic_out->p[i_plane].i_visible_pitch / p_pic_out->p[i_plane].i_pixel_pitch) ) p_sys->b_init = false; } } p_sys->s_current_param.i_pict_width = (int) p_pic_in->p[0].i_visible_pitch / p_pic_in->p[0].i_pixel_pitch; p_sys->s_current_param.i_pict_height = (int) p_pic_in->p[0].i_visible_lines; p_sys->s_current_param.i_desk_width = (int) p_pic_out->p[0].i_visible_pitch / p_pic_out->p[0].i_pixel_pitch; p_sys->s_current_param.i_desk_height = (int) p_pic_out->p[0].i_visible_lines; /* assert no mismatch between sizes */ if ( p_sys->s_current_param.i_pict_width != p_sys->s_current_param.i_desk_width || p_sys->s_current_param.i_pict_height != p_sys->s_current_param.i_desk_height || p_sys->s_current_param.i_pict_width != (int) p_fmt_in->i_visible_width || p_sys->s_current_param.i_pict_height != (int) p_fmt_in->i_visible_height ) { picture_Release(p_pic_in); picture_Release(p_pic_out); return NULL; } vlc_mutex_lock( &p_sys->lock ); /* check if we have to compute initial data */ if ( p_sys->b_change_param || p_sys->b_bake_request || !p_sys->b_init ) { if ( p_sys->s_allocated.i_rows != p_sys->s_new_param.i_rows || p_sys->s_allocated.i_cols != p_sys->s_new_param.i_cols || p_sys->s_allocated.i_rotate != p_sys->s_new_param.i_rotate || p_sys->s_allocated.i_mode != p_sys->s_new_param.i_mode || p_sys->b_bake_request || !p_sys->b_init ) { p_sys->b_bake_request = true; p_sys->b_init = false; p_sys->b_shuffle_rqst = true; p_sys->b_shape_init = false; } if ( p_sys->s_current_param.i_border != p_sys->s_new_param.i_border || p_sys->s_current_param.i_shape_size != p_sys->s_new_param.i_shape_size ) { p_sys->b_bake_request = true; p_sys->b_shape_init = false; } /* depending on the game selected, set associated internal flags */ switch ( p_sys->s_new_param.i_mode ) { case 0: /* jigsaw puzzle */ p_sys->s_new_param.b_advanced = true; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = false; break; case 1: /* sliding puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = true; p_sys->s_new_param.b_near = true; break; case 2: /* swap puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = true; break; case 3: /* exchange puzzle */ p_sys->s_new_param.b_advanced = false; p_sys->s_new_param.b_blackslot = false; p_sys->s_new_param.b_near = false; break; } p_sys->s_current_param.i_mode = p_sys->s_new_param.i_mode; if ( p_sys->s_current_param.b_blackslot != p_sys->s_new_param.b_blackslot && p_sys->i_selected == NO_PCE && p_sys->s_current_param.b_blackslot ) p_sys->i_selected = 0; if ( p_sys->s_current_param.i_auto_shuffle_speed != p_sys->s_new_param.i_auto_shuffle_speed ) p_sys->i_auto_shuffle_countdown_val = init_countdown(p_sys->s_new_param.i_auto_shuffle_speed); if ( p_sys->s_current_param.i_auto_solve_speed != p_sys->s_new_param.i_auto_solve_speed ) p_sys->i_auto_solve_countdown_val = init_countdown(p_sys->s_current_param.i_auto_solve_speed); p_sys->s_current_param.i_rows = p_sys->s_new_param.i_rows; p_sys->s_current_param.i_cols = p_sys->s_new_param.i_cols; p_sys->s_current_param.i_pieces_nbr = p_sys->s_current_param.i_rows * p_sys->s_current_param.i_cols; p_sys->s_current_param.b_advanced = p_sys->s_new_param.b_advanced; if (!p_sys->s_new_param.b_advanced) { p_sys->s_current_param.b_blackslot = p_sys->s_new_param.b_blackslot; p_sys->s_current_param.b_near = p_sys->s_new_param.b_near || p_sys->s_new_param.b_blackslot; p_sys->s_current_param.i_border = 0; p_sys->s_current_param.b_preview = false; p_sys->s_current_param.i_preview_size= 0; p_sys->s_current_param.i_shape_size = 0; p_sys->s_current_param.i_auto_shuffle_speed = 0; p_sys->s_current_param.i_auto_solve_speed = 0; p_sys->s_current_param.i_rotate = 0; } else { p_sys->s_current_param.b_blackslot = false; p_sys->s_current_param.b_near = false; p_sys->s_current_param.i_border = p_sys->s_new_param.i_border; p_sys->s_current_param.b_preview = p_sys->s_new_param.b_preview; p_sys->s_current_param.i_preview_size = p_sys->s_new_param.i_preview_size; p_sys->s_current_param.i_shape_size = p_sys->s_new_param.i_shape_size; p_sys->s_current_param.i_auto_shuffle_speed = p_sys->s_new_param.i_auto_shuffle_speed; p_sys->s_current_param.i_auto_solve_speed = p_sys->s_new_param.i_auto_solve_speed; p_sys->s_current_param.i_rotate = p_sys->s_new_param.i_rotate; } p_sys->b_change_param = false; } vlc_mutex_unlock( &p_sys->lock ); /* generate initial puzzle data when needed */ if ( p_sys->b_bake_request ) { if (!p_sys->b_shuffle_rqst) { /* here we have to keep the same position * we have to save locations before generating new data */ save_game_t *ps_save_game = puzzle_save(p_filter); if (!ps_save_game) return CopyInfoAndRelease( p_pic_out, p_pic_in ); i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in ); if ( i_ret != VLC_SUCCESS ) { free(ps_save_game->ps_pieces); free(ps_save_game); return CopyInfoAndRelease( p_pic_out, p_pic_in ); } puzzle_load( p_filter, ps_save_game); free(ps_save_game->ps_pieces); free(ps_save_game); } else { i_ret = puzzle_bake( p_filter, p_pic_out, p_pic_in ); if ( i_ret != VLC_SUCCESS ) return CopyInfoAndRelease( p_pic_out, p_pic_in ); } } /* shuffle the desk and generate pieces data */ if ( p_sys->b_shuffle_rqst && p_sys->b_init ) { i_ret = puzzle_bake_piece ( p_filter ); if (i_ret != VLC_SUCCESS) return CopyInfoAndRelease( p_pic_out, p_pic_in ); } /* preset output pic */ if ( !p_sys->b_bake_request && !p_sys->b_shuffle_rqst && p_sys->b_init && !p_sys->b_finished ) puzzle_preset_desk_background(p_pic_out, 0, 127, 127); else { /* copy src to dst during init & bake process */ for( uint8_t i_plane = 0; i_plane < p_pic_out->i_planes; i_plane++ ) memcpy( p_pic_out->p[i_plane].p_pixels, p_pic_in->p[i_plane].p_pixels, p_pic_in->p[i_plane].i_pitch * (int32_t) p_pic_in->p[i_plane].i_visible_lines ); } vlc_mutex_lock( &p_sys->pce_lock ); /* manage the game, adjust locations, groups and regenerate some corrupted data if any */ for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { puzzle_solve_pces_accuracy( p_filter ); } for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 4 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { puzzle_solve_pces_group( p_filter ); } if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ) puzzle_count_pce_group( p_filter); if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ) { i_ret = puzzle_sort_layers( p_filter); if (i_ret != VLC_SUCCESS) { vlc_mutex_unlock( &p_sys->pce_lock ); return CopyInfoAndRelease( p_pic_out, p_pic_in ); } } for (uint32_t i = 0; i < __MAX( 4, p_sys->s_allocated.i_pieces_nbr / 24 ) && ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->s_current_param.b_advanced ); i++) { p_sys->i_calc_corn_loop++; p_sys->i_calc_corn_loop %= p_sys->s_allocated.i_pieces_nbr; puzzle_calculate_corners( p_filter, p_sys->i_calc_corn_loop ); } /* computer moves some piece depending on auto_solve and auto_shuffle param */ if ( !p_sys->b_bake_request && !p_sys->b_mouse_drag && p_sys->b_init && p_sys->ps_puzzle_array != NULL && p_sys->s_current_param.b_advanced ) { puzzle_auto_shuffle( p_filter ); puzzle_auto_solve( p_filter ); } vlc_mutex_unlock( &p_sys->pce_lock ); /* draw output pic */ if ( !p_sys->b_bake_request && p_sys->b_init && p_sys->ps_puzzle_array != NULL ) { puzzle_draw_borders(p_filter, p_pic_in, p_pic_out); p_sys->i_pointed_pce = NO_PCE; puzzle_draw_pieces(p_filter, p_pic_in, p_pic_out); /* when puzzle_draw_pieces() has not updated p_sys->i_pointed_pce, * use puzzle_find_piece to define the piece pointed by the mouse */ if (p_sys->i_pointed_pce == NO_PCE) p_sys->i_mouse_drag_pce = puzzle_find_piece( p_filter, p_sys->i_mouse_x, p_sys->i_mouse_y, -1); else p_sys->i_mouse_drag_pce = p_sys->i_pointed_pce; if (p_sys->s_current_param.b_preview ) puzzle_draw_preview(p_filter, p_pic_in, p_pic_out); /* highlight the selected piece when not playing jigsaw mode */ if ( p_sys->i_selected != NO_PCE && !p_sys->s_current_param.b_blackslot && !p_sys->s_current_param.b_advanced ) { int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols); int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols); puzzle_draw_rectangle(p_pic_out, p_sys->ps_puzzle_array[r][c][0].i_x, p_sys->ps_puzzle_array[r][c][0].i_y, p_sys->ps_puzzle_array[r][c][0].i_width, p_sys->ps_puzzle_array[r][c][0].i_lines, 255, 127, 127); } /* draw the blackslot when playing sliding puzzle mode */ if ( p_sys->i_selected != NO_PCE && p_sys->s_current_param.b_blackslot && !p_sys->s_current_param.b_advanced ) { int32_t c = (p_sys->i_selected % p_sys->s_allocated.i_cols); int32_t r = (p_sys->i_selected / p_sys->s_allocated.i_cols); puzzle_fill_rectangle(p_pic_out, p_sys->ps_puzzle_array[r][c][0].i_x, p_sys->ps_puzzle_array[r][c][0].i_y, p_sys->ps_puzzle_array[r][c][0].i_width, p_sys->ps_puzzle_array[r][c][0].i_lines, 0, 127, 127); } /* Draw the 'puzzle_shuffle' button if the puzzle is finished */ if ( p_sys->b_finished ) puzzle_draw_sign(p_pic_out, 0, 0, SHUFFLE_WIDTH, SHUFFLE_LINES, ppsz_shuffle_button, false); /* draw an arrow at mouse pointer to indicate current action (rotation...) */ if ((p_sys->i_mouse_drag_pce != NO_PCE) && !p_sys->b_mouse_drag && !p_sys->b_finished && p_sys->s_current_param.b_advanced ) { vlc_mutex_lock( &p_sys->pce_lock ); int32_t i_delta_x; if (p_sys->s_current_param.i_rotate != 3) i_delta_x = 0; else if ( (p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_actual_angle & 1) == 0) i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_width / 6; else i_delta_x = p_sys->ps_desk_planes[0].i_pce_max_lines / 6; if (p_sys->s_current_param.i_rotate == 0) p_sys->i_mouse_action = 0; else if (p_sys->s_current_param.i_rotate == 1) p_sys->i_mouse_action = 2; else if ( p_sys->i_mouse_x >= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x + i_delta_x) ) p_sys->i_mouse_action = -1; /* rotate counterclockwise */ else if ( p_sys->i_mouse_x <= ( p_sys->ps_pieces[p_sys->i_mouse_drag_pce].i_center_x - i_delta_x) ) p_sys->i_mouse_action = +1; else p_sys->i_mouse_action = 4; /* center click: only mirror */ if ( p_sys->i_mouse_action == +1 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, false); else if ( p_sys->i_mouse_action == -1 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_rot_arrow_sign, true); else if ( p_sys->i_mouse_action == 4 ) puzzle_draw_sign(p_pic_out, p_sys->i_mouse_x - ARROW_WIDTH, p_sys->i_mouse_y, ARROW_WIDTH, ARROW_LINES, ppsz_mir_arrow_sign, false); vlc_mutex_unlock( &p_sys->pce_lock ); } } return CopyInfoAndRelease( p_pic_out, p_pic_in ); }
/** * Filter a picture */ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } /* */ vlc_mutex_lock( &p_sys->lock ); if( p_sys->b_change ) { p_sys->i_rows = p_sys->change.i_rows; p_sys->i_cols = p_sys->change.i_cols; p_sys->b_blackslot = p_sys->change.b_blackslot; p_sys->b_change = false; Shuffle( p_sys ); } vlc_mutex_unlock( &p_sys->lock ); /* */ const int i_rows = p_sys->i_rows; const int i_cols = p_sys->i_cols; /* Draw each piece of the puzzle at the right place */ for( int i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ ) { const plane_t *p_in = &p_pic->p[i_plane]; plane_t *p_out = &p_outpic->p[i_plane]; for( int i = 0; i < i_cols * i_rows; i++ ) { int i_piece_height = p_out->i_visible_lines / i_rows; int i_piece_width = p_out->i_visible_pitch / i_cols; int i_col = (i % i_cols) * i_piece_width; int i_row = (i / i_cols) * i_piece_height; int i_last_row = i_row + i_piece_height; int i_ocol = (p_sys->pi_order[i] % i_cols) * i_piece_width; int i_orow = (p_sys->pi_order[i] / i_cols) * i_piece_height; if( p_sys->b_blackslot && !p_sys->b_finished && i == p_sys->i_selected ) { uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 ); for( int r = i_row; r < i_last_row; r++ ) { memset( p_out->p_pixels + r * p_out->i_pitch + i_col, color, i_piece_width ); } } else { for( int r = i_row, or = i_orow; r < i_last_row; r++, or++ ) { memcpy( p_out->p_pixels + r * p_out->i_pitch + i_col, p_in->p_pixels + or * p_in->i_pitch + i_ocol, i_piece_width ); } } /* Draw the borders of the selected slot */ if( i_plane == 0 && !p_sys->b_blackslot && p_sys->i_selected == i ) { memset( p_out->p_pixels + i_row * p_out->i_pitch + i_col, 0xff, i_piece_width ); for( int r = i_row; r < i_last_row; r++ ) { p_out->p_pixels[r * p_out->i_pitch + i_col + 0 + 0 ] = 0xff; p_out->p_pixels[r * p_out->i_pitch + i_col + i_piece_width - 1 ] = 0xff; } memset( p_out->p_pixels + (i_last_row - 1) * p_out->i_pitch + i_col, 0xff, i_piece_width ); } } } /* Draw the 'Shuffle' button if the puzzle is finished */ if( p_sys->b_finished ) { plane_t *p_out = &p_outpic->p[Y_PLANE]; for( int i = 0; i < SHUFFLE_HEIGHT; i++ ) { for( int j = 0; j < SHUFFLE_WIDTH; j++ ) { if( shuffle_button[i][j] == '.' ) p_out->p_pixels[ i * p_out->i_pitch + j ] = 0xff; } } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Invert image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; int i, j; uint8_t *p_src = NULL; uint8_t *p_out = NULL; int i_src_pitch; int i_out_pitch; int pix; const int v1 = -1; const int v2 = 3; /* 2^3 = 8 */ if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } /* process the Y plane */ p_src = p_pic->p[Y_PLANE].p_pixels; p_out = p_outpic->p[Y_PLANE].p_pixels; i_src_pitch = p_pic->p[Y_PLANE].i_pitch; i_out_pitch = p_outpic->p[Y_PLANE].i_pitch; /* perform convolution only on Y plane. Avoid border line. */ vlc_mutex_lock( &p_filter->p_sys->lock ); for( i = 0; i < p_pic->p[Y_PLANE].i_visible_lines; i++ ) { if( (i == 0) || (i == p_pic->p[Y_PLANE].i_visible_lines - 1) ) { for( j = 0; j < p_pic->p[Y_PLANE].i_visible_pitch; j++ ) p_out[i * i_out_pitch + j] = clip( p_src[i * i_src_pitch + j] ); continue ; } for( j = 0; j < p_pic->p[Y_PLANE].i_visible_pitch; j++ ) { if( (j == 0) || (j == p_pic->p[Y_PLANE].i_visible_pitch - 1) ) { p_out[i * i_out_pitch + j] = p_src[i * i_src_pitch + j]; continue ; } pix = (p_src[(i - 1) * i_src_pitch + j - 1] * v1) + (p_src[(i - 1) * i_src_pitch + j ] * v1) + (p_src[(i - 1) * i_src_pitch + j + 1] * v1) + (p_src[(i ) * i_src_pitch + j - 1] * v1) + (p_src[(i ) * i_src_pitch + j ] << v2) + (p_src[(i ) * i_src_pitch + j + 1] * v1) + (p_src[(i + 1) * i_src_pitch + j - 1] * v1) + (p_src[(i + 1) * i_src_pitch + j ] * v1) + (p_src[(i + 1) * i_src_pitch + j + 1] * v1); pix = pix >= 0 ? clip(pix) : -clip(pix * -1); p_out[i * i_out_pitch + j] = clip( p_src[i * i_src_pitch + j] + p_filter->p_sys->tab_precalc[pix + 256] ); } } vlc_mutex_unlock( &p_filter->p_sys->lock ); plane_CopyPixels( &p_outpic->p[U_PLANE], &p_pic->p[U_PLANE] ); plane_CopyPixels( &p_outpic->p[V_PLANE], &p_pic->p[V_PLANE] ); return CopyInfoAndRelease( p_outpic, p_pic ); }
/** * Filter a picture */ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } /* */ vlc_mutex_lock( &p_sys->lock ); if( p_sys->b_change ) { p_sys->i_rows = p_sys->change.i_rows; p_sys->i_cols = p_sys->change.i_cols; p_sys->b_blackslot = p_sys->change.b_blackslot; p_sys->b_change = false; Shuffle( p_sys ); } vlc_mutex_unlock( &p_sys->lock ); /* */ const int i_rows = p_sys->i_rows; const int i_cols = p_sys->i_cols; /* */ for( int i_plane = 0; i_plane < p_outpic->i_planes; i_plane++ ) { const plane_t *p_in = &p_pic->p[i_plane]; const int i_pitch = p_in->i_pitch; plane_t *p_out = &p_outpic->p[i_plane]; for( int i = 0; i < i_cols * i_rows; i++ ) { int i_col = i % i_cols; int i_row = i / i_cols; int i_ocol = p_sys->pi_order[i] % i_cols; int i_orow = p_sys->pi_order[i] / i_cols; int i_last_row = i_row + 1; i_orow *= p_in->i_lines / i_rows; i_row *= p_in->i_lines / i_rows; i_last_row *= p_in->i_lines / i_rows; if( p_sys->b_blackslot && p_sys->b_finished && i == p_sys->i_selected ) { uint8_t color = ( i_plane == Y_PLANE ? 0x0 : 0x80 ); for( ; i_row < i_last_row; i_row++, i_orow++ ) { memset( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols, color, i_pitch / i_cols ); } } else { for( ; i_row < i_last_row; i_row++, i_orow++ ) { memcpy( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols, p_in->p_pixels + i_orow * i_pitch + i_ocol * i_pitch / i_cols, i_pitch / i_cols ); } } } } if( p_sys->i_selected != -1 && !p_sys->b_blackslot ) { const plane_t *p_in = &p_pic->p[Y_PLANE]; const int i_pitch = p_in->i_pitch; plane_t *p_out = &p_outpic->p[Y_PLANE]; int i_col = p_sys->i_selected % i_cols; int i_row = p_sys->i_selected / i_cols; int i_last_row = i_row + 1; i_row *= p_in->i_lines / i_rows; i_last_row *= p_in->i_lines / i_rows; memset( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols, 0xff, i_pitch / i_cols ); for( ; i_row < i_last_row; i_row++ ) { p_out->p_pixels[ i_row * i_pitch + i_col * i_pitch / i_cols ] = 0xff; p_out->p_pixels[ i_row * i_pitch + (i_col+1) * i_pitch / i_cols - 1 ] = 0xff; } i_row--; memset( p_out->p_pixels + i_row * i_pitch + i_col * i_pitch / i_cols, 0xff, i_pitch / i_cols ); } if( p_sys->b_finished ) { plane_t *p_out = &p_outpic->p[Y_PLANE]; for( int i = 0; i < SHUFFLE_HEIGHT; i++ ) { for( int j = 0; j < SHUFFLE_WIDTH; j++ ) { if( shuffle_button[i][j] == '.' ) p_out->p_pixels[ i * p_out->i_pitch + j ] = 0xff; } } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Distort image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; int i_index; double f_angle; mtime_t new_date = mdate(); if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } p_filter->p_sys->f_angle -= (p_filter->p_sys->last_date - new_date) / 100000.0; p_filter->p_sys->last_date = new_date; f_angle = p_filter->p_sys->f_angle; for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) { int i_line, i_first_line, i_num_lines, i_offset, i_pixel_pitch, i_visible_pixels; uint8_t black_pixel; uint8_t *p_in, *p_out; black_pixel = ( p_pic->i_planes > 1 && i_index == Y_PLANE ) ? 0x00 : 0x80; i_num_lines = p_pic->p[i_index].i_visible_lines; i_pixel_pitch = p_pic->p[i_index].i_pixel_pitch; switch( p_filter->fmt_in.video.i_chroma ) { CASE_PACKED_YUV_422 // Quick hack to fix u/v inversion occuring with 2 byte pixel pitch i_pixel_pitch *= 2; break; } i_visible_pixels = p_pic->p[i_index].i_visible_pitch/i_pixel_pitch; i_first_line = i_num_lines * 4 / 5; p_in = p_pic->p[i_index].p_pixels; p_out = p_outpic->p[i_index].p_pixels; for( i_line = 0 ; i_line < i_first_line ; i_line++ ) { memcpy( p_out, p_in, p_pic->p[i_index].i_visible_pitch ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } /* Ok, we do 3 times the sin() calculation for each line. So what ? */ for( i_line = i_first_line ; i_line < i_num_lines ; i_line++ ) { /* Calculate today's offset, don't go above 1/20th of the screen */ i_offset = (int)( (double)(i_visible_pixels) * sin( f_angle + 2.0 * (double)i_line / (double)( 1 + i_line - i_first_line) ) * (double)(i_line - i_first_line) / (double)i_num_lines / 8.0 )*i_pixel_pitch; if( i_offset ) { if( i_offset < 0 ) { memcpy( p_out, p_in - i_offset, p_pic->p[i_index].i_visible_pitch + i_offset ); p_in -= p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; memset( p_out + i_offset, black_pixel, -i_offset ); } else { memcpy( p_out + i_offset, p_in, p_pic->p[i_index].i_visible_pitch - i_offset ); memset( p_out, black_pixel, i_offset ); p_in -= p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } else { memcpy( p_out, p_in, p_pic->p[i_index].i_visible_pitch ); p_in -= p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } } return CopyInfoAndRelease( p_outpic, p_pic ); }
/***************************************************************************** * Render: displays previously rendered output ***************************************************************************** * This function send the currently rendered image to Distort image, waits * until it is displayed and switch the two rendering buffers, preparing next * frame. *****************************************************************************/ static picture_t *Filter( filter_t *p_filter, picture_t *p_pic ) { picture_t *p_outpic; int i_index; double f_angle; mtime_t new_date = mdate(); if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } p_filter->p_sys->f_angle += (new_date - p_filter->p_sys->last_date) / 200000.0; p_filter->p_sys->last_date = new_date; f_angle = p_filter->p_sys->f_angle; for( i_index = 0 ; i_index < p_pic->i_planes ; i_index++ ) { int i_line, i_num_lines, i_visible_pitch, i_pixel_pitch, i_offset, i_visible_pixels; uint8_t black_pixel; uint8_t *p_in, *p_out; p_in = p_pic->p[i_index].p_pixels; p_out = p_outpic->p[i_index].p_pixels; i_num_lines = p_pic->p[i_index].i_visible_lines; i_visible_pitch = p_pic->p[i_index].i_visible_pitch; i_pixel_pitch = p_pic->p[i_index].i_pixel_pitch; i_visible_pixels = i_visible_pitch/i_pixel_pitch; black_pixel = ( p_pic->i_planes > 1 && i_index == Y_PLANE ) ? 0x00 : 0x80; /* Ok, we do 3 times the sin() calculation for each line. So what ? */ for( i_line = 0 ; i_line < i_num_lines ; i_line++ ) { /* Calculate today's offset, don't go above 1/20th of the screen */ i_offset = (int)( (double)(i_visible_pixels) * sin( f_angle + 10.0 * (double)i_line / (double)i_num_lines ) / 20.0 )*i_pixel_pitch; if( i_offset ) { if( i_offset < 0 ) { vlc_memcpy( p_out, p_in - i_offset, i_visible_pitch + i_offset ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; vlc_memset( p_out + i_offset, black_pixel, -i_offset ); } else { vlc_memcpy( p_out + i_offset, p_in, i_visible_pitch - i_offset ); vlc_memset( p_out, black_pixel, i_offset ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } else { vlc_memcpy( p_out, p_in, i_visible_pitch ); p_in += p_pic->p[i_index].i_pitch; p_out += p_outpic->p[i_index].i_pitch; } } } return CopyInfoAndRelease( p_outpic, p_pic ); }