C++程序  |  1300行  |  50.46 KB

/*
 * Copyright (c) 2011 Intel Corporation. All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Jason Hu  <jason.hu@intel.com>
 *    Zhaohan Ren  <zhaohan.ren@intel.com>
 *    Shengquan Yuan  <shengquan.yuan@intel.com>
 *
 */

#include <X11/Xutil.h>
#include <X11/extensions/Xrandr.h>
#include <va/va_backend.h>
#include "psb_output.h"
#include "psb_surface.h"
#include "psb_buffer.h"
#include "psb_x11.h"
#include "psb_drv_debug.h"

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "psb_surface_ext.h"
#include <wsbm/wsbm_manager.h>
#include "psb_drv_video.h"
#include "psb_xrandr.h"
#include <sys/types.h>

#define INIT_DRIVER_DATA    psb_driver_data_p driver_data = (psb_driver_data_p) ctx->pDriverData
#define INIT_OUTPUT_PRIV    psb_x11_output_p output = (psb_x11_output_p)(((psb_driver_data_p)ctx->pDriverData)->ws_priv)
#define SURFACE(id)     ((object_surface_p) object_heap_lookup( &driver_data->surface_heap, id ))

static int
psb_x11_getWindowCoordinate(Display * display,
                            Window x11_window_id,
                            psb_x11_win_t * psX11Window,
                            int * pbIsVisible)
{
    Window DummyWindow;
    Status status;
    XWindowAttributes sXWinAttrib;

    if ((status = XGetWindowAttributes(display,
                                       x11_window_id,
                                       &sXWinAttrib)) == 0) {
        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get X11 window coordinates - error %lu\n", __func__, (unsigned long)status);
        return -1;
    }

    psX11Window->i32Left = sXWinAttrib.x;
    psX11Window->i32Top = sXWinAttrib.y;
    psX11Window->ui32Width = sXWinAttrib.width;
    psX11Window->ui32Height = sXWinAttrib.height;
    *pbIsVisible = (sXWinAttrib.map_state == IsViewable);

    if (!*pbIsVisible)
        return 0;

    if (XTranslateCoordinates(display,
                              x11_window_id,
                              DefaultRootWindow(display),
                              0,
                              0,
                              &psX11Window->i32Left,
                              &psX11Window->i32Top,
                              &DummyWindow) == 0) {
        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to tranlate X coordinates - error %lu\n", __func__, (unsigned long)status);
        return -1;
    }

    psX11Window->i32Right  = psX11Window->i32Left + psX11Window->ui32Width - 1;
    psX11Window->i32Bottom = psX11Window->i32Top + psX11Window->ui32Height - 1;

    return 0;
}
static psb_x11_clip_list_t *
psb_x11_createClipBoxNode(psb_x11_win_t *       pRect,
                          psb_x11_clip_list_t * pClipNext)
{
    psb_x11_clip_list_t * pCurrent = NULL;

    pCurrent = (psb_x11_clip_list_t *)calloc(1, sizeof(psb_x11_clip_list_t));
    if (pCurrent) {
        pCurrent->rect = *pRect;
        pCurrent->next = pClipNext;

        return pCurrent;
    } else
        return pClipNext;
}

void
psb_x11_freeWindowClipBoxList(psb_x11_clip_list_t * pHead)
{
    psb_x11_clip_list_t * pNext = NULL;

    while (pHead) {
        pNext = pHead->next;
        free(pHead);
        pHead = pNext;
    }
}

#define IS_BETWEEN_RANGE(a,b,c) ((a<=b)&&(b<=c))

static psb_x11_clip_list_t *
psb_x11_substractRects(Display *             display,
                       psb_x11_clip_list_t * psRegion,
                       psb_x11_win_t *       psRect)
{
    psb_x11_clip_list_t * psCur, * psPrev, * psFirst, * psNext;
    psb_x11_win_t sCreateRect;
    int display_width  = (int)(DisplayWidth(display, DefaultScreen(display))) - 1;
    int display_height = (int)(DisplayHeight(display, DefaultScreen(display))) - 1;

    psFirst = psb_x11_createClipBoxNode(psRect, NULL);

    if (psFirst->rect.i32Left < 0)
        psFirst->rect.i32Left = 0;
    else if (psFirst->rect.i32Left > display_width)
        psFirst->rect.i32Left = display_width;

    if (psFirst->rect.i32Right < 0)
        psFirst->rect.i32Right = 0;
    else if (psFirst->rect.i32Right > display_width)
        psFirst->rect.i32Right = display_width;

    if (psFirst->rect.i32Top < 0)
        psFirst->rect.i32Top = 0;
    else if (psFirst->rect.i32Top > display_height)
        psFirst->rect.i32Top = display_height;

    if (psFirst->rect.i32Bottom < 0)
        psFirst->rect.i32Bottom = 0;
    else if (psFirst->rect.i32Bottom > display_height)
        psFirst->rect.i32Bottom = display_height;

    while (psRegion) {
        psCur  = psFirst;
        psPrev = NULL;

        while (psCur) {
            psNext = psCur->next;

            if ((psRegion->rect.i32Left > psCur->rect.i32Left) &&
                (psRegion->rect.i32Left <= psCur->rect.i32Right)) {
                sCreateRect.i32Right = psRegion->rect.i32Left - 1;

                sCreateRect.i32Left = psCur->rect.i32Left;
                sCreateRect.i32Top = psCur->rect.i32Top;
                sCreateRect.i32Bottom = psCur->rect.i32Bottom;

                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);

                if (!psPrev)
                    psPrev = psFirst;

                psCur->rect.i32Left = psRegion->rect.i32Left;
            }

            if ((psRegion->rect.i32Right >= psCur->rect.i32Left) &&
                (psRegion->rect.i32Right < psCur->rect.i32Right))

            {
                sCreateRect.i32Left = psRegion->rect.i32Right + 1;

                sCreateRect.i32Right = psCur->rect.i32Right;
                sCreateRect.i32Top = psCur->rect.i32Top;
                sCreateRect.i32Bottom = psCur->rect.i32Bottom;

                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);

                if (!psPrev)
                    psPrev = psFirst;

                psCur->rect.i32Right = psRegion->rect.i32Right;
            }

            if ((psRegion->rect.i32Top > psCur->rect.i32Top) &&
                (psRegion->rect.i32Top <= psCur->rect.i32Bottom)) {
                sCreateRect.i32Bottom = psRegion->rect.i32Top - 1;

                sCreateRect.i32Left   = psCur->rect.i32Left;
                sCreateRect.i32Right  = psCur->rect.i32Right;
                sCreateRect.i32Top    = psCur->rect.i32Top;

                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);

                if (!psPrev)
                    psPrev = psFirst;

                psCur->rect.i32Top = psRegion->rect.i32Top;
            }

            if ((psRegion->rect.i32Bottom >= psCur->rect.i32Top) &&
                (psRegion->rect.i32Bottom <  psCur->rect.i32Bottom)) {
                sCreateRect.i32Top    = psRegion->rect.i32Bottom + 1;
                sCreateRect.i32Left   = psCur->rect.i32Left;
                sCreateRect.i32Right  = psCur->rect.i32Right;
                sCreateRect.i32Bottom = psCur->rect.i32Bottom;

                psFirst = psb_x11_createClipBoxNode(&sCreateRect, psFirst);

                if (!psPrev)
                    psPrev = psFirst;

                psCur->rect.i32Bottom = psRegion->rect.i32Bottom;
            }

            if ((IS_BETWEEN_RANGE(psRegion->rect.i32Left, psCur->rect.i32Left,   psRegion->rect.i32Right)) &&
                (IS_BETWEEN_RANGE(psRegion->rect.i32Left, psCur->rect.i32Right,  psRegion->rect.i32Right)) &&
                (IS_BETWEEN_RANGE(psRegion->rect.i32Top,  psCur->rect.i32Top,    psRegion->rect.i32Bottom)) &&
                (IS_BETWEEN_RANGE(psRegion->rect.i32Top,  psCur->rect.i32Bottom, psRegion->rect.i32Bottom))) {
                if (psPrev) {
                    psPrev->next = psCur->next;
                    free(psCur);
                    psCur = psPrev;
                } else {
                    free(psCur);
                    psCur = NULL;
                    psFirst = psNext;
                }
            }
            psPrev = psCur;
            psCur  = psNext;
        }//while(psCur)
        psRegion = psRegion->next;
    }//while(psRegion)

    return psFirst;
}

