All pastes #210759 Raw Edit

Miscellany

public c v1 · immutable
#210759 ·published 2006-10-19 23:59 UTC
rendered paste body
/* * ---------------------------------------------------------------------------- * Video driver for kaa.xine - provides BGRA OSD and frame-to-buffer features * ---------------------------------------------------------------------------- * $Id: video_out_kaa.c 1654 2006-07-11 03:30:57Z tack $ * * ---------------------------------------------------------------------------- * Copyright (C) 2004-2005 Jason Tackaberry <tack@sault.org> * * Maintainer:    Jason Tackaberry <tack@sault.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MER- * CHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * ---------------------------------------------------------------------------- */#include <math.h>#include <malloc.h>#include <assert.h>#ifndef __USE_XOPEN2K#define __USE_XOPEN2K // for pthread_mutex_timedlock#endif#include <pthread.h>//#include "../config.h"#include "video_out_kaa.h"// Uncomment this for profiling info.#define STOPWATCH 4#define clamp(a,min,max) (((a)>(max))?(max):(((a)<(min))?(min):(a)))static int _kaa_blend_osd(kaa_driver_t *this, kaa_frame_t *frame);#ifdef STOPWATCHstatic void stopwatch(int n, char *text, ...){    va_list ap;    struct timezone tz;    static struct {        struct timeval tv, last_tv;        char text[250];    } t[10];    if (n > STOPWATCH)        return;    gettimeofday(&t[n].tv, &tz);    if (!text) {        fprintf(stderr, "@@@ Stopwatch (%d): %s: %ld usec\n", n, t[n].text,               (t[n].tv.tv_sec - t[n].last_tv.tv_sec) * 1000000 +               (t[n].tv.tv_usec - t[n].last_tv.tv_usec));    } else {        t[n].last_tv.tv_sec = t[n].tv.tv_sec;        t[n].last_tv.tv_usec = t[n].tv.tv_usec;        va_start(ap, text);        vsprintf(t[n].text, text, ap);        va_end(ap);    }}#else#define stopwatch(n, text, ...)#endif#if defined(ARCH_X86) || defined(ARCH_X86_64)    #define C64(x) ((uint64_t)((x)|(x)<<16))<<32 | (uint64_t)(x) | (uint64_t)(x)<<16    static uint64_t  __attribute__((used)) __attribute__((aligned(8))) MM_global_alpha;    static uint64_t  __attribute__((used)) __attribute__((aligned(8))) MM_ROUND = C64(0x80);    #ifdef ARCH_X86_64        #define REG_c  "rcx"    #else        #define REG_c  "ecx"    #endif#endif/////////////////////////////////////////////////////////////////////////////#define FP_BITS 18#define rgb2y(R,G,B) ( (Y_R[ R ] + Y_G[ G ] + Y_B[ B ]) >> FP_BITS )#define rgb2u(R,G,B) ( (U_R[ R ] + U_G[ G ] + U_B[ B ]) >> FP_BITS )#define rgb2v(R,G,B) ( (V_R[ R ] + V_G[ G ] + V_B[ B ]) >> FP_BITS )static int Y_R[256], Y_G[256], Y_B[256],           U_R[256], U_G[256], U_B[256],           V_R[256], V_G[256], V_B[256];static voidinit_rgb2yuv_tables(){    int i;    #define myround(n) (n >= 0) ? (int)(n + 0.5) : (int)(n - 0.5);    for (i = 0; i < 256; i++) {        Y_R[i] = myround(0.299 * (double)i * 219.0 / 255.0 * (double)(1<<FP_BITS));        Y_G[i] = myround(0.587 * (double)i * 219.0 / 255.0 * (double)(1<<FP_BITS));        Y_B[i] = myround((0.114 * (double)i * 219.0 / 255.0 *                  (double)(1<<FP_BITS)) + (double)(1<<(FP_BITS-1)) +                  (16.0 * (double)(1<<FP_BITS)));        U_R[i] = myround(-0.168736 * (double)i * 224.0 / 255.0 *                 (double)(1<<FP_BITS));        U_G[i] = myround(-0.331264 * (double)i * 224.0 / 255.0 *                 (double)(1<<FP_BITS));        U_B[i] = myround((0.500 * (double)i * 224.0 / 255.0 *                  (double)(1<<FP_BITS)) + (double)(1<<(FP_BITS-1)) +                 (128.0 * (double)(1<<FP_BITS)));        V_R[i] = myround(0.500 * (double)i * 224.0 / 255.0 * (double)(1<<FP_BITS));        V_G[i] = myround(-0.418688 * (double)i * 224.0 / 255.0 *                 (double)(1<<FP_BITS));        V_B[i] = myround((-0.081312 * (double)i * 224.0 / 255.0 *                  (double)(1<<FP_BITS)) + (double)(1<<(FP_BITS-1)) +                 (128.0 * (double)(1<<FP_BITS)));    }}static voidfree_overlay_data(kaa_driver_t *this){    int i, p;    uint8_t **planes[] = {        this->osd_planes, this->osd_pre_planes,        this->osd_alpha_planes, this->osd_pre_alpha_planes, NULL    };    for (p = 0; planes[p] != NULL; p++) {        for (i = 0; i < 3; i++) {            // plane[1] == plane[2] for alpha planes, so only free one.            if (planes[p][i] && (p < 2 || i < 2))                free(planes[p][i]);            planes[p][i] = NULL;        }    }}static voidalloc_overlay_data(kaa_driver_t *this, int format){    int w = this->osd_w, h = this->osd_h;    free_overlay_data(this);    if (format == XINE_IMGFMT_YV12) {        this->osd_planes[0] = (uint8_t *)memalign(16, w * h);        this->osd_planes[1] = (uint8_t *)memalign(16, w * h / 4);        this->osd_planes[2] = (uint8_t *)memalign(16, w * h / 4);        this->osd_alpha_planes[0] = (uint8_t *)memalign(16, w * h);        this->osd_alpha_planes[1] = (uint8_t *)memalign(16, w * h / 4);        this->osd_alpha_planes[2] = this->osd_alpha_planes[1];        this->osd_pre_planes[0] = (uint8_t *)memalign(16, w * h);        this->osd_pre_planes[1] = (uint8_t *)memalign(16, w * h / 4);        this->osd_pre_planes[2] = (uint8_t *)memalign(16, w * h / 4);        this->osd_pre_alpha_planes[0] = (uint8_t *)memalign(16, w * h);        this->osd_pre_alpha_planes[1] = (uint8_t *)memalign(16, w * h / 4);        this->osd_pre_alpha_planes[2] = this->osd_pre_alpha_planes[1];        this->osd_strides[0] = w;        this->osd_strides[1] = this->osd_strides[2] = w >> 1;    }    else if (format == XINE_IMGFMT_YUY2) {        this->osd_planes[0] = (uint8_t *)memalign(16, w * h * 2);        this->osd_planes[1] = this->osd_planes[2] = 0;        this->osd_alpha_planes[0] = (uint8_t *)memalign(16, w * h * 2);        this->osd_alpha_planes[1] = this->osd_alpha_planes[2] = 0;        this->osd_pre_planes[0] = (uint8_t *)memalign(16, w * h * 2);        this->osd_pre_planes[1] = this->osd_pre_planes[2] = 0;        this->osd_pre_alpha_planes[0] = (uint8_t *)memalign(16, w * h * 2);        this->osd_pre_alpha_planes[1] = this->osd_pre_alpha_planes[2] = 0;        this->osd_strides[0] = w * 2;        this->osd_strides[1] = this->osd_strides[2] = 0;    } else {        printf("ERROR: unsupported frame format; osd disabled.\n");    }    this->osd_format = format;}static inline int_check_bounds(kaa_driver_t *this, const char *func, int x, int y, int w, int h){    if (x < 0 || y < 0 || w <= 0 || h <= 0 ||        x >= this->osd_w || x+w > this->osd_w ||        y >= this->osd_h || y+h > this->osd_h) {        printf("! WARNING: rect (%d,%d %dx%d) passed to %s outside bounds (%dx%d)\n",           x, y, w, h, func, this->osd_w, this->osd_h);        return 0;    }    return 1;}#define check_bounds(this, x, y, w, h) _check_bounds(this, __FUNCTION__, x, y, w, h)static voidcalculate_slice(kaa_driver_t *this){    int x, y, n_plane, h, row_stride, slice_y1 = -2, slice_y2 = -2;    uint8_t *p;    n_plane = this->osd_format == XINE_IMGFMT_YV12 ? 1 : 0;    p = this->osd_alpha_planes[n_plane];    row_stride = this->osd_strides[n_plane];    h = this->osd_h >> n_plane;    stopwatch(3, "calculate_slice");    #define check_opaque(type) \            if (*(type*)(p + x)) { \                if (slice_y1 == -2) \                    slice_y1 = y; \                else \                    slice_y2 = y; \                x = row_stride; \                break; \            }    for (y = 0; y < h; y++) {        for (x = 0; x < row_stride-7; x += 8)            check_opaque(uint64_t);        for (; x < row_stride-3; x += 4)            check_opaque(uint32_t);        for (; x < row_stride-1; x += 2)            check_opaque(uint16_t);        p += row_stride;    }    stopwatch(3, NULL);    this->osd_slice_y = 0; //clamp((slice_y1 - 2) * (n_plane + 1), 0, this->osd_h);    this->osd_slice_h = this->osd_h; //clamp((slice_y2 + 2) * (n_plane + 1), 0, this->osd_h) - this->osd_slice_y;    //printf("SLICE: %d %d\n", this->osd_slice_y, this->osd_slice_h);}static voidconvert_bgra_to_yuy2a(kaa_driver_t *this, int rx, int ry, int rw, int rh){    uint8_t r1, g1, b1, a1, r2, g2, b2, a2, *src_ptr, *dst_ptr, *dst_a_ptr;    int x, y, dst_stride, src_stride;    stopwatch(2, "convert_bgra_to_yuy2a (%d,%d %dx%d)", rx, ry, rw, rh);    src_stride = this->osd_stride;    dst_stride = this->osd_strides[0];    src_ptr = this->osd_buffer + (rx*4) + (ry*src_stride);    dst_ptr = this->osd_planes[0] + (rx*2 + ry * dst_stride);    dst_a_ptr = this->osd_alpha_planes[0] + (rx*2 + ry * dst_stride);    // This is not the most graceful code ...    for (y = 0; y < rh; y++) {        for (x = 0; x < rw; x+=2) {            b1 = src_ptr[4*x+0];            g1 = src_ptr[4*x+1];            r1 = src_ptr[4*x+2];            a1 = src_ptr[4*x+3];            b2 = src_ptr[4*x+4];            g2 = src_ptr[4*x+5];            r2 = src_ptr[4*x+6];            a2 = src_ptr[4*x+7];            dst_ptr[2*x] = rgb2y(r1, g1, b1);            dst_ptr[2*x+2] = rgb2y(r2, g2, b2);            dst_a_ptr[2*x] = a1;            dst_a_ptr[2*x+2] = a2;            dst_ptr[x*2+1] = rgb2u((r1+r2)>>1, (g1+g2)>>1, (b1+b2)>>1);            dst_ptr[x*2+3] = rgb2v((r1+r2)>>1, (g1+g2)>>1, (b1+b2)>>1);            dst_a_ptr[x*2+1] = dst_a_ptr[x*2+3] = (a1+a2)>>1;        }        dst_ptr += dst_stride;        dst_a_ptr += dst_stride;        src_ptr += src_stride;    }    stopwatch(2, NULL);}static voidconvert_bgra_to_yv12a(kaa_driver_t *this, int rx, int ry, int rw, int rh){    int x, y;    unsigned char *y_ptr, *u_ptr, *v_ptr, *a_ptr, *uva_ptr, *src_ptr,                  r, g, b, a;    int luma_offset = rx + ry * this->osd_w;    unsigned int src_stride = this->osd_stride,                 chroma_stride = this->osd_w >> 1;    int chroma_offset = (rx >> 1) + (ry >> 1) * chroma_stride;    stopwatch(2, "convert_bgra_to_yv12a (%d,%d %dx%d)", rx, ry, rw, rh);    src_ptr = this->osd_buffer + (rx*4) + (ry*this->osd_stride);    y_ptr = this->osd_planes[0] + luma_offset;    u_ptr = this->osd_planes[1] + chroma_offset;    v_ptr = this->osd_planes[2] + chroma_offset;    a_ptr = this->osd_alpha_planes[0] + luma_offset;    uva_ptr = this->osd_alpha_planes[1] + chroma_offset;    for (y = 0; y < rh; y += 2) {        for (x = 0; x < rw >> 1; x++) {            b = src_ptr[8*x+0];            g = src_ptr[8*x+1];            r = src_ptr[8*x+2];            a = src_ptr[8*x+3];            y_ptr[2*x] = rgb2y(r, g, b);            a_ptr[2*x] = a;            b = (b + src_ptr[8*x+0+src_stride])>>1;            g = (g + src_ptr[8*x+1+src_stride])>>1;            r = (r + src_ptr[8*x+2+src_stride])>>1;            u_ptr[x] = rgb2u(r, g, b);            v_ptr[x] = rgb2v(r, g, b);            uva_ptr[x] = (a + src_ptr[8*x+3+src_stride])>>1;            y_ptr[2*x+1] = rgb2y(src_ptr[8*x+6], src_ptr[8*x+5], src_ptr[8*x+4]);            a_ptr[2*x+1] = src_ptr[8*x+7];        }        y_ptr += this->osd_w;        a_ptr += this->osd_w;        src_ptr += src_stride;        for (x = 0; x < rw >> 1; x++) {            y_ptr[2*x] = rgb2y(src_ptr[8*x+2], src_ptr[8*x+1], src_ptr[8*x+0]);            a_ptr[2*x] = src_ptr[8*x+3];            y_ptr[2*x+1] = rgb2y(src_ptr[8*x+6], src_ptr[8*x+5], src_ptr[8*x+4]);            a_ptr[2*x+1] = src_ptr[8*x+7];        }        y_ptr += this->osd_w;        a_ptr += this->osd_w;        src_ptr += src_stride;        u_ptr += chroma_stride;        v_ptr += chroma_stride;        uva_ptr += chroma_stride;    }    stopwatch(2, NULL);}static voidconvert_bgra_to_frame_format(kaa_driver_t *this, int rx, int ry, int rw, int rh){    if (!this->osd_planes[0]) // Not allocated yet.        return;    if (!check_bounds(this, rx, ry, rw, rh))        return;    rx=ry=0;    rw=this->osd_w; rh=this->osd_h;        if (this->osd_format == XINE_IMGFMT_YV12)        convert_bgra_to_yv12a(this, rx, ry, rw, rh);    else if (this->osd_format == XINE_IMGFMT_YUY2)        convert_bgra_to_yuy2a(this, rx, ry, rw, rh);}static inline uint8_tmultiply_alpha(uint8_t r, uint8_t a){    int temp = (r * a) + 0x80;    return ((temp + (temp >> 8)) >> 8);}/// Blends src on top of dst at the given alpha level.#define blend_byte(dst, src, alpha) multiply_alpha(dst, alpha) + src;static inline voidpremultiply_alpha_byte(uint8_t byte, uint8_t alpha,                       uint8_t *dst_byte, uint8_t *dst_alpha,                       int global_alpha){    uint8_t a = (global_alpha < 255) ? alpha * global_alpha >> 8 : alpha;    *dst_byte = multiply_alpha(byte, a);    *dst_alpha = 255-a;}/** * \brief Alpha-multiplies 8 consecutive bytes. C version. */static inline voidpremultiply_alpha_byte_8_C(uint8_t *byte, uint8_t *alpha,                           uint8_t *dst_byte, uint8_t *dst_alpha,                           int global_alpha){    int i;    for (i = 0; i < 8; i++)        premultiply_alpha_byte(*(byte++), *(alpha++), dst_byte++, dst_alpha++, global_alpha);}#if defined(ARCH_X86) || defined(ARCH_X86_64)/** * \brief Alpha-multiplies 8 consecutive bytes. MMX version. */static inline voidpremultiply_alpha_byte_8_MMX(uint8_t *byte, uint8_t *alpha,                             uint8_t *dst_byte, uint8_t *dst_alpha,                             int global_alpha){    asm volatile(        ".balign 16 \n\t"        "movq (%3), %%mm5\n\t"        // %mm5 = alpha        "cmp $255, %4\n\t"           // don't apply layer alpha if it's 100% opaque        "je 42f\n\t"        // Modify alpha from image with layer alpha        "movq %%mm5, %%mm6\n\t"       // %mm6 = %mm5 = alpha        "punpcklbw %%mm7, %%mm5\n\t"  // %mm5 = low dword of alpha        "punpckhbw %%mm7, %%mm6\n\t"  // %mm6 = hi dword of alpha        "pmullw "MANGLE(MM_global_alpha)", %%mm5\n\t"  // alpha * global_alpha        "pmullw "MANGLE(MM_global_alpha)", %%mm6\n\t"        "psrlw $8, %%mm5\n\t"         // Divide by 256        "psrlw $8, %%mm6\n\t"        "packuswb %%mm6, %%mm5\n\t"   // Pack back into %mm5        "42: \n\t"        "movq %%mm4, %%mm6\n\t"       // %mm4 = %mm6 = 255        "psubb %%mm5, %%mm6\n\t"      // %mm6 = 255 - alpha        "movq %%mm6, (%1)\n\t"        // save modified alpha        // Do alpha * bytes        "movq (%2), %%mm0\n\t"        // %mm0 = byte        "movq %%mm0, %%mm1\n\t"       // %mm1 = byte        "punpcklbw %%mm7, %%mm0\n\t"  // %mm0 = low dword of bytes        "punpckhbw %%mm7, %%mm1\n\t"  // %mm1 = hi dword of bytes        "movq %%mm5, %%mm6\n\t"       // %mm5 = %mm6 = alpha        "punpcklbw %%mm7, %%mm5\n\t"  // %mm5 = low dword alpha        "punpckhbw %%mm7, %%mm6\n\t"  // %mm6 = hi dword alpha        "pmullw %%mm5, %%mm0\n\t"     // alpha * bytes = (r*a)        "pmullw %%mm6, %%mm1\n\t"        // approximate division by 255        "movq "MANGLE(MM_ROUND)", %%mm6\n\t"   // %mm4 = round        "paddw %%mm6, %%mm0\n\t"      // (r*a) + 0x80        "paddw %%mm6, %%mm1\n\t"        "movq %%mm0, %%mm2\n\t"       // temp = (r*a) + 0x80        "movq %%mm1, %%mm3\n\t"        "psrlw $8, %%mm0\n\t"         // temp >> 8        "psrlw $8, %%mm1\n\t"        "paddw %%mm2, %%mm0\n\t"      // temp + (temp >> 8)        "paddw %%mm3, %%mm1\n\t"        "psrlw $8, %%mm0\n\t"         // (temp+(temp>>8))>>8        "psrlw $8, %%mm1\n\t"        "packuswb %%mm1, %%mm0\n\t"        "movq %%mm0, (%0)\n\t"    :  "+r" (dst_byte),             // %0       "+r" (dst_alpha)             // %1    :  "r" (byte),                  // %2       "r" (alpha),                 // %3       "r" (global_alpha));         // %4}#endifstatic void(*premultiply_alpha_byte_8)(uint8_t *byte, uint8_t *alpha,                            uint8_t *dst_byte, uint8_t *dst_alpha,                            int global_alpha);static voidimage_premultiply_alpha(kaa_driver_t *this, int rx, int ry, int rw, int rh){    uint8_t *ptr[3], *alpha_ptr[3], *pre_ptr[3], *pre_alpha_ptr[3];    int i, x, y, n_planes, offset[3], global_alpha = this->osd_alpha;    if (!this->osd_planes[0]) // Not allocated yet.        return;    if (!check_bounds(this, rx, ry, rw, rh))        return;    stopwatch(2, "premultiply_alpha (%d,%d %dx%d)", rx, ry, rw, rh);    if (global_alpha > 255)        global_alpha = 255;    rx=ry=0;    rw=this->osd_w; rh=this->osd_h;    if (this->osd_format == XINE_IMGFMT_YV12) {        offset[0] = rx + ry * this->osd_strides[0];        offset[1] = offset[2] = (rx >> 1) + (ry >> 1) * this->osd_strides[1];    } else {        offset[0] = (rx*2) + ry * this->osd_strides[0];        offset[1] = offset[2] = 0;        rw *= 2;    }    for (i = 0; i < 3 && this->osd_planes[i]; i++) {        ptr[i] = this->osd_planes[i] + offset[i];        alpha_ptr[i] = this->osd_alpha_planes[i] + offset[i];        pre_ptr[i] = this->osd_pre_planes[i] + offset[i];        pre_alpha_ptr[i] = this->osd_pre_alpha_planes[i] + offset[i];    }#if defined(ARCH_X86) || defined(ARCH_X86_64)    if (xine_mm_accel() & MM_ACCEL_X86_MMX) {        MM_global_alpha = C64(global_alpha);        asm volatile(            "pxor %%mm7, %%mm7\n\t"                // zero out %mm7            "pcmpeqb %%mm4, %%mm4\n\t"             // %mm4 = 255's            ::: "memory"        );    }#endif    for (y = 0; y < rh; y++) {        n_planes = 1;        for (x = 0; x < rw; x += 8)            premultiply_alpha_byte_8(&ptr[0][x], &alpha_ptr[0][x], &pre_ptr[0][x], &pre_alpha_ptr[0][x], global_alpha);        for (; x < rw; x++)            premultiply_alpha_byte(ptr[0][x], alpha_ptr[0][x], &pre_ptr[0][x], &pre_alpha_ptr[0][x], global_alpha);        if (y % 2 == 0 && this->osd_format == XINE_IMGFMT_YV12) {            for (x = 0; x < (rw >> 1); x += 8) {                premultiply_alpha_byte_8(&ptr[1][x], &alpha_ptr[1][x], &pre_ptr[1][x], &pre_alpha_ptr[1][x], global_alpha);                premultiply_alpha_byte_8(&ptr[2][x], &alpha_ptr[2][x], &pre_ptr[2][x], &pre_alpha_ptr[2][x], global_alpha);            }            for (; x < rw >> 1; x++) {                premultiply_alpha_byte(ptr[1][x], alpha_ptr[1][x], &pre_ptr[1][x], &pre_alpha_ptr[1][x], global_alpha);                premultiply_alpha_byte(ptr[2][x], alpha_ptr[2][x], &pre_ptr[2][x], &pre_alpha_ptr[2][x], global_alpha);            }            n_planes = 3;        }        for (i = 0; i < n_planes; i++) {            ptr[i] += this->osd_strides[i];            alpha_ptr[i] += this->osd_strides[i];            pre_ptr[i] += this->osd_strides[i];            pre_alpha_ptr[i] += this->osd_strides[i];        }    }#if defined(ARCH_X86) || defined(ARCH_X86_64)    if (xine_mm_accel() & MM_ACCEL_X86_MMX)        asm volatile( "emms\n\t" ::: "memory" );#endif    stopwatch(2, NULL);}static inline voidblend_plane_C(long w, long slice_h, uint8_t *dst, uint8_t *src,              uint8_t *overlay, uint8_t *alpha, long frame_stride,              long overlay_stride){    int x, y;    for (y = 0; y < slice_h; y++) {        for (x = 0; x < w; x++)            *(dst + x) = blend_byte(*(src+x), *(overlay+x), *(alpha+x));        dst += frame_stride;        src += frame_stride;        overlay += overlay_stride;        alpha += overlay_stride;    }}#if defined(ARCH_X86) || defined(ARCH_X86_64)static inline voidblend_plane_MMX(long w, long slice_h, uint8_t *dst, uint8_t *src,                uint8_t *overlay, uint8_t *alpha, long frame_stride,                long overlay_stride){    int i, y, q = w / 8, r = w % 8;    assert(w <= frame_stride && w <= overlay_stride);    for (y = 0; y < slice_h; y++) {        if (q) {            asm volatile(                ".balign 16 \n\t"                "xor %%"REG_c", %%"REG_c"\n\t"                "1: \n\t"                "movq (%1, %%"REG_c"), %%mm0\n\t"        // %mm0 = mpi                "movq %%mm0, %%mm1\n\t"       // %mm1 = mpi                "movq (%3, %%"REG_c"), %%mm2\n\t"        // %mm2 = %mm3 = 255 - alpha                "movq %%mm2, %%mm3\n\t"                "punpcklbw %%mm7, %%mm0\n\t"  // %mm0 = low dword of mpi                "punpckhbw %%mm7, %%mm1\n\t"  // %mm1 = hi dword of mpi                "punpcklbw %%mm7, %%mm2\n\t"  // %mm0 = low dword of 255-a                "punpckhbw %%mm7, %%mm3\n\t"  // %mm1 = hi dword of 255-a                "pmullw %%mm2, %%mm0\n\t"     // (255-a) * mpi = (r*a)                "pmullw %%mm3, %%mm1\n\t"                // approximate division by 255                "paddw %%mm5, %%mm0\n\t"      // (r*a) + 0x80                "paddw %%mm5, %%mm1\n\t"                "movq %%mm0, %%mm2\n\t"       // temp = (r*a) + 0x80                "movq %%mm1, %%mm3\n\t"                "psrlw $8, %%mm0\n\t"         // temp >> 8                "psrlw $8, %%mm1\n\t"                "paddw %%mm2, %%mm0\n\t"      // temp + (temp >> 8)                "paddw %%mm3, %%mm1\n\t"                "psrlw $8, %%mm0\n\t"         // (temp+(temp>>8))>>8                "psrlw $8, %%mm1\n\t"                // MPI plane now alpha-multiplied. Add to premultiplied                // overlay plane.                "movq (%2, %%"REG_c"), %%mm2\n\t"        // %mm2 = src image (overlay)                "packuswb %%mm1, %%mm0\n\t"                "paddb %%mm2, %%mm0\n\t"                "movq %%mm0, (%0, %%"REG_c")\n\t"        // Store to dst (mpi)                "add $8, %%"REG_c"\n\t"                "cmp %4, %%"REG_c"\n\t"                "jb 1b \n\t"            : "+r" (dst),              "+r" (src),              "+r" (overlay),              "+r" (alpha)            : "m" (w)            : "%"REG_c);        }        // Blend the last few pixels of this row ...        if (r) {            for (i = 0; i < r; i++)                *(dst+i) = blend_byte(*(src+i), *(overlay+i), *(alpha+i));        }        src += frame_stride;        dst += frame_stride;        alpha += overlay_stride;        overlay += overlay_stride;    }}#endifstatic void(*blend_plane)(long w, long slice_h, uint8_t *dst, uint8_t *src,               uint8_t *overlay, uint8_t *alpha, long frame_stride,               long overlay_stride);static inline voidblend_image(kaa_driver_t *this, vo_frame_t *frame){    int slice_y, slice_h, w, i, c, plane;    uint8_t *dst_frame_planes[3], *src_frame_planes[3], *overlay, *src, *dst, *alpha,            *overlay_planes[3], *alpha_planes[3];    if (!this->osd_planes[0]) // Not allocated yet.        return;    // Clip the slice to the frame image.    slice_y = 0; //clamp(this->osd_slice_y, 0, frame->height);    slice_h = this->osd_h; //clamp(this->osd_slice_h, 0, frame->height - slice_y);    stopwatch(5, "blend_image (0,%d, %dx%d)",  slice_y, this->osd_w, slice_h);    for (i = 0, c = 0; i < 3; i++, c = 1)  {        // Setup buffer positions for overlay, mpi src and mpi dst.        overlay_planes[i] = this->osd_pre_planes[i];        alpha_planes[i] = this->osd_pre_alpha_planes[i];        dst_frame_planes[i] = frame->base[i] + ((slice_y >> c) * frame->pitches[i]);        src_frame_planes[i] = frame->base[i] + ((slice_y >> c) * frame->pitches[i]);        overlay_planes[i] += (slice_y >> c) * this->osd_strides[i];        alpha_planes[i] += (slice_y >> c) * this->osd_strides[i];    }#if defined(ARCH_X86) || defined(ARCH_X86_64)    if (xine_mm_accel() & MM_ACCEL_X86_MMX) {        asm volatile(            "pxor %%mm7, %%mm7\n\t"                // zero out %mm7            "movq "MANGLE(MM_ROUND)", %%mm5\n\t"   // %mm5 = round            ::: "memory"        );    }#endif    w = this->osd_w;    if (frame->format == XINE_IMGFMT_YUY2)        w *= 2;    for (plane = 0; plane < 3 && this->osd_planes[plane]; plane++) {        if (plane == 1 && frame->format == XINE_IMGFMT_YV12) {            w >>= 1;            slice_h >>= 1;        }        overlay = overlay_planes[plane];        alpha = alpha_planes[plane];        src = src_frame_planes[plane];        dst = dst_frame_planes[plane];        // Global alpha is 256 which means ignore per-pixel alpha. Do        // straight memcpy.        if (this->osd_alpha == 256) {            xine_fast_memcpy(dst, overlay, this->osd_strides[plane] * slice_h);        } else {            blend_plane(w, slice_h, dst, src, overlay, alpha,                        frame->pitches[plane], this->osd_strides[plane]);        }    }#if defined(ARCH_X86) || defined(ARCH_X86_64)    if (xine_mm_accel() & MM_ACCEL_X86_MMX)        asm volatile( "emms\n\t" ::: "memory" );#endif    stopwatch(5, NULL);}/////////////////////////////////////////////////////////////////////////////static uint32_tkaa_get_capabilities(vo_driver_t *this_gen){    //kaa_driver_t *this = (kaa_driver_t *)this_gen;    //printf("kaa: get_capabilities\n");    return VO_CAP_YV12 | VO_CAP_YUY2;}static voidkaa_frame_field(vo_frame_t *frame_gen, int which){    kaa_frame_t *frame = (kaa_frame_t *)frame_gen;    //printf("kaa_frame_field %d\n", which);    frame->passthrough_frame->field(frame->passthrough_frame, which);}static voidkaa_frame_proc_frame(vo_frame_t *frame_gen){    kaa_frame_t *frame = (kaa_frame_t *)frame_gen;    //printf("kaa_frame_proc_frame\n");    frame->passthrough_frame->proc_frame(frame->passthrough_frame);}static voidkaa_frame_dispose(vo_frame_t *vo_img){    kaa_frame_t *frame = (kaa_frame_t *)vo_img;    //printf("kaa_frame_dispose\n");    pthread_mutex_destroy(&frame->vo_frame.mutex);    // Why does this segfault?    //if (frame->passthrough_frame)    //    frame->passthrough_frame->dispose(frame->passthrough_frame);    if (frame->driver->handle_frame_cb)        frame->driver->handle_frame_cb(KAA_VO_HANDLE_FRAME_DISPOSE, vo_img, &frame->user_data, frame->driver->handle_frame_cb_data);    free(frame);}void vo_frame_inc_lock(vo_frame_t *img){}void vo_frame_dec_lock(vo_frame_t *img){}static vo_frame_t *kaa_alloc_frame(vo_driver_t *this_gen){    kaa_frame_t *frame;    kaa_driver_t *this = (kaa_driver_t *)this_gen;    //printf("kaa_alloc_frame\n");    frame = (kaa_frame_t *)xine_xmalloc(sizeof(kaa_frame_t));    if (!frame)        return NULL;    pthread_mutex_init(&frame->vo_frame.mutex, NULL);    frame->vo_frame.base[0] = NULL;    frame->vo_frame.base[1] = NULL;    frame->vo_frame.base[2] = NULL;    frame->passthrough_frame = this->passthrough->alloc_frame(this->passthrough);    frame->passthrough_frame->free = vo_frame_dec_lock;    frame->passthrough_frame->lock = vo_frame_inc_lock;    if (frame->passthrough_frame->proc_frame)        frame->vo_frame.proc_frame = kaa_frame_proc_frame;    frame->vo_frame.field = kaa_frame_field;    frame->vo_frame.dispose = kaa_frame_dispose;    frame->vo_frame.driver = this_gen;    frame->driver = this;    if (this->handle_frame_cb)        this->handle_frame_cb(KAA_VO_HANDLE_FRAME_ALLOC, (vo_frame_t *)frame, &frame->user_data, this->handle_frame_cb_data);    return (vo_frame_t *)frame;}static voidkaa_update_frame_format (vo_driver_t *this_gen,                vo_frame_t *frame_gen,                uint32_t width, uint32_t height,                double ratio, int format, int flags){    kaa_driver_t *this = (kaa_driver_t *)this_gen;    kaa_frame_t *frame = (kaa_frame_t *)frame_gen;    //printf("kaa_update_frame_format: %x format=%d  %dx%d\n", frame, format, width, height);    // XXX: locking in this function risks deadlock.    frame_gen->proc_called=0;    this->passthrough->update_frame_format(this->passthrough,        frame->passthrough_frame, width, height, ratio, format, flags);    xine_fast_memcpy(&frame->vo_frame.pitches, frame->passthrough_frame->pitches, sizeof(int)*3);    xine_fast_memcpy(&frame->vo_frame.base, frame->passthrough_frame->base, sizeof(char *)*3);    if (this->handle_frame_cb)        this->handle_frame_cb(KAA_VO_HANDLE_FRAME_UPDATE, frame_gen, &frame->user_data, this->handle_frame_cb_data);    frame->width = width;    frame->height = height;    frame->format = format;    frame->ratio = ratio;    frame->flags = flags;}static intkaa_redraw_needed(vo_driver_t *vo){    kaa_driver_t *this = (kaa_driver_t *)vo;    int redraw = this->needs_redraw;    this->needs_redraw = 0;    return redraw || (this->do_passthrough && this->passthrough->redraw_needed(this->passthrough));}static int_kaa_blend_osd(kaa_driver_t *this, kaa_frame_t *frame){    pthread_mutex_lock(&this->osd_buffer_lock);    int resized = frame->width != this->osd_w || frame->height != this->osd_h;    if (resized || frame->format != this->osd_format) {        if (this->osd_configure_cb && resized) {            // XXX: could configure cb cause reentry here?  If so, will deadlock.            this->osd_configure_cb(frame->width, frame->height, frame->ratio, this->osd_configure_cb_data,                                   &this->osd_buffer, &this->osd_stride);        }        if (this->osd_buffer && this->osd_stride > 0) {            this->osd_w = frame->width;            this->osd_h = frame->height;            this->osd_slice_h = frame->height;            alloc_overlay_data(this, frame->format);            convert_bgra_to_frame_format(this, 0, 0, frame->width, frame->height);            image_premultiply_alpha(this, 0, 0, frame->width, frame->height);            calculate_slice(this);        } else {            printf("OSD CONFIGURE FAILED\n");        }    }    if (this->osd_visible && this->osd_alpha > 0 && this->osd_buffer)        blend_image(this, &frame->vo_frame);    pthread_mutex_unlock(&this->osd_buffer_lock);    return 1;}static voidkaa_display_frame (vo_driver_t *this_gen, vo_frame_t *frame_gen){    kaa_driver_t *this = (kaa_driver_t *)this_gen;    kaa_frame_t *frame = (kaa_frame_t *)frame_gen;    if (this->handle_frame_cb)        this->handle_frame_cb(KAA_VO_HANDLE_FRAME_DISPLAY_PRE_OSD, frame_gen, &frame->user_data, this->handle_frame_cb_data);    if (this->osd_configure_cb)        _kaa_blend_osd(this, frame);    if (this->handle_frame_cb)        this->handle_frame_cb(KAA_VO_HANDLE_FRAME_DISPLAY_POST_OSD, frame_gen, &frame->user_data, this->handle_frame_cb_data);    if (frame->passthrough_frame->proc_slice) {        // Serious kludge!  For passthrough drivers that do slices, we delay        // processing them until now so that we have a chance to blend the        // OSD.        int i;        uint8_t *src[3] = {frame->vo_frame.base[0], frame->vo_frame.base[1], frame->vo_frame.base[2]};        for (i = 0; i < frame->height / 16; i++) {            frame->passthrough_frame->proc_slice(frame->passthrough_frame, src);            src[0] += frame->vo_frame.pitches[0] * 16;            src[1] += frame->vo_frame.pitches[1] * 8;            src[2] += frame->vo_frame.pitches[2] * 8;        }    }    if (this->passthrough && this->do_passthrough)        this->passthrough->display_frame(this->passthrough, frame->passthrough_frame);    this->last_frame = frame;    frame->vo_frame.free(&frame->vo_frame);}static intkaa_get_property (vo_driver_t *this_gen, int property){    if(this_gen==NULL)        return 0;    else    {        kaa_driver_t *this = (kaa_driver_t *)this_gen;        return this->passthrough->get_property(this->passthrough, property);    }}static intkaa_set_property (vo_driver_t *this_gen,                int property, int value){    kaa_driver_t *this = (kaa_driver_t *)this_gen;    return this->passthrough->set_property(this->passthrough, property, value);}static voidkaa_get_property_min_max (vo_driver_t *this_gen,                     int property, int *min, int *max){    kaa_driver_t *this = (kaa_driver_t *)this_gen;    //printf("kaa_get_property_min_max\n");    this->passthrough->get_property_min_max(this->passthrough, property, min, max);}static intkaa_gui_data_exchange (vo_driver_t *this_gen,                 int data_type, void *data){    kaa_driver_t *this = (kaa_driver_t *)this_gen;    switch(data_type) {        case GUI_SEND_KAA_VO_SET_PASSTHROUGH:            this->do_passthrough = (int)data;            if (this->do_passthrough)                this->needs_redraw = 1;            break;        case GUI_SEND_KAA_VO_OSD_SET_VISIBILITY:            this->osd_visible = (int)data;            this->needs_redraw = 1;            break;        case GUI_SEND_KAA_VO_OSD_INVALIDATE_RECT:        {            struct { int x, y, w, h; } *r = data;            int i;            pthread_mutex_lock(&this->osd_buffer_lock);            for (i = 0; r[i].w; i++) {                convert_bgra_to_frame_format(this, r[i].x, r[i].y, r[i].w, r[i].h);                image_premultiply_alpha(this, r[i].x, r[i].y, r[i].w, r[i].h);            }            calculate_slice(this);            pthread_mutex_unlock(&this->osd_buffer_lock);            this->needs_redraw = 1;            break;        }        case GUI_SEND_KAA_VO_OSD_SET_ALPHA:        {            int alpha = (int)data;            pthread_mutex_lock(&this->osd_buffer_lock);            if (alpha != this->osd_alpha) {                this->osd_alpha = alpha;                image_premultiply_alpha(this, 0, 0, this->osd_w, this->osd_h);                this->needs_redraw = 1;            }            pthread_mutex_unlock(&this->osd_buffer_lock);            break;        }        /*        case GUI_SEND_KAA_VO_OSD_SET_SLICE:        {            struct { int y, h; } *slice = data;            this->osd_slice_y = slice->y;            this->osd_slice_h = slice->h;            this->needs_redraw = 1;            break;        }        */    }    return this->passthrough->gui_data_exchange(this->passthrough, data_type, data);}static void kaa_overlay_begin (vo_driver_t *this_gen,                  vo_frame_t *frame_gen, int changed) {  kaa_driver_t  *this  = (kaa_driver_t *) this_gen;  this->alphablend_extra_data.offset_x = frame_gen->overlay_offset_x;  this->alphablend_extra_data.offset_y = frame_gen->overlay_offset_y;}static voidkaa_overlay_blend(vo_driver_t *this_gen, vo_frame_t *frame_gen, vo_overlay_t *vo_overlay){    kaa_frame_t *frame = (kaa_frame_t *)frame_gen;    kaa_driver_t *this = (kaa_driver_t *)this_gen;    if (frame->format == XINE_IMGFMT_YV12)       _x_blend_yuv(frame->vo_frame.base, vo_overlay,                      frame->width, frame->height,                      frame->vo_frame.pitches, &this->alphablend_extra_data);    else       _x_blend_yuy2(frame->vo_frame.base[0], vo_overlay,                      frame->width, frame->height,                      frame->vo_frame.pitches[0], &this->alphablend_extra_data);}static voidkaa_dispose(vo_driver_t *this_gen){    kaa_driver_t *this = (kaa_driver_t *)this_gen;    //printf("kaa_dispose\n");    //this->yuv2rgb_factory->dispose(this->yuv2rgb_factory);    free_overlay_data(this);    pthread_mutex_destroy(&this->lock);    pthread_mutex_destroy(&this->osd_buffer_lock);    free(this);}static vo_driver_t *kaa_open_plugin(video_driver_class_t *class_gen, const void *visual_gen){    kaa_class_t *class = (kaa_class_t *)class_gen;    kaa_visual_t *visual = (kaa_visual_t *)visual_gen;    kaa_driver_t *this;    // This deadlocks -- xine-lib needs fixing.  For now, caller will have to do this.    /*    vo_driver_t *passthrough;    passthrough = _x_load_video_output_plugin(class->xine, visual->passthrough_driver,                                              visual->passthrough_visual_type, visual->passthrough_visual);    if (!passthrough) {        return NULL;    }    */    //printf("kaa_open_plugin\n");    this = (kaa_driver_t *)xine_xmalloc(sizeof(kaa_driver_t));    memset(this, 0, sizeof(kaa_driver_t));    if (!this)        return NULL;    this->xine = class->xine;    this->config = class->config;    pthread_mutex_init(&this->lock, NULL);    pthread_mutex_init(&this->osd_buffer_lock, NULL);    this->vo_driver.get_capabilities        = kaa_get_capabilities;    this->vo_driver.alloc_frame             = kaa_alloc_frame;    this->vo_driver.update_frame_format     = kaa_update_frame_format;    this->vo_driver.overlay_begin           = kaa_overlay_begin;    this->vo_driver.overlay_blend           = kaa_overlay_blend;    this->vo_driver.overlay_end             = NULL;    this->vo_driver.display_frame           = kaa_display_frame;    this->vo_driver.get_property            = kaa_get_property;    this->vo_driver.set_property            = kaa_set_property;    this->vo_driver.get_property_min_max    = kaa_get_property_min_max;    this->vo_driver.gui_data_exchange       = kaa_gui_data_exchange;    this->vo_driver.dispose                 = kaa_dispose;    this->vo_driver.redraw_needed           = kaa_redraw_needed;    //this->passthrough           = passthrough;    this->passthrough           = visual->passthrough;    this->osd_buffer            = 0;    this->osd_stride            = 0;    this->handle_frame_cb       = visual->handle_frame_cb;    this->handle_frame_cb_data  = visual->handle_frame_cb_data;    this->osd_configure_cb      = visual->osd_configure_cb;    this->osd_configure_cb_data = visual->osd_configure_cb_data;    this->do_passthrough        = 1;    this->osd_visible           = 0;    this->osd_w                 = -1;    this->osd_h                 = -1;    this->osd_alpha             = 255;    return &this->vo_driver;}static char *kaa_get_identifier(video_driver_class_t *this_gen){    return "kaa";}static char *kaa_get_description(video_driver_class_t *this_gen){    return "Passthrough driver with OSD and buffer output.";}static voidkaa_dispose_class(video_driver_class_t *this_gen){    //printf("kaa_dispose_class\n");    free(this_gen);}static void *kaa_init_class (xine_t *xine, void *visual_gen){    //printf("kaa_init_class\n");    kaa_class_t *this;    this = (kaa_class_t *)xine_xmalloc(sizeof(kaa_class_t));    init_rgb2yuv_tables();    premultiply_alpha_byte_8 = premultiply_alpha_byte_8_C;    blend_plane = blend_plane_C;#if defined(ARCH_X86) || defined(ARCH_X86_64)    if (xine_mm_accel() & MM_ACCEL_X86_MMX) {        premultiply_alpha_byte_8 = premultiply_alpha_byte_8_MMX;        blend_plane = blend_plane_MMX;    }#endif    this->driver_class.open_plugin      = kaa_open_plugin;    this->driver_class.get_identifier   = kaa_get_identifier;    this->driver_class.get_description  = kaa_get_description;    this->driver_class.dispose          = kaa_dispose_class;    this->config = xine->config;    this->xine   = xine;    return this;}static vo_info_t kaa_vo_info = {    1,    XINE_VISUAL_TYPE_NONE};plugin_info_t xine_vo_kaa_plugin_info[] = {    { PLUGIN_VIDEO_OUT, 21, "kaa", XINE_VERSION_CODE, &kaa_vo_info, &kaa_init_class },    { PLUGIN_NONE, 0, "", 0, NULL, NULL }};