#include "osd.h"
#include "common.h"
#include <string.h>

typedef unsigned char *PBYTE;
#include <fmp.h>
#include <rm84mpegcmn.h>
#include <hwiface.h>

//#define EM84_HAS_4MB  1
extern int sOSDHas4MB;

#define MAX_AREAS 10

#define MAX_HILITE_COLORS 128

#define COL_A 0xFF000000
#define COL_R 0x00FF0000
#define COL_G 0x0000FF00
#define COL_B 0x000000FF

#define COL_A_SH 24
#define COL_R_SH 16
#define COL_G_SH  8
#define COL_B_SH  0


#define EM84OSD_MAX_WIDTH  720
#define EM84OSD_MAX_HEIGHT 576
#define EM84OSD_MAX_COLORS 256

#define EM84OSD_HEADERSIZE   8
#define EM84OSD_OFFSET_BMP (EM84OSD_HEADERSIZE + EM84OSD_MAX_COLORS * 4)

#define EM84OSD_HWBUFSIZE  (mOSDHas4MB ? 2000000 : 40944)
//#define EM84OSD_HWBUFSIZE  2000000

#define EM84OSD_MAX_BUFFERSIZE (EM84OSD_OFFSET_BMP + (EM84OSD_MAX_WIDTH * EM84OSD_MAX_HEIGHT))



class cOsdEm84xx: public cOsd {
private:

   IOsd *mOsd;
   unsigned char *mOsdBuffer;
   unsigned char *mCOsdBuffer;
   tColor *mPaletteEM84;
   int *mMappedColors[MAX_AREAS];
   int mUsedColors;
   int mCurwidth;
   int mCurheight;
   int mCompLines;
   int mBufSize;
   int mBmpOffset;
   int mMaxColors;
   int mOSDHas4MB;
   bool mUseColZ;
   bool mCompress;
   bool mAllFilled;
   bool mUseSplash; // for further use ...
   OSD_WND mWnd;

protected:
   void ResetOSD();
   void DisplayOSD();
   void AnalyzeAreas();
   void SetOSDPalette();
   void SetOSDBitmap();
   int SuiteColorToPalette(tColor vdrcolor);
   static void rgb2yuv(double R,double G,double B,double *y,double *u,double *v);
   void FillOSDHeader();
   int Compress2();
   int Compress4();
   int Compress7();
   //void LogAll();

public:
   cOsdEm84xx(int Left, int Top);
   virtual ~cOsdEm84xx();

   virtual eOsdError CanHandleAreas(const tArea *Areas, int NumAreas);
   virtual void Flush(void);
};



cOsdEm84xx::cOsdEm84xx(int Left, int Top):
cOsd(Left, Top)
{
   Dprintf("%s - %d %d\n", __PRETTY_FUNCTION__, Left, Top);

   mOsdBuffer = (unsigned char *)malloc(EM84OSD_MAX_BUFFERSIZE);
   mOSDHas4MB = sOSDHas4MB;

   if( !mOSDHas4MB )
      mCOsdBuffer = (unsigned char *)malloc(EM84OSD_HWBUFSIZE);
   else
      mCOsdBuffer = NULL;

   mPaletteEM84 = (tColor *)malloc(sizeof(tColor)*EM84OSD_MAX_COLORS);
   mUseSplash = false;
   mMaxColors = EM84OSD_MAX_COLORS;
   if(FMPQueryInterface(IID_IOSD, (void**)&mOsd)) {
      Dprintf("could not open OSD\n");
      mOsd = NULL;
   }

   for( int i = 0; i < MAX_AREAS; i++ )
      mMappedColors[i] = NULL;

   mWnd.x = mWnd.y = mWnd.w = mWnd.h = 0;
}