static int
psb_x11_createWindowClipBoxList(Display *              display,
                                Window                 x11_window_id,
                                psb_x11_clip_list_t ** ppWindowClipBoxList,
                                unsigned int *         pui32NumClipBoxList)
{
    Window CurrentWindow = x11_window_id;
    Window RootWindow, ParentWindow, ChildWindow;
    Window * pChildWindow;
    Status XResult;
    unsigned int i32NumChildren, i;
    int bIsVisible;
    unsigned int ui32NumRects = 0;
    psb_x11_clip_list_t *psRegions = NULL;
    psb_x11_win_t sRect;

    if (!display || (!ppWindowClipBoxList) || (!pui32NumClipBoxList))
        return -1;

    XResult = XQueryTree(display,
                         CurrentWindow,
                         &RootWindow,
                         &ParentWindow,
                         &pChildWindow,
                         &i32NumChildren);
    if (XResult == 0)
        return -2;

    if (i32NumChildren) {
        for (i = 0; i < i32NumChildren; i++) {

            psb_x11_getWindowCoordinate(display, x11_window_id, &sRect, &bIsVisible);
            if (bIsVisible) {
                psRegions = psb_x11_createClipBoxNode(&sRect, psRegions);
                ui32NumRects++;
            }
        }
        XFree(pChildWindow);
        i32NumChildren = 0;
    }

    while (CurrentWindow != RootWindow) {
        ChildWindow   = CurrentWindow;
        CurrentWindow = ParentWindow;

        XResult = XQueryTree(display,
                             CurrentWindow,
                             &RootWindow,
                             &ParentWindow,
                             &pChildWindow,
                             &i32NumChildren);
        if (XResult == 0) {
            if (i32NumChildren)
                XFree(pChildWindow);

            psb_x11_freeWindowClipBoxList(psRegions);
            return -3;
        }

        if (i32NumChildren) {
            unsigned int iStartWindow = 0;

            for (i = 0; i < i32NumChildren; i++) {
                if (pChildWindow[i] == ChildWindow) {
                    iStartWindow = i;
                    break;
                }
            }

            if (i == i32NumChildren) {
                XFree(pChildWindow);
                psb_x11_freeWindowClipBoxList(psRegions);
                return -4;
            }

            for (i = iStartWindow + 1; i < i32NumChildren; i++) {
                psb_x11_getWindowCoordinate(display, pChildWindow[i], &sRect, &bIsVisible);
                if (bIsVisible) {
                    psRegions = psb_x11_createClipBoxNode(&sRect, psRegions);
                    ui32NumRects++;
                }
            }

            XFree(pChildWindow);
        }
    }

    ui32NumRects = 0;

    if (psRegions) {
        psb_x11_getWindowCoordinate(display, x11_window_id, &sRect, &bIsVisible);
        *ppWindowClipBoxList = psb_x11_substractRects(display, psRegions, &sRect);
        psb_x11_freeWindowClipBoxList(psRegions);

        psRegions = *ppWindowClipBoxList;

        while (psRegions) {
            ui32NumRects++;
            psRegions = psRegions->next;
        }
    } else {
        *ppWindowClipBoxList = psb_x11_substractRects(display, NULL, &sRect);
        ui32NumRects = 1;
    }

    *pui32NumClipBoxList = ui32NumRects;

    return 0;
}

static int psb_cleardrawable_stopoverlay(
    VADriverContextP ctx,
    Drawable draw, /* X Drawable */
    short destx,
    short desty,
    unsigned short destw,
    unsigned short desth
)
{
    INIT_DRIVER_DATA;
    INIT_OUTPUT_PRIV;

    XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, destx, desty, destw, desth);
    XSync((Display *)ctx->native_dpy, False);

    driver_data->cur_displaying_surface = VA_INVALID_SURFACE;
    driver_data->last_displaying_surface = VA_INVALID_SURFACE;

    return 0;
}

