/******************************************************************************
*                            recordMyDesktop                                  *
*******************************************************************************
*                                                                             *
*            Copyright (C) 2006,2007 John Varouhakis                          *
*                                                                             *
*                                                                             *
*   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            *
*   MERCHANTABILITY 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  *
*                                                                             *
*                                                                             *
*                                                                             *
*   For further information contact me at johnvarouhakis@gmail.com            *
******************************************************************************/

#ifndef RMDMACRO_H
#define RMDMACRO_H 1

#ifdef HAVE_CONFIG_H
    #include <config.h>
#endif

#include "rmdtypes.h"

//define which way we are reading a pixmap
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define __ABYTE 3
#define __RBYTE 2
#define __GBYTE 1
#define __BBYTE 0

#elif __BYTE_ORDER == __BIG_ENDIAN

#define __ABYTE 0
#define __RBYTE 1
#define __GBYTE 2
#define __BBYTE 3

#else
#error Only little-endian and big-endian systems are supported
#endif

#define __RVALUE_32(tmp_val) (((tmp_val)&0x00ff0000)>>16)
#define __GVALUE_32(tmp_val) (((tmp_val)&0x0000ff00)>>8)
#define __BVALUE_32(tmp_val) (((tmp_val)&0x000000ff))

#define __R16_MASK  0xf800
#define __G16_MASK  0x7e0
#define __B16_MASK  0x1f

#define __RVALUE_16(tmp_val) ((((tmp_val)&__R16_MASK)>>11)*8)
#define __GVALUE_16(tmp_val) ((((tmp_val)&__G16_MASK)>>5)*4)
#define __BVALUE_16(tmp_val) ((((tmp_val)&__B16_MASK))*8)

//xfixes pointer data are written as unsigned long
//(even though the server returns CARD32)
//so we need to set the step accordingly to
//avoid problems (amd64 has 8byte ulong)
#define RMD_ULONG_SIZE_T (sizeof(unsigned long))

//size of stride when comparing planes(depending on type)
//this is just to avoid thousands of sizeof's
#ifdef HAVE_U_INT64_T
    #define COMPARE_STRIDE  8
#else
    #define COMPARE_STRIDE  4
#endif

//500 mb file size
#define CACHE_FILE_SIZE_LIMIT (500*1<<20)
//minimize hard disk access
#define CACHE_OUT_BUFFER_SIZE 4096


//The width, in bytes, of the blocks
//on which the y,u and v planes are broken.
//These blocks are square.
#define Y_UNIT_WIDTH    0x0010
#define UV_UNIT_WIDTH   0x0008

//The number of bytes for every
//sub-block of the y,u and v planes.
//Since the blocks are square
//these are obviously the squares
//of the widths(specified above),
//but the definitions bellow are only
//for convenience anyway.
#define Y_UNIT_BYTES    0x0100
#define UV_UNIT_BYTES   0x0040

#ifdef HAVE_LIBASOUND
    #define DEFAULT_AUDIO_DEVICE "hw:0,0"
#else
    #define DEFAULT_AUDIO_DEVICE "/dev/dsp"
#endif