cOsdEm84xx::~cOsdEm84xx()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   if(mOsd) {
      mOsd->lpVtbl->Flush(mOsd);
      mOsd->lpVtbl->Off(mOsd);
   }

   for( int i = 0; i < MAX_AREAS; i++ ) {
      if( mMappedColors[i] != NULL )
         free(mMappedColors[i]);
   }
   if(mPaletteEM84 != NULL)
      free(mPaletteEM84);
   if(mOsdBuffer != NULL)
      free(mOsdBuffer);
   if(mCOsdBuffer != NULL)
      free(mCOsdBuffer);
}

void cOsdEm84xx::ResetOSD()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   if(!mOsd) {
      if(FMPQueryInterface(IID_IOSD, (void**)&mOsd)) {
         Dprintf("could not open OSD\n");
         mOsd = NULL;
         return;
      }
   }
   memset(mOsdBuffer, 0, EM84OSD_MAX_BUFFERSIZE);

   if( mCOsdBuffer )
      memset(mCOsdBuffer, 0, EM84OSD_HWBUFSIZE);

   memset(mPaletteEM84, 0, sizeof(tColor)*EM84OSD_MAX_COLORS);
   mCompLines = 0;
   mCompress = false;
   mAllFilled = true;

   mBufSize = mBmpOffset = 0;

   mCurwidth = EM84OSD_MAX_WIDTH;
   mCurheight = EM84OSD_MAX_HEIGHT;
   mUseSplash = false;

   // reserve color 0 for unused parts of screen
   if(mUseColZ)
      mUsedColors = 1;
   else
      mUsedColors = 0;

   for( int i = 0; i < MAX_AREAS; i++ ) {
      if( mMappedColors[i] != NULL ) {
         free(mMappedColors[i]);
         mMappedColors[i] = NULL;
      }
   }
}

eOsdError cOsdEm84xx::CanHandleAreas(const tArea *Areas, int NumAreas)
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);
   int maxBpp = 0;
   int totSize = 0;
   int maxX = 0, maxY = 0;
   eOsdError Result = cOsd::CanHandleAreas(Areas, NumAreas);
   if(Result == oeOk) {
      if( NumAreas > MAX_AREAS )
         return oeTooManyAreas;

      for(int i = 0; i < NumAreas; i++) {
         if( Areas[i].bpp > maxBpp)
            maxBpp = Areas[i].bpp;

         Dprintf("Area %d (%d bpp) %d-%d-%d-%d\n", i, Areas[i].bpp, Areas[i].x1,Areas[i].x2,Areas[i].y1,Areas[i].y2 );
         if(Areas[i].bpp > 8)
            return oeBppNotSupported;
         if(Areas[i].Width() < 1 || Areas[i].Height() < 1 || Areas[i].x2 > EM84OSD_MAX_WIDTH || Areas[i].y2 > EM84OSD_MAX_HEIGHT)
            return oeWrongAreaSize;

         totSize += Areas[i].Width() * Areas[i].Height();
         if((Areas[i].x1 + Areas[i].Width()) > maxX)
            maxX = Areas[i].x1+Areas[i].Width();
         if((Areas[i].y1 + Areas[i].Height()) > maxY)
            maxY = Areas[i].y1 + Areas[i].Height();
      }
      // Check for reserving blank color
      if( NumAreas > 1 && totSize < (maxX * maxY) )
         mUseColZ = 1;
      else
         mUseColZ = 0;

      // Check if we have to compress and reduce maxColors if necessary
      if( maxX * maxY + EM84OSD_HEADERSIZE + EM84OSD_MAX_COLORS * 4 > EM84OSD_HWBUFSIZE )
         mMaxColors = 128;
      else
         mMaxColors = 256;

   }
   return Result;
}


void cOsdEm84xx::Flush(void)
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   ResetOSD();

   // Check for size of OSD
   AnalyzeAreas();

   // Decide how many Colors to use
   SetOSDPalette();

   // Fill the OSD Buffer
   SetOSDBitmap();

   DisplayOSD();
}