static VAStatus psb_DisplayRGBASubpicture(
    PsbVASurfaceRec *subpicture,
    VADriverContextP ctx,
    int win_width,
    int win_height,
    int surface_x,
    int surface_y,
    int surface_w,
    int surface_h,
    psb_extvideo_subtitle subtitle
)
{
    INIT_DRIVER_DATA;
    INIT_OUTPUT_PRIV;
    XImage *ximg = NULL;
    Visual *visual;
    PsbPortPrivRec *pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
    struct _WsbmBufferObject *bo = subpicture->bo;
    int image_width, image_height, width, height, size;
    int srcx, srcy, srcw, srch;
    int destx, desty, destw, desth;
    int depth, i;

    if (subpicture->fourcc != VA_FOURCC_RGBA) {
        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Invalid image format, ONLY support RGBA subpicture now.\n", __func__);
        return VA_STATUS_ERROR_INVALID_IMAGE_FORMAT;
    }

    for (i = 0; subpicture != NULL; subpicture = subpicture->next, i++) {
        srcx = subpicture->subpic_srcx;
        srcy = subpicture->subpic_srcy;
        srcw = subpicture->subpic_srcw;
        srch = subpicture->subpic_srch;

        destx = subpicture->subpic_dstx + surface_x;
        desty = subpicture->subpic_dsty + surface_y;
        destw = subpicture->subpic_dstw;
        desth = subpicture->subpic_dsth;

        image_width = subpicture->width;
        image_height = subpicture->height;
        size = subpicture->size;

        //clip in image region
        if (srcx < 0) {
            srcw += srcx;
            srcx = 0;
        }

        if (srcy < 0) {
            srch += srcy;
            srcy = 0;
        }

        if ((srcx + srcw) > image_width)
            srcw = image_width - srcx;
        if ((srcy + srch) > image_height)
            srch = image_height - srcy;

        //clip in drawable region
        if (destx < 0) {
            destw += destx;
            destx = 0;
        }

        if (desty < 0) {
            desth += desty;
            desty = 0;
        }

        if ((destx + destw) > surface_w)
            destw = surface_w - destx;
        if ((desty + desth) > surface_h)
            desth = surface_h - desty;

        if (srcw <= destw)
            width = srcw;
        else
            width = destw;

        if (srch <= desth)
            height = srch;
        else
            height = desth;

        visual = DefaultVisual(ctx->native_dpy, 0);
        depth = DefaultDepth(ctx->native_dpy, 0);

        ximg = XCreateImage(ctx->native_dpy, visual, depth, ZPixmap, 0, NULL, image_width, image_height, 32, 0);

        if (NULL == ximg) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: XCreateImage failed! at L%d\n", __func__, __LINE__);
            return VA_STATUS_ERROR_UNKNOWN;
        }

        ximg->data = wsbmBOMap(bo, WSBM_ACCESS_READ);
        if (NULL == ximg->data) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to map to ximg->data.\n", __func__);
            return VA_STATUS_ERROR_ALLOCATION_FAILED;
        }

        pPriv->clear_key[i].subpic_dstx = destx;
        pPriv->clear_key[i].subpic_dsty = desty;
        pPriv->clear_key[i].subpic_dstw = destw;
        pPriv->clear_key[i].subpic_dsth = desth;
        if (psb_xrandr_extvideo_mode()) {
            /*It is a HACK: Adjust subtitle to proper position.*/
            float xScale, yScale;

            xScale = win_width * 1.0 / surface_w;
            yScale = win_height * 1.0 / surface_h;
            destx = subpicture->subpic_dstx * xScale;
            desty = subpicture->subpic_dsty * yScale;
        }
        XPutImage(ctx->native_dpy, output->output_drawable, output->gc, ximg, srcx, srcy, destx, desty, width, height);
        XSync((Display *)ctx->native_dpy, False);

        if (psb_xrandr_extvideo_mode() &&
            (subtitle == ONLY_HDMI || subtitle == BOTH)) {
            float xScale, yScale;

            xScale = pPriv->extend_display_width * 1.0 / surface_w;
            yScale = pPriv->extend_display_height * 1.0 / surface_h;

            destx = subpicture->subpic_dstx * xScale;
            desty = subpicture->subpic_dsty * yScale;

            XPutImage(ctx->native_dpy, output->extend_drawable, output->extend_gc, ximg,
                      srcx, srcy, destx, desty, destw, desth);
            XSync((Display *)ctx->native_dpy, False);
        }

        pPriv->subpic_clear_flag = 0;
        ximg->data = NULL;
        wsbmBOUnmap(bo);
        if (NULL != ximg)
            XDestroyImage(ximg);
    }
    return VA_STATUS_SUCCESS;
}

static VAStatus psb_repaint_colorkey(
    VADriverContextP ctx,
    Drawable draw, /* X Drawable */
    VASurfaceID surface,
    int x11_window_width,
    int x11_window_height
)
{
    INIT_DRIVER_DATA;
    INIT_OUTPUT_PRIV;
    int i, ret;
    psb_x11_clip_list_t *pClipNext = NULL;
    VARectangle *pVaWindowClipRects = NULL;
    object_surface_p obj_surface = SURFACE(surface);
    PsbPortPrivRec *pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);

    if (output->frame_count % 500 == 0 || driver_data->xrandr_update) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Repaint color key.\n");
        if (output->pClipBoxList)
            psb_x11_freeWindowClipBoxList(output->pClipBoxList);
        /* get window clipbox */
        ret = psb_x11_createWindowClipBoxList(ctx->native_dpy, draw, &output->pClipBoxList, &output->ui32NumClipBoxList);
        if (ret != 0) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: get window clip boxes error # %d\n", __func__, ret);
            return VA_STATUS_ERROR_UNKNOWN;
        }
        if (output->frame_count == 500)
            output->frame_count = 0;

        driver_data->xrandr_update = 0;
    }

    pVaWindowClipRects = (VARectangle *)calloc(1, sizeof(VARectangle) * output->ui32NumClipBoxList);
    if (!pVaWindowClipRects) {
        psb_x11_freeWindowClipBoxList(output->pClipBoxList);
        return VA_STATUS_ERROR_ALLOCATION_FAILED;
    }

    memset(pVaWindowClipRects, 0, sizeof(VARectangle)*output->ui32NumClipBoxList);
    pClipNext = output->pClipBoxList;
