+
+/**
+ * Close the filter
+ */
+void Close( vlc_object_t *p_this ) {
+ filter_t *p_filter = (filter_t *)p_this;
+ filter_sys_t *p_sys = p_filter->p_sys;
+
+ var_DelCallback( p_filter, CFG_PREFIX "rows", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "cols", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "border", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "preview", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "preview-size", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "shape-size", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "auto-shuffle", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "auto-solve", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "rotation", puzzle_Callback, p_sys );
+ var_DelCallback( p_filter, CFG_PREFIX "mode", puzzle_Callback, p_sys );
+
+ vlc_mutex_destroy( &p_sys->lock );
+ vlc_mutex_destroy( &p_sys->pce_lock );
+
+ /* Free allocated memory */
+ puzzle_free_ps_puzzle_array ( p_filter );
+ puzzle_free_ps_pieces_shapes ( p_filter);
+ puzzle_free_ps_pieces ( p_filter );
+ free(p_sys->ps_desk_planes);
+ free(p_sys->ps_pict_planes);
+ free( p_sys->pi_order );
+
+ for (int32_t i_shape = 0; i_shape<SHAPES_QTY; i_shape++)
+ free(p_sys->ps_bezier_pts_H[i_shape]);
+ free(p_sys->ps_bezier_pts_H);
+
+ free( p_sys );
+}
+
+/**
+ * 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 )