void cOsdEm84xx::AnalyzeAreas()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);
   cBitmap *Bitmap;

   int maxX = 0, maxY = 0;
   // first build a common palette and query the size of the Bitmap !?!?
   for(int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
      int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
      if(Bitmap->Dirty(x1, y1, x2, y2)) {
         // commit colors:
         Dprintf("Area %d Dirty %d-%d-%d-%d\n", i, x1,x2,y1,y2 );
         Dprintf("Area %d X-Y %d-%d\n", i, Bitmap->X0(), Bitmap->Y0() );
         int NumColors;
         const tColor *Colors = Bitmap->Colors(NumColors);
         if(Colors) {
            mMappedColors[i] = (int*)malloc((NumColors+1)*sizeof(int));

            mMappedColors[i][0] = NumColors;
            for(int j = 0; j < mMappedColors[i][0]; j++)
               mMappedColors[i][j+1] = SuiteColorToPalette(Colors[j]);

            if((Bitmap->X0()+Bitmap->Width()) > maxX)
               maxX = Bitmap->X0()+Bitmap->Width();
            if((Bitmap->Y0()+Bitmap->Height()) > maxY)
               maxY = Bitmap->Y0()+Bitmap->Height();
         }
      }
   }
   if( EM84OSD_HWBUFSIZE > 1000000 ) {
      mCurwidth = EM84OSD_MAX_WIDTH;
      mCurheight = EM84OSD_MAX_HEIGHT;
   }
   else {
      mCurwidth = maxX < EM84OSD_MAX_WIDTH ? maxX : EM84OSD_MAX_WIDTH;
      mCurheight = maxY < EM84OSD_MAX_HEIGHT ? maxY : EM84OSD_MAX_HEIGHT;
   }

   int colors = 0;

   if( !colors ) {
      if( mUsedColors > 128 )
         mUsedColors = 256;
      else if( mUsedColors > 16 )
         mUsedColors = 128;
      else if( mUsedColors > 4 )
         mUsedColors = 16;
      else
         mUsedColors = 4;
   }

   // Calculate size of bitmap
   if( mUsedColors < 16 )  // 4 or 8 colors
      mBufSize = ((mCurwidth+3)/4)*mCurheight;
   else if( mUsedColors < 128 ) // 16 or 32 colors
      mBufSize = ((mCurwidth+1)/2)*mCurheight;
   else // 256 colors
      mBufSize = mCurwidth*mCurheight;

   // Check if we have to compress
   if( mBufSize + EM84OSD_HEADERSIZE + mUsedColors * 4 > EM84OSD_HWBUFSIZE ) {
      mBufSize = mCurwidth*mCurheight;
      mCompress = true;
      // ToDo: Cannot Compress 256 Colors so do anything useful to reduce colors !!!!
      if(mUsedColors > 128)
         mUsedColors = 128;
   }
   else
      mCompress = false;

   // Calculate the offset of the bitmap
   mBmpOffset = EM84OSD_HEADERSIZE + mUsedColors * 4;
} 


void cOsdEm84xx::SetOSDPalette()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   int idx;
   double a,y,u,v;
   tColor color;
   unsigned char* ptr = mOsdBuffer + EM84OSD_HEADERSIZE;


   // Now map palette to OSD
   for(idx=0; idx < mUsedColors; idx++) {
      color = mPaletteEM84[idx];

      rgb2yuv((double)((color & COL_R ) >> COL_R_SH),
              (double)((color & COL_G ) >> COL_G_SH),
              (double)((color & COL_B ) >> COL_B_SH),
              &y,&u,&v);

      a = (( color & COL_A ) >> COL_A_SH);
      *ptr++ = (unsigned char) a;
      *ptr++ = (unsigned char) y;
      *ptr++ = (unsigned char) u;
      *ptr++ = (unsigned char) v;
//       Dprintf("Color: %X - %X %X %X %X\n", color, a, y, u, v );
   }
}