#define CLIP_EVENT_AREA(e,brwin,wgeom){\
    if(((e)->area.x<=(brwin)->rgeom.x)&&((e)->area.y<=(brwin)->rgeom.y)&&\
        ((e)->area.width>=(brwin)->rgeom.width)&&\
        ((e)->area.height<(brwin)->rgeom.height)){\
        (wgeom)->x=(brwin)->rgeom.x;\
        (wgeom)->y=(brwin)->rgeom.y;\
        (wgeom)->width=(brwin)->rgeom.width;\
        (wgeom)->height=(brwin)->rgeom.height;\
    }\
    else{\
        (wgeom)->x=((((e)->area.x+(e)->area.width>=(brwin)->rgeom.x)&&\
        ((e)->area.x<=(brwin)->rgeom.x+(brwin)->rgeom.width))?\
        (((e)->area.x<=(brwin)->rgeom.x)?(brwin)->rgeom.x:(e)->area.x):-1);\
    \
        (wgeom)->y=((((e)->area.y+(e)->area.height>=(brwin)->rgeom.y)&&\
        ((e)->area.y<=(brwin)->rgeom.y+(brwin)->rgeom.height))?\
        (((e)->area.y<=(brwin)->rgeom.y)?(brwin)->rgeom.y:(e)->area.y):-1);\
    \
        (wgeom)->width=((e)->area.x<=(brwin)->rgeom.x)?\
        (e)->area.width-((brwin)->rgeom.x-(e)->area.x):\
        ((e)->area.x<=(brwin)->rgeom.x+(brwin)->rgeom.width)?\
        (((brwin)->rgeom.width-(e)->area.x+(brwin)->rgeom.x<(e)->area.width)?\
        (brwin)->rgeom.width-(e)->area.x+(brwin)->rgeom.x:e->area.width):-1;\
    \
        (wgeom)->height=((e)->area.y<=(brwin)->rgeom.y)?\
        (e)->area.height-((brwin)->rgeom.y-(e)->area.y):\
        ((e)->area.y<=(brwin)->rgeom.y+(brwin)->rgeom.height)?\
        (((brwin)->rgeom.height-(e)->area.y+\
         (brwin)->rgeom.y<(e)->area.height)?\
         (brwin)->rgeom.height-(e)->area.y+\
         (brwin)->rgeom.y:(e)->area.height):-1;\
    \
        if((wgeom)->width>(brwin)->rgeom.width)\
            (wgeom)->width=(brwin)->rgeom.width;\
        if((wgeom)->height>(brwin)->rgeom.height)\
            (wgeom)->height=(brwin)->rgeom.height;\
    }\
}

#define CLIP_DUMMY_POINTER_AREA(dummy_p_area,brwin,wgeom){\
    (wgeom)->x=((((dummy_p_area).x+\
                (dummy_p_area).width>=(brwin)->rgeom.x)&&\
                ((dummy_p_area).x<=(brwin)->rgeom.x+\
                (brwin)->rgeom.width))?\
                (((dummy_p_area).x<=(brwin)->rgeom.x)?\
                (brwin)->rgeom.x:(dummy_p_area).x):-1);\
    (wgeom)->y=((((dummy_p_area).y+\
                (dummy_p_area).height>=(brwin)->rgeom.y)&&\
                ((dummy_p_area).y<=(brwin)->rgeom.y+\
                (brwin)->rgeom.height))?\
                (((dummy_p_area).y<=(brwin)->rgeom.y)?\
                (brwin)->rgeom.y:(dummy_p_area).y):-1);\
    (wgeom)->width=((dummy_p_area).x<=(brwin)->rgeom.x)?\
                (dummy_p_area).width-\
                ((brwin)->rgeom.x-(dummy_p_area).x):\
                ((dummy_p_area).x<=(brwin)->rgeom.x+\
                (brwin)->rgeom.width)?\
                ((brwin)->rgeom.width-(dummy_p_area).x+\
                (brwin)->rgeom.x<(dummy_p_area).width)?\
                (brwin)->rgeom.width-(dummy_p_area).x+\
                (brwin)->rgeom.x:(dummy_p_area).width:-1;\
    (wgeom)->height=((dummy_p_area).y<=(brwin)->rgeom.y)?\
                (dummy_p_area).height-\
                ((brwin)->rgeom.y-(dummy_p_area).y):\
                ((dummy_p_area).y<=(brwin)->rgeom.y+\
                (brwin)->rgeom.height)?\
                ((brwin)->rgeom.height-(dummy_p_area).y+\
                (brwin)->rgeom.y<(dummy_p_area).height)?\
                (brwin)->rgeom.height-(dummy_p_area).y+\
                (brwin)->rgeom.y:(dummy_p_area).height:-1;\
    if((wgeom)->width>(brwin)->rgeom.width)\
        (wgeom)->width=(brwin)->rgeom.width;\
    if((wgeom)->height>(brwin)->rgeom.height)\
        (wgeom)->height=(brwin)->rgeom.height;\
}



