#include <assert.h> #include <X11/Xlib.h> #include <X11/extensions/XvMC.h> #include <vl_display.h> #include <vl_screen.h> #include <vl_context.h> #include <vl_surface.h> #include <vl_types.h> static enum vlMacroBlockType TypeToVL(int xvmc_mb_type) { if (xvmc_mb_type & XVMC_MB_TYPE_INTRA) return vlMacroBlockTypeIntra; if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == XVMC_MB_TYPE_MOTION_FORWARD) return vlMacroBlockTypeFwdPredicted; if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == XVMC_MB_TYPE_MOTION_BACKWARD) return vlMacroBlockTypeBkwdPredicted; if ((xvmc_mb_type & (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) == (XVMC_MB_TYPE_MOTION_FORWARD | XVMC_MB_TYPE_MOTION_BACKWARD)) return vlMacroBlockTypeBiPredicted; assert(0); return -1; } static enum vlPictureType PictureToVL(int xvmc_pic) { switch (xvmc_pic) { case XVMC_TOP_FIELD: return vlPictureTypeTopField; case XVMC_BOTTOM_FIELD: return vlPictureTypeBottomField; case XVMC_FRAME_PICTURE: return vlPictureTypeFrame; default: assert(0); } return -1; } static enum vlMotionType MotionToVL(int xvmc_motion_type, int xvmc_dct_type) { switch (xvmc_motion_type) { case XVMC_PREDICTION_FRAME: return xvmc_dct_type == XVMC_DCT_TYPE_FIELD ? vlMotionType16x8 : vlMotionTypeFrame; case XVMC_PREDICTION_FIELD: return vlMotionTypeField; case XVMC_PREDICTION_DUAL_PRIME: return vlMotionTypeDualPrime; default: assert(0); } return -1; } Status XvMCCreateSurface(Display *display, XvMCContext *context, XvMCSurface *surface) { struct vlContext *vl_ctx; struct vlSurface *vl_sfc; assert(display); if (!context) return XvMCBadContext; if (!surface) return XvMCBadSurface; vl_ctx = context->privData; assert(display == vlGetNativeDisplay(vlGetDisplay(vlContextGetScreen(vl_ctx)))); if (vlCreateSurface(vlContextGetScreen(vl_ctx), context->width, context->height, vlGetPictureFormat(vl_ctx), &vl_sfc)) { return BadAlloc; } vlBindToContext(vl_sfc, vl_ctx); surface->surface_id = XAllocID(display); surface->context_id = context->context_id; surface->surface_type_id = context->surface_type_id; surface->width = context->width; surface->height = context->height; surface->privData = vl_sfc; return Success; } Status XvMCRenderSurface ( Display *display, 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 vlContext *vl_ctx; struct vlSurface *target_vl_surface; struct vlSurface *past_vl_surface; struct vlSurface *future_vl_surface; struct vlMpeg2MacroBlockBatch batch; struct vlMpeg2MacroBlock vl_macroblocks[num_macroblocks]; unsigned int i; assert(display); if (!context) return XvMCBadContext; if (!target_surface) return XvMCBadSurface; if ( picture_structure != XVMC_TOP_FIELD && picture_structure != XVMC_BOTTOM_FIELD && picture_structure != XVMC_FRAME_PICTURE ) return BadValue; if (future_surface && !past_surface) return BadMatch; vl_ctx = context->privData; assert(display == vlGetNativeDisplay(vlGetDisplay(vlContextGetScreen(vl_ctx)))); target_vl_surface = target_surface->privData; past_vl_surface = past_surface ? past_surface->privData : NULL; future_vl_surface = future_surface ? future_surface->privData : NULL; 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); batch.past_surface = past_vl_surface; batch.future_surface = future_vl_surface; batch.picture_type = PictureToVL(picture_structure); batch.field_order = flags & XVMC_SECOND_FIELD ? vlFieldOrderSecond : vlFieldOrderFirst; batch.num_macroblocks = num_macroblocks; batch.macroblocks = vl_macroblocks; for (i = 0; i < num_macroblocks; ++i) { unsigned int j = first_macroblock + i; unsigned int k, l, m; batch.macroblocks[i].mbx = macroblocks->macro_blocks[j].x; batch.macroblocks[i].mby = macroblocks->macro_blocks[j].y; batch.macroblocks[i].mb_type = TypeToVL(macroblocks->macro_blocks[j].macroblock_type); if (batch.macroblocks[i].mb_type != vlMacroBlockTypeIntra) batch.macroblocks[i].mo_type = MotionToVL(macroblocks->macro_blocks[j].motion_type, macroblocks->macro_blocks[j].dct_type); batch.macroblocks[i].dct_type = macroblocks->macro_blocks[j].dct_type == XVMC_DCT_TYPE_FIELD ? vlDCTTypeFieldCoded : vlDCTTypeFrameCoded; for (k = 0; k < 2; ++k) for (l = 0; l < 2; ++l) for (m = 0; m < 2; ++m) batch.macroblocks[i].PMV[k][l][m] = macroblocks->macro_blocks[j].PMV[k][l][m]; batch.macroblocks[i].cbp = macroblocks->macro_blocks[j].coded_block_pattern; batch.macroblocks[i].blocks = blocks->blocks + (macroblocks->macro_blocks[j].index * 64); } vlRenderMacroBlocksMpeg2(&batch, target_vl_surface); return Success; } Status XvMCFlushSurface(Display *display, XvMCSurface *surface) { struct vlSurface *vl_sfc; assert(display); if (!surface) return XvMCBadSurface; vl_sfc = surface->privData; assert(display == vlGetNativeDisplay(vlGetDisplay(vlSurfaceGetScreen(vl_sfc)))); vlSurfaceFlush(vl_sfc); return Success; } Status XvMCSyncSurface(Display *display, XvMCSurface *surface) { struct vlSurface *vl_sfc; assert(display); if (!surface) return XvMCBadSurface; vl_sfc = surface->privData; assert(display == vlGetNativeDisplay(vlGetDisplay(vlSurfaceGetScreen(vl_sfc)))); vlSurfaceSync(vl_sfc); return Success; } Status XvMCPutSurface ( Display *display, 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 ) { Window root; int x, y; unsigned int width, height; unsigned int border_width; unsigned int depth; struct vlSurface *vl_sfc; assert(display); if (!surface) return XvMCBadSurface; if (XGetGeometry(display, drawable, &root, &x, &y, &width, &height, &border_width, &depth) == BadDrawable) return BadDrawable; assert(flags == XVMC_TOP_FIELD || flags == XVMC_BOTTOM_FIELD || flags == XVMC_FRAME_PICTURE); /* TODO: Correct for negative srcx,srcy & destx,desty by clipping */ assert(srcx + srcw - 1 < surface->width); assert(srcy + srch - 1 < surface->height); /* XXX: 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 will be clipped * for a few frames until the app updates destw and desth. */ /*assert(destx + destw - 1 < width); assert(desty + desth - 1 < height);*/ vl_sfc = surface->privData; vlPutPicture(vl_sfc, drawable, srcx, srcy, srcw, srch, destx, desty, destw, desth, width, height, PictureToVL(flags)); return Success; } Status XvMCGetSurfaceStatus(Display *display, XvMCSurface *surface, int *status) { struct vlSurface *vl_sfc; enum vlResourceStatus res_status; assert(display); if (!surface) return XvMCBadSurface; assert(status); vl_sfc = surface->privData; assert(display == vlGetNativeDisplay(vlGetDisplay(vlSurfaceGetScreen(vl_sfc)))); vlSurfaceGetStatus(vl_sfc, &res_status); switch (res_status) { case vlResourceStatusFree: { *status = 0; break; } case vlResourceStatusRendering: { *status = XVMC_RENDERING; break; } case vlResourceStatusDisplaying: { *status = XVMC_DISPLAYING; break; } default: assert(0); } return Success; } Status XvMCDestroySurface(Display *display, XvMCSurface *surface) { struct vlSurface *vl_sfc; assert(display); if (!surface) return XvMCBadSurface; vl_sfc = surface->privData; assert(display == vlGetNativeDisplay(vlGetDisplay(vlSurfaceGetScreen(vl_sfc)))); vlDestroySurface(vl_sfc); return Success; } Status XvMCHideSurface(Display *display, XvMCSurface *surface) { struct vlSurface *vl_sfc; assert(display); if (!surface) return XvMCBadSurface; vl_sfc = surface->privData; assert(display == vlGetNativeDisplay(vlGetDisplay(vlSurfaceGetScreen(vl_sfc)))); /* No op, only for overlaid rendering */ return Success; }