void cOsdEm84xx::SetOSDBitmap()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   int x, y, cy;
   int cIdx;
   int cByte = 0,cShift = 0;
   unsigned char colorByte = 0, cColor = 0;
   unsigned char * bmpPtr;
   int cWidth = mCurwidth;
   int bmpIdx = 0;
   cBitmap *Bitmap;

   // Check for byte allignment if colors
   if(!mCompress) {
      if(mUsedColors == 16)
         cWidth = (mCurwidth + 1) / 2;
      else
         if(mUsedColors < 16)
         cWidth = (mCurwidth+3) / 4;
   }

   // now map all bitmaps to buffer
   for( int i = 0; (Bitmap = GetBitmap(i)) != NULL; i++) {
      if(mMappedColors[i] != NULL) {
         // draw window to osd!

         for(y = 0; y < Bitmap->Height(); y++) {
            cy = Bitmap->Y0()+y;

            if(mCompress || mUsedColors > 16) 
               bmpIdx = (cy*mCurwidth)+Bitmap->X0();
            else {
               if(mUsedColors == 16) {
                  bmpIdx = (cy*cWidth)+(Bitmap->X0()/2);
                  cByte = Bitmap->X0() % 2;
               }
               else {
                  bmpIdx = (cy*cWidth)+(Bitmap->X0()/4);
                  cByte = Bitmap->X0() % 4;
                  cShift = ( 3 - cByte ) * 2;
               }
            }

            bmpPtr = mOsdBuffer+mBmpOffset+bmpIdx;
            colorByte = *bmpPtr;

            for(x = 0; x < Bitmap->Width(); x++) {
               cIdx = *((unsigned char*)(Bitmap->Data(x,y)));

               if(cIdx >= mMappedColors[i][0]) {
                  // ToDo: Do something useful to map Colors
                  cIdx = cIdx % mMappedColors[i][0];
               }
               cColor = (unsigned char)mMappedColors[i][cIdx+1];
               if(mCompress || mUsedColors > 16) {
                  *bmpPtr = cColor;
                  bmpPtr++;
               }
               else {
                  // No Compression but less colors so use less Bits for colors
                  if(mUsedColors == 16) {
                     // half Byte for colors
                     cColor &= 0x0F;
                     if(cByte) {
                        colorByte |= cColor;
                        *bmpPtr = colorByte;
                        bmpPtr++;
                        cByte = 0;
                     }
                     else {
                        colorByte = cColor << 4;
                        cByte = 1;
                     }
                  }
                  else {
                     // qByte for Colors
                     cColor &= 0x03;
                     if(cByte==3) {
                        colorByte |= cColor;
                        *bmpPtr = colorByte;
                        bmpPtr++;
                        colorByte = 0;
                        cByte = 0;
                        cShift = 6;
                     }
                     else {
                        colorByte |= (cColor << cShift);
                        cByte++;
                        cShift -= 2;
                     }
                  }
               }
            }
            if(cByte)
               *bmpPtr = colorByte;
         }
      }
   }

   Dprintf("MCW %d-%d\n", mCurwidth, mCurheight );
}


int cOsdEm84xx::SuiteColorToPalette(tColor vdrcolor)
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   int difr, difg, difb;
   int alldif;
   int i;
   int start = 0;
   int stop = mUsedColors;

   for(i=start ; i < stop; i++) {
      if( mPaletteEM84[i] == vdrcolor )
         return i;
   }

   if(mUsedColors < mMaxColors) {
//       Dprintf("Color: %d - %X\n", mUsedColors, vdrcolor );
      mPaletteEM84[mUsedColors] = vdrcolor;
      mUsedColors++;
      return(mUsedColors-1);
   }

   // choose best one! ;)
   int found = -1;
   alldif = 3*256;

   start = 0;
   stop  = EM84OSD_MAX_COLORS;

   for(i=start; i < stop; i++) {
      difr = (( mPaletteEM84[i] & vdrcolor ) & COL_R ) >> COL_R_SH;
      difg = (( mPaletteEM84[i] & vdrcolor ) & COL_G ) >> COL_G_SH;
      difb = (( mPaletteEM84[i] & vdrcolor ) & COL_B ) >> COL_B_SH;
      if(difr < 0)
         difr = -1*difr;
      if(difg < 0)
         difg = -1*difg;
      if(difb < 0)
         difb = -1*difb;

      if((difr + difg + difb) < alldif) {
         alldif = (difr + difg + difb);
         found = i;
      }
   }
   Dprintf("Color: %X mapped: %d\n", vdrcolor, found );

   return found;
}