#define DEFAULT_ARGS(args){\
    (args)->delay=0;\
    if(getenv("DISPLAY")!=NULL){\
        (args)->display=(char *)malloc(strlen(getenv("DISPLAY"))+1);\
        strcpy((args)->display,getenv("DISPLAY"));\
    }\
    else\
        (args)->display=NULL;\
    (args)->windowid=\
    (args)->x=\
    (args)->y=\
    (args)->width=\
    (args)->height=\
    (args)->nosound=\
    (args)->full_shots=\
    (args)->follow_mouse=\
    (args)->encOnTheFly=\
    (args)->nowmcheck=\
    (args)->overwrite=\
    (args)->use_jack=\
    (args)->noshared=\
    (args)->no_encode=\
    (args)->jack_nports=0;\
    (args)->jack_ringbuffer_secs=3.0;\
    (args)->jack_port_names=NULL;\
    (args)->zerocompression=\
    (args)->no_quick_subsample=1;\
    (args)->filename=(char *)malloc(8);\
    strcpy((args)->filename,"out.ogg");\
    (args)->cursor_color=1;\
    (args)->have_dummy_cursor=0;\
    (args)->xfixes_cursor=1;\
    (args)->device=(char *)malloc(strlen(DEFAULT_AUDIO_DEVICE)+1);\
    strcpy((args)->device,DEFAULT_AUDIO_DEVICE);\
    (args)->fps=15;\
    (args)->channels=1;\
    (args)->frequency=22050;\
    (args)->buffsize=4096;\
    (args)->v_bitrate=45000;\
    (args)->v_quality=63;\
    (args)->s_quality=10;\
    (args)->workdir=(char *)malloc(5);\
    strcpy((args)->workdir,"/tmp");\
}

#define QUERY_DISPLAY_SPECS(display,specstruct){\
    (specstruct)->screen=DefaultScreen(display);\
    (specstruct)->width=DisplayWidth(display,(specstruct)->screen);\
    (specstruct)->height=DisplayHeight(display,(specstruct)->screen);\
    (specstruct)->root=RootWindow(display,(specstruct)->screen);\
    (specstruct)->visual=DefaultVisual(display,(specstruct)->screen);\
    (specstruct)->gc=DefaultGC(display,(specstruct)->screen);\
    (specstruct)->depth=DefaultDepth(display,(specstruct)->screen);\
    (specstruct)->bpixel=XBlackPixel(display,(specstruct)->screen);\
    (specstruct)->wpixel=XWhitePixel(display,(specstruct)->screen);\
}

#define AVG_4_PIXELS(data_array,width_img,k_tm,i_tm,offset)\
    ((data_array[(k_tm*width_img+i_tm)*RMD_ULONG_SIZE_T+offset]+\
    data_array[((k_tm-1)*width_img+i_tm)*RMD_ULONG_SIZE_T+offset]+\
    data_array[(k_tm*width_img+i_tm-1)*RMD_ULONG_SIZE_T+offset]+\
    data_array[((k_tm-1)*width_img+i_tm-1)*RMD_ULONG_SIZE_T+offset])/4)


//the 4 most significant bytes represent the A component which
//does not need to be added on t_val, as it is always unused
#define CALC_TVAL_AVG_32(t_val,datapi,datapi_next){\
    register unsigned int t1,t2,t3,t4;\
    t1=*datapi;\
    t2=*(datapi+1);\
    t3=*datapi_next;\
    t4=*(datapi_next+1);\
    t_val=((((t1&0x00ff0000) +(t2&0x00ff0000)+\
            (t3&0x00ff0000)+(t4&0x00ff0000))/4)&0x00ff0000)+\
          ((((t1&0x0000ff00) +(t2&0x0000ff00)+\
            (t3&0x0000ff00)+(t4&0x0000ff00))/4)&0x0000ff00)+\
          ((((t1&0x000000ff) +(t2&0x000000ff)+\
            (t3&0x000000ff)+(t4&0x000000ff))/4)&0x000000ff);\
}