#ifdef CLIP_DEBUG
    drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Total %d clip boxes\n", __func__, output->ui32NumClipBoxList);
#endif
    for (i = 0; i < output->ui32NumClipBoxList; i++) {
        pVaWindowClipRects[i].x      = pClipNext->rect.i32Left;
        pVaWindowClipRects[i].y      = pClipNext->rect.i32Top;
        pVaWindowClipRects[i].width  = pClipNext->rect.i32Right - pClipNext->rect.i32Left;
        pVaWindowClipRects[i].height = pClipNext->rect.i32Bottom - pClipNext->rect.i32Top;
#ifdef CLIP_DEBUG
        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: clip boxes Left Top (%d, %d) Right Bottom (%d, %d) width %d height %d\n", __func__,
                           pClipNext->rect.i32Left, pClipNext->rect.i32Top,
                           pClipNext->rect.i32Right, pClipNext->rect.i32Bottom,
                           pVaWindowClipRects[i].width, pVaWindowClipRects[i].height);
#endif
        pClipNext = pClipNext->next;
    }

    /* repaint the color key when window size changed*/
    if (!obj_surface->subpictures &&
        ((pPriv->x11_window_width != x11_window_width) ||
         (pPriv->x11_window_height != x11_window_height))) {
        pPriv->x11_window_width = x11_window_width;
        pPriv->x11_window_height = x11_window_height;
        XSetForeground((Display *)ctx->native_dpy, output->gc, pPriv->colorKey);
        XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
        XSync((Display *)ctx->native_dpy, False);
    }


    if ((!obj_surface->subpictures) &&
        ((output->ui32NumClipBoxList != pPriv->last_num_clipbox) ||
         (memcmp(&pVaWindowClipRects[0], &(pPriv->last_clipbox[0]), (output->ui32NumClipBoxList > 16 ? 16 : output->ui32NumClipBoxList)*sizeof(VARectangle)) != 0))) {
        pPriv->last_num_clipbox = output->ui32NumClipBoxList;
        memcpy(&pPriv->last_clipbox[0], &pVaWindowClipRects[0], (output->ui32NumClipBoxList > 16 ? 16 : output->ui32NumClipBoxList)*sizeof(VARectangle));
        XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
        XSync((Display *)ctx->native_dpy, False);
    }

    free(pVaWindowClipRects);

    return VA_STATUS_SUCCESS;
}