void cOsdEm84xx::DisplayOSD()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   if(!mOsd )
      return;

   if( mCompress ) {
      if(mCOsdBuffer == NULL)
         mCOsdBuffer = (unsigned char *)malloc(EM84OSD_HWBUFSIZE);

      memset(mCOsdBuffer,0x00,EM84OSD_HWBUFSIZE);

      mCompLines = 0;
      if( mUsedColors < 9 )
         mBufSize = Compress2();
      else if( mUsedColors < 33 )
         mBufSize = Compress4();
      else
         mBufSize = Compress7();

      memcpy(mOsdBuffer + mBmpOffset, mCOsdBuffer, mBufSize);

      if( mCompLines > 0 && mCompLines < mCurheight ) {
         Dprintf("Comp: (%d,%d)\n", mCompLines, mCurheight);
         mCurheight = mCompLines - 1;
      }
//      if ( size > EM84OSD_HWBUFSIZE ) {
      // for further use: enable splashosd !!
//      }
   }

   FillOSDHeader();

   //LogAll();
   mOsd->lpVtbl->Flush(mOsd);

   //  if ( Wnd.x < Left() || Wnd.y < Top() || Wnd.w > mCurwidth || Wnd.h > mCurheight )

   mWnd.x = Left();
   mWnd.y = Top();
   mWnd.w = mCurwidth;
   mWnd.h = mCurheight;
//    Dprintf("Win(%d,%d,%d,%d) - %d\n", mWnd.x, mWnd.y, mWnd.w, mWnd.h, mBufSize);

   mOsd->lpVtbl->Write(mOsd , mOsdBuffer, mBmpOffset + mBufSize);
   mOsd->lpVtbl->SetDest(mOsd , &mWnd);
   //OSSleep(10);
   mOsd->lpVtbl->On(mOsd );
}

void cOsdEm84xx::FillOSDHeader()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   int size = 0, clut = 0, bpp = 0, comp = 0;

   if( mUsedColors < 5 ) {
      clut = 0x01;
      bpp = 0x00;
   }
   else if( mUsedColors == 8 ) {
      clut = 0x02;
      bpp = 0x00;
   }
   else if( mUsedColors == 16 ) {
      clut = 0x03;
      bpp = 0x01;
   }
   else if( mUsedColors == 32 ) {
      clut = 0x04;
      bpp = 0x01;
   }
   else if( mUsedColors == 128 ) {
      clut = 0x06;
      bpp = 0x02;
   }
   else if( mUsedColors == 256 ) {
      clut = 0x07;
      bpp = 0x03;
   }
   else {
      Dprintf("Illegal number of colors %d\n", mUsedColors);
      return;
   }

   if(mCompress)
      comp = 0x01;

   mOsdBuffer[0] = comp | (bpp << 1) | (clut << 3);


   size = mBmpOffset + mBufSize;
   mOsdBuffer[1] = size >> 16;
   mOsdBuffer[2] = (size >> 8) & 0xff;
   mOsdBuffer[3] = size & 0xff;
   mOsdBuffer[4] = mCurwidth >> 8;
   mOsdBuffer[5] = mCurwidth & 0xff;
   mOsdBuffer[6] = mCurheight >> 8;
   mOsdBuffer[7] = mCurheight & 0xff;

   Dprintf("MOSDBuf(%02X%02X%02X%02X%02X%02X%02X%02X)\n", 
           mOsdBuffer[0],
           mOsdBuffer[1],
           mOsdBuffer[2],
           mOsdBuffer[3],
           mOsdBuffer[4],
           mOsdBuffer[5],
           mOsdBuffer[6],
           mOsdBuffer[7]);
}