//when adding the r values, we go beyond
//the (16 bit)range of the t_val variable, but we are performing
//32 bit arithmetics, so there's no problem.
//(This note is useless, I'm just adding because
//the addition of the A components in CALC_TVAL_AVG_32,
//now removed as uneeded, produced an overflow which would have caused
//color distrtion, where it one of the R,G or B components)
#define CALC_TVAL_AVG_16(t_val,datapi,datapi_next){\
    register u_int16_t t1,t2,t3,t4;\
    t1=*datapi;\
    t2=*(datapi+1);\
    t3=*datapi_next;\
    t4=*(datapi_next+1);\
    t_val=((((t1&__R16_MASK) +(t2&__R16_MASK)+\
             (t3&__R16_MASK)+(t4&__R16_MASK))/4)&__R16_MASK)+\
          ((((t1&__G16_MASK) +(t2&__G16_MASK)+\
             (t3&__G16_MASK)+(t4&__G16_MASK))/4)&__G16_MASK)+\
          ((((t1&__B16_MASK) +(t2&__B16_MASK)+\
             (t3&__B16_MASK)+(t4&__B16_MASK))/4)&__B16_MASK);\
}

#define POINT_IN_BLOCK(xv,yv,widthv,blocksize) ((yv/blocksize)*\
                                                (widthv/blocksize)+\
                                                (xv/blocksize))