static VAStatus psb_extendMode_getCoordinate(
    PsbPortPrivPtr pPriv,
    psb_xrandr_location extend_location,
    short destx,
    short desty,
    short srcx,
    short srcy,
    float xScaleFactor,
    float yScaleFactor,
    int *x11_window_width,
    int *x11_window_height,
    psb_overlay_rect_p local_rect,
    psb_overlay_rect_p extend_rect,
    enum overlay_id_t *extend_overlay
)
{
    switch (extend_location) {
    case LEFT_OF:
        if ((destx + *x11_window_width) > (pPriv->display_width + pPriv->extend_display_width)) {
            *x11_window_width = pPriv->display_width + pPriv->extend_display_width - destx;
        }
        if (((desty + *x11_window_height) < pPriv->display_height) &&
            ((desty + *x11_window_height) < pPriv->extend_display_height))
            local_rect->dHeight = extend_rect->dHeight = *x11_window_height;
        else if (pPriv->display_height < pPriv->extend_display_height) {
            local_rect->dHeight = pPriv->display_height - desty;
            if ((desty + *x11_window_height) > pPriv->extend_display_height)
                extend_rect->dHeight = *x11_window_height = pPriv->extend_display_height - desty;
            else
                extend_rect->dHeight = *x11_window_height;
        } else {
            extend_rect->dHeight = pPriv->extend_display_height - desty;
            if ((desty + *x11_window_height) > pPriv->display_height)
                local_rect->dHeight = *x11_window_height = pPriv->display_height - desty;
            else
                local_rect->dHeight = *x11_window_height;
        }

        if ((destx < pPriv->extend_display_width) && ((destx + *x11_window_width) < pPriv->extend_display_width)) {
            local_rect->dWidth = 0;
            extend_rect->dWidth = *x11_window_width;
            *extend_overlay = OVERLAY_A;
            local_rect->destx = 0;
        } else if ((destx < pPriv->extend_display_width) && ((destx + *x11_window_width) >= pPriv->extend_display_width)) {
            extend_rect->dWidth = pPriv->extend_display_width - destx;
            local_rect->dWidth = *x11_window_width - extend_rect->dWidth;
            local_rect->destx = 0;
        } else {
            local_rect->dWidth = *x11_window_width;
            extend_rect->dWidth = 0;
            local_rect->destx = destx - pPriv->extend_display_width;
        }
        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);

        local_rect->srcx = srcx + extend_rect->sWidth;
        extend_rect->srcx = srcx;
        local_rect->srcy = extend_rect->srcy = srcy;

        extend_rect->destx = destx;
        local_rect->desty = extend_rect->desty = desty;
        break;
    case RIGHT_OF:
        if ((destx + *x11_window_width) > (pPriv->display_width + pPriv->extend_display_width)) {
            *x11_window_width = pPriv->display_width + pPriv->extend_display_width - destx;
        }
        if (((desty + *x11_window_height) < pPriv->display_height) &&
            ((desty + *x11_window_height) < pPriv->extend_display_height))
            local_rect->dHeight = extend_rect->dHeight = *x11_window_height;
        else if (pPriv->display_height < pPriv->extend_display_height) {
            local_rect->dHeight = pPriv->display_height - desty;
            if ((desty + *x11_window_height) > pPriv->extend_display_height)
                extend_rect->dHeight = *x11_window_height = pPriv->extend_display_height - desty;
            else
                extend_rect->dHeight = *x11_window_height;
        } else {
            extend_rect->dHeight = pPriv->extend_display_height - desty;
            if ((desty + *x11_window_height) > pPriv->display_height)
                local_rect->dHeight = *x11_window_height = pPriv->display_height - desty;
            else
                local_rect->dHeight = *x11_window_height;
        }

        if ((destx < pPriv->display_width) && ((destx + *x11_window_width) < pPriv->display_width)) {
            local_rect->dWidth = *x11_window_width;
            extend_rect->dWidth = 0;
            extend_rect->destx = 0;
        } else if ((destx < pPriv->display_width) && ((destx + *x11_window_width) >= pPriv->display_width)) {
            local_rect->dWidth = pPriv->display_width - destx;
            extend_rect->dWidth = *x11_window_width - local_rect->dWidth;
            extend_rect->destx = 0;
        } else {
            local_rect->dWidth = 0;
            extend_rect->dWidth = *x11_window_width;
            *extend_overlay = OVERLAY_A;
            extend_rect->destx = destx - pPriv->display_width;
        }
        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);

        local_rect->srcx = srcx;
        extend_rect->srcx = srcx + local_rect->sWidth;
        local_rect->srcy = extend_rect->srcy = srcy;

        local_rect->destx = destx;
        local_rect->desty = extend_rect->desty = desty;
        break;
    case ABOVE:
        if (((destx + *x11_window_width) < pPriv->display_width) &&
            ((destx + *x11_window_width) < pPriv->extend_display_width))
            local_rect->dWidth = extend_rect->dWidth = *x11_window_width;
        else if (pPriv->display_width < pPriv->extend_display_width) {
            local_rect->dWidth = pPriv->display_width - destx;
            if ((destx + *x11_window_width) > pPriv->extend_display_width)
                extend_rect->dWidth = *x11_window_width = pPriv->extend_display_width - destx;
            else
                extend_rect->dWidth = *x11_window_width;
        } else {
            extend_rect->dWidth = pPriv->extend_display_width - destx;
            if ((destx + *x11_window_width) > pPriv->display_width)
                local_rect->dWidth = *x11_window_width = pPriv->display_width - destx;
            else
                local_rect->dWidth = *x11_window_width;
        }

        if ((desty + *x11_window_height) > (pPriv->display_height + pPriv->extend_display_height)) {
            *x11_window_height = pPriv->display_height + pPriv->extend_display_height - desty;
        }

        if ((desty < pPriv->extend_display_height) && ((desty + *x11_window_height) < pPriv->extend_display_height)) {
            local_rect->dHeight = 0;
            extend_rect->dHeight = *x11_window_height;
            *extend_overlay = OVERLAY_A;
            local_rect->desty = 0;
        } else if ((desty < pPriv->extend_display_height) && ((desty + *x11_window_height) >= pPriv->extend_display_height)) {
            extend_rect->dHeight = pPriv->extend_display_height - desty;
            local_rect->dHeight = *x11_window_height - extend_rect->dHeight;
            local_rect->desty = 0;
        } else {
            local_rect->dHeight = *x11_window_height;
            extend_rect->dHeight = 0;
            local_rect->desty = desty - pPriv->extend_display_height;
        }
        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);

        local_rect->srcy = srcy + extend_rect->sHeight;
        extend_rect->srcy = srcy;
        local_rect->srcx = extend_rect->srcx = srcx;

        extend_rect->desty = desty;
        local_rect->destx = extend_rect->destx = destx;
        break;
    case BELOW:
        if (((destx + *x11_window_width) < pPriv->display_width) &&
            ((destx + *x11_window_width) < pPriv->extend_display_width))
            local_rect->dWidth = extend_rect->dWidth = *x11_window_width;
        else if (pPriv->display_width < pPriv->extend_display_width) {
            local_rect->dWidth = pPriv->display_width - destx;
            if ((destx + *x11_window_width) > pPriv->extend_display_width)
                extend_rect->dWidth = *x11_window_width = pPriv->extend_display_width - destx;
            else
                extend_rect->dWidth = *x11_window_width;
        } else {
            extend_rect->dWidth = pPriv->extend_display_width - destx;
            if ((destx + *x11_window_width) > pPriv->display_width)
                local_rect->dWidth = *x11_window_width = pPriv->display_width - destx;
            else
                local_rect->dWidth = *x11_window_width;
        }

        if ((desty + *x11_window_height) > (pPriv->display_height + pPriv->extend_display_height)) {
            *x11_window_height = pPriv->display_height + pPriv->extend_display_height - desty;
        }

        if ((desty < pPriv->display_height) && ((desty + *x11_window_height) < pPriv->display_height)) {
            local_rect->dHeight = *x11_window_height;
            extend_rect->dHeight = 0;
            extend_rect->desty = 0;
        } else if ((desty < pPriv->display_height) && ((desty + *x11_window_height) >= pPriv->display_height)) {
            local_rect->dHeight = pPriv->display_height - desty;
            extend_rect->dHeight = *x11_window_height - local_rect->dHeight;
            extend_rect->desty = 0;
        } else {
            local_rect->dHeight = 0;
            extend_rect->dHeight = *x11_window_height;
            *extend_overlay = OVERLAY_A;
            extend_rect->desty = desty - pPriv->display_height;
        }
        local_rect->sWidth = (unsigned short)(local_rect->dWidth * xScaleFactor);
        local_rect->sHeight = (unsigned short)(local_rect->dHeight * yScaleFactor);
        extend_rect->sWidth = (unsigned short)(extend_rect->dWidth * xScaleFactor);
        extend_rect->sHeight = (unsigned short)(extend_rect->dHeight * yScaleFactor);

        local_rect->srcy = srcy;
        extend_rect->srcy = srcy + local_rect->sHeight;
        local_rect->srcx = extend_rect->srcx = srcx;

        local_rect->desty = desty;
        local_rect->destx = extend_rect->destx = destx;
        break;
    case NORMAL:
    default:
        break;
    }
    return VA_STATUS_SUCCESS;
}

static void psb_init_subpicture(VADriverContextP ctx, PsbPortPrivPtr pPriv)
{
    INIT_DRIVER_DATA;
    struct drm_psb_register_rw_arg regs;
    unsigned int subpicture_enable_mask = REGRWBITS_DSPACNTR;

    if (!pPriv->subpicture_enabled) {
        if (psb_xrandr_hdmi_enabled())
            subpicture_enable_mask |= REGRWBITS_DSPBCNTR;
        if (psb_xrandr_mipi1_enabled())
            subpicture_enable_mask |= REGRWBITS_DSPCCNTR;

        memset(&regs, 0, sizeof(regs));
        regs.subpicture_enable_mask = subpicture_enable_mask;
        pPriv->subpicture_enable_mask = subpicture_enable_mask;
        pPriv->subpicture_enabled = 1;
        drmCommandWriteRead(driver_data->drm_fd, DRM_PSB_REGISTER_RW, &regs, sizeof(regs));
    }
}