int cOsdEm84xx::Compress2()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   int iBufSize = (mCurwidth * mCurheight);
   int oBufSize = EM84OSD_HWBUFSIZE - mBmpOffset;
   unsigned char b,b1,b2, oldb, newb, incomplete, temp;
   int iIdx, oIdx, count, newline, size;
   unsigned char *iBuf = mOsdBuffer + mBmpOffset;
   unsigned char *oBuf = mCOsdBuffer;

   oIdx = 0;
   mCompLines = 0;
   iIdx = 0;
   size = 0;
   newline = 0;
   incomplete = 0;
   b = iBuf[0] & 0x03;

   while(iIdx < iBufSize && oIdx < oBufSize) {
      oldb = b;
      count = 0;
      while((iIdx < iBufSize) && (count < 60) && (b == oldb) && (size < mCurwidth)) {
         count++;
         oldb = b;
         b = iBuf[iIdx] & 0x03;

         iIdx++;

         if(newline) {
            oldb = b;
            newline = 0;
         }

         size++;
      }

      if(size == mCurwidth) {
         b1 = oldb & 0x03;
         newb = 0;
         newb = newb | b1;
         size = 0;
         if(incomplete == 1) {
            temp = (newb >> 4) & 0x0F;
            oBuf[oIdx] = oBuf[oIdx] | temp;
            oIdx++;
            temp = newb & 0x0F;
            oBuf[oIdx] = 0xF0 & (temp << 4);
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuf[oIdx] = newb;
            oIdx++;
         }

         newline = 1;
         mCompLines++;
      }
      else if(count < 4) {
         b1 = (oldb & 0x03);
         b2 = (count & 0x03);
         newb = (b2 << 2) | (b1);
         newb = (newb << 4) & 0xF0;
         if(incomplete == 1) {
            temp = (newb >> 4) & 0x0F;
            oBuf[oIdx] = oBuf[oIdx] | temp;
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuf[oIdx] = newb;
            incomplete = 1;
         }
      }
      else if(count >= 4) {
         if(count % 4 != 0) {
            b1 = (oldb & 0x03);
            newb = 0;
            newb = ((count / 4) << 2) | b1;
            if(incomplete == 1) {
               temp = (newb >> 4) & 0x0F;
               oBuf[oIdx] = oBuf[oIdx] | temp;
               oIdx++;
               temp = newb & 0x0F;
               oBuf[oIdx] = temp << 4;
               incomplete = 1;
            }
            else {
               oBuf[oIdx] = newb;
               oIdx++;
            }

            newb = 0;
            b2 = count % 4;
            newb = (b2 << 2) | b1;
            if(incomplete == 1) {
               temp = (newb) & 0x0F;
               oBuf[oIdx] = oBuf[oIdx] | temp;
               oIdx++;
               incomplete = 0;
            }
            else {
               oBuf[oIdx] = (newb << 4) & 0xF0;
               incomplete = 1;
            }
         }
         else {
            b1 = (oldb & 0x03);
            newb = 0;
            newb = ((count / 4) << 2) | b1;
            if(incomplete == 1) {
               temp = (newb >> 4) & 0x0F;
               oBuf[oIdx] = oBuf[oIdx] | temp;
               oIdx++;
               temp = newb & 0x0F;
               oBuf[oIdx] = temp << 4;
               incomplete = 1;
            }
            else {
               oBuf[oIdx] = newb;
               oIdx++;
            }
         }
      }
      else {
         Dprintf("Error count");
      }
   }
   Dprintf("%s(%d - %d)(%d lines)\n", __PRETTY_FUNCTION__, oIdx, iBufSize, mCompLines);

   return oIdx;
}


