VAStatus vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; if (buf->derived_surface.resource) { if (buf->export_refcount > 0) return VA_STATUS_ERROR_INVALID_BUFFER; pipe_resource_reference(&buf->derived_surface.resource, NULL); } FREE(buf->data); FREE(buf); handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id); return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id) { vlVaDriver *drv; vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); mtx_lock(&drv->mutex); buf = handle_table_get(drv->htab, buf_id); if (!buf) { mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_INVALID_BUFFER; } if (buf->derived_surface.resource) pipe_resource_reference(&buf->derived_surface.resource, NULL); FREE(buf->data); FREE(buf); handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id); mtx_unlock(&drv->mutex); return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroyConfig(VADriverContextP ctx, VAConfigID config_id) { vlVaDriver *drv; vlVaConfig *config; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; pipe_mutex_lock(drv->mutex); config = handle_table_get(drv->htab, config_id); if (!config) return VA_STATUS_ERROR_INVALID_CONFIG; FREE(config); handle_table_remove(drv->htab, config_id); pipe_mutex_unlock(drv->mutex); return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroyImage(VADriverContextP ctx, VAImageID image) { VAImage *vaimage; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; vaimage = handle_table_get(VL_VA_DRIVER(ctx)->htab, image); if (!vaimage) return VA_STATUS_ERROR_INVALID_IMAGE; handle_table_remove(VL_VA_DRIVER(ctx)->htab, image); FREE(vaimage); return vlVaDestroyBuffer(ctx, vaimage->buf); }
VAStatus vlVaReleaseBufferHandle(VADriverContextP ctx, VABufferID buf_id) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; if (buf->export_refcount == 0) return VA_STATUS_ERROR_INVALID_BUFFER; if (--buf->export_refcount == 0) { VABufferInfo * const buf_info = &buf->export_state; switch (buf_info->mem_type) { case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: close((intptr_t)buf_info->handle); break; default: return VA_STATUS_ERROR_INVALID_BUFFER; } buf_info->mem_type = 0; } return VA_STATUS_SUCCESS; }
VAStatus vlVaBufferSetNumElements(VADriverContextP ctx, VABufferID buf_id, unsigned int num_elements) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; if (buf->derived_surface.resource) return VA_STATUS_ERROR_INVALID_BUFFER; buf->data = REALLOC(buf->data, buf->size * buf->num_elements, buf->size * num_elements); buf->num_elements = num_elements; if (!buf->data) return VA_STATUS_ERROR_ALLOCATION_FAILED; return VA_STATUS_SUCCESS; }
VAStatus vlVaCreateBuffer(VADriverContextP ctx, VAContextID context, VABufferType type, unsigned int size, unsigned int num_elements, void *data, VABufferID *buf_id) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = CALLOC(1, sizeof(vlVaBuffer)); if (!buf) return VA_STATUS_ERROR_ALLOCATION_FAILED; buf->type = type; buf->size = size; buf->num_elements = num_elements; buf->data = MALLOC(size * num_elements); if (!buf->data) { FREE(buf); return VA_STATUS_ERROR_ALLOCATION_FAILED; } if (data) memcpy(buf->data, data, size * num_elements); *buf_id = handle_table_add(VL_VA_DRIVER(ctx)->htab, buf); return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces) { vlVaDriver *drv; int i; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); pipe_mutex_lock(drv->mutex); for (i = 0; i < num_surfaces; ++i) { vlVaSurface *surf = handle_table_get(drv->htab, surface_list[i]); if (!surf) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_SURFACE; } if (surf->buffer) surf->buffer->destroy(surf->buffer); util_dynarray_fini(&surf->subpics); FREE(surf); handle_table_remove(drv->htab, surface_list[i]); } pipe_mutex_unlock(drv->mutex); return VA_STATUS_SUCCESS; }
VAStatus vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context, VABufferID *filters, unsigned int num_filters, VAProcPipelineCaps *pipeline_cap) { unsigned int i = 0; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; if (!pipeline_cap) return VA_STATUS_ERROR_INVALID_PARAMETER; if (num_filters && !filters) return VA_STATUS_ERROR_INVALID_PARAMETER; pipeline_cap->pipeline_flags = 0; pipeline_cap->filter_flags = 0; pipeline_cap->num_forward_references = 0; pipeline_cap->num_backward_references = 0; pipeline_cap->num_input_color_standards = 1; pipeline_cap->input_color_standards = vpp_input_color_standards; pipeline_cap->num_output_color_standards = 1; pipeline_cap->output_color_standards = vpp_output_color_standards; for (i = 0; i < num_filters; i++) { vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]); if (!buf || buf->type >= VABufferTypeMax) return VA_STATUS_ERROR_INVALID_BUFFER; } return VA_STATUS_SUCCESS; }
VAStatus vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id) { vlVaDriver *drv; vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(drv->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; if (buf->export_refcount > 0) return VA_STATUS_ERROR_INVALID_BUFFER; if (buf->derived_surface.resource) { if (!buf->derived_surface.transfer) return VA_STATUS_ERROR_INVALID_BUFFER; pipe_buffer_unmap(drv->pipe, buf->derived_surface.transfer); buf->derived_surface.transfer = NULL; } return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroyContext(VADriverContextP ctx, VAContextID context_id) { vlVaDriver *drv; vlVaContext *context; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); context = handle_table_get(drv->htab, context_id); if (context->decoder) { if (u_reduce_video_profile(context->decoder->profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) { FREE(context->desc.h264.pps->sps); FREE(context->desc.h264.pps); } if (u_reduce_video_profile(context->decoder->profile) == PIPE_VIDEO_FORMAT_HEVC) { FREE(context->desc.h265.pps->sps); FREE(context->desc.h265.pps); } context->decoder->destroy(context->decoder); } FREE(context); handle_table_remove(drv->htab, context_id); return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroyBuffer(VADriverContextP ctx, VABufferID buf_id) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; FREE(buf->data); FREE(buf); handle_table_remove(VL_VA_DRIVER(ctx)->htab, buf_id); return VA_STATUS_SUCCESS; }
VAStatus vlVaBeginPicture(VADriverContextP ctx, VAContextID context_id, VASurfaceID render_target) { vlVaDriver *drv; vlVaContext *context; vlVaSurface *surf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; mtx_lock(&drv->mutex); context = handle_table_get(drv->htab, context_id); if (!context) { mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_INVALID_CONTEXT; } if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_MPEG12) { context->desc.mpeg12.intra_matrix = NULL; context->desc.mpeg12.non_intra_matrix = NULL; } surf = handle_table_get(drv->htab, render_target); mtx_unlock(&drv->mutex); if (!surf || !surf->buffer) return VA_STATUS_ERROR_INVALID_SURFACE; context->target_id = render_target; surf->ctx = context_id; context->target = surf->buffer; context->mjpeg.sampling_factor = 0; if (!context->decoder) { /* VPP */ if (context->templat.profile == PIPE_VIDEO_PROFILE_UNKNOWN && context->target->buffer_format != PIPE_FORMAT_B8G8R8A8_UNORM && context->target->buffer_format != PIPE_FORMAT_R8G8B8A8_UNORM && context->target->buffer_format != PIPE_FORMAT_B8G8R8X8_UNORM && context->target->buffer_format != PIPE_FORMAT_R8G8B8X8_UNORM && context->target->buffer_format != PIPE_FORMAT_NV12 && context->target->buffer_format != PIPE_FORMAT_P016) return VA_STATUS_ERROR_UNIMPLEMENTED; return VA_STATUS_SUCCESS; } if (context->decoder->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) context->needs_begin_frame = true; return VA_STATUS_SUCCESS; }
VAStatus vlVaSyncSurface(VADriverContextP ctx, VASurfaceID render_target) { vlVaDriver *drv; vlVaContext *context; vlVaSurface *surf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; pipe_mutex_lock(drv->mutex); surf = handle_table_get(drv->htab, render_target); if (!surf || !surf->buffer) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_SURFACE; } if (!surf->feedback) { // No outstanding operation: nothing to do. pipe_mutex_unlock(drv->mutex); return VA_STATUS_SUCCESS; } context = handle_table_get(drv->htab, surf->ctx); if (!context) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_CONTEXT; } if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { int frame_diff; if (context->desc.h264enc.frame_num_cnt >= surf->frame_num_cnt) frame_diff = context->desc.h264enc.frame_num_cnt - surf->frame_num_cnt; else frame_diff = 0xFFFFFFFF - surf->frame_num_cnt + 1 + context->desc.h264enc.frame_num_cnt; if ((frame_diff == 0) && (surf->force_flushed == false) && (context->desc.h264enc.frame_num_cnt % 2 != 0)) { context->decoder->flush(context->decoder); context->first_single_submitted = true; } context->decoder->get_feedback(context->decoder, surf->feedback, &(surf->coded_buf->coded_size)); surf->feedback = NULL; } pipe_mutex_unlock(drv->mutex); return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroyImage(VADriverContextP ctx, VAImageID image) { vlVaDriver *drv; VAImage *vaimage; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); pipe_mutex_lock(drv->mutex); vaimage = handle_table_get(drv->htab, image); if (!vaimage) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_IMAGE; } handle_table_remove(VL_VA_DRIVER(ctx)->htab, image); pipe_mutex_unlock(drv->mutex); FREE(vaimage); return vlVaDestroyBuffer(ctx, vaimage->buf); }
VAStatus vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff) { vlVaDriver *drv; vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; if (!pbuff) return VA_STATUS_ERROR_INVALID_PARAMETER; mtx_lock(&drv->mutex); buf = handle_table_get(drv->htab, buf_id); if (!buf || buf->export_refcount > 0) { mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_INVALID_BUFFER; } if (buf->derived_surface.resource) { struct pipe_resource *resource; struct pipe_box box = {}; resource = buf->derived_surface.resource; box.width = resource->width0; box.height = resource->height0; box.depth = resource->depth0; *pbuff = drv->pipe->transfer_map(drv->pipe, resource, 0, PIPE_TRANSFER_WRITE, &box, &buf->derived_surface.transfer); mtx_unlock(&drv->mutex); if (!buf->derived_surface.transfer || !*pbuff) return VA_STATUS_ERROR_INVALID_BUFFER; if (buf->type == VAEncCodedBufferType) { ((VACodedBufferSegment*)buf->data)->buf = *pbuff; ((VACodedBufferSegment*)buf->data)->size = buf->coded_size; ((VACodedBufferSegment*)buf->data)->next = NULL; *pbuff = buf->data; } } else { mtx_unlock(&drv->mutex); *pbuff = buf->data; } return VA_STATUS_SUCCESS; }
VAStatus vlVaQueryVideoProcPipelineCaps(VADriverContextP ctx, VAContextID context, VABufferID *filters, unsigned int num_filters, VAProcPipelineCaps *pipeline_cap) { unsigned int i = 0; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; if (!pipeline_cap) return VA_STATUS_ERROR_INVALID_PARAMETER; if (num_filters && !filters) return VA_STATUS_ERROR_INVALID_PARAMETER; pipeline_cap->pipeline_flags = 0; pipeline_cap->filter_flags = 0; pipeline_cap->num_forward_references = 0; pipeline_cap->num_backward_references = 0; pipeline_cap->num_input_color_standards = ARRAY_SIZE(vpp_input_color_standards); pipeline_cap->input_color_standards = vpp_input_color_standards; pipeline_cap->num_output_color_standards = ARRAY_SIZE(vpp_output_color_standards); pipeline_cap->output_color_standards = vpp_output_color_standards; for (i = 0; i < num_filters; i++) { vlVaBuffer *buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, filters[i]); VAProcFilterParameterBufferBase *filter; if (!buf || buf->type != VAProcFilterParameterBufferType) return VA_STATUS_ERROR_INVALID_BUFFER; filter = buf->data; switch (filter->type) { case VAProcFilterDeinterlacing: { VAProcFilterParameterBufferDeinterlacing *deint = buf->data; if (deint->algorithm == VAProcDeinterlacingMotionAdaptive) { pipeline_cap->num_forward_references = 1; pipeline_cap->num_backward_references = 2; } break; } default: return VA_STATUS_ERROR_UNIMPLEMENTED; } } return VA_STATUS_SUCCESS; }
VAStatus vlVaEndPicture(VADriverContextP ctx, VAContextID context_id) { vlVaDriver *drv; vlVaContext *context; vlVaBuffer *coded_buf; unsigned int coded_size; void *feedback; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; pipe_mutex_lock(drv->mutex); context = handle_table_get(drv->htab, context_id); pipe_mutex_unlock(drv->mutex); if (!context) return VA_STATUS_ERROR_INVALID_CONTEXT; if (!context->decoder) { if (context->templat.profile != PIPE_VIDEO_PROFILE_UNKNOWN) return VA_STATUS_ERROR_INVALID_CONTEXT; /* VPP */ return VA_STATUS_SUCCESS; } context->mpeg4.frame_num++; if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { coded_buf = context->coded_buf; getEncParamPreset(context); context->decoder->begin_frame(context->decoder, context->target, &context->desc.base); context->decoder->encode_bitstream(context->decoder, context->target, coded_buf->derived_surface.resource, &feedback); context->decoder->end_frame(context->decoder, context->target, &context->desc.base); context->decoder->flush(context->decoder); context->decoder->get_feedback(context->decoder, feedback, &coded_size); coded_buf->coded_size = coded_size; } else context->decoder->end_frame(context->decoder, context->target, &context->desc.base); return VA_STATUS_SUCCESS; }
VAStatus vlVaUnmapBuffer(VADriverContextP ctx, VABufferID buf_id) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; /* Nothing to do here */ return VA_STATUS_SUCCESS; }
VAStatus vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; *pbuff = buf->data; return VA_STATUS_SUCCESS; }
VAStatus vlVaBeginPicture(VADriverContextP ctx, VAContextID context_id, VASurfaceID render_target) { vlVaDriver *drv; vlVaContext *context; vlVaSurface *surf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; pipe_mutex_lock(drv->mutex); context = handle_table_get(drv->htab, context_id); if (!context) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_CONTEXT; } surf = handle_table_get(drv->htab, render_target); pipe_mutex_unlock(drv->mutex); if (!surf || !surf->buffer) return VA_STATUS_ERROR_INVALID_SURFACE; context->target = surf->buffer; if (!context->decoder) { /* VPP */ if (context->templat.profile == PIPE_VIDEO_PROFILE_UNKNOWN && context->target->buffer_format != PIPE_FORMAT_B8G8R8A8_UNORM && context->target->buffer_format != PIPE_FORMAT_R8G8B8A8_UNORM && context->target->buffer_format != PIPE_FORMAT_B8G8R8X8_UNORM && context->target->buffer_format != PIPE_FORMAT_R8G8B8X8_UNORM && context->target->buffer_format != PIPE_FORMAT_NV12) return VA_STATUS_ERROR_UNIMPLEMENTED; return VA_STATUS_SUCCESS; } if (context->decoder->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) context->decoder->begin_frame(context->decoder, context->target, &context->desc.base); return VA_STATUS_SUCCESS; }
VAStatus vlVaBufferInfo(VADriverContextP ctx, VABufferID buf_id, VABufferType *type, unsigned int *size, unsigned int *num_elements) { vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; buf = handle_table_get(VL_VA_DRIVER(ctx)->htab, buf_id); if (!buf) return VA_STATUS_ERROR_INVALID_BUFFER; *type = buf->type; *size = buf->size; *num_elements = buf->num_elements; return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroyContext(VADriverContextP ctx, VAContextID context_id) { vlVaDriver *drv; vlVaContext *context; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); pipe_mutex_lock(drv->mutex); context = handle_table_get(drv->htab, context_id); if (!context) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_CONTEXT; } if (context->decoder) { if (context->desc.base.entry_point != PIPE_VIDEO_ENTRYPOINT_ENCODE) { if (u_reduce_video_profile(context->decoder->profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) { FREE(context->desc.h264.pps->sps); FREE(context->desc.h264.pps); } if (u_reduce_video_profile(context->decoder->profile) == PIPE_VIDEO_FORMAT_HEVC) { FREE(context->desc.h265.pps->sps); FREE(context->desc.h265.pps); } } context->decoder->destroy(context->decoder); } if (context->deint) { vl_deint_filter_cleanup(context->deint); FREE(context->deint); } FREE(context); handle_table_remove(drv->htab, context_id); pipe_mutex_unlock(drv->mutex); return VA_STATUS_SUCCESS; }
VAStatus vlVaMapBuffer(VADriverContextP ctx, VABufferID buf_id, void **pbuff) { vlVaDriver *drv; vlVaBuffer *buf; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; if (!pbuff) return VA_STATUS_ERROR_INVALID_PARAMETER; pipe_mutex_lock(drv->mutex); buf = handle_table_get(drv->htab, buf_id); if (!buf || buf->export_refcount > 0) { pipe_mutex_unlock(drv->mutex); return VA_STATUS_ERROR_INVALID_BUFFER; } if (buf->derived_surface.resource) { *pbuff = pipe_buffer_map(drv->pipe, buf->derived_surface.resource, PIPE_TRANSFER_WRITE, &buf->derived_surface.transfer); pipe_mutex_unlock(drv->mutex); if (!buf->derived_surface.transfer || !*pbuff) return VA_STATUS_ERROR_INVALID_BUFFER; } else { pipe_mutex_unlock(drv->mutex); *pbuff = buf->data; } return VA_STATUS_SUCCESS; }
VAStatus vlVaQueryConfigAttributes(VADriverContextP ctx, VAConfigID config_id, VAProfile *profile, VAEntrypoint *entrypoint, VAConfigAttrib *attrib_list, int *num_attribs) { vlVaDriver *drv; vlVaConfig *config; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; pipe_mutex_lock(drv->mutex); config = handle_table_get(drv->htab, config_id); pipe_mutex_unlock(drv->mutex); if (!config) return VA_STATUS_ERROR_INVALID_CONFIG; *profile = PipeToProfile(config->profile); if (config->profile == PIPE_VIDEO_PROFILE_UNKNOWN) { *entrypoint = VAEntrypointVideoProc; *num_attribs = 0; return VA_STATUS_SUCCESS; } *entrypoint = config->entrypoint; *num_attribs = 1; attrib_list[0].type = VAConfigAttribRTFormat; attrib_list[0].value = config->rt_format; return VA_STATUS_SUCCESS; }
VAStatus vlVaDestroySurfaces(VADriverContextP ctx, VASurfaceID *surface_list, int num_surfaces) { vlVaDriver *drv; int i; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); for (i = 0; i < num_surfaces; ++i) { vlVaSurface *surf = handle_table_get(drv->htab, surface_list[i]); if (surf->buffer) surf->buffer->destroy(surf->buffer); if(surf->fence) drv->pipe->screen->fence_reference(drv->pipe->screen, &surf->fence, NULL); util_dynarray_fini(&surf->subpics); FREE(surf); handle_table_remove(drv->htab, surface_list[i]); } return VA_STATUS_SUCCESS; }
VAStatus vlVaEndPicture(VADriverContextP ctx, VAContextID context_id) { vlVaDriver *drv; vlVaContext *context; vlVaBuffer *coded_buf; vlVaSurface *surf; void *feedback; struct pipe_screen *screen; bool supported; bool realloc = false; enum pipe_format format; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; mtx_lock(&drv->mutex); context = handle_table_get(drv->htab, context_id); mtx_unlock(&drv->mutex); if (!context) return VA_STATUS_ERROR_INVALID_CONTEXT; if (!context->decoder) { if (context->templat.profile != PIPE_VIDEO_PROFILE_UNKNOWN) return VA_STATUS_ERROR_INVALID_CONTEXT; /* VPP */ return VA_STATUS_SUCCESS; } mtx_lock(&drv->mutex); surf = handle_table_get(drv->htab, context->target_id); context->mpeg4.frame_num++; screen = context->decoder->context->screen; supported = screen->get_video_param(screen, context->decoder->profile, context->decoder->entrypoint, surf->buffer->interlaced ? PIPE_VIDEO_CAP_SUPPORTS_INTERLACED : PIPE_VIDEO_CAP_SUPPORTS_PROGRESSIVE); if (!supported) { surf->templat.interlaced = screen->get_video_param(screen, context->decoder->profile, context->decoder->entrypoint, PIPE_VIDEO_CAP_PREFERS_INTERLACED); realloc = true; } format = screen->get_video_param(screen, context->decoder->profile, PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_PREFERED_FORMAT); if (surf->buffer->buffer_format != format && surf->buffer->buffer_format == PIPE_FORMAT_NV12) { /* check originally as NV12 only */ surf->templat.buffer_format = format; realloc = true; } if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_JPEG && surf->buffer->buffer_format == PIPE_FORMAT_NV12) { if (context->mjpeg.sampling_factor == 0x211111 || context->mjpeg.sampling_factor == 0x221212) { surf->templat.buffer_format = PIPE_FORMAT_YUYV; realloc = true; } else if (context->mjpeg.sampling_factor != 0x221111) { /* Not NV12 either */ mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_INVALID_SURFACE; } } if (realloc) { struct pipe_video_buffer *old_buf = surf->buffer; if (vlVaHandleSurfaceAllocate(drv, surf, &surf->templat) != VA_STATUS_SUCCESS) { mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_ALLOCATION_FAILED; } if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { if (old_buf->interlaced) { struct u_rect src_rect, dst_rect; dst_rect.x0 = src_rect.x0 = 0; dst_rect.y0 = src_rect.y0 = 0; dst_rect.x1 = src_rect.x1 = surf->templat.width; dst_rect.y1 = src_rect.y1 = surf->templat.height; vl_compositor_yuv_deint_full(&drv->cstate, &drv->compositor, old_buf, surf->buffer, &src_rect, &dst_rect, VL_COMPOSITOR_WEAVE); } else { /* Can't convert from progressive to interlaced yet */ mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_INVALID_SURFACE; } } old_buf->destroy(old_buf); context->target = surf->buffer; } if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) { coded_buf = context->coded_buf; if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) { getEncParamPresetH264(context); context->desc.h264enc.frame_num_cnt++; } else if (u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_HEVC) getEncParamPresetH265(context); context->decoder->begin_frame(context->decoder, context->target, &context->desc.base); context->decoder->encode_bitstream(context->decoder, context->target, coded_buf->derived_surface.resource, &feedback); surf->feedback = feedback; surf->coded_buf = coded_buf; } context->decoder->end_frame(context->decoder, context->target, &context->desc.base); if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE && u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_MPEG4_AVC) { int idr_period = context->desc.h264enc.gop_size / context->gop_coeff; int p_remain_in_idr = idr_period - context->desc.h264enc.frame_num; surf->frame_num_cnt = context->desc.h264enc.frame_num_cnt; surf->force_flushed = false; if (context->first_single_submitted) { context->decoder->flush(context->decoder); context->first_single_submitted = false; surf->force_flushed = true; } if (p_remain_in_idr == 1) { if ((context->desc.h264enc.frame_num_cnt % 2) != 0) { context->decoder->flush(context->decoder); context->first_single_submitted = true; } else context->first_single_submitted = false; surf->force_flushed = true; } } else if (context->decoder->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE && u_reduce_video_profile(context->templat.profile) == PIPE_VIDEO_FORMAT_HEVC) context->desc.h265enc.frame_num++; mtx_unlock(&drv->mutex); return VA_STATUS_SUCCESS; }
VAStatus vlVaRenderPicture(VADriverContextP ctx, VAContextID context_id, VABufferID *buffers, int num_buffers) { vlVaDriver *drv; vlVaContext *context; VAStatus vaStatus = VA_STATUS_SUCCESS; unsigned i; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; mtx_lock(&drv->mutex); context = handle_table_get(drv->htab, context_id); if (!context) { mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_INVALID_CONTEXT; } for (i = 0; i < num_buffers; ++i) { vlVaBuffer *buf = handle_table_get(drv->htab, buffers[i]); if (!buf) { mtx_unlock(&drv->mutex); return VA_STATUS_ERROR_INVALID_BUFFER; } switch (buf->type) { case VAPictureParameterBufferType: vaStatus = handlePictureParameterBuffer(drv, context, buf); break; case VAIQMatrixBufferType: handleIQMatrixBuffer(context, buf); break; case VASliceParameterBufferType: handleSliceParameterBuffer(context, buf); break; case VASliceDataBufferType: handleVASliceDataBufferType(context, buf); break; case VAProcPipelineParameterBufferType: vaStatus = vlVaHandleVAProcPipelineParameterBufferType(drv, context, buf); break; case VAEncSequenceParameterBufferType: vaStatus = handleVAEncSequenceParameterBufferType(drv, context, buf); break; case VAEncMiscParameterBufferType: vaStatus = handleVAEncMiscParameterBufferType(context, buf); break; case VAEncPictureParameterBufferType: vaStatus = handleVAEncPictureParameterBufferType(drv, context, buf); break; case VAEncSliceParameterBufferType: vaStatus = handleVAEncSliceParameterBufferType(drv, context, buf); break; case VAHuffmanTableBufferType: vlVaHandleHuffmanTableBufferType(context, buf); break; default: break; } } mtx_unlock(&drv->mutex); return vaStatus; }
VAStatus vlVaCreateContext(VADriverContextP ctx, VAConfigID config_id, int picture_width, int picture_height, int flag, VASurfaceID *render_targets, int num_render_targets, VAContextID *context_id) { vlVaDriver *drv; vlVaContext *context; vlVaConfig *config; int is_vpp; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; drv = VL_VA_DRIVER(ctx); pipe_mutex_lock(drv->mutex); config = handle_table_get(drv->htab, config_id); pipe_mutex_unlock(drv->mutex); is_vpp = config->profile == PIPE_VIDEO_PROFILE_UNKNOWN && !picture_width && !picture_height && !flag && !render_targets && !num_render_targets; if (!(picture_width && picture_height) && !is_vpp) return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT; context = CALLOC(1, sizeof(vlVaContext)); if (!context) return VA_STATUS_ERROR_ALLOCATION_FAILED; if (is_vpp) { context->decoder = NULL; } else { context->templat.profile = config->profile; context->templat.entrypoint = config->entrypoint; context->templat.chroma_format = PIPE_VIDEO_CHROMA_FORMAT_420; context->templat.width = picture_width; context->templat.height = picture_height; context->templat.expect_chunked_decode = true; switch (u_reduce_video_profile(context->templat.profile)) { case PIPE_VIDEO_FORMAT_MPEG12: case PIPE_VIDEO_FORMAT_VC1: case PIPE_VIDEO_FORMAT_MPEG4: context->templat.max_references = 2; break; case PIPE_VIDEO_FORMAT_MPEG4_AVC: context->templat.max_references = 0; if (config->entrypoint != PIPE_VIDEO_ENTRYPOINT_ENCODE) { context->desc.h264.pps = CALLOC_STRUCT(pipe_h264_pps); if (!context->desc.h264.pps) { FREE(context); return VA_STATUS_ERROR_ALLOCATION_FAILED; } context->desc.h264.pps->sps = CALLOC_STRUCT(pipe_h264_sps); if (!context->desc.h264.pps->sps) { FREE(context->desc.h264.pps); FREE(context); return VA_STATUS_ERROR_ALLOCATION_FAILED; } } break; case PIPE_VIDEO_FORMAT_HEVC: context->templat.max_references = num_render_targets; context->desc.h265.pps = CALLOC_STRUCT(pipe_h265_pps); if (!context->desc.h265.pps) { FREE(context); return VA_STATUS_ERROR_ALLOCATION_FAILED; } context->desc.h265.pps->sps = CALLOC_STRUCT(pipe_h265_sps); if (!context->desc.h265.pps->sps) { FREE(context->desc.h265.pps); FREE(context); return VA_STATUS_ERROR_ALLOCATION_FAILED; } break; default: break; } } context->desc.base.profile = config->profile; context->desc.base.entry_point = config->entrypoint; if (config->entrypoint == PIPE_VIDEO_ENTRYPOINT_ENCODE) context->desc.h264enc.rate_ctrl.rate_ctrl_method = config->rc; pipe_mutex_lock(drv->mutex); *context_id = handle_table_add(drv->htab, context); pipe_mutex_unlock(drv->mutex); return VA_STATUS_SUCCESS; }
VAStatus vlVaCreateSurfaces2(VADriverContextP ctx, unsigned int format, unsigned int width, unsigned int height, VASurfaceID *surfaces, unsigned int num_surfaces, VASurfaceAttrib *attrib_list, unsigned int num_attribs) { vlVaDriver *drv; VASurfaceAttribExternalBuffers *memory_attibute; struct pipe_video_buffer templat; struct pipe_screen *pscreen; int i; int memory_type; int expected_fourcc; VAStatus vaStatus; if (!ctx) return VA_STATUS_ERROR_INVALID_CONTEXT; if (!(width && height)) return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT; drv = VL_VA_DRIVER(ctx); if (!drv) return VA_STATUS_ERROR_INVALID_CONTEXT; pscreen = VL_VA_PSCREEN(ctx); if (!pscreen) return VA_STATUS_ERROR_INVALID_CONTEXT; /* Default. */ memory_attibute = NULL; memory_type = VA_SURFACE_ATTRIB_MEM_TYPE_VA; expected_fourcc = 0; for (i = 0; i < num_attribs && attrib_list; i++) { if ((attrib_list[i].type == VASurfaceAttribPixelFormat) && (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) { if (attrib_list[i].value.type != VAGenericValueTypeInteger) return VA_STATUS_ERROR_INVALID_PARAMETER; expected_fourcc = attrib_list[i].value.value.i; } if ((attrib_list[i].type == VASurfaceAttribMemoryType) && (attrib_list[i].flags & VA_SURFACE_ATTRIB_SETTABLE)) { if (attrib_list[i].value.type != VAGenericValueTypeInteger) return VA_STATUS_ERROR_INVALID_PARAMETER; switch (attrib_list[i].value.value.i) { case VA_SURFACE_ATTRIB_MEM_TYPE_VA: case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: memory_type = attrib_list[i].value.value.i; break; default: return VA_STATUS_ERROR_UNSUPPORTED_MEMORY_TYPE; } } if ((attrib_list[i].type == VASurfaceAttribExternalBufferDescriptor) && (attrib_list[i].flags == VA_SURFACE_ATTRIB_SETTABLE)) { if (attrib_list[i].value.type != VAGenericValueTypePointer) return VA_STATUS_ERROR_INVALID_PARAMETER; memory_attibute = (VASurfaceAttribExternalBuffers *)attrib_list[i].value.value.p; } } if (VA_RT_FORMAT_YUV420 != format && VA_RT_FORMAT_YUV422 != format && VA_RT_FORMAT_YUV444 != format && VA_RT_FORMAT_RGB32 != format) { return VA_STATUS_ERROR_UNSUPPORTED_RT_FORMAT; } switch (memory_type) { case VA_SURFACE_ATTRIB_MEM_TYPE_VA: break; case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: if (!memory_attibute) return VA_STATUS_ERROR_INVALID_PARAMETER; expected_fourcc = memory_attibute->pixel_format; break; default: assert(0); } memset(&templat, 0, sizeof(templat)); if (expected_fourcc) { templat.buffer_format = VaFourccToPipeFormat(expected_fourcc); templat.interlaced = 0; } else { templat.buffer_format = pscreen->get_video_param ( pscreen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_PREFERED_FORMAT ); templat.interlaced = pscreen->get_video_param ( pscreen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_BITSTREAM, PIPE_VIDEO_CAP_PREFERS_INTERLACED ); } templat.chroma_format = ChromaToPipe(format); templat.width = width; templat.height = height; memset(surfaces, VA_INVALID_ID, num_surfaces * sizeof(VASurfaceID)); for (i = 0; i < num_surfaces; i++) { vlVaSurface *surf = CALLOC(1, sizeof(vlVaSurface)); if (!surf) goto no_res; surf->templat = templat; switch (memory_type) { case VA_SURFACE_ATTRIB_MEM_TYPE_VA: surf->buffer = drv->pipe->create_video_buffer(drv->pipe, &templat); if (!surf->buffer) goto no_res; util_dynarray_init(&surf->subpics); surfaces[i] = handle_table_add(drv->htab, surf); break; case VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME: vaStatus = suface_from_external_memory(ctx, surf, memory_attibute, i, surfaces, &templat); if (vaStatus != VA_STATUS_SUCCESS) goto no_res; break; default: assert(0); } } return VA_STATUS_SUCCESS; no_res: if (i) vlVaDestroySurfaces(ctx, surfaces, i); return VA_STATUS_ERROR_ALLOCATION_FAILED; }