static void psb_clear_subpictures(
    VADriverContextP ctx,
    PsbPortPrivPtr pPriv,
    int win_width,
    int win_height,
    object_surface_p obj_surface
)
{
    INIT_OUTPUT_PRIV;
    PsbVASurfaceRec *subpicture = (PsbVASurfaceRec *)obj_surface->subpictures;
    int i;

    if (subpicture == NULL) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Surface has no subpicture to render.\n");
        return;
    }

    for (i = 0; subpicture != NULL; subpicture = subpicture->next, i++) {
        if ((subpicture->subpic_dstx != pPriv->clear_key[i].subpic_dstx) ||
            (subpicture->subpic_dsty != pPriv->clear_key[i].subpic_dsty) ||
            (subpicture->subpic_dstw != pPriv->clear_key[i].subpic_dstw) ||
            (subpicture->subpic_dsth != pPriv->clear_key[i].subpic_dsth)) {
            XSetForeground((Display *)ctx->native_dpy, output->gc, 0);
            XFillRectangle((Display *)ctx->native_dpy, output->output_drawable, output->gc, 0, 0, win_width, win_height);
            XSync((Display *)ctx->native_dpy, False);
            if (psb_xrandr_extvideo_mode()) {
                XSetForeground((Display *)ctx->native_dpy, output->extend_gc, 0);
                XFillRectangle((Display *)ctx->native_dpy, output->extend_drawable, output->extend_gc,
                               0, 0, pPriv->extend_display_width, pPriv->extend_display_height);
                XSync((Display *)ctx->native_dpy, False);
            }
            pPriv->subpic_clear_flag = 1;
        }
    }
    return;
}

