bool vl_deint_filter_init(struct vl_deint_filter *filter, struct pipe_context *pipe, unsigned video_width, unsigned video_height, bool skip_chroma, bool spatial_filter) { struct pipe_rasterizer_state rs_state; struct pipe_blend_state blend; struct pipe_sampler_state sampler; struct pipe_vertex_element ve; struct vertex2f sizes; struct pipe_video_buffer templ; assert(filter && pipe); assert(video_width && video_height); memset(filter, 0, sizeof(*filter)); filter->pipe = pipe; filter->skip_chroma = skip_chroma; filter->video_width = video_width; filter->video_height = video_height; /* TODO: handle other than 4:2:0 subsampling */ memset(&templ, 0, sizeof(templ)); templ.buffer_format = pipe->screen->get_video_param ( pipe->screen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_UNKNOWN, PIPE_VIDEO_CAP_PREFERED_FORMAT ); templ.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; templ.width = video_width; templ.height = video_height; templ.interlaced = true; filter->video_buffer = vl_video_buffer_create(pipe, &templ); if (!filter->video_buffer) goto error_video_buffer; memset(&rs_state, 0, sizeof(rs_state)); rs_state.half_pixel_center = true; rs_state.bottom_edge_rule = true; rs_state.depth_clip_near = 1; rs_state.depth_clip_far = 1; filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state); if (!filter->rs_state) goto error_rs_state; memset(&blend, 0, sizeof blend); blend.rt[0].colormask = PIPE_MASK_R; filter->blend[0] = pipe->create_blend_state(pipe, &blend); if (!filter->blend[0]) goto error_blendR; blend.rt[0].colormask = PIPE_MASK_G; filter->blend[1] = pipe->create_blend_state(pipe, &blend); if (!filter->blend[1]) goto error_blendG; blend.rt[0].colormask = PIPE_MASK_B; filter->blend[2] = pipe->create_blend_state(pipe, &blend); if (!filter->blend[2]) goto error_blendB; memset(&sampler, 0, sizeof(sampler)); sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.min_img_filter = PIPE_TEX_FILTER_LINEAR; sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler.mag_img_filter = PIPE_TEX_FILTER_LINEAR; sampler.normalized_coords = 1; filter->sampler[0] = pipe->create_sampler_state(pipe, &sampler); filter->sampler[1] = filter->sampler[2] = filter->sampler[3] = filter->sampler[0]; if (!filter->sampler[0]) goto error_sampler; filter->quad = vl_vb_upload_quads(pipe); if(!filter->quad.buffer.resource) goto error_quad; memset(&ve, 0, sizeof(ve)); ve.src_offset = 0; ve.instance_divisor = 0; ve.vertex_buffer_index = 0; ve.src_format = PIPE_FORMAT_R32G32_FLOAT; filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve); if (!filter->ves) goto error_ves; sizes.x = 1.0f / video_width; sizes.y = 1.0f / video_height; filter->vs = create_vert_shader(filter); if (!filter->vs) goto error_vs; filter->fs_copy_top = create_copy_frag_shader(filter, 0); if (!filter->fs_copy_top) goto error_fs_copy_top; filter->fs_copy_bottom = create_copy_frag_shader(filter, 1); if (!filter->fs_copy_bottom) goto error_fs_copy_bottom; filter->fs_deint_top = create_deint_frag_shader(filter, 0, &sizes, spatial_filter); if (!filter->fs_deint_top) goto error_fs_deint_top; filter->fs_deint_bottom = create_deint_frag_shader(filter, 1, &sizes, spatial_filter); if (!filter->fs_deint_bottom) goto error_fs_deint_bottom; return true; error_fs_deint_bottom: pipe->delete_fs_state(pipe, filter->fs_deint_top); error_fs_deint_top: pipe->delete_fs_state(pipe, filter->fs_copy_bottom); error_fs_copy_bottom: pipe->delete_fs_state(pipe, filter->fs_copy_top); error_fs_copy_top: pipe->delete_vs_state(pipe, filter->vs); error_vs: pipe->delete_vertex_elements_state(pipe, filter->ves); error_ves: pipe_resource_reference(&filter->quad.buffer.resource, NULL); error_quad: pipe->delete_sampler_state(pipe, filter->sampler); error_sampler: pipe->delete_blend_state(pipe, filter->blend[2]); error_blendB: pipe->delete_blend_state(pipe, filter->blend[1]); error_blendG: pipe->delete_blend_state(pipe, filter->blend[0]); error_blendR: pipe->delete_rasterizer_state(pipe, filter->rs_state); error_rs_state: filter->video_buffer->destroy(filter->video_buffer); error_video_buffer: return false; }
struct pipe_video_decoder * vl_create_mpeg12_decoder(struct pipe_context *context, enum pipe_video_profile profile, enum pipe_video_entrypoint entrypoint, enum pipe_video_chroma_format chroma_format, unsigned width, unsigned height, unsigned max_references, bool expect_chunked_decode) { const unsigned block_size_pixels = VL_BLOCK_WIDTH * VL_BLOCK_HEIGHT; const struct format_config *format_config; struct vl_mpeg12_decoder *dec; assert(u_reduce_video_profile(profile) == PIPE_VIDEO_CODEC_MPEG12); dec = CALLOC_STRUCT(vl_mpeg12_decoder); if (!dec) return NULL; dec->base.context = context; dec->base.profile = profile; dec->base.entrypoint = entrypoint; dec->base.chroma_format = chroma_format; dec->base.width = width; dec->base.height = height; dec->base.max_references = max_references; dec->base.destroy = vl_mpeg12_destroy; dec->base.begin_frame = vl_mpeg12_begin_frame; dec->base.decode_macroblock = vl_mpeg12_decode_macroblock; dec->base.decode_bitstream = vl_mpeg12_decode_bitstream; dec->base.end_frame = vl_mpeg12_end_frame; dec->base.flush = vl_mpeg12_flush; dec->blocks_per_line = MAX2(util_next_power_of_two(dec->base.width) / block_size_pixels, 4); dec->num_blocks = (dec->base.width * dec->base.height) / block_size_pixels; dec->width_in_macroblocks = align(dec->base.width, VL_MACROBLOCK_WIDTH) / VL_MACROBLOCK_WIDTH; dec->expect_chunked_decode = expect_chunked_decode; /* TODO: Implement 422, 444 */ assert(dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420); if (dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_420) { dec->chroma_width = dec->base.width / 2; dec->chroma_height = dec->base.height / 2; dec->num_blocks = dec->num_blocks * 2; } else if (dec->base.chroma_format == PIPE_VIDEO_CHROMA_FORMAT_422) { dec->chroma_width = dec->base.width; dec->chroma_height = dec->base.height / 2; dec->num_blocks = dec->num_blocks * 2 + dec->num_blocks; } else { dec->chroma_width = dec->base.width; dec->chroma_height = dec->base.height; dec->num_blocks = dec->num_blocks * 3; } dec->quads = vl_vb_upload_quads(dec->base.context); dec->pos = vl_vb_upload_pos( dec->base.context, dec->base.width / VL_MACROBLOCK_WIDTH, dec->base.height / VL_MACROBLOCK_HEIGHT ); dec->ves_ycbcr = vl_vb_get_ves_ycbcr(dec->base.context); dec->ves_mv = vl_vb_get_ves_mv(dec->base.context); switch (entrypoint) { case PIPE_VIDEO_ENTRYPOINT_BITSTREAM: format_config = find_format_config(dec, bitstream_format_config, num_bitstream_format_configs); break; case PIPE_VIDEO_ENTRYPOINT_IDCT: format_config = find_format_config(dec, idct_format_config, num_idct_format_configs); break; case PIPE_VIDEO_ENTRYPOINT_MC: format_config = find_format_config(dec, mc_format_config, num_mc_format_configs); break; default: assert(0); FREE(dec); return NULL; } if (!format_config) { FREE(dec); return NULL; } if (!init_zscan(dec, format_config)) goto error_zscan; if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) { if (!init_idct(dec, format_config)) goto error_sources; } else { if (!init_mc_source_widthout_idct(dec, format_config)) goto error_sources; } if (!vl_mc_init(&dec->mc_y, dec->base.context, dec->base.width, dec->base.height, VL_MACROBLOCK_HEIGHT, format_config->mc_scale, mc_vert_shader_callback, mc_frag_shader_callback, dec)) goto error_mc_y; // TODO if (!vl_mc_init(&dec->mc_c, dec->base.context, dec->base.width, dec->base.height, VL_BLOCK_HEIGHT, format_config->mc_scale, mc_vert_shader_callback, mc_frag_shader_callback, dec)) goto error_mc_c; if (!init_pipe_state(dec)) goto error_pipe_state; return &dec->base; error_pipe_state: vl_mc_cleanup(&dec->mc_c); error_mc_c: vl_mc_cleanup(&dec->mc_y); error_mc_y: if (entrypoint <= PIPE_VIDEO_ENTRYPOINT_IDCT) { vl_idct_cleanup(&dec->idct_y); vl_idct_cleanup(&dec->idct_c); dec->idct_source->destroy(dec->idct_source); } dec->mc_source->destroy(dec->mc_source); error_sources: vl_zscan_cleanup(&dec->zscan_y); vl_zscan_cleanup(&dec->zscan_c); error_zscan: FREE(dec); return NULL; }
bool vl_matrix_filter_init(struct vl_matrix_filter *filter, struct pipe_context *pipe, unsigned video_width, unsigned video_height, unsigned matrix_width, unsigned matrix_height, const float *matrix_values) { struct pipe_rasterizer_state rs_state; struct pipe_blend_state blend; struct pipe_sampler_state sampler; struct pipe_vertex_element ve; struct vertex2f *offsets, v, sizes; unsigned i, num_offsets = matrix_width * matrix_height; assert(filter && pipe); assert(video_width && video_height); assert(matrix_width && matrix_height); memset(filter, 0, sizeof(*filter)); filter->pipe = pipe; memset(&rs_state, 0, sizeof(rs_state)); rs_state.half_pixel_center = true; rs_state.bottom_edge_rule = true; rs_state.depth_clip_near = 1; rs_state.depth_clip_far = 1; filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state); if (!filter->rs_state) goto error_rs_state; memset(&blend, 0, sizeof blend); blend.rt[0].rgb_func = PIPE_BLEND_ADD; blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].alpha_func = PIPE_BLEND_ADD; blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; blend.logicop_func = PIPE_LOGICOP_CLEAR; blend.rt[0].colormask = PIPE_MASK_RGBA; filter->blend = pipe->create_blend_state(pipe, &blend); if (!filter->blend) goto error_blend; memset(&sampler, 0, sizeof(sampler)); sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.compare_mode = PIPE_TEX_COMPARE_NONE; sampler.compare_func = PIPE_FUNC_ALWAYS; sampler.normalized_coords = 1; filter->sampler = pipe->create_sampler_state(pipe, &sampler); if (!filter->sampler) goto error_sampler; filter->quad = vl_vb_upload_quads(pipe); if(!filter->quad.buffer.resource) goto error_quad; memset(&ve, 0, sizeof(ve)); ve.src_offset = 0; ve.instance_divisor = 0; ve.vertex_buffer_index = 0; ve.src_format = PIPE_FORMAT_R32G32_FLOAT; filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve); if (!filter->ves) goto error_ves; offsets = MALLOC(sizeof(struct vertex2f) * num_offsets); if (!offsets) goto error_offsets; sizes.x = (float)(matrix_width - 1) / 2.0f; sizes.y = (float)(matrix_height - 1) / 2.0f; for (v.x = -sizes.x, i = 0; v.x <= sizes.x; v.x += 1.0f) for (v.y = -sizes.y; v.y <= sizes.y; v.y += 1.0f) offsets[i++] = v; for (i = 0; i < num_offsets; ++i) { offsets[i].x /= video_width; offsets[i].y /= video_height; } filter->vs = create_vert_shader(filter); if (!filter->vs) goto error_vs; filter->fs = create_frag_shader(filter, num_offsets, offsets, matrix_values); if (!filter->fs) goto error_fs; FREE(offsets); return true; error_fs: pipe->delete_vs_state(pipe, filter->vs); error_vs: FREE(offsets); error_offsets: pipe->delete_vertex_elements_state(pipe, filter->ves); error_ves: pipe_resource_reference(&filter->quad.buffer.resource, NULL); error_quad: pipe->delete_sampler_state(pipe, filter->sampler); error_sampler: pipe->delete_blend_state(pipe, filter->blend); error_blend: pipe->delete_rasterizer_state(pipe, filter->rs_state); error_rs_state: return false; }
bool vl_median_filter_init(struct vl_median_filter *filter, struct pipe_context *pipe, unsigned width, unsigned height, unsigned size, enum vl_median_filter_shape shape) { struct pipe_rasterizer_state rs_state; struct pipe_blend_state blend; struct pipe_sampler_state sampler; struct vertex2f *offsets = NULL; struct pipe_vertex_element ve; unsigned i, num_offsets = 0; assert(filter && pipe); assert(width && height); assert(size > 1 && size < 20); memset(filter, 0, sizeof(*filter)); filter->pipe = pipe; memset(&rs_state, 0, sizeof(rs_state)); rs_state.half_pixel_center = true; rs_state.bottom_edge_rule = true; rs_state.depth_clip_near = 1; rs_state.depth_clip_far = 1; filter->rs_state = pipe->create_rasterizer_state(pipe, &rs_state); if (!filter->rs_state) goto error_rs_state; memset(&blend, 0, sizeof blend); blend.rt[0].rgb_func = PIPE_BLEND_ADD; blend.rt[0].rgb_src_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].rgb_dst_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].alpha_func = PIPE_BLEND_ADD; blend.rt[0].alpha_src_factor = PIPE_BLENDFACTOR_ONE; blend.rt[0].alpha_dst_factor = PIPE_BLENDFACTOR_ONE; blend.logicop_func = PIPE_LOGICOP_CLEAR; blend.rt[0].colormask = PIPE_MASK_RGBA; filter->blend = pipe->create_blend_state(pipe, &blend); if (!filter->blend) goto error_blend; memset(&sampler, 0, sizeof(sampler)); sampler.wrap_s = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.wrap_t = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.wrap_r = PIPE_TEX_WRAP_CLAMP_TO_EDGE; sampler.min_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.min_mip_filter = PIPE_TEX_MIPFILTER_NONE; sampler.mag_img_filter = PIPE_TEX_FILTER_NEAREST; sampler.compare_mode = PIPE_TEX_COMPARE_NONE; sampler.compare_func = PIPE_FUNC_ALWAYS; sampler.normalized_coords = 1; filter->sampler = pipe->create_sampler_state(pipe, &sampler); if (!filter->sampler) goto error_sampler; filter->quad = vl_vb_upload_quads(pipe); if(!filter->quad.buffer.resource) goto error_quad; memset(&ve, 0, sizeof(ve)); ve.src_offset = 0; ve.instance_divisor = 0; ve.vertex_buffer_index = 0; ve.src_format = PIPE_FORMAT_R32G32_FLOAT; filter->ves = pipe->create_vertex_elements_state(pipe, 1, &ve); if (!filter->ves) goto error_ves; generate_offsets(shape, size, &offsets, &num_offsets); if (!offsets) goto error_offsets; for (i = 0; i < num_offsets; ++i) { offsets[i].x /= width; offsets[i].y /= height; } filter->vs = create_vert_shader(filter); if (!filter->vs) goto error_vs; filter->fs = create_frag_shader(filter, offsets, num_offsets); if (!filter->fs) goto error_fs; FREE(offsets); return true; error_fs: pipe->delete_vs_state(pipe, filter->vs); error_vs: FREE(offsets); error_offsets: pipe->delete_vertex_elements_state(pipe, filter->ves); error_ves: pipe_resource_reference(&filter->quad.buffer.resource, NULL); error_quad: pipe->delete_sampler_state(pipe, filter->sampler); error_sampler: pipe->delete_blend_state(pipe, filter->blend); error_blend: pipe->delete_rasterizer_state(pipe, filter->rs_state); error_rs_state: return false; }