PUBLIC Status XvMCSetSubpicturePalette(Display *dpy, XvMCSubpicture *subpicture, unsigned char *palette) { XvMCSubpicturePrivate *subpicture_priv; XvMCContextPrivate *context_priv; struct pipe_context *pipe; struct pipe_box dst_box = {0, 0, 0, 0, 1, 1}; assert(dpy); assert(palette); if (!subpicture) return XvMCBadSubpicture; subpicture_priv = subpicture->privData; context_priv = subpicture_priv->context->privData; pipe = context_priv->pipe; dst_box.width = subpicture->num_palette_entries; upload_sampler(pipe, subpicture_priv->palette, &dst_box, palette, 0, 0, 0); XVMC_MSG(XVMC_TRACE, "[XvMC] Palette of Subpicture %p set.\n", subpicture); return Success; }
static int PipeToComponentOrder(enum pipe_format format, char *component_order) { assert(component_order); switch (format) { case PIPE_FORMAT_B8G8R8X8_UNORM: return 0; case PIPE_FORMAT_R4A4_UNORM: case PIPE_FORMAT_A4R4_UNORM: component_order[0] = 'Y'; component_order[1] = 'U'; component_order[2] = 'V'; component_order[3] = 'A'; return 4; default: XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized PIPE_FORMAT 0x%08X.\n", format); component_order[0] = 0; component_order[1] = 0; component_order[2] = 0; component_order[3] = 0; return 0; } }
PUBLIC Status XvMCGetAttribute(Display *dpy, XvMCContext *context, Atom attribute, int *value) { XvMCContextPrivate *context_priv; const char *attr; assert(dpy); if (!context || !context->privData) return XvMCBadContext; context_priv = context->privData; attr = XGetAtomName(dpy, attribute); if (!attr) return XvMCBadContext; if (strcmp(attr, XV_BRIGHTNESS)) *value = context_priv->procamp.brightness * 1000; else if (strcmp(attr, XV_CONTRAST)) *value = context_priv->procamp.contrast * 1000 - 1000; else if (strcmp(attr, XV_SATURATION)) *value = context_priv->procamp.saturation * 1000 + 1000; else if (strcmp(attr, XV_HUE)) *value = context_priv->procamp.hue * 1000; else if (strcmp(attr, XV_COLORSPACE)) *value = context_priv->color_standard == VL_CSC_COLOR_STANDARD_BT_709; else return BadName; XVMC_MSG(XVMC_TRACE, "[XvMC] Got value %d for attribute %s.\n", *value, attr); return Success; }
PUBLIC Status XvMCDestroySubpicture(Display *dpy, XvMCSubpicture *subpicture) { XvMCSubpicturePrivate *subpicture_priv; XVMC_MSG(XVMC_TRACE, "[XvMC] Destroying subpicture %p.\n", subpicture); assert(dpy); if (!subpicture) return XvMCBadSubpicture; subpicture_priv = subpicture->privData; pipe_sampler_view_reference(&subpicture_priv->sampler, NULL); pipe_sampler_view_reference(&subpicture_priv->palette, NULL); FREE(subpicture_priv); XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p destroyed.\n", subpicture); return Success; }
PUBLIC Status XvMCSyncSurface(Display *dpy, XvMCSurface *surface) { assert(dpy); if (!surface) return XvMCBadSurface; XVMC_MSG(XVMC_TRACE, "[XvMC] Syncing surface %p\n", surface); return Success; }
PUBLIC Status XvMCCompositeSubpicture(Display *dpy, XvMCSubpicture *subpicture, XvImage *image, short srcx, short srcy, unsigned short width, unsigned short height, short dstx, short dsty) { XvMCSubpicturePrivate *subpicture_priv; XvMCContextPrivate *context_priv; struct pipe_context *pipe; struct pipe_box dst_box = {dstx, dsty, 0, width, height, 1}; unsigned src_stride; XVMC_MSG(XVMC_TRACE, "[XvMC] Compositing subpicture %p.\n", subpicture); assert(dpy); if (!subpicture) return XvMCBadSubpicture; assert(image); if (subpicture->xvimage_id != image->id) return BadMatch; /* No planar support for now */ if (image->num_planes != 1) return BadMatch; subpicture_priv = subpicture->privData; context_priv = subpicture_priv->context->privData; pipe = context_priv->pipe; /* clipping should be done by upload_sampler and regardles what the documentation says image->pitches[0] doesn't seems to be in bytes, so don't use it */ src_stride = image->width * util_format_get_blocksize(subpicture_priv->sampler->texture->format); upload_sampler(pipe, subpicture_priv->sampler, &dst_box, image->data, src_stride, srcx, srcy); XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p composited.\n", subpicture); return Success; }
static unsigned NumPaletteEntries4XvID(int xvimage_id) { switch (xvimage_id) { case FOURCC_RGB: return 0; case FOURCC_AI44: case FOURCC_IA44: return 16; default: XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id); return 0; } }
PUBLIC Status XvMCFlushSurface(Display *dpy, XvMCSurface *surface) { assert(dpy); if (!surface) return XvMCBadSurface; // don't call flush here, because this is usually // called once for every slice instead of every frame XVMC_MSG(XVMC_TRACE, "[XvMC] Flushing surface %p\n", surface); return Success; }
static enum pipe_video_chroma_format FormatToPipe(int xvmc_format) { switch (xvmc_format) { case XVMC_CHROMA_FORMAT_420: return PIPE_VIDEO_CHROMA_FORMAT_420; case XVMC_CHROMA_FORMAT_422: return PIPE_VIDEO_CHROMA_FORMAT_422; case XVMC_CHROMA_FORMAT_444: return PIPE_VIDEO_CHROMA_FORMAT_444; default: assert(0); } XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized format 0x%08X.\n", xvmc_format); return -1; }
static enum pipe_format XvIDToPipe(int xvimage_id) { switch (xvimage_id) { case FOURCC_RGB: return PIPE_FORMAT_B8G8R8X8_UNORM; case FOURCC_AI44: return PIPE_FORMAT_R4A4_UNORM; case FOURCC_IA44: return PIPE_FORMAT_A4R4_UNORM; default: XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized Xv image ID 0x%08X.\n", xvimage_id); return PIPE_FORMAT_NONE; } }
static enum pipe_video_profile ProfileToPipe(int xvmc_profile) { if (xvmc_profile & XVMC_MPEG_1) assert(0); if (xvmc_profile & XVMC_MPEG_2) return PIPE_VIDEO_PROFILE_MPEG2_MAIN; if (xvmc_profile & XVMC_H263) assert(0); if (xvmc_profile & XVMC_MPEG_4) assert(0); assert(0); XVMC_MSG(XVMC_ERR, "[XvMC] Unrecognized profile 0x%08X.\n", xvmc_profile); return -1; }
PUBLIC Status XvMCSetAttribute(Display *dpy, XvMCContext *context, Atom attribute, int value) { XvMCContextPrivate *context_priv; const char *attr; vl_csc_matrix csc; assert(dpy); if (!context || !context->privData) return XvMCBadContext; context_priv = context->privData; attr = XGetAtomName(dpy, attribute); if (!attr) return XvMCBadContext; if (strcmp(attr, XV_BRIGHTNESS)) context_priv->procamp.brightness = value / 1000.0f; else if (strcmp(attr, XV_CONTRAST)) context_priv->procamp.contrast = value / 1000.0f + 1.0f; else if (strcmp(attr, XV_SATURATION)) context_priv->procamp.saturation = value / 1000.0f + 1.0f; else if (strcmp(attr, XV_HUE)) context_priv->procamp.hue = value / 1000.0f; else if (strcmp(attr, XV_COLORSPACE)) context_priv->color_standard = value ? VL_CSC_COLOR_STANDARD_BT_601 : VL_CSC_COLOR_STANDARD_BT_709; else return BadName; vl_csc_get_matrix ( context_priv->color_standard, &context_priv->procamp, true, &csc ); vl_compositor_set_csc_matrix(&context_priv->cstate, (const vl_csc_matrix *)&csc); XVMC_MSG(XVMC_TRACE, "[XvMC] Set attribute %s to value %d.\n", attr, value); return Success; }
PUBLIC XvAttribute* XvMCQueryAttributes(Display *dpy, XvMCContext *context, int *number) { XvAttribute *result; assert(dpy && number); if (!context || !context->privData) return NULL; result = malloc(sizeof(attributes)); if (!result) return NULL; memcpy(result, attributes, sizeof(attributes)); *number = sizeof(attributes) / sizeof(XvAttribute); XVMC_MSG(XVMC_TRACE, "[XvMC] Returning %d attributes for context %p.\n", *number, context); return result; }
PUBLIC Status XvMCBlendSubpicture(Display *dpy, XvMCSurface *target_surface, XvMCSubpicture *subpicture, short subx, short suby, unsigned short subw, unsigned short subh, short surfx, short surfy, unsigned short surfw, unsigned short surfh) { struct u_rect src_rect = {subx, subx + subw, suby, suby + subh}; struct u_rect dst_rect = {surfx, surfx + surfw, surfy, surfy + surfh}; XvMCSurfacePrivate *surface_priv; XvMCSubpicturePrivate *subpicture_priv; XVMC_MSG(XVMC_TRACE, "[XvMC] Associating subpicture %p with surface %p.\n", subpicture, target_surface); assert(dpy); if (!target_surface) return XvMCBadSurface; if (!subpicture) return XvMCBadSubpicture; if (target_surface->context_id != subpicture->context_id) return BadMatch; /* TODO: Verify against subpicture independent scaling */ surface_priv = target_surface->privData; subpicture_priv = subpicture->privData; /* TODO: Assert rects are within bounds? Or clip? */ subpicture_priv->src_rect = src_rect; subpicture_priv->dst_rect = dst_rect; surface_priv->subpicture = subpicture; subpicture_priv->surface = target_surface; return Success; }
PUBLIC Status XvMCPutSurface(Display *dpy, XvMCSurface *surface, Drawable drawable, short srcx, short srcy, unsigned short srcw, unsigned short srch, short destx, short desty, unsigned short destw, unsigned short desth, int flags) { static int dump_window = -1; struct pipe_context *pipe; struct vl_compositor *compositor; struct vl_compositor_state *cstate; struct vl_screen *vscreen; XvMCSurfacePrivate *surface_priv; XvMCContextPrivate *context_priv; XvMCSubpicturePrivate *subpicture_priv; XvMCContext *context; struct u_rect src_rect = {srcx, srcx + srcw, srcy, srcy + srch}; struct u_rect dst_rect = {destx, destx + destw, desty, desty + desth}; struct pipe_resource *tex; struct pipe_surface surf_templ, *surf; struct u_rect *dirty_area; XVMC_MSG(XVMC_TRACE, "[XvMC] Displaying surface %p.\n", surface); assert(dpy); if (!surface || !surface->privData) return XvMCBadSurface; surface_priv = surface->privData; context = surface_priv->context; context_priv = context->privData; assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE); assert(srcx + srcw - 1 < surface->width); assert(srcy + srch - 1 < surface->height); subpicture_priv = surface_priv->subpicture ? surface_priv->subpicture->privData : NULL; pipe = context_priv->pipe; compositor = &context_priv->compositor; cstate = &context_priv->cstate; vscreen = context_priv->vscreen; tex = vscreen->texture_from_drawable(vscreen, (void *)drawable); dirty_area = vscreen->get_dirty_area(vscreen); memset(&surf_templ, 0, sizeof(surf_templ)); surf_templ.format = tex->format; surf = pipe->create_surface(pipe, tex, &surf_templ); if (!surf) return BadDrawable; /* * Some apps (mplayer) hit these asserts because they call * this function after the window has been resized by the WM * but before they've handled the corresponding XEvent and * know about the new dimensions. The output should be clipped * until the app updates destw and desth. */ /* assert(destx + destw - 1 < drawable_surface->width); assert(desty + desth - 1 < drawable_surface->height); */ RecursiveEndFrame(surface_priv); context_priv->decoder->flush(context_priv->decoder); vl_compositor_clear_layers(cstate); vl_compositor_set_buffer_layer(cstate, compositor, 0, surface_priv->video_buffer, &src_rect, NULL, VL_COMPOSITOR_WEAVE); if (subpicture_priv) { XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p has subpicture %p.\n", surface, surface_priv->subpicture); assert(subpicture_priv->surface == surface); if (subpicture_priv->palette) vl_compositor_set_palette_layer(cstate, compositor, 1, subpicture_priv->sampler, subpicture_priv->palette, &subpicture_priv->src_rect, &subpicture_priv->dst_rect, true); else vl_compositor_set_rgba_layer(cstate, compositor, 1, subpicture_priv->sampler, &subpicture_priv->src_rect, &subpicture_priv->dst_rect, NULL); surface_priv->subpicture = NULL; subpicture_priv->surface = NULL; } // Workaround for r600g, there seems to be a bug in the fence refcounting code pipe->screen->fence_reference(pipe->screen, &surface_priv->fence, NULL); vl_compositor_set_layer_dst_area(cstate, 0, &dst_rect); vl_compositor_set_layer_dst_area(cstate, 1, &dst_rect); vl_compositor_render(cstate, compositor, surf, dirty_area, true); pipe->flush(pipe, &surface_priv->fence, 0); XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for display. Pushing to front buffer.\n", surface); pipe->screen->flush_frontbuffer(pipe->screen, tex, 0, 0, vscreen->get_private(vscreen), NULL); if(dump_window == -1) { dump_window = debug_get_num_option("XVMC_DUMP", 0); } if(dump_window) { static unsigned int framenum = 0; char cmd[256]; sprintf(cmd, "xwd -id %d -out xvmc_frame_%08d.xwd", (int)drawable, ++framenum); if (system(cmd) != 0) XVMC_MSG(XVMC_ERR, "[XvMC] Dumping surface %p failed.\n", surface); } XVMC_MSG(XVMC_TRACE, "[XvMC] Pushed surface %p to front buffer.\n", surface); return Success; }
PUBLIC Status XvMCCreateSubpicture(Display *dpy, XvMCContext *context, XvMCSubpicture *subpicture, unsigned short width, unsigned short height, int xvimage_id) { XvMCContextPrivate *context_priv; XvMCSubpicturePrivate *subpicture_priv; struct pipe_context *pipe; struct pipe_resource tex_templ, *tex; struct pipe_sampler_view sampler_templ; Status ret; XVMC_MSG(XVMC_TRACE, "[XvMC] Creating subpicture %p.\n", subpicture); assert(dpy); if (!context) return XvMCBadContext; context_priv = context->privData; pipe = context_priv->pipe; if (!subpicture) return XvMCBadSubpicture; if (width > context_priv->subpicture_max_width || height > context_priv->subpicture_max_height) return BadValue; ret = Validate(dpy, context->port, context->surface_type_id, xvimage_id); if (ret != Success) return ret; subpicture_priv = CALLOC(1, sizeof(XvMCSubpicturePrivate)); if (!subpicture_priv) return BadAlloc; memset(&tex_templ, 0, sizeof(tex_templ)); tex_templ.target = PIPE_TEXTURE_2D; tex_templ.format = XvIDToPipe(xvimage_id); tex_templ.last_level = 0; if (pipe->screen->get_video_param(pipe->screen, PIPE_VIDEO_PROFILE_UNKNOWN, PIPE_VIDEO_ENTRYPOINT_UNKNOWN, PIPE_VIDEO_CAP_NPOT_TEXTURES)) { tex_templ.width0 = width; tex_templ.height0 = height; } else { tex_templ.width0 = util_next_power_of_two(width); tex_templ.height0 = util_next_power_of_two(height); } tex_templ.depth0 = 1; tex_templ.array_size = 1; tex_templ.usage = PIPE_USAGE_DYNAMIC; tex_templ.bind = PIPE_BIND_SAMPLER_VIEW; tex_templ.flags = 0; tex = pipe->screen->resource_create(pipe->screen, &tex_templ); memset(&sampler_templ, 0, sizeof(sampler_templ)); u_sampler_view_default_template(&sampler_templ, tex, tex->format); subpicture_priv->sampler = pipe->create_sampler_view(pipe, tex, &sampler_templ); pipe_resource_reference(&tex, NULL); if (!subpicture_priv->sampler) { FREE(subpicture_priv); return BadAlloc; } subpicture_priv->context = context; subpicture->subpicture_id = XAllocID(dpy); subpicture->context_id = context->context_id; subpicture->xvimage_id = xvimage_id; subpicture->width = width; subpicture->height = height; subpicture->num_palette_entries = NumPaletteEntries4XvID(xvimage_id); subpicture->entry_bytes = PipeToComponentOrder(tex_templ.format, subpicture->component_order); subpicture->privData = subpicture_priv; if (subpicture->num_palette_entries > 0) { tex_templ.target = PIPE_TEXTURE_1D; tex_templ.format = PIPE_FORMAT_R8G8B8X8_UNORM; tex_templ.width0 = subpicture->num_palette_entries; tex_templ.height0 = 1; tex_templ.usage = PIPE_USAGE_DEFAULT; tex = pipe->screen->resource_create(pipe->screen, &tex_templ); memset(&sampler_templ, 0, sizeof(sampler_templ)); u_sampler_view_default_template(&sampler_templ, tex, tex->format); sampler_templ.swizzle_a = PIPE_SWIZZLE_ONE; subpicture_priv->palette = pipe->create_sampler_view(pipe, tex, &sampler_templ); pipe_resource_reference(&tex, NULL); if (!subpicture_priv->sampler) { FREE(subpicture_priv); return BadAlloc; } } SyncHandle(); XVMC_MSG(XVMC_TRACE, "[XvMC] Subpicture %p created.\n", subpicture); return Success; }
PUBLIC Status XvMCRenderSurface(Display *dpy, XvMCContext *context, unsigned int picture_structure, XvMCSurface *target_surface, XvMCSurface *past_surface, XvMCSurface *future_surface, unsigned int flags, unsigned int num_macroblocks, unsigned int first_macroblock, XvMCMacroBlockArray *macroblocks, XvMCBlockArray *blocks ) { struct pipe_mpeg12_macroblock mb[num_macroblocks]; struct pipe_video_codec *decoder; struct pipe_mpeg12_picture_desc desc; XvMCContextPrivate *context_priv; XvMCSurfacePrivate *target_surface_priv; XvMCSurfacePrivate *past_surface_priv; XvMCSurfacePrivate *future_surface_priv; XvMCMacroBlock *xvmc_mb; XVMC_MSG(XVMC_TRACE, "[XvMC] Rendering to surface %p, with past %p and future %p\n", target_surface, past_surface, future_surface); assert(dpy); if (!context || !context->privData) return XvMCBadContext; if (!target_surface || !target_surface->privData) return XvMCBadSurface; if (picture_structure != XVMC_TOP_FIELD && picture_structure != XVMC_BOTTOM_FIELD && picture_structure != XVMC_FRAME_PICTURE) return BadValue; /* Bkwd pred equivalent to fwd (past && !future) */ if (future_surface && !past_surface) return BadMatch; assert(context->context_id == target_surface->context_id); assert(!past_surface || context->context_id == past_surface->context_id); assert(!future_surface || context->context_id == future_surface->context_id); assert(macroblocks); assert(blocks); assert(macroblocks->context_id == context->context_id); assert(blocks->context_id == context->context_id); assert(flags == 0 || flags == XVMC_SECOND_FIELD); context_priv = context->privData; decoder = context_priv->decoder; target_surface_priv = target_surface->privData; past_surface_priv = past_surface ? past_surface->privData : NULL; future_surface_priv = future_surface ? future_surface->privData : NULL; assert(target_surface_priv->context == context); assert(!past_surface || past_surface_priv->context == context); assert(!future_surface || future_surface_priv->context == context); // call end frame on all referenced frames if (past_surface) RecursiveEndFrame(past_surface->privData); if (future_surface) RecursiveEndFrame(future_surface->privData); xvmc_mb = macroblocks->macro_blocks + first_macroblock; /* If the surface we're rendering hasn't changed the ref frames shouldn't change. */ if (target_surface_priv->picture_structure > 0 && ( target_surface_priv->picture_structure != picture_structure || target_surface_priv->ref[0] != past_surface || target_surface_priv->ref[1] != future_surface || (xvmc_mb->x == 0 && xvmc_mb->y == 0))) { // If they change anyway we must assume that the current frame is ended RecursiveEndFrame(target_surface_priv); } target_surface_priv->ref[0] = past_surface; target_surface_priv->ref[1] = future_surface; if (target_surface_priv->picture_structure) GetPictureDescription(target_surface_priv, &desc); else { target_surface_priv->picture_structure = picture_structure; GetPictureDescription(target_surface_priv, &desc); decoder->begin_frame(decoder, target_surface_priv->video_buffer, &desc.base); } MacroBlocksToPipe(context_priv, target_surface_priv, picture_structure, xvmc_mb, blocks, mb, num_macroblocks); context_priv->decoder->decode_macroblock(context_priv->decoder, target_surface_priv->video_buffer, &desc.base, &mb[0].base, num_macroblocks); XVMC_MSG(XVMC_TRACE, "[XvMC] Submitted surface %p for rendering.\n", target_surface); return Success; }
PUBLIC Status XvMCCreateSurface(Display *dpy, XvMCContext *context, XvMCSurface *surface) { XvMCContextPrivate *context_priv; struct pipe_context *pipe; XvMCSurfacePrivate *surface_priv; struct pipe_video_buffer tmpl; XVMC_MSG(XVMC_TRACE, "[XvMC] Creating surface %p.\n", surface); assert(dpy); if (!context) return XvMCBadContext; if (!surface) return XvMCBadSurface; context_priv = context->privData; pipe = context_priv->pipe; surface_priv = CALLOC(1, sizeof(XvMCSurfacePrivate)); if (!surface_priv) return BadAlloc; memset(&tmpl, 0, sizeof(tmpl)); tmpl.buffer_format = pipe->screen->get_video_param ( pipe->screen, context_priv->decoder->profile, context_priv->decoder->entrypoint, PIPE_VIDEO_CAP_PREFERED_FORMAT ); tmpl.chroma_format = context_priv->decoder->chroma_format; tmpl.width = context_priv->decoder->width; tmpl.height = context_priv->decoder->height; tmpl.interlaced = pipe->screen->get_video_param ( pipe->screen, context_priv->decoder->profile, context_priv->decoder->entrypoint, PIPE_VIDEO_CAP_PREFERS_INTERLACED ); surface_priv->video_buffer = pipe->create_video_buffer(pipe, &tmpl); if (!surface_priv->video_buffer) { FREE(surface_priv); return BadAlloc; } surface_priv->context = context; surface->surface_id = XAllocID(dpy); surface->context_id = context->context_id; surface->surface_type_id = context->surface_type_id; surface->width = context->width; surface->height = context->height; surface->privData = surface_priv; SyncHandle(); XVMC_MSG(XVMC_TRACE, "[XvMC] Surface %p created.\n", surface); return Success; }
static Status Validate(Display *dpy, XvPortID port, int surface_type_id, unsigned int width, unsigned int height, int flags, bool *found_port, int *screen, int *chroma_format, int *mc_type, int *surface_flags, unsigned short *subpic_max_w, unsigned short *subpic_max_h) { bool found_surface = false; XvAdaptorInfo *adaptor_info; unsigned int num_adaptors; int num_types; unsigned int max_width = 0, max_height = 0; Status ret; assert(dpy); assert(found_port); assert(screen); assert(chroma_format); assert(mc_type); assert(surface_flags); assert(subpic_max_w); assert(subpic_max_h); *found_port = false; for (int i = 0; i < XScreenCount(dpy); ++i) { ret = XvQueryAdaptors(dpy, XRootWindow(dpy, i), &num_adaptors, &adaptor_info); if (ret != Success) return ret; for (unsigned int j = 0; j < num_adaptors && !*found_port; ++j) { for (unsigned int k = 0; k < adaptor_info[j].num_ports && !*found_port; ++k) { XvMCSurfaceInfo *surface_info; if (adaptor_info[j].base_id + k != port) continue; *found_port = true; surface_info = XvMCListSurfaceTypes(dpy, adaptor_info[j].base_id, &num_types); if (!surface_info) { XvFreeAdaptorInfo(adaptor_info); return BadAlloc; } for (int l = 0; l < num_types && !found_surface; ++l) { if (surface_info[l].surface_type_id != surface_type_id) continue; found_surface = true; max_width = surface_info[l].max_width; max_height = surface_info[l].max_height; *chroma_format = surface_info[l].chroma_format; *mc_type = surface_info[l].mc_type; *surface_flags = surface_info[l].flags; *subpic_max_w = surface_info[l].subpicture_max_width; *subpic_max_h = surface_info[l].subpicture_max_height; *screen = i; XVMC_MSG(XVMC_TRACE, "[XvMC] Found requested context surface format.\n" \ "[XvMC] screen=%u, port=%u\n" \ "[XvMC] id=0x%08X\n" \ "[XvMC] max width=%u, max height=%u\n" \ "[XvMC] chroma format=0x%08X\n" \ "[XvMC] acceleration level=0x%08X\n" \ "[XvMC] flags=0x%08X\n" \ "[XvMC] subpicture max width=%u, max height=%u\n", i, port, surface_type_id, max_width, max_height, *chroma_format, *mc_type, *surface_flags, *subpic_max_w, *subpic_max_h); } free(surface_info); } } XvFreeAdaptorInfo(adaptor_info); } if (!*found_port) { XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable port.\n"); return XvBadPort; } if (!found_surface) { XVMC_MSG(XVMC_ERR, "[XvMC] Could not find a suitable surface.\n"); return BadMatch; } if (width > max_width || height > max_height) { XVMC_MSG(XVMC_ERR, "[XvMC] Requested context dimensions (w=%u,h=%u) too large (max w=%u,h=%u).\n", width, height, max_width, max_height); return BadValue; } if (flags != XVMC_DIRECT && flags != 0) { XVMC_MSG(XVMC_ERR, "[XvMC] Invalid context flags 0x%08X.\n", flags); return BadValue; } return Success; }
PUBLIC Status XvMCCreateContext(Display *dpy, XvPortID port, int surface_type_id, int width, int height, int flags, XvMCContext *context) { bool found_port; int scrn = 0; int chroma_format = 0; int mc_type = 0; int surface_flags = 0; unsigned short subpic_max_w = 0; unsigned short subpic_max_h = 0; Status ret; struct vl_screen *vscreen; struct pipe_context *pipe; struct pipe_video_codec templat = {0}; XvMCContextPrivate *context_priv; vl_csc_matrix csc; XVMC_MSG(XVMC_TRACE, "[XvMC] Creating context %p.\n", context); assert(dpy); if (!context) return XvMCBadContext; ret = Validate(dpy, port, surface_type_id, width, height, flags, &found_port, &scrn, &chroma_format, &mc_type, &surface_flags, &subpic_max_w, &subpic_max_h); /* Success and XvBadPort have the same value */ if (ret != Success || !found_port) return ret; /* XXX: Current limits */ if (chroma_format != XVMC_CHROMA_FORMAT_420) { XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsupported chroma format.\n"); return BadImplementation; } if ((mc_type & ~XVMC_IDCT) != (XVMC_MOCOMP | XVMC_MPEG_2)) { XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Non-MPEG2/Mocomp/iDCT acceleration unsupported.\n"); return BadImplementation; } if (surface_flags & XVMC_INTRA_UNSIGNED) { XVMC_MSG(XVMC_ERR, "[XvMC] Cannot decode requested surface type. Unsigned intra unsupported.\n"); return BadImplementation; } context_priv = CALLOC(1, sizeof(XvMCContextPrivate)); if (!context_priv) return BadAlloc; /* TODO: Reuse screen if process creates another context */ vscreen = vl_screen_create(dpy, scrn); if (!vscreen) { XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL screen.\n"); FREE(context_priv); return BadAlloc; } pipe = vscreen->pscreen->context_create(vscreen->pscreen, vscreen, 0); if (!pipe) { XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL context.\n"); vl_screen_destroy(vscreen); FREE(context_priv); return BadAlloc; } templat.profile = ProfileToPipe(mc_type); templat.entrypoint = (mc_type & XVMC_IDCT) ? PIPE_VIDEO_ENTRYPOINT_IDCT : PIPE_VIDEO_ENTRYPOINT_MC; templat.chroma_format = FormatToPipe(chroma_format); templat.width = width; templat.height = height; templat.max_references = 2; templat.expect_chunked_decode = true; context_priv->decoder = pipe->create_video_codec(pipe, &templat); if (!context_priv->decoder) { XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL decoder.\n"); pipe->destroy(pipe); vl_screen_destroy(vscreen); FREE(context_priv); return BadAlloc; } if (!vl_compositor_init(&context_priv->compositor, pipe)) { XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor.\n"); context_priv->decoder->destroy(context_priv->decoder); pipe->destroy(pipe); vl_screen_destroy(vscreen); FREE(context_priv); return BadAlloc; } if (!vl_compositor_init_state(&context_priv->cstate, pipe)) { XVMC_MSG(XVMC_ERR, "[XvMC] Could not create VL compositor state.\n"); vl_compositor_cleanup(&context_priv->compositor); context_priv->decoder->destroy(context_priv->decoder); pipe->destroy(pipe); vl_screen_destroy(vscreen); FREE(context_priv); return BadAlloc; } context_priv->color_standard = debug_get_bool_option("G3DVL_NO_CSC", FALSE) ? VL_CSC_COLOR_STANDARD_IDENTITY : VL_CSC_COLOR_STANDARD_BT_601; context_priv->procamp = vl_default_procamp; vl_csc_get_matrix ( context_priv->color_standard, &context_priv->procamp, true, &csc ); vl_compositor_set_csc_matrix(&context_priv->cstate, (const vl_csc_matrix *)&csc); context_priv->vscreen = vscreen; context_priv->pipe = pipe; context_priv->subpicture_max_width = subpic_max_w; context_priv->subpicture_max_height = subpic_max_h; context->context_id = XAllocID(dpy); context->surface_type_id = surface_type_id; context->width = width; context->height = height; context->flags = flags; context->port = port; context->privData = context_priv; SyncHandle(); XVMC_MSG(XVMC_TRACE, "[XvMC] Context %p created.\n", context); return Success; }