/** * 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_width || p_sys->s_current_param.i_pict_height != (int) p_fmt_in->i_height ) 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 ); }
static int Open(vlc_object_t *obj) { filter_t *filter = (filter_t *)obj; filter_sys_t *sys = NULL; HINSTANCE hdecoder_dll = NULL; HINSTANCE d3d9_dll = NULL; HRESULT hr; picture_t *dst = NULL; GUID *processorGUIDs = NULL; GUID *processorGUID = NULL; IDirectXVideoProcessorService *processor = NULL; if (filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE && filter->fmt_in.video.i_chroma != VLC_CODEC_D3D9_OPAQUE_10B) return VLC_EGENERIC; if (!video_format_IsSimilar(&filter->fmt_in.video, &filter->fmt_out.video)) return VLC_EGENERIC; d3d9_dll = LoadLibrary(TEXT("D3D9.DLL")); if (!d3d9_dll) goto error; hdecoder_dll = LoadLibrary(TEXT("DXVA2.DLL")); if (!hdecoder_dll) goto error; dst = filter_NewPicture(filter); if (dst == NULL) goto error; if (!dst->p_sys) { msg_Dbg(filter, "D3D9 opaque without a texture"); goto error; } sys = calloc(1, sizeof (*sys)); if (unlikely(sys == NULL)) goto error; HRESULT (WINAPI *CreateVideoService)(IDirect3DDevice9 *, REFIID riid, void **ppService); CreateVideoService = (void *)GetProcAddress(hdecoder_dll, "DXVA2CreateVideoService"); if (CreateVideoService == NULL) goto error; hr = IDirect3DSurface9_GetDevice( dst->p_sys->surface, &sys->d3ddev ); if (FAILED(hr)) goto error; D3DSURFACE_DESC dstDesc; hr = IDirect3DSurface9_GetDesc( dst->p_sys->surface, &dstDesc ); if (unlikely(FAILED(hr))) goto error; hr = CreateVideoService( sys->d3ddev, &IID_IDirectXVideoProcessorService, (void**)&processor); if (FAILED(hr)) goto error; DXVA2_VideoDesc dsc; ZeroMemory(&dsc, sizeof(dsc)); dsc.SampleWidth = dstDesc.Width; dsc.SampleHeight = dstDesc.Height; dsc.Format = dstDesc.Format; if (filter->fmt_in.video.i_frame_rate && filter->fmt_in.video.i_frame_rate_base) { dsc.InputSampleFreq.Numerator = filter->fmt_in.video.i_frame_rate; dsc.InputSampleFreq.Denominator = filter->fmt_in.video.i_frame_rate_base; } else { dsc.InputSampleFreq.Numerator = 0; dsc.InputSampleFreq.Denominator = 0; } dsc.OutputFrameFreq = dsc.InputSampleFreq; DXVA2_ExtendedFormat *pFormat = &dsc.SampleFormat; pFormat->SampleFormat = dst->b_top_field_first ? DXVA2_SampleFieldInterleavedEvenFirst : DXVA2_SampleFieldInterleavedOddFirst; UINT count = 0; hr = IDirectXVideoProcessorService_GetVideoProcessorDeviceGuids( processor, &dsc, &count, &processorGUIDs); if (FAILED(hr)) goto error; char *psz_mode = var_InheritString( filter, "deinterlace-mode" ); const struct filter_mode_t *p_mode = GetFilterMode(psz_mode); if (p_mode == NULL) { msg_Dbg(filter, "unknown mode %s, trying blend", psz_mode); p_mode = GetFilterMode("blend"); } if (strcmp(p_mode->psz_mode, psz_mode)) msg_Dbg(filter, "using %s deinterlacing mode", p_mode->psz_mode); DXVA2_VideoProcessorCaps caps, best_caps; unsigned best_score = 0; for (UINT i=0; i<count; ++i) { hr = IDirectXVideoProcessorService_GetVideoProcessorCaps( processor, processorGUIDs+i, &dsc, dsc.Format, &caps); if ( FAILED(hr) || !caps.DeinterlaceTechnology ) continue; unsigned score = (caps.DeinterlaceTechnology & p_mode->i_mode) ? 10 : 1; if (best_score < score) { best_score = score; best_caps = caps; processorGUID = processorGUIDs + i; } } if (processorGUID == NULL) { msg_Dbg(filter, "Could not find a filter to output the required format"); goto error; } hr = IDirectXVideoProcessorService_CreateVideoProcessor( processor, processorGUID, &dsc, dsc.Format, 1, &sys->processor ); if (FAILED(hr)) goto error; hr = IDirectXVideoProcessorService_CreateSurface( processor, dstDesc.Width, dstDesc.Height, 0, dstDesc.Format, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &sys->hw_surface, NULL); if (FAILED(hr)) goto error; sys->hdecoder_dll = hdecoder_dll; sys->d3d9_dll = d3d9_dll; sys->decoder_caps = best_caps; InitDeinterlacingContext( &sys->context ); sys->context.settings = p_mode->settings; sys->context.settings.b_use_frame_history = best_caps.NumBackwardRefSamples != 0 || best_caps.NumForwardRefSamples != 0; if (sys->context.settings.b_use_frame_history != p_mode->settings.b_use_frame_history) msg_Dbg( filter, "deinterlacing not using frame history as requested"); if (sys->context.settings.b_double_rate) sys->context.pf_render_ordered = RenderPic; else sys->context.pf_render_single_pic = RenderSinglePic; video_format_t out_fmt; GetDeinterlacingOutput( &sys->context, &out_fmt, &filter->fmt_in.video ); if( !filter->b_allow_fmt_out_change && out_fmt.i_height != filter->fmt_in.video.i_height ) { goto error; } CoTaskMemFree(processorGUIDs); IDirectXVideoProcessorService_Release(processor); picture_Release(dst); sys->buffer_new = filter->owner.video.buffer_new; filter->owner.video.buffer_new = NewOutputPicture; filter->fmt_out.video = out_fmt; filter->pf_video_filter = Deinterlace; filter->pf_flush = Flush; filter->p_sys = sys; return VLC_SUCCESS; error: CoTaskMemFree(processorGUIDs); if (sys && sys->processor) IDirectXVideoProcessor_Release( sys->processor ); if (processor) IDirectXVideoProcessorService_Release(processor); if (sys && sys->d3ddev) IDirect3DDevice9_Release( sys->d3ddev ); if (hdecoder_dll) FreeLibrary(hdecoder_dll); if (d3d9_dll) FreeLibrary(d3d9_dll); if (dst) picture_Release(dst); free(sys); return VLC_EGENERIC; }
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; int i_line, i_col; 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( i_line = 0 ; i_line < i_visible_lines ; i_line++ ) { for( i_col = 0; i_col < i_visible_pitch ; i_col++ ) { type_t t_value = 0; int x; const int c = i_line*i_in_pitch+i_col; for( 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( i_line = 0 ; i_line < i_visible_lines ; i_line++ ) { for( i_col = 0; i_col < i_visible_pitch ; i_col++ ) { type_t t_value = 0; int y; const int c = i_line*i_in_pitch+i_col; for( 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 ); }
static picture_t *video_new( filter_t *p_filter ) { return filter_NewPicture( (filter_t*)p_filter->p_owner ); }
/**************************************************************************** * 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_plane; 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( 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 */ vlc_memset( p_out, i_padd_color, i_ypadd * p_outplane->i_pitch ); p_out += i_ypadd * p_outplane->i_pitch; int i_line; for( 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 */ vlc_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 */ vlc_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 */ vlc_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 */ vlc_memset( p_out, i_padd_color, ( i_outheight - i_ypadd - i_height ) * p_outplane->i_pitch ); } return CopyInfoAndRelease( p_outpic, p_pic ); }
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; int i_sin, i_cos; if( !p_pic ) return NULL; p_outpic = filter_NewPicture( p_filter ); if( !p_outpic ) { picture_Release( p_pic ); return NULL; } vlc_spin_lock( &p_sys->lock ); i_sin = p_sys->i_sin; i_cos = p_sys->i_cos; vlc_spin_unlock( &p_sys->lock ); for( int i_plane = 0 ; i_plane < p_pic->i_planes ; i_plane++ ) { 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_pitch = p_pic->p[i_plane].i_pitch; const int i_hidden_pitch = i_pitch - i_visible_pitch; const int i_aspect = ( i_visible_lines * p_pic->p[Y_PLANE].i_visible_pitch ) / ( p_pic->p[Y_PLANE].i_visible_lines * i_visible_pitch ); /* = 2 for U and V planes in YUV 4:2:2, = 1 otherwise */ const int i_line_center = i_visible_lines>>1; const int i_col_center = i_visible_pitch>>1; const uint8_t *p_in = p_pic->p[i_plane].p_pixels; uint8_t *p_out = p_outpic->p[i_plane].p_pixels; uint8_t *p_outendline = p_out + i_visible_pitch; const uint8_t *p_outend = p_out + i_visible_lines * i_pitch; const uint8_t black_pixel = ( i_plane == Y_PLANE ) ? 0x00 : 0x80; const int i_line_next = i_cos / i_aspect -i_sin*i_visible_pitch; const int i_col_next = -i_sin / i_aspect -i_cos*i_visible_pitch; int i_line_orig0 = ( - i_cos * i_line_center / i_aspect - i_sin * i_col_center + (1<<11) ); int i_col_orig0 = i_sin * i_line_center / i_aspect - i_cos * i_col_center + (1<<11); for( ; p_outendline < p_outend; p_out += i_hidden_pitch, p_outendline += i_pitch, i_line_orig0 += i_line_next, i_col_orig0 += i_col_next ) { for( ; p_out < p_outendline; p_out++, i_line_orig0 += i_sin, i_col_orig0 += i_cos ) { const int i_line_orig = (i_line_orig0>>12)*i_aspect + i_line_center; const int i_col_orig = (i_col_orig0>>12) + i_col_center; const uint8_t* p_orig_offset = p_in + i_line_orig * i_pitch + i_col_orig; const uint8_t i_line_percent = (i_line_orig0>>4) & 255; const uint8_t i_col_percent = (i_col_orig0 >>4) & 255; if( -1 <= i_line_orig && i_line_orig < i_visible_lines && -1 <= i_col_orig && i_col_orig < i_visible_pitch ) { #define test 1 #undef test #ifdef test if( ( i_col_orig > i_visible_pitch/2 ) ) #endif { uint8_t i_curpix = black_pixel; uint8_t i_colpix = black_pixel; uint8_t i_linpix = black_pixel; uint8_t i_nexpix = black_pixel; if( ( 0 <= i_line_orig ) && ( 0 <= i_col_orig ) ) i_curpix = *p_orig_offset; p_orig_offset++; if( ( i_col_orig < i_visible_pitch - 1) && ( i_line_orig >= 0 ) ) i_colpix = *p_orig_offset; p_orig_offset+=i_pitch; if( ( i_line_orig < i_visible_lines - 1) && ( i_col_orig < i_visible_pitch - 1) ) i_nexpix = *p_orig_offset; p_orig_offset--; if( ( i_line_orig < i_visible_lines - 1) && ( i_col_orig >= 0 ) ) i_linpix = *p_orig_offset; unsigned int temp = 0; temp+= i_curpix * (256 - i_line_percent) * ( 256 - i_col_percent ); temp+= i_linpix * i_line_percent * (256 - i_col_percent ); temp+= i_nexpix * ( i_col_percent) * ( i_line_percent); temp+= i_colpix * i_col_percent * (256 - i_line_percent ); *p_out = temp >> 16; } #ifdef test else if (i_col_orig == i_visible_pitch/2 ) { *p_out = black_pixel; } else *p_out = *p_orig_offset; #endif #undef test } else { *p_out = black_pixel; } }
/* This is the filter function. See Open(). */ picture_t *Deinterlace( filter_t *p_filter, picture_t *p_pic ) { filter_sys_t *p_sys = p_filter->p_sys; picture_t *p_dst[DEINTERLACE_DST_SIZE]; /* Request output picture */ p_dst[0] = filter_NewPicture( p_filter ); if( p_dst[0] == NULL ) { picture_Release( p_pic ); return NULL; } picture_CopyProperties( p_dst[0], p_pic ); /* Any unused p_dst pointers must be NULL, because they are used to check how many output frames we have. */ for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i ) p_dst[i] = NULL; /* Update the input frame history, if the currently active algorithm needs it. */ if( p_sys->b_use_frame_history ) { /* Duplicate the picture * TODO when the vout rework is finished, picture_Hold() might be enough * but becarefull, the pitches must match */ picture_t *p_dup = picture_NewFromFormat( &p_pic->format ); if( p_dup ) picture_Copy( p_dup, p_pic ); /* Slide the history */ if( p_sys->pp_history[0] ) picture_Release( p_sys->pp_history[0] ); for( int i = 1; i < HISTORY_SIZE; i++ ) p_sys->pp_history[i-1] = p_sys->pp_history[i]; p_sys->pp_history[HISTORY_SIZE-1] = p_dup; } /* Slide the metadata history. */ for( int i = 1; i < METADATA_SIZE; i++ ) { p_sys->meta.pi_date[i-1] = p_sys->meta.pi_date[i]; p_sys->meta.pi_nb_fields[i-1] = p_sys->meta.pi_nb_fields[i]; p_sys->meta.pb_top_field_first[i-1] = p_sys->meta.pb_top_field_first[i]; } /* The last element corresponds to the current input frame. */ p_sys->meta.pi_date[METADATA_SIZE-1] = p_pic->date; p_sys->meta.pi_nb_fields[METADATA_SIZE-1] = p_pic->i_nb_fields; p_sys->meta.pb_top_field_first[METADATA_SIZE-1] = p_pic->b_top_field_first; /* Remember the frame offset that we should use for this frame. The value in p_sys will be updated to reflect the correct value for the *next* frame when we call the renderer. */ int i_frame_offset = p_sys->i_frame_offset; int i_meta_idx = (METADATA_SIZE-1) - i_frame_offset; /* These correspond to the current *outgoing* frame. */ bool b_top_field_first; int i_nb_fields; if( i_frame_offset != CUSTOM_PTS ) { /* Pick the correct values from the history. */ b_top_field_first = p_sys->meta.pb_top_field_first[i_meta_idx]; i_nb_fields = p_sys->meta.pi_nb_fields[i_meta_idx]; } else { /* Framerate doublers must not request CUSTOM_PTS, as they need the original field timings, and need Deinterlace() to allocate the correct number of output frames. */ assert( !p_sys->b_double_rate ); /* NOTE: i_nb_fields is only used for framerate doublers, so it is unused in this case. b_top_field_first is only passed to the algorithm. We assume that algorithms that request CUSTOM_PTS will, if necessary, extract the TFF/BFF information themselves. */ b_top_field_first = p_pic->b_top_field_first; /* this is not guaranteed to be meaningful */ i_nb_fields = p_pic->i_nb_fields; /* unused */ } /* For framerate doublers, determine field duration and allocate output frames. */ mtime_t i_field_dur = 0; int i_double_rate_alloc_end = 0; /* One past last for allocated output frames in p_dst[]. Used only for framerate doublers. Will be inited below. Declared here because the PTS logic needs the result. */ if( p_sys->b_double_rate ) { /* Calculate one field duration. */ int i = 0; int iend = METADATA_SIZE-1; /* Find oldest valid logged date. The current input frame doesn't count. */ for( ; i < iend; i++ ) if( p_sys->meta.pi_date[i] > VLC_TS_INVALID ) break; if( i < iend ) { /* Count how many fields the valid history entries (except the new frame) represent. */ int i_fields_total = 0; for( int j = i ; j < iend; j++ ) i_fields_total += p_sys->meta.pi_nb_fields[j]; /* One field took this long. */ i_field_dur = (p_pic->date - p_sys->meta.pi_date[i]) / i_fields_total; } /* Note that we default to field duration 0 if it could not be determined. This behaves the same as the old code - leaving the extra output frame dates the same as p_pic->date if the last cached date was not valid. */ i_double_rate_alloc_end = i_nb_fields; if( i_nb_fields > DEINTERLACE_DST_SIZE ) { /* Note that the effective buffer size depends also on the constant private_picture in vout_wrapper.c, since that determines the maximum number of output pictures filter_NewPicture() will successfully allocate for one input frame. */ msg_Err( p_filter, "Framerate doubler: output buffer too small; "\ "fields = %d, buffer size = %d. Dropping the "\ "remaining fields.", i_nb_fields, DEINTERLACE_DST_SIZE ); i_double_rate_alloc_end = DEINTERLACE_DST_SIZE; } /* Allocate output frames. */ for( int i = 1; i < i_double_rate_alloc_end ; ++i ) { p_dst[i-1]->p_next = p_dst[i] = filter_NewPicture( p_filter ); if( p_dst[i] ) { picture_CopyProperties( p_dst[i], p_pic ); } else { msg_Err( p_filter, "Framerate doubler: could not allocate "\ "output frame %d", i+1 ); i_double_rate_alloc_end = i; /* Inform the PTS logic about the correct end position. */ break; /* If this happens, the rest of the allocations aren't likely to work, either... */ } } /* Now we have allocated *up to* the correct number of frames; normally, exactly the correct number. Upon alloc failure, we may have succeeded in allocating *some* output frames, but fewer than were desired. In such a case, as many will be rendered as were successfully allocated. Note that now p_dst[i] != NULL for 0 <= i < i_double_rate_alloc_end. */ } assert( p_sys->b_double_rate || p_dst[1] == NULL ); assert( i_nb_fields > 2 || p_dst[2] == NULL ); /* Render */ switch( p_sys->i_mode ) { case DEINTERLACE_DISCARD: RenderDiscard( p_dst[0], p_pic, 0 ); break; case DEINTERLACE_BOB: RenderBob( p_dst[0], p_pic, !b_top_field_first ); if( p_dst[1] ) RenderBob( p_dst[1], p_pic, b_top_field_first ); if( p_dst[2] ) RenderBob( p_dst[2], p_pic, !b_top_field_first ); break;; case DEINTERLACE_LINEAR: RenderLinear( p_filter, p_dst[0], p_pic, !b_top_field_first ); if( p_dst[1] ) RenderLinear( p_filter, p_dst[1], p_pic, b_top_field_first ); if( p_dst[2] ) RenderLinear( p_filter, p_dst[2], p_pic, !b_top_field_first ); break; case DEINTERLACE_MEAN: RenderMean( p_filter, p_dst[0], p_pic ); break; case DEINTERLACE_BLEND: RenderBlend( p_filter, p_dst[0], p_pic ); break; case DEINTERLACE_X: RenderX( p_dst[0], p_pic ); break; case DEINTERLACE_YADIF: if( RenderYadif( p_filter, p_dst[0], p_pic, 0, 0 ) ) goto drop; break; case DEINTERLACE_YADIF2X: if( RenderYadif( p_filter, p_dst[0], p_pic, 0, !b_top_field_first ) ) goto drop; if( p_dst[1] ) RenderYadif( p_filter, p_dst[1], p_pic, 1, b_top_field_first ); if( p_dst[2] ) RenderYadif( p_filter, p_dst[2], p_pic, 2, !b_top_field_first ); break; case DEINTERLACE_PHOSPHOR: if( RenderPhosphor( p_filter, p_dst[0], 0, !b_top_field_first ) ) goto drop; if( p_dst[1] ) RenderPhosphor( p_filter, p_dst[1], 1, b_top_field_first ); if( p_dst[2] ) RenderPhosphor( p_filter, p_dst[2], 2, !b_top_field_first ); break; case DEINTERLACE_IVTC: /* Note: RenderIVTC will automatically drop the duplicate frames produced by IVTC. This is part of normal operation. */ if( RenderIVTC( p_filter, p_dst[0] ) ) goto drop; break; } /* Set output timestamps, if the algorithm didn't request CUSTOM_PTS for this frame. */ assert( i_frame_offset <= METADATA_SIZE || i_frame_offset == CUSTOM_PTS ); if( i_frame_offset != CUSTOM_PTS ) { mtime_t i_base_pts = p_sys->meta.pi_date[i_meta_idx]; /* Note: in the usual case (i_frame_offset = 0 and b_double_rate = false), this effectively does nothing. This is needed to correct the timestamp when i_frame_offset > 0. */ p_dst[0]->date = i_base_pts; if( p_sys->b_double_rate ) { /* Processing all actually allocated output frames. */ for( int i = 1; i < i_double_rate_alloc_end; ++i ) { /* XXX it's not really good especially for the first picture, but * I don't think that delaying by one frame is worth it */ if( i_base_pts > VLC_TS_INVALID ) p_dst[i]->date = i_base_pts + i * i_field_dur; else p_dst[i]->date = VLC_TS_INVALID; } } } for( int i = 0; i < DEINTERLACE_DST_SIZE; ++i ) { if( p_dst[i] ) { p_dst[i]->b_progressive = true; p_dst[i]->i_nb_fields = 2; } } picture_Release( p_pic ); return p_dst[0]; drop: picture_Release( p_dst[0] ); for( int i = 1; i < DEINTERLACE_DST_SIZE; ++i ) { if( p_dst[i] ) picture_Release( p_dst[i] ); } picture_Release( p_pic ); return NULL; }
/***************************************************************************** * Buffer management *****************************************************************************/ static picture_t *BufferNew( filter_t *p_filter ) { filter_t *p_parent = (filter_t*)p_filter->p_owner; return filter_NewPicture( p_parent ); }
/***************************************************************************** * 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 */ plane_CopyPixels( &p_outpic->p[Y_PLANE], &p_pic->p[Y_PLANE] ); /* 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 ); }
/** * 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 ); }
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; 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; } 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 ); }
/** * Video filter */ static picture_t *FilterVideo( filter_t *p_filter, picture_t *p_src ) { filter_sys_t *p_sys = p_filter->p_sys; logo_list_t *p_list = &p_sys->list; picture_t *p_dst = filter_NewPicture( p_filter ); if( !p_dst ) goto exit; picture_Copy( p_dst, p_src ); /* */ vlc_mutex_lock( &p_sys->lock ); logo_t *p_logo; if( p_list->i_next_pic < p_src->date ) p_logo = LogoListNext( p_list, p_src->date ); else p_logo = LogoListCurrent( p_list ); /* */ const picture_t *p_pic = p_logo->p_pic; if( p_pic ) { const video_format_t *p_fmt = &p_pic->format; const int i_dst_w = p_filter->fmt_out.video.i_visible_width; const int i_dst_h = p_filter->fmt_out.video.i_visible_height; if( p_sys->i_pos ) { if( p_sys->i_pos & SUBPICTURE_ALIGN_BOTTOM ) { p_sys->i_pos_y = i_dst_h - p_fmt->i_visible_height; } else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_TOP) ) { p_sys->i_pos_y = ( i_dst_h - p_fmt->i_visible_height ) / 2; } else { p_sys->i_pos_y = 0; } if( p_sys->i_pos & SUBPICTURE_ALIGN_RIGHT ) { p_sys->i_pos_x = i_dst_w - p_fmt->i_visible_width; } else if ( !(p_sys->i_pos & SUBPICTURE_ALIGN_LEFT) ) { p_sys->i_pos_x = ( i_dst_w - p_fmt->i_visible_width ) / 2; } else { p_sys->i_pos_x = 0; } } /* */ const int i_alpha = p_logo->i_alpha != -1 ? p_logo->i_alpha : p_list->i_alpha; if( filter_ConfigureBlend( p_sys->p_blend, i_dst_w, i_dst_h, p_fmt ) || filter_Blend( p_sys->p_blend, p_dst, p_sys->i_pos_x, p_sys->i_pos_y, p_pic, i_alpha ) ) { msg_Err( p_filter, "failed to blend a picture" ); } } vlc_mutex_unlock( &p_sys->lock ); exit: picture_Release( p_src ); return p_dst; }
/***************************************************************************** * 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 ); }