VAStatus psb_putsurface_coverlay(
    VADriverContextP ctx,
    VASurfaceID surface,
    Drawable draw, /* X Drawable */
    short srcx,
    short srcy,
    unsigned short srcw,
    unsigned short srch,
    short destx,
    short desty,
    unsigned short destw,
    unsigned short desth,
    VARectangle *cliprects, /* client supplied clip list */
    unsigned int number_cliprects, /* number of clip rects in the clip list */
    unsigned int flags /* de-interlacing flags */
)
{
    INIT_DRIVER_DATA;
    INIT_OUTPUT_PRIV;
    int ret;
    int x11_window_width = destw, x11_window_height = desth;
    psb_xrandr_location extend_location;
    object_surface_p obj_surface = SURFACE(surface);
    PsbPortPrivRec *pPriv = (PsbPortPrivPtr)(&driver_data->coverlay_priv);
    int primary_crtc_x, primary_crtc_y, extend_crtc_x, extend_crtc_y;
    enum pipe_id_t local_pipe = PIPEA, extend_pipe = PIPEB;
    int surfacex = destx, surfacey = desty;
    float xScaleFactor, yScaleFactor;
    Rotation rotation = RR_Rotate_0;
    psb_output_device local_device, extend_device;
    psb_extvideo_subtitle subtitle;

    if (flags & VA_CLEAR_DRAWABLE) {
        drv_debug_msg(VIDEO_DEBUG_GENERAL, "Clean draw with color 0x%08x\n", driver_data->clear_color);
        psb_cleardrawable_stopoverlay(ctx, draw, destx, desty, destw, desth);

        return VA_STATUS_SUCCESS;
    }

    if (output->frame_count % 500 == 0 || driver_data->xrandr_update) {
        /* get window screen coordination */
        ret = psb_x11_getWindowCoordinate(ctx->native_dpy, draw, &output->winRect, &output->bIsVisible);
        if (ret != 0) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get X11 window coordinates error # %d\n", __func__, ret);
            return VA_STATUS_ERROR_UNKNOWN;
        }
    }

    if (!output->bIsVisible) {
        return VA_STATUS_SUCCESS;
    }

    if (NULL == obj_surface) {
        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Invalid surface id 0x%08x.\n", __func__, surface);
        return VA_STATUS_ERROR_INVALID_SURFACE;
    }

    if (output->output_drawable != draw) {
        output->output_drawable = draw;
    }

    if (!output->gc) {
        output->gc = XCreateGC((Display *)ctx->native_dpy, draw, 0, NULL);
        /* paint the color key */
        if (!obj_surface->subpictures && !driver_data->overlay_auto_paint_color_key) {
            XSetForeground((Display *)ctx->native_dpy, output->gc, pPriv->colorKey);
            XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
            XSync((Display *)ctx->native_dpy, False);
        }
    }

    if (driver_data->use_xrandr_thread && !driver_data->xrandr_thread_id) {
        ret = psb_xrandr_thread_create(ctx);
        if (ret != 0) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to create psb xrandr thread error # %d\n", __func__, ret);
            return VA_STATUS_ERROR_UNKNOWN;
        }
    }

    ret = psb_xrandr_local_crtc_coordinate(&local_device, &primary_crtc_x, &primary_crtc_y, &pPriv->display_width, &pPriv->display_height, &rotation);
    if (ret != VA_STATUS_SUCCESS) {
        drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get primary crtc coordinates error # %d\n", __func__, ret);
        return VA_STATUS_ERROR_UNKNOWN;
    }
    switch (local_device) {
    case LVDS0:
    case MIPI0:
        local_pipe = PIPEA;
        break;
        /* single HDMI */
    case HDMI:
        local_pipe = PIPEB;
        break;
    case MIPI1:
        local_pipe = PIPEC;
        break;
    }

    if (!psb_xrandr_single_mode()) {

        ret = psb_xrandr_extend_crtc_coordinate(&extend_device, &extend_crtc_x, &extend_crtc_y,
                                                &pPriv->extend_display_width, &pPriv->extend_display_height, &extend_location, &rotation);
        if (ret != VA_STATUS_SUCCESS) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get extend crtc coordinates error # %d\n", __func__, ret);
            return VA_STATUS_ERROR_UNKNOWN;
        }

        switch (extend_device) {
        case HDMI:
            extend_pipe = PIPEB;
            break;
        case MIPI1:
            extend_pipe = PIPEC;
            break;
        default:
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to get extend pipe\n", __func__);
            break;
        }
    }

    /*clip in the window area*/
    if (destx < 0) {
        x11_window_width += destx;
        destx = 0;
    }

    if (desty < 0) {
        x11_window_height += desty;
        desty = 0;
    }

    if (srcx < 0) {
        srcw += srcx;
        srcx = 0;
    }

    if (srcy < 0) {
        srch += srcy;
        srcy = 0;
    }

    if ((destx + x11_window_width) > output->winRect.ui32Width)
        x11_window_width = output->winRect.ui32Width - destx;

    if ((desty + x11_window_height) > output->winRect.ui32Height)
        x11_window_height = output->winRect.ui32Height - desty;

    /*translate destx, desty into screen coordinate*/
    destx += output->winRect.i32Left;
    desty += output->winRect.i32Top;

    /*clip in the screen area*/
    xScaleFactor = srcw * 1.0 / x11_window_width;
    yScaleFactor = srch * 1.0 / x11_window_height;

    if (destx < 0) {
        x11_window_width += destx;
        srcx = (short)((-destx) * xScaleFactor);
        destx = 0;
    }

    if (desty < 0) {
        x11_window_height += desty;
        srcy = (short)((-desty) * yScaleFactor);
        desty = 0;
    }

    /* display by overlay */
    if (psb_xrandr_single_mode() || IS_MRST(driver_data)) {
        if ((destx + x11_window_width) > pPriv->display_width) {
            x11_window_width = pPriv->display_width - destx;
            srcw = (unsigned short)(x11_window_width * xScaleFactor);
        }

        if ((desty + x11_window_height) > pPriv->display_height) {
            x11_window_height = pPriv->display_height - desty;
            srch = (unsigned short)(x11_window_height * yScaleFactor);
        }

        if (!driver_data->overlay_auto_paint_color_key) {
            ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
            if (ret != 0) {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
                return VA_STATUS_ERROR_UNKNOWN;
            }
        }

        psb_putsurface_overlay(
            ctx, surface, srcx, srcy, srcw, srch,
            /* screen coordinate */
            destx, desty, x11_window_width, x11_window_height,
            flags, OVERLAY_A, local_pipe);
    } else if (psb_xrandr_clone_mode()) {
        psb_overlay_rect_t local_rect, extend_rect;

        if (output->extend_drawable) {
            XDestroyWindow(ctx->native_dpy, output->extend_drawable);
            output->extend_drawable = 0;
            XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
            output->extend_gc = 0;
        }

        if (((destx + x11_window_width) < pPriv->display_width) &&
            ((destx + x11_window_width) < pPriv->extend_display_width))
            local_rect.dWidth = extend_rect.dWidth = x11_window_width;
        else if (pPriv->display_width < pPriv->extend_display_width) {
            local_rect.dWidth = pPriv->display_width - destx;
            if ((destx + x11_window_width) > pPriv->extend_display_width)
                extend_rect.dWidth = x11_window_width = pPriv->extend_display_width - destx;
            else
                extend_rect.dWidth = x11_window_width;
        } else {
            extend_rect.dWidth = pPriv->extend_display_width - destx;
            if ((destx + x11_window_width) > pPriv->display_width)
                local_rect.dWidth = x11_window_width = pPriv->display_width - destx;
            else
                local_rect.dWidth = x11_window_width;
        }

        if (((desty + x11_window_height) < pPriv->display_height) &&
            ((desty + x11_window_height) < pPriv->extend_display_height))
            local_rect.dHeight = extend_rect.dHeight = x11_window_height;
        else if (pPriv->display_height < pPriv->extend_display_height) {
            local_rect.dHeight = pPriv->display_height - desty;
            if ((desty + x11_window_height) > pPriv->extend_display_height)
                extend_rect.dHeight = x11_window_height = pPriv->extend_display_height - desty;
            else
                extend_rect.dHeight = x11_window_height;
        } else {
            extend_rect.dHeight = pPriv->extend_display_height - desty;
            if ((desty + x11_window_height) > pPriv->display_height)
                local_rect.dHeight = x11_window_height = pPriv->display_height - desty;
            else
                local_rect.dHeight = x11_window_height;
        }
        if ((driver_data->mipi0_rotation != VA_ROTATION_NONE) ||
            (driver_data->hdmi_rotation != VA_ROTATION_NONE)) {
            local_rect.sWidth = srcw;
            local_rect.sHeight = srch;
            extend_rect.sWidth = srcw;
            extend_rect.sHeight = srch;
        } else {
            local_rect.sWidth = (unsigned short)(local_rect.dWidth * xScaleFactor);
            local_rect.sHeight = (unsigned short)(local_rect.dHeight * yScaleFactor);
            extend_rect.sWidth = (unsigned short)(extend_rect.dWidth * xScaleFactor);
            extend_rect.sHeight = (unsigned short)(extend_rect.dHeight * yScaleFactor);
        }
        ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
        if (ret != 0) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
            return VA_STATUS_ERROR_UNKNOWN;
        }
        psb_putsurface_overlay(
            ctx, surface, srcx, srcy, extend_rect.sWidth, extend_rect.sHeight,
            /* screen coordinate */
            destx, desty, extend_rect.dWidth, extend_rect.dHeight,
            flags, OVERLAY_C, extend_pipe);
        psb_putsurface_overlay(
            ctx, surface,  srcx, srcy, local_rect.sWidth, local_rect.sHeight,
            /* screen coordinate */
            destx, desty, local_rect.dWidth, local_rect.dHeight,
            flags, OVERLAY_A, local_pipe);
    } else if (psb_xrandr_extend_mode()) {
        if (driver_data->extend_fullscreen) {
            switch (extend_location) {
            case RIGHT_OF:
                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, pPriv->display_width, 0, pPriv->extend_display_width, pPriv->extend_display_height);
                break;
            case BELOW:
                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, 0, pPriv->display_height, pPriv->extend_display_width, pPriv->extend_display_height);
                break;
            case LEFT_OF:
            case ABOVE:
                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, 0, 0, pPriv->extend_display_width, pPriv->extend_display_height);
                break;
            default:
                break;

            }
            XSetForeground((Display *)ctx->native_dpy, output->gc, pPriv->colorKey);
            XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, pPriv->extend_display_width, pPriv->extend_display_height);
            XFlush(ctx->native_dpy);

            psb_putsurface_overlay(
                ctx, surface, srcx, srcy, srcw, srch,
                /* screen coordinate */
                0, 0, pPriv->extend_display_width, pPriv->extend_display_height,
                flags, OVERLAY_A, PIPEB);
        } else {
            psb_overlay_rect_t local_rect, extend_rect;
            enum overlay_id_t extend_overlay = OVERLAY_C;

            if (output->extend_drawable) {
                XDestroyWindow(ctx->native_dpy, output->extend_drawable);
                output->extend_drawable = 0;
                XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
                output->extend_gc = 0;
            }
            memset(&local_rect, 0, sizeof(psb_overlay_rect_t));
            memset(&extend_rect, 0, sizeof(psb_overlay_rect_t));
            psb_extendMode_getCoordinate(pPriv, extend_location, destx, desty, srcx, srcy,
                                         xScaleFactor, yScaleFactor, &x11_window_width, &x11_window_height,
                                         &local_rect, &extend_rect, &extend_overlay);

            ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
            if (ret != 0) {
                drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
                return VA_STATUS_ERROR_UNKNOWN;
            }

            if ((extend_rect.dWidth > 0) && (extend_rect.dHeight > 0)) {
                psb_putsurface_overlay(
                    ctx, surface,
                    extend_rect.srcx, extend_rect.srcy, extend_rect.sWidth, extend_rect.sHeight,
                    extend_rect.destx, extend_rect.desty, extend_rect.dWidth, extend_rect.dHeight,
                    flags, extend_overlay, extend_pipe);
            }
            if ((local_rect.dWidth > 0) && (local_rect.dHeight > 0)) {
                psb_putsurface_overlay(
                    ctx, surface,
                    local_rect.srcx, local_rect.srcy, local_rect.sWidth, local_rect.sHeight,
                    local_rect.destx, local_rect.desty, local_rect.dWidth, local_rect.dHeight,
                    flags, OVERLAY_A, local_pipe);
            }
        }
    } else if (psb_xrandr_extvideo_mode()) {
        unsigned int xres, yres, xoffset, yoffset, overscanmode, pannelfitting, x, y;
        psb_extvideo_center center;

        psb_xrandr_extvideo_prop(&xres, &yres, &xoffset, &yoffset, &center, &subtitle, &overscanmode, &pannelfitting);
        x = xoffset;
        y = yoffset;

        switch (extend_location) {
        case RIGHT_OF:
            x += pPriv->display_width;
            break;
        case BELOW:
            y += pPriv->display_height;
            break;
        case NORMAL:
            break;
        case LEFT_OF:
            if (driver_data->xrandr_dirty & PSB_NEW_EXTVIDEO) {
                destx += pPriv->extend_display_width;
                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, destx, desty, x11_window_width, x11_window_height);
                XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
                XFlush(ctx->native_dpy);
            }
            destx = destx - pPriv->extend_display_width;
            break;
        case ABOVE:
            if (driver_data->xrandr_dirty & PSB_NEW_EXTVIDEO) {
                desty += pPriv->extend_display_height;
                XMoveResizeWindow(ctx->native_dpy, output->output_drawable, destx, desty, x11_window_width, x11_window_height);
                XFillRectangle((Display *)ctx->native_dpy, draw, output->gc, 0, 0, x11_window_width, x11_window_height);
                XFlush(ctx->native_dpy);
            }
            desty = desty - pPriv->extend_display_height;
            break;
        }
        if ((destx + x11_window_width) > pPriv->display_width)
            x11_window_width = pPriv->display_width - destx;
        if ((desty + x11_window_height) > pPriv->display_height)
            x11_window_height = pPriv->display_height - desty;

        if (driver_data->xrandr_dirty & PSB_NEW_EXTVIDEO) {
            Window extend_win;
            extend_win = psb_xrandr_create_full_screen_window(x, y, xres, yres);
            if (output->extend_drawable != extend_win) {
                output->extend_drawable = extend_win;
                if (output->extend_gc)
                    XFreeGC((Display *)ctx->native_dpy, output->extend_gc);
                output->extend_gc = XCreateGC((Display *)ctx->native_dpy, extend_win, 0, NULL);

                /* paint the color key */
                if (!obj_surface->subpictures) {
                    XSetForeground((Display *)ctx->native_dpy, output->extend_gc, pPriv->colorKey);
                    XFillRectangle((Display *)ctx->native_dpy, extend_win, output->extend_gc, 0, 0, xres, yres);
                    XSync((Display *)ctx->native_dpy, False);
                }
            }
            driver_data->xrandr_dirty &= ~PSB_NEW_EXTVIDEO;
        }

        ret = psb_repaint_colorkey(ctx, draw, surface, x11_window_width, x11_window_height);
        if (ret != 0) {
            drv_debug_msg(VIDEO_DEBUG_ERROR, "%s: Failed to repaint color key error # %d\n", __func__, ret);
            return VA_STATUS_ERROR_UNKNOWN;
        }

        psb_putsurface_overlay(
            ctx, surface, srcx, srcy, srcw, srch,
            /* screen coordinate */
            xoffset, yoffset, xres, yres,
            flags, OVERLAY_C, PIPEB);
        psb_putsurface_overlay(
            ctx, surface, srcx, srcy, srcw, srch,
            /* screen coordinate */
            destx, desty,
            x11_window_width, x11_window_height,
            flags, OVERLAY_A, local_pipe);
    }

    /*Init Overlay subpicuture blending and make proper clear.*/
    if (pPriv->is_mfld && obj_surface->subpictures) {
        PsbVASurfaceRec *subpicture = (PsbVASurfaceRec *)obj_surface->subpictures;

        psb_init_subpicture(ctx, pPriv);
        /*clear changed subpicture zones in drawable.*/
        psb_clear_subpictures(ctx, pPriv, x11_window_width, x11_window_height, obj_surface);
        if (pPriv->subpic_clear_flag) {
            psb_DisplayRGBASubpicture(subpicture, ctx, x11_window_width, x11_window_height,
                                      surfacex, surfacey, obj_surface->width, obj_surface->height, subtitle);
        }
    }

    output->frame_count++;

    return VA_STATUS_SUCCESS;
}