int cOsdEm84xx::Compress4()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   int iBufSize = (mCurwidth * mCurheight);
   int oBufSize = EM84OSD_HWBUFSIZE - mBmpOffset;
   unsigned char b = 0, oldb;
   int iIdx, oIdx, oldoidx, count, newcount, size;
   unsigned char *iBuf = mOsdBuffer + mBmpOffset;
   unsigned char *oBuf = mCOsdBuffer;

   oIdx = 0;
   oldoidx = 0;
   iIdx = 0;
   size = mCurwidth; // Little trick to initiate newline variables

   while(iIdx < iBufSize && oIdx < oBufSize) {
      if(size >= mCurwidth) {
         mCompLines++;
         size = 1;
         b = iBuf[iIdx] & 0x0F;
         iIdx++;
//          Dprintf("\nCompressed:\n");
//          while( oldoidx < oIdx ) {
//             Dprintf("%02x ", oBuf[oldoidx]);
//             oldoidx++;
//          }
//          Dprintf("\n");
      }
      count = 0;
      oldb = b;
      while((iIdx < iBufSize) && (b == oldb) && (size < (int) mCurwidth)) {
         b = iBuf[iIdx] & 0x0f;
         iIdx++;
//          if(size < 40) {
//             Dprintf("%02x ", b);
//          }
         count++;
         size++;
      }
      if(size == (int) mCurwidth && oldb == b) {
         oBuf[oIdx] = oldb & 0x0F;
         oIdx++;
         count = 0;
      }

      while( count >= 8) {
         if(count > 64)
            newcount = 64/8;
         else
            newcount = count/8;

         oBuf[oIdx] = (((newcount-1) << 4)|0x80) | oldb;
         oIdx++;
         count -= newcount * 8;
      }
      if(count > 0) {
         oBuf[oIdx] = (count << 4) | oldb;
         oIdx++;
      }
      if(size == mCurwidth && oldb != b) {
         oBuf[oIdx] = (0x01 << 4) | oldb;
         oIdx++;
      }
   }

   Dprintf("%s(%d - %d)(%d lines)\n", __PRETTY_FUNCTION__, oIdx, iBufSize, mCompLines);

   return oIdx;
}

int cOsdEm84xx::Compress7()
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);

   int iBufSize = (mCurwidth * mCurheight);
   int oBufSize = EM84OSD_HWBUFSIZE - mBmpOffset;
   unsigned char b,b1, oldb, temp, incomplete = 0;
   int iIdx, oIdx, count, size, half, newcount, oldoidx;
   unsigned char *iBuf = mOsdBuffer + mBmpOffset;
   unsigned char *oBuf = mCOsdBuffer;

   oIdx = 0;
   oldoidx = 0;
   mCompLines = 0;
   iIdx = 0;
   half = 0;
   b = iBuf[0] & 0x7f;
   size = mCurwidth; // Little trick to initiate newline variables

   while(iIdx < iBufSize && oIdx < oBufSize) {
      if(size >= mCurwidth) {
         mCompLines++;
         incomplete = 0;
         size = 1;
         b = iBuf[iIdx] & 0x0F;
         iIdx++;
//          Dprintf("\nCompressed:\n");
//          while( oldoidx < oIdx ) {
//             Dprintf("%02x ", oBuf[oldoidx]);
//             oldoidx++;
//          }
//          Dprintf("\n");
      }
      count = 0;
      oldb = b;

      while((iIdx < iBufSize) && (b == oldb) && (size < (int) mCurwidth)) {
         oldb = b;
         b = iBuf[iIdx] & 0x7f;
         iIdx++;
//          if(size < 40) {
//             Dprintf("%02x ", b);
//          }
         count++;
         size++;
      }

      if(size == mCurwidth && oldb == b) {
         // Do not matter about last pixel if line has changed !!!
         if(incomplete == 1) {
            oBuf[oIdx] |= 0x08;
            oIdx++;
            oBuf[oIdx] = b;
            oIdx++;
         }
         else {
            temp = (b >> 4) & 0x0F;
            oBuf[oIdx] = 0x80 | temp;
            oIdx++;
            oBuf[oIdx] = (b & 0x0F) << 4;
            oIdx++;
         }
         count = 0;
      }
      while( count >= 16 ) {
         if(count > 72)
            newcount = 72/8;
         else
            newcount = count/8;

         b1 = ((newcount-2) << 3) | 0xC0;
         if(incomplete) {
            oBuf[oIdx] |= ((b1 & 0xF0) >> 4);
            oIdx++;
            oBuf[oIdx] = ((b1<<4)& 0xF0) | oldb;
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuf[oIdx] = b1 | ((oldb & 0xF0) >> 4 );
            oIdx++;
            oBuf[oIdx] = (oldb & 0x0F) << 4;
            incomplete = 1;
         }
         count -= newcount * 8;
      }
      while( count >= 2 ) {
         if(count > 7)
            newcount = 7;
         else
            newcount = count;

         b1 = ((newcount-1) << 3) | 0x80;
         if(incomplete) {
            oBuf[oIdx] |= (b1 & 0xF0) >> 4;
            oIdx++;
            oBuf[oIdx] = ((b1<<4)& 0xF0) | oldb;
            oIdx++;
            incomplete = 0;
         }
         else {
            oBuf[oIdx] = b1 | ((oldb & 0xF0) >> 4 );
            oIdx++;
            oBuf[oIdx] = (oldb & 0x0F) << 4;
            incomplete = 1;
         }
         count -= newcount;
      }
      if( count == 1 ) {
         if(incomplete) {
            oBuf[oIdx] |= (oldb & 0xF0) >> 4;
            oIdx++;
            oBuf[oIdx] = (oldb << 4) & 0xF0;
         }
         else {
            oBuf[oIdx] = oldb & 0x7F;
            oIdx++;
         }
         count = 0;
      }
      if(size == mCurwidth && oldb != b) {
         if(incomplete) {
            oBuf[oIdx] |= (b & 0xF0) >> 4;
            oIdx++;
            oBuf[oIdx] = (b << 4) & 0xF0;
            oIdx++;
         }
         else {
            oBuf[oIdx] = b & 0x7F;
            oIdx++;
         }
      }
   }

   Dprintf("%s(%d - %d)(%d lines)\n", __PRETTY_FUNCTION__, oIdx, iBufSize, mCompLines);

   return oIdx;
}


