diff options
Diffstat (limited to 'src/xvmc/surface.c')
-rw-r--r-- | src/xvmc/surface.c | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/src/xvmc/surface.c b/src/xvmc/surface.c new file mode 100644 index 00000000000..7c5f45bd346 --- /dev/null +++ b/src/xvmc/surface.c @@ -0,0 +1,355 @@ +#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; +} |