#define UPDATE_Y_PLANE(data,\
                       x_tm,\
                       y_tm,\
                       height_tm,\
                       width_tm,\
                       yuv,\
                       __bit_depth__){ \
    int k,i;\
    register u_int##__bit_depth__##_t t_val;\
    register unsigned char  *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
                            *_yr=Yr,*_yg=Yg,*_yb=Yb;\
    register u_int##__bit_depth__##_t *datapi=(u_int##__bit_depth__##_t *)data;\
    for(k=0;k<height_tm;k++){\
        for(i=0;i<width_tm;i++){\
            t_val=*datapi;\
            *yuv_y=_yr[__RVALUE_##__bit_depth__(t_val)] +\
                   _yg[__GVALUE_##__bit_depth__(t_val)] +\
                   _yb[__BVALUE_##__bit_depth__(t_val)] ;\
            datapi++;\
            yuv_y++;\
        }\
        yuv_y+=yuv->y_width-width_tm;\
    }\
}

#define UPDATE_Y_PLANE_DBUF(data,\
                            data_back,\
                            x_tm,\
                            y_tm,\
                            height_tm,\
                            width_tm,\
                            yuv,\
                            __bit_depth__){ \
    int k,i;\
    register u_int##__bit_depth__##_t t_val;\
    register unsigned char  *yuv_y=yuv->y+x_tm+y_tm*yuv->y_width,\
                            *_yr=Yr,*_yg=Yg,*_yb=Yb;\
    register u_int##__bit_depth__##_t *datapi=(u_int##__bit_depth__##_t *)data,\
                            *datapi_back=(u_int##__bit_depth__##_t *)data_back;\
    for(k=0;k<height_tm;k++){\
        for(i=0;i<width_tm;i++){\
            if(*datapi!=*datapi_back){\
                t_val=*datapi;\
                *yuv_y=_yr[__RVALUE_##__bit_depth__(t_val)] +\
                    _yg[__GVALUE_##__bit_depth__(t_val)] +\
                    _yb[__BVALUE_##__bit_depth__(t_val)] ;\
                yblocks[POINT_IN_BLOCK(i,k,width_tm,Y_UNIT_WIDTH)]=1;\
            }\
            datapi++;\
            datapi_back++;\
            yuv_y++;\
        }\
        yuv_y+=yuv->y_width-width_tm;\
    }\
}

#define UPDATE_A_UV_PIXEL(yuv_u,\
                          yuv_v,\
                          t_val,\
                          datapi,\
                          datapi_next,\
                          _ur,_ug,_ubvr,_vg,_vb,\
                          __sampling_type,\
                          __bit_depth__)\
            if(__sampling_type==__PXL_AVERAGE){\
                CALC_TVAL_AVG_##__bit_depth__(t_val,datapi,datapi_next)\
            }\
            else\
                t_val=*datapi;\
            *yuv_u=\
            _ur[__RVALUE_##__bit_depth__(t_val)] +\
            _ug[__GVALUE_##__bit_depth__(t_val)] +\
            _ubvr[__BVALUE_##__bit_depth__(t_val)];\
            *yuv_v=\
            _ubvr[__RVALUE_##__bit_depth__(t_val)] +\
            _vg[__GVALUE_##__bit_depth__(t_val)] +\
            _vb[__BVALUE_##__bit_depth__(t_val)];\


#define UPDATE_UV_PLANES(data,\
                         x_tm,\
                         y_tm,\
                         height_tm,\
                         width_tm,\
                         yuv,\
                         __sampling_type,\
                         __bit_depth__){  \
    int k,i;\
    register u_int##__bit_depth__##_t t_val;\
    register unsigned char  *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
                            *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
                            *_ur=Ur,*_ug=Ug,*_ubvr=UbVr,\
                            *_vg=Vg,*_vb=Vb;\
    register u_int##__bit_depth__##_t *datapi=(u_int##__bit_depth__##_t *)data,\
                                      *datapi_next=NULL;\
    if(__sampling_type==__PXL_AVERAGE){\
        datapi_next=datapi+width_tm;\
    }\
    for(k=0;k<height_tm;k+=2){\
        for(i=0;i<width_tm;i+=2){\
            UPDATE_A_UV_PIXEL(  yuv_u,\
                                yuv_v,\
                                t_val,\
                                datapi,\
                                datapi_next,\
                                _ur,_ug,_ubvr,_vg,_vb,\
                                __sampling_type,\
                                __bit_depth__)\
            datapi+=2;\
            if(__sampling_type==__PXL_AVERAGE)\
                datapi_next+=2;\
            yuv_u++;\
            yuv_v++;\
        }\
        yuv_u+=(yuv->y_width-width_tm)/2;\
        yuv_v+=(yuv->y_width-width_tm)/2;\
        datapi+=width_tm;\
        if(__sampling_type==__PXL_AVERAGE)\
            datapi_next+=width_tm;\
    }\
}

#define UPDATE_UV_PLANES_DBUF(  data,\
                                data_back,\
                                x_tm,\
                                y_tm,\
                                height_tm,\
                                width_tm,\
                                yuv,\
                                __sampling_type,\
                                __bit_depth__){  \
    int k,i;\
    register u_int##__bit_depth__##_t t_val;\
    register unsigned char  *yuv_u=yuv->u+x_tm/2+(y_tm*yuv->uv_width)/2,\
                            *yuv_v=yuv->v+x_tm/2+(y_tm*yuv->uv_width)/2,\
                            *_ur=Ur,*_ug=Ug,*_ubvr=UbVr,\
                            *_vg=Vg,*_vb=Vb;\
    register u_int##__bit_depth__##_t *datapi=(u_int##__bit_depth__##_t *)data,\
                                      *datapi_next=NULL,\
                            *datapi_back=(u_int##__bit_depth__##_t *)data_back,\
                            *datapi_back_next=NULL;\
    if(__sampling_type==__PXL_AVERAGE){\
        datapi_next=datapi+width_tm;\
        datapi_back_next=datapi_back+width_tm;\
        for(k=0;k<height_tm;k+=2){\
            for(i=0;i<width_tm;i+=2){\
                if(( (*datapi!=*datapi_back) ||\
                    (*(datapi+1)!=*(datapi_back+1)) ||\
                    (*datapi_next!=*datapi_back_next) ||\
                    (*(datapi_next+1)!=*(datapi_back_next+1)))){\
                    UPDATE_A_UV_PIXEL(  yuv_u,\
                                        yuv_v,\
                                        t_val,\
                                        datapi,\
                                        datapi_next,\
                                        _ur,_ug,_ubvr,_vg,_vb,\
                                        __sampling_type,\
                                        __bit_depth__)\
                    ublocks[POINT_IN_BLOCK(i,k,width_tm,Y_UNIT_WIDTH)]=1;\
                    vblocks[POINT_IN_BLOCK(i,k,width_tm,Y_UNIT_WIDTH)]=1;\
                }\
                datapi+=2;\
                datapi_back+=2;\
                if(__sampling_type==__PXL_AVERAGE){\
                    datapi_next+=2;\
                    datapi_back_next+=2;\
                }\
                yuv_u++;\
                yuv_v++;\
            }\
            yuv_u+=(yuv->y_width-width_tm)/2;\
            yuv_v+=(yuv->y_width-width_tm)/2;\
            datapi+=width_tm;\
            datapi_back+=width_tm;\
            if(__sampling_type==__PXL_AVERAGE){\
                datapi_next+=width_tm;\
                datapi_back_next+=width_tm;\
            }\
        }\
    }\
    else{\
        for(k=0;k<height_tm;k+=2){\
            for(i=0;i<width_tm;i+=2){\
                if ((*datapi!=*datapi_back)){\
                    UPDATE_A_UV_PIXEL(  yuv_u,\
                                        yuv_v,\
                                        t_val,\
                                        datapi,\
                                        datapi_next,\
                                        _ur,_ug,_ubvr,_vg,_vb,\
                                        __sampling_type,\
                                        __bit_depth__)\
                    ublocks[POINT_IN_BLOCK(i,k,width_tm,Y_UNIT_WIDTH)]=1;\
                    vblocks[POINT_IN_BLOCK(i,k,width_tm,Y_UNIT_WIDTH)]=1;\
                }\
                datapi+=2;\
                datapi_back+=2;\
                if(__sampling_type==__PXL_AVERAGE){\
                    datapi_next+=2;\
                    datapi_back_next+=2;\
                }\
                yuv_u++;\
                yuv_v++;\
            }\
            yuv_u+=(yuv->y_width-width_tm)/2;\
            yuv_v+=(yuv->y_width-width_tm)/2;\
            datapi+=width_tm;\
            datapi_back+=width_tm;\
            if(__sampling_type==__PXL_AVERAGE){\
                datapi_next+=width_tm;\
                datapi_back_next+=width_tm;\
            }\
        }\
    }\
}

#define UPDATE_YUV_BUFFER(yuv,\
                          data,\
                          data_back,\
                          x_tm,\
                          y_tm,\
                          width_tm,\
                          height_tm,\
                          __sampling_type,\
                          __color_depth){\
    if(data_back==NULL){\
        if((__color_depth==24)||(__color_depth==32)){\
            UPDATE_Y_PLANE(data,x_tm,y_tm,height_tm,width_tm,yuv,32)\
            UPDATE_UV_PLANES(data,x_tm,y_tm,height_tm,width_tm,\
                             yuv,__sampling_type,32)\
        }\
        else if(__color_depth==16){\
            UPDATE_Y_PLANE(data,x_tm,y_tm,height_tm,width_tm,yuv,16)\
            UPDATE_UV_PLANES(data,x_tm,y_tm,height_tm,width_tm,\
                            yuv,__sampling_type,16)\
        }\
    }\
    else{\
        if((__color_depth==24)||(__color_depth==32)){\
            UPDATE_Y_PLANE_DBUF(data,data_back,x_tm,y_tm,\
                                height_tm,width_tm,yuv,32)\
            UPDATE_UV_PLANES_DBUF(data,data_back,x_tm,y_tm,height_tm,width_tm,\
                                  yuv,__sampling_type,32)\
        }\
        else if(__color_depth==16){\
            UPDATE_Y_PLANE_DBUF(data,data_back,x_tm,y_tm,\
                                height_tm,width_tm,yuv,16)\
            UPDATE_UV_PLANES_DBUF(data,data_back,x_tm,y_tm,height_tm,width_tm,\
                                  yuv,__sampling_type,16)\
        }\
    }\
}



#define XFIXES_POINTER_TO_YUV(yuv,\
                              data,\
                              x_tm,\
                              y_tm,\
                              width_tm,\
                              height_tm,\
                              x_offset,\
                              y_offset,\
                              column_discard_stride){\
    int i,k,j=0;\
    unsigned char avg0,avg1,avg2,avg3;\
    int x_2=x_tm/2,y_2=y_tm/2;\
    for(k=y_offset;k<y_offset+height_tm;k++){\
        for(i=x_offset;i<x_offset+width_tm;i++){\
                j=k*(width_tm+column_discard_stride)+i;\
                yuv->y[x_tm+(i-x_offset)+(k+y_tm-y_offset)*yuv->y_width]=\
                    (yuv->y[x_tm+(i-x_offset)+(k-y_offset+y_tm)*yuv->y_width]*\
                    (UCHAR_MAX-data[(j*RMD_ULONG_SIZE_T)+__ABYTE])+\
                    (Yr[data[(j*RMD_ULONG_SIZE_T)+__RBYTE]]+\
                    Yg[data[(j*RMD_ULONG_SIZE_T)+__GBYTE]] +\
                    Yb[data[(j*RMD_ULONG_SIZE_T)+__BBYTE]])*\
                data[(j*RMD_ULONG_SIZE_T)+__ABYTE])/UCHAR_MAX ;\
                if((k%2)&&(i%2)){\
                    avg3=AVG_4_PIXELS(data,\
                                      (width_tm+column_discard_stride),\
                                      k,i,__ABYTE);\
                    avg2=AVG_4_PIXELS(data,\
                                      (width_tm+column_discard_stride),\
                                      k,i,__RBYTE);\
                    avg1=AVG_4_PIXELS(data,\
                                      (width_tm+column_discard_stride),\
                                      k,i,__GBYTE);\
                    avg0=AVG_4_PIXELS(data,\
                                      (width_tm+column_discard_stride),\
                                      k,i,__BBYTE);\
                    yuv->u[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\
                           yuv->uv_width]=\
                    (yuv->u[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\
                            yuv->uv_width]*\
                    (UCHAR_MAX-avg3)+\
                    (Ur[avg2] + Ug[avg1] +UbVr[avg0])*avg3)/UCHAR_MAX;\
                    yuv->v[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\
                           yuv->uv_width]=\
                    (yuv->v[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*\
                            yuv->uv_width]*\
                    (UCHAR_MAX-avg3)+\
                    (UbVr[avg2] + Vg[avg1] +Vb[avg0])*avg3)/UCHAR_MAX;\
                }\
        }\
    }\
}

#define DUMMY_POINTER_TO_YUV(yuv,\
                             data_tm,\
                             x_tm,\
                             y_tm,\
                             width_tm,\
                             height_tm,\
                             x_offset,\
                             y_offset,\
                             no_pixel){\
    int i,k,j=0;\
    int x_2=x_tm/2,y_2=y_tm/2,y_width_2=(yuv)->y_width/2;\
    for(k=y_offset;k<y_offset+height_tm;k++){\
        for(i=x_offset;i<x_offset+width_tm;i++){\
            j=k*16+i;\
            if(data_tm[(j*4)]!=(no_pixel)){\
                (yuv)->y[x_tm+(i-x_offset)+((k-y_offset)+y_tm)*(yuv)->y_width]=\
                    Yr[data_tm[(j*4)+__RBYTE]] +\
                    Yg[data_tm[(j*4)+__GBYTE]] +\
                    Yb[data_tm[(j*4)+__BBYTE]];\
                if((k%2)&&(i%2)){\
                    yuv->u[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*y_width_2]=\
                        Ur[data_tm[(k*width_tm+i)*4+__RBYTE]] +\
                        Ug[data_tm[(k*width_tm+i)*4+__GBYTE]] +\
                        UbVr[data_tm[(k*width_tm+i)*4+__BBYTE]];\
                    yuv->v[x_2+(i-x_offset)/2+((k-y_offset)/2+y_2)*y_width_2]=\
                        UbVr[data_tm[(k*width_tm+i)*4+__RBYTE]] +\
                        Vg[data_tm[(k*width_tm+i)*4+__GBYTE]] +\
                        Vb[data_tm[(k*width_tm+i)*4+__BBYTE]] ;\
                }\
            }\
        }\
    }\
}

#define MARK_BACK_BUFFER(   data,\
                            x_tm,\
                            y_tm,\
                            width_tm,\
                            height_tm,\
                            buffer_width,\
                            __bit_depth__){\
    if((__bit_depth__==24)||(__bit_depth__==32)){\
        MARK_BACK_BUFFER_C( data,\
                            x_tm,\
                            y_tm,\
                            width_tm,\
                            height_tm,\
                            buffer_width,\
                            32)\
    }\
    else{\
        MARK_BACK_BUFFER_C( data,\
                            x_tm,\
                            y_tm,\
                            width_tm,\
                            height_tm,\
                            buffer_width,\
                            16)\
    }\
}\


#define MARK_BACK_BUFFER_C( data,\
                            x_tm,\
                            y_tm,\
                            width_tm,\
                            height_tm,\
                            buffer_width,\
                            __bit_depth__){\
    int k,i;\
    register u_int##__bit_depth__##_t\
        *datapi=\
            ((u_int##__bit_depth__##_t *)data)+y_tm*buffer_width+x_tm;\
    for(k=0;k<height_tm;k++){\
        for(i=0;i<width_tm;i++){\
            *datapi+=1;\
            datapi++;\
        }\
        datapi+=buffer_width-width_tm;\
    }\
}

#define I16TOA(number,buffer){\
    int t_num=(number),__k=0,__i=0;\
    char *t_buf=malloc(8);\
    t_num=t_num&((2<<15)-1);\
    while(t_num>0){\
        int digit=t_num%10;\
        t_buf[__k]=digit+48;\
        t_num-=digit;\
        t_num/=10;\
        __k++;\
    }\
    while(__k>0)\
        (buffer)[__i++]=t_buf[--__k];\
    (buffer)[__i]='\0';\
    free(t_buf);\
};\

#define INIT_FRAME(frame_t,fheader_t,yuv_t,\
                   YBlocks_t,UBlocks_t,VBlocks_t){\
    (frame_t)->header=(fheader_t);\
    (frame_t)->YBlocks=YBlocks_t;\
    (frame_t)->UBlocks=UBlocks_t;\
    (frame_t)->VBlocks=VBlocks_t;\
    (frame_t)->YData=malloc((yuv_t)->y_width*(yuv_t)->y_height);\
    (frame_t)->UData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\
    (frame_t)->VData=malloc((yuv_t)->uv_width*(yuv_t)->uv_height);\
};

#define CLEAR_FRAME(frame_t){\
    free((frame_t)->YData);\
    free((frame_t)->UData);\
    free((frame_t)->VData);\
};

#ifdef HAVE_JACK_H

#define CHECK_DLERRORS_FATAL(__error_p)\
    if((__error_p=dlerror())!=NULL){\
        fprintf(stderr,"%s\n",__error_p);\
        return 1;\
    }

#define DLSYM_AND_CHECK(lib_handle,__call_name__,__error_p)\
    __call_name__##_p=dlsym(lib_handle,#__call_name__);\
    CHECK_DLERRORS_FATAL(__error_p)

#endif

#endif