void cOsdEm84xx::rgb2yuv(double R,double G,double B,double *y,double *u,double *v)
{
   *y=(0.257*R + 0.504*G + 0.098*B) + 16.0;
   *u=(-0.148*R - 0.291*G + 0.439*B) + 128.0;
   *v=(0.439*R - 0.368*G - 0.071*B) + 128.0;
}


// void cOsdEm84xx::LogAll()
// {
//    char *fname;
//    FILE * fhdl;
//    static int num = 0;
//    asprintf( &fname, "/tmp/%d_%d_%d.log", mCurwidth, mCurheight,num++);
//    fhdl = fopen( fname, "wb");
//    fprintf(fhdl, "W; %d H: %d\n",mCurwidth,mCurheight);
//
//    for( int i = 0; i < MAX_AREAS; i++ ) {
//       if(mMappedColors[i] != NULL) {
//          fprintf( fhdl, "\nColMap-%d : ", i );
//          for( int j = 0; j < mMappedColors[i][0]; j++) {
//             fprintf( fhdl, "\n%02X ", mMappedColors[i][j+1] );
//          }
//       }
//    }
//    fwrite( mOsdBuffer, 1, mBufSize, fhdl);
//    fprintf( fhdl, "\n\n");
//    if( mCompress ) {
//       fwrite( mCOsdBuffer, 1, EM84OSD_HWBUFSIZE - mBmpOffset, fhdl);
//       fwrite( "\n\n", 2, 1, fhdl);
//    }
//    fclose( fhdl );
// }

cOsdProviderEm84xx::cOsdProviderEm84xx(void)
{
   Dprintf("%s\n", __PRETTY_FUNCTION__);
}


cOsd *cOsdProviderEm84xx::CreateOsd(int Left, int Top)
{
   Dprintf("%s(%d,%d)\n", __PRETTY_FUNCTION__, Left, Top);
   return new cOsdEm84xx(Left, Top);
}

