static int release_image(VAImage *va_image) { VAAPIContext * const vaapi = vaapi_get_context(); VAStatus status; status = vaUnmapBuffer(vaapi->display, va_image->buf); if (!vaapi_check_status(status, "vaUnmapBuffer()")) return -1; return 0; }
static int bind_image(VAImage *va_image, Image *image) { VAAPIContext * const vaapi = vaapi_get_context(); VAImageFormat * const va_format = &va_image->format; VAStatus status; void *va_image_data; unsigned int i; if (va_image->num_planes > MAX_IMAGE_PLANES) return -1; status = vaMapBuffer(vaapi->display, va_image->buf, &va_image_data); if (!vaapi_check_status(status, "vaMapBuffer()")) return -1; memset(image, 0, sizeof(*image)); image->format = va_format->fourcc; if (is_vaapi_rgb_format(va_format)) { image->format = image_rgba_format( va_format->bits_per_pixel, va_format->byte_order == VA_MSB_FIRST, va_format->red_mask, va_format->green_mask, va_format->blue_mask, va_format->alpha_mask ); if (!image->format) return -1; } image->width = va_image->width; image->height = va_image->height; image->num_planes = va_image->num_planes; for (i = 0; i < va_image->num_planes; i++) { image->pixels[i] = (uint8_t *)va_image_data + va_image->offsets[i]; image->pitches[i] = va_image->pitches[i]; } return 0; }
int decode(void) { VAAPIContext * const vaapi = vaapi_get_context(); VAPictureParameterBufferMPEG4 *pic_param; VASliceParameterBufferMPEG4 *slice_param; VAIQMatrixBufferMPEG4 *iq_matrix; int i, slice_count; MPEG4PictureInfo mpeg4_pic_info; MPEG4SliceInfo mpeg4_slice_info; MPEG4IQMatrix mpeg4_iq_matrix; const uint8_t *mpeg4_slice_data; unsigned int mpeg4_slice_data_size; if (!vaapi) return -1; mpeg4_get_picture_info(&mpeg4_pic_info); if (vaapi_init_decoder(VAProfileMPEG4AdvancedSimple, VAEntrypointVLD, mpeg4_pic_info.width, mpeg4_pic_info.height) < 0) return -1; if ((pic_param = vaapi_alloc_picture(sizeof(*pic_param))) == NULL) return -1; #define COPY(field) \ pic_param->field = mpeg4_pic_info.field #define COPY_BFM(a,b,c) \ pic_param->BFM(a,b,c) = mpeg4_pic_info.a.b.c pic_param->vop_width = mpeg4_pic_info.width; pic_param->vop_height = mpeg4_pic_info.height; pic_param->forward_reference_picture = 0xffffffff; pic_param->backward_reference_picture = 0xffffffff; pic_param->BFV(vol_fields, value) = 0; /* reset all bits */ COPY_BFM(vol_fields, bits, short_video_header); COPY_BFM(vol_fields, bits, chroma_format); COPY_BFM(vol_fields, bits, interlaced); COPY_BFM(vol_fields, bits, obmc_disable); COPY_BFM(vol_fields, bits, sprite_enable); COPY_BFM(vol_fields, bits, sprite_warping_accuracy); COPY_BFM(vol_fields, bits, quant_type); COPY_BFM(vol_fields, bits, quarter_sample); COPY_BFM(vol_fields, bits, data_partitioned); COPY_BFM(vol_fields, bits, reversible_vlc); COPY(no_of_sprite_warping_points); for (i = 0; i < 3; i++) { COPY(sprite_trajectory_du[i]); COPY(sprite_trajectory_dv[i]); } COPY(quant_precision); pic_param->BFV(vop_fields, value) = 0; /* reset all bits */ COPY_BFM(vop_fields, bits, vop_coding_type); COPY_BFM(vop_fields, bits, backward_reference_vop_coding_type); COPY_BFM(vop_fields, bits, vop_rounding_type); COPY_BFM(vop_fields, bits, intra_dc_vlc_thr); COPY_BFM(vop_fields, bits, top_field_first); COPY_BFM(vop_fields, bits, alternate_vertical_scan_flag); COPY(vop_fcode_forward); COPY(vop_fcode_backward); COPY(num_gobs_in_vop); COPY(num_macroblocks_in_gob); COPY(TRB); COPY(TRD); #if (VA_CHECK_VERSION(0,31,1) /* XXX: update when changes are merged */ || \ (VA_CHECK_VERSION(0,31,0) && VA_SDS_VERSION >= 4)) COPY(vop_time_increment_resolution); COPY_BFM(vol_fields, bits, resync_marker_disable); #endif #undef COPY_BFM #undef COPY if (mpeg4_iq_matrix.load_intra_quant_mat || mpeg4_iq_matrix.load_non_intra_quant_mat) { if ((iq_matrix = vaapi_alloc_iq_matrix(sizeof(*iq_matrix))) == NULL) return -1; mpeg4_get_iq_matrix(&mpeg4_iq_matrix); #define COPY(field) iq_matrix->field = mpeg4_iq_matrix.field COPY(load_intra_quant_mat); COPY(load_non_intra_quant_mat); for (i = 0; i < 64; i++) { COPY(intra_quant_mat[i]); COPY(non_intra_quant_mat[i]); } #undef COPY } slice_count = mpeg4_get_slice_count(); for (i = 0; i < slice_count; i++) { if (mpeg4_get_slice_info(i, &mpeg4_slice_info) < 0) return -1; if (mpeg4_get_slice_data(i, &mpeg4_slice_data, &mpeg4_slice_data_size) < 0) return -1; if (mpeg4_slice_data_size != mpeg4_slice_info.slice_data_size) return -1; if ((slice_param = vaapi_alloc_slice(sizeof(*slice_param), mpeg4_slice_data, mpeg4_slice_data_size)) == NULL) return -1; #define COPY(field) slice_param->field = mpeg4_slice_info.field COPY(macroblock_offset); COPY(macroblock_number); COPY(quant_scale); #undef COPY } return vaapi_decode(); }
int get_image(VASurfaceID surface, Image *dst_img) { VAAPIContext * const vaapi = vaapi_get_context(); VAImage image; VAImageFormat *image_format = NULL; VAStatus status; Image bound_image; int i, is_bound_image = 0, is_derived_image = 0, error = -1; image.image_id = VA_INVALID_ID; image.buf = VA_INVALID_ID; if (!image_format) { status = vaDeriveImage(vaapi->display, surface, &image); if (vaapi_check_status(status, "vaDeriveImage()")) { if (image.image_id != VA_INVALID_ID && image.buf != VA_INVALID_ID) { D(bug("using vaDeriveImage()\n")); is_derived_image = 1; image_format = &image.format; } else { D(bug("vaDeriveImage() returned success but VA image is invalid. Trying vaGetImage()\n")); } } } if (!image_format) { for (i = 0; image_formats[i] != 0; i++) { if (get_image_format(vaapi, image_formats[i], &image_format)) break; } } if (!image_format) goto end; D(bug("selected %s image format for getimage\n", string_of_VAImageFormat(image_format))); if (!is_derived_image) { status = vaCreateImage(vaapi->display, image_format, vaapi->picture_width, vaapi->picture_height, &image); if (!vaapi_check_status(status, "vaCreateImage()")) goto end; D(bug("created image with id 0x%08x and buffer id 0x%08x\n", image.image_id, image.buf)); VARectangle src_rect; src_rect.x = 0; src_rect.y = 0; src_rect.width = vaapi->picture_width; src_rect.height = vaapi->picture_height; D(bug("src rect (%d,%d):%ux%u\n", src_rect.x, src_rect.y, src_rect.width, src_rect.height)); status = vaGetImage( vaapi->display, vaapi->surface_id, src_rect.x, src_rect.y, src_rect.width, src_rect.height, image.image_id ); if (!vaapi_check_status(status, "vaGetImage()")) { vaDestroyImage(vaapi->display, image.image_id); goto end; } } if (bind_image(&image, &bound_image) < 0) goto end; is_bound_image = 1; if (image_convert(dst_img, &bound_image) < 0) goto end; error = 0; end: if (is_bound_image) { if (release_image(&image) < 0) error = -1; } if (image.image_id != VA_INVALID_ID) { status = vaDestroyImage(vaapi->display, image.image_id); if (!vaapi_check_status(status, "vaDestroyImage()")) error = -1; } return error; }
int vaapi_init_decoder(VAProfile profile, VAEntrypoint entrypoint, unsigned int picture_width, unsigned int picture_height) { VAAPIContext * const vaapi = vaapi_get_context(); VAConfigAttrib attrib; VAConfigID config_id = 0; VAContextID context_id = 0; VASurfaceID surface_id = 0; VAStatus status; if (!vaapi) return -1; #if 0 if (common_init_decoder(picture_width, picture_height) < 0) return -1; #endif if (!has_profile(vaapi, profile)) return -1; if (!has_entrypoint(vaapi, profile, entrypoint)) return -1; if (vaapi->profile != profile || vaapi->entrypoint != entrypoint) { if (vaapi->config_id) vaDestroyConfig(vaapi->display, vaapi->config_id); attrib.type = VAConfigAttribRTFormat; status = vaGetConfigAttributes(vaapi->display, profile, entrypoint, &attrib, 1); if (!vaapi_check_status(status, "vaGetConfigAttributes()")) return -1; if ((attrib.value & VA_RT_FORMAT_YUV420) == 0) return -1; status = vaCreateConfig(vaapi->display, profile, entrypoint, &attrib, 1, &config_id); if (!vaapi_check_status(status, "vaCreateConfig()")) return -1; } else config_id = vaapi->config_id; if (vaapi->picture_width != picture_width || vaapi->picture_height != picture_height) { if (vaapi->surface_id) vaDestroySurfaces(vaapi->display, &vaapi->surface_id, 1); status = vaCreateSurfaces(vaapi->display, picture_width, picture_height, VA_RT_FORMAT_YUV420, 1, &surface_id); if (!vaapi_check_status(status, "vaCreateSurfaces()")) return -1; if (vaapi->context_id) vaDestroyContext(vaapi->display, vaapi->context_id); status = vaCreateContext(vaapi->display, config_id, picture_width, picture_height, VA_PROGRESSIVE, &surface_id, 1, &context_id); if (!vaapi_check_status(status, "vaCreateContext()")) return -1; } else { context_id = vaapi->context_id; surface_id = vaapi->surface_id; } vaapi->config_id = config_id; vaapi->context_id = context_id; vaapi->surface_id = surface_id; vaapi->profile = profile; vaapi->entrypoint = entrypoint; vaapi->picture_width = picture_width; vaapi->picture_height = picture_height; return 0; }
int vaapi_exit(void) { VAAPIContext * const vaapi = vaapi_get_context(); unsigned int i; if (!vaapi) return 0; #if USE_GLX if (display_type() == DISPLAY_GLX) vaapi_glx_destroy_surface(); #endif destroy_buffers(vaapi->display, &vaapi->pic_param_buf_id, 1); destroy_buffers(vaapi->display, &vaapi->iq_matrix_buf_id, 1); destroy_buffers(vaapi->display, &vaapi->bitplane_buf_id, 1); destroy_buffers(vaapi->display, vaapi->slice_buf_ids, vaapi->n_slice_buf_ids); if (vaapi->subpic_flags) { free(vaapi->subpic_flags); vaapi->subpic_flags = NULL; } if (vaapi->subpic_formats) { free(vaapi->subpic_formats); vaapi->subpic_formats = NULL; vaapi->n_subpic_formats = 0; } if (vaapi->image_formats) { free(vaapi->image_formats); vaapi->image_formats = NULL; vaapi->n_image_formats = 0; } if (vaapi->entrypoints) { free(vaapi->entrypoints); vaapi->entrypoints = NULL; vaapi->n_entrypoints = 0; } if (vaapi->profiles) { free(vaapi->profiles); vaapi->profiles = NULL; vaapi->n_profiles = 0; } if (vaapi->slice_params) { free(vaapi->slice_params); vaapi->slice_params = NULL; vaapi->slice_params_alloc = 0; vaapi->n_slice_params = 0; } if (vaapi->slice_buf_ids) { free(vaapi->slice_buf_ids); vaapi->slice_buf_ids = NULL; vaapi->n_slice_buf_ids = 0; } if (vaapi->subpic_image.image_id != VA_INVALID_ID) { vaDestroyImage(vaapi->display, vaapi->subpic_image.image_id); vaapi->subpic_image.image_id = VA_INVALID_ID; } for (i = 0; i < ARRAY_ELEMS(vaapi->subpic_ids); i++) { if (vaapi->subpic_ids[i] != VA_INVALID_ID) { vaDestroySubpicture(vaapi->display, vaapi->subpic_ids[i]); vaapi->subpic_ids[i] = VA_INVALID_ID; } } if (vaapi->surface_id) { vaDestroySurfaces(vaapi->display, &vaapi->surface_id, 1); vaapi->surface_id = 0; } if (vaapi->context_id) { vaDestroyContext(vaapi->display, vaapi->context_id); vaapi->context_id = 0; } if (vaapi->config_id) { vaDestroyConfig(vaapi->display, vaapi->config_id); vaapi->config_id = 0; } if (vaapi->display) { vaTerminate(vaapi->display); vaapi->display = NULL; } free(vaapi_context); return 0; }