
////////////////////////////////////////////////////////////
//          Row conversion primitive functors
////////////////////////////////////////////////////////////


class AConvertVideoLine
{
public:
    char Orientation;

    AConvertVideoLine(): Orientation(0) {}

    virtual unsigned RowStart(unsigned y, unsigned Width) const = 0;
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const = 0;    
};

//---------------------------------------------------------

class AConvertVideoLine_V210: public AConvertVideoLine
{
public:
    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      //i = Camera->GetBufferData() + y*((Width*16/6+127)&0xFFFFFF80);	// padding 128 bytes, 16 byte block holds 6 pixels
      // recommended calculation  rowbytes = ((Width + 47) / 48) * 128
      return y*128*((Width+47)/48);
    }
};

class ConvertVideoLine_00_V210: public AConvertVideoLine_V210
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      V210_RGB(Out, (uint32_t*)In, LoopCount);
    }
};

class ConvertVideoLine_01_V210: public AConvertVideoLine_V210
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      V210_Gray24(Out, (uint32_t*)In, LoopCount);
    }
};

class ConvertVideoLine_02_V210: public AConvertVideoLine_V210
{
public:
    unsigned threshold;

    ConvertVideoLine_02_V210(unsigned iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      V210_Gray24(Out, (uint32_t*)In, LoopCount);
      while(LoopCount-->0)
      {
        Out[0]=Out[1]=Out[2] = (*In >= threshold) ? 255 : 0;
        Out+=3;
        In+=3;
      }
    }
};

class ConvertVideoLine_11_V210: public AConvertVideoLine_V210
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      V210_Gray8(Out, (uint32_t*)In, LoopCount);
    }
};

class ConvertVideoLine_12_V210: public AConvertVideoLine_V210
{
public:
    unsigned threshold;

    ConvertVideoLine_12_V210(unsigned iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      V210_Gray8(Out, (uint32_t*)In, LoopCount);
      while(LoopCount-->0)
      {
        *Out = (*Out >= threshold) ? 255 : 0;
        Out++;
      }
    }
};


//---------------------------------------------------------

class AConvertVideoLine_U32: public AConvertVideoLine
{
public:
    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      return y*4*Width;
    }
};

class ConvertVideoLine_00_R210: public AConvertVideoLine_U32
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = LD_UINT32_HI(In);
        Out[2] = 0xFF&(D>>2);
        Out[1] = 0xFF&(D>>12);
        Out[0] = 0xFF&(D>>22);
        In+=4;
        Out+=3;
      } 
    }
};

class ConvertVideoLine_01_R210: public AConvertVideoLine_U32
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = LD_UINT32_HI(In);
        Out[0]=Out[1]=Out[2] = (0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22)) / 3;
        In+=4;
        Out+=3;
      }      
    }
};

class ConvertVideoLine_02_R210: public AConvertVideoLine_U32
{
public:
    unsigned thr3;

    ConvertVideoLine_02_R210(unsigned iniThreshold): thr3(3*iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = LD_UINT32_HI(In);
        Out[0]=Out[1]=Out[2] = ((0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22))>=thr3) ? 255 : 0;
        In+=4;
        Out+=3;
      }      
    }
};

class ConvertVideoLine_11_R210: public AConvertVideoLine_U32
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = LD_UINT32_HI(In);
        *Out++ = (0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22)) / 3;
        In+=4;
      }
    }
};

class ConvertVideoLine_12_R210: public AConvertVideoLine_U32
{
public:
    unsigned thr3;

    ConvertVideoLine_12_R210(unsigned iniThreshold): thr3(3*iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = LD_UINT32_HI(In);
        *Out++ = ((0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22))>=thr3) ? 255 : 0;
        In+=4;                      
      }
    }
};


//---------------------------------------------------------


class ConvertVideoLine_00_vfA2R10G10B10: public AConvertVideoLine_U32
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = *(uint32_t*)In;
        Out[2] = 0xFF&(D>>2);
        Out[1] = 0xFF&(D>>12);
        Out[0] = 0xFF&(D>>22);
        In+=4;
        Out+=3;
      }
    }
};


class ConvertVideoLine_00_vfA2B10G10R10: public AConvertVideoLine_U32
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = *(uint32_t*)In;
        Out[0] = 0xFF&(D>>2);
        Out[1] = 0xFF&(D>>12);
        Out[2] = 0xFF&(D>>22);
        In+=4;
        Out+=3;
      }
    }
};

class ConvertVideoLine_01_vfA2x10G10x10: public AConvertVideoLine_U32
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = *(uint32_t*)In;
        Out[0]=Out[1]=Out[2] = (0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22)) / 3;
        In+=4;
        Out+=3;
      }
    }
};

class ConvertVideoLine_02_vfA2x10G10x10: public AConvertVideoLine_U32
{
public:
    unsigned thr3;

    ConvertVideoLine_02_vfA2x10G10x10(unsigned iniThreshold): thr3(3*iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = *(uint32_t*)In;
        Out[0]=Out[1]=Out[2] = ((0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22)) >=thr3) ? 255 : 0;
        In+=4;
        Out+=3;
      }
    }
};

class ConvertVideoLine_11_vfA2x10G10x10: public AConvertVideoLine_U32
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = *(uint32_t*)In;
        *Out++ = (0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22)) / 3;
        In+=4;
      }
    }
};

class ConvertVideoLine_12_vfA2x10G10x10: public AConvertVideoLine_U32
{
public:
    uint16_t thr3;

    ConvertVideoLine_12_vfA2x10G10x10(unsigned char iniThreshold): thr3(3*iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint32_t D = *(uint32_t*)In;
        *Out++ = ((0xFF&(D>>2) + 0xFF&(D>>12) + 0xFF&(D>>22)) >=thr3) ? 255 : 0;
        In+=4;
      }
    }
};


//---------------------------------------------------------

class AConvertVideoLine_U16: public AConvertVideoLine
{
public:
    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      return y*2*Width;
    }
};


class ConvertVideoLine_00_RGB565: public AConvertVideoLine_U16
{
public:
    //ConvertVideoLine_00_RGB565() {Orientation=1;}

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint16_t W = *(uint16_t*)In;
	In += 2;
	*Out++ = (W>>8) & 0xF8;
	*Out++ = (W>>3) & 0xFC;
	*Out++ = (W<<3) & 0xF8;
      }
    }
};

class ConvertVideoLine_01_RGB565: public AConvertVideoLine_U16
{
public:
    //ConvertVideoLine_01_RGB565() {Orientation=1;}

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint16_t W = *(uint16_t*)In;
	In += 2;
	Out[0]=Out[1]=Out[2] = (((W>>8) & 0xF8) + ((W>>3) & 0xFC) + ((W<<3) & 0xF8)) / 3;
	Out+=3;
     }
    }
};

class ConvertVideoLine_02_RGB565: public AConvertVideoLine_U16
{
public:
    unsigned thr3;

    ConvertVideoLine_02_RGB565(unsigned iniThreshold): thr3(3*iniThreshold) {Orientation=1;};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const uint16_t W = *(uint16_t*)In;
        In += 2;
	Out[0]=Out[1]=Out[2] = ((((W>>8) & 0xF8) + ((W>>3) & 0xFC) + ((W<<3) & 0xF8))>=thr3) ? 255 : 0;
	Out+=3;
      }
    }
};

class ConvertVideoLine_11_RGB565: public AConvertVideoLine_U16
{
public:
    //ConvertVideoLine_11_RGB565() {Orientation=1;}

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint16_t W = *(uint16_t*)In;
        In += 2;
        *Out++ = (((W>>8) & 0xF8) + ((W>>3) & 0xFC) + ((W<<3) & 0xF8)) / 3;
      }
    }
};

class ConvertVideoLine_12_RGB565: public AConvertVideoLine_U16
{
public:
    unsigned thr3;

    ConvertVideoLine_12_RGB565(unsigned iniThreshold): thr3(3*iniThreshold) {Orientation=1;};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const uint16_t W = *(uint16_t*)In;
        In += 2;
	*Out++ = ((((W>>8) & 0xF8) + ((W>>3) & 0xFC) + ((W<<3) & 0xF8))>=thr3) ? 255 : 0;
      }
    }
};


//---------------------------------------------------------


class ConvertVideoLine_00_RGB555: public AConvertVideoLine_U16
{
public:
    //ConvertVideoLine_00_RGB555() {Orientation=1;}

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint16_t W = *(uint16_t*)In;
	In += 2;
	*Out++ = (W>>7) & 0xF8;
	*Out++ = (W>>2) & 0xF8;
	*Out++ = (W<<3) & 0xF8;
      }
    }
};

class ConvertVideoLine_01_RGB555: public AConvertVideoLine_U16
{
public:
    //ConvertVideoLine_01_RGB555() {Orientation=1;}

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint16_t W = *(uint16_t*)In;
	In += 2;
	Out[0]=Out[1]=Out[2] = (((W>>7) & 0xF8) + ((W>>2) & 0xF8) + ((W<<3) & 0xF8)) / 3;
	Out+=3;
     }
    }
};

class ConvertVideoLine_02_RGB555: public AConvertVideoLine_U16
{
public:
    unsigned thr3;

    ConvertVideoLine_02_RGB555(unsigned iniThreshold): thr3(3*iniThreshold) {Orientation=1;};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const uint16_t W = *(uint16_t*)In;
        In += 2;
	Out[0]=Out[1]=Out[2] = ((((W>>7) & 0xF8) + ((W>>2) & 0xF8) + ((W<<3) & 0xF8))>=thr3) ? 255 : 0;
	Out+=3;
      }
    }
};

class ConvertVideoLine_11_RGB555: public AConvertVideoLine_U16
{
public:
    //ConvertVideoLine_11_RGB555() {Orientation=1;}

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        const uint16_t W = *(uint16_t*)In;
        In += 2;
        *Out++ = (((W>>7) & 0xF8) + ((W>>2) & 0xF8) + ((W<<3) & 0xF8)) / 3;
      }
    }
};

class ConvertVideoLine_12_RGB555: public AConvertVideoLine_U16
{
public:
    unsigned thr3;

    ConvertVideoLine_12_RGB555(unsigned iniThreshold): thr3(3*iniThreshold) {Orientation=1;};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const uint16_t W = *(uint16_t*)In;
        In += 2;
	*Out++ = ((((W>>7) & 0xF8) + ((W>>2) & 0xF8) + ((W<<3) & 0xF8))>=thr3) ? 255 : 0;
      }
    }
};


//---------------------------------------------------------


class ConvertVideoLine_00_UYVY: public AConvertVideoLine_U16
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      UYVY_RGB(Out, In, LoopCount);
    }
};

class ConvertVideoLine_01_UYVY: public AConvertVideoLine_U16
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      In++;
      while(LoopCount-->0)   //converts to 3xGray
      {
        Out[0]=Out[1]=Out[2] = *In;
        In += 2;
	Out += 3;
      }
    }
};

class ConvertVideoLine_02_UYVY: public AConvertVideoLine_U16
{
public:
    unsigned threshold;

    ConvertVideoLine_02_UYVY(unsigned iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      In++;
      while(LoopCount-->0)   //converts to 3xGray
      {
        Out[0]=Out[1]=Out[2] = (*In>=threshold) ? 255 : 0;
        In += 2;
	Out += 3;
      }
    }
};


class ConvertVideoLine_11_UYVY: public AConvertVideoLine_U16
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      Conv16_8(Out,(uint16_t*)In, LoopCount);    
    }
};

class ConvertVideoLine_12_UYVY: public AConvertVideoLine_U16
{
public:
    unsigned threshold;

    ConvertVideoLine_12_UYVY(unsigned iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      In++;
      while(LoopCount-->0)   //converts to 3xGray
      {
        *(Out++) = (*In>=threshold) ? 255 : 0;
        In += 2;
      }
    }
};

//----------------------------------------------------------------

class ConvertVideoLine_00_YVYU: public AConvertVideoLine_U16
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      YVYU_RGB(Out, In, LoopCount);
    }
};

class ConvertVideoLine_00_YUYV: public AConvertVideoLine_U16
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      YUYV_RGB(Out, In, LoopCount);			// Converts to RGB
    }
};


class ConvertVideoLine_01_YxYx: public AConvertVideoLine_U16
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)   //converts to 3xGray
      {
        Out[0]=Out[1]=Out[2] = *In;
        In += 2;
	Out += 3;
      }
    }
};

class ConvertVideoLine_02_YxYx: public AConvertVideoLine_U16
{
public:
    unsigned char threshold;

    ConvertVideoLine_02_YxYx(unsigned char iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)   //converts to 3xGray
      {
        Out[0]=Out[1]=Out[2] = (*In>=threshold) ? 255 : 0;
        In += 2;
	Out += 3;
      }
    }
};

class ConvertVideoLine_11_YxYx: public AConvertVideoLine_U16
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)   //converts to 3xGray
      {
        *(Out++) = *In;
        In += 2;	
      }
    }
};

class ConvertVideoLine_12_YxYx: public AConvertVideoLine_U16
{
public:
    unsigned char threshold;

    ConvertVideoLine_12_YxYx(unsigned char iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)   //converts to 3xGray
      {
        *(Out++) = (*In>=threshold) ? 255 : 0;
        In += 2;	
      }
    }
};


//---------------------------------------------------------

class AConvertVideoLine_U8: public AConvertVideoLine
{
public:
    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      return y*Width;
    }
};


class ConvertVideoLine_00_RGB8: public AConvertVideoLine_U8
{
public:
    const TCameraPalette *pPal;
    ConvertVideoLine_00_RGB8(const TCameraPalette *NewPal): pPal(NewPal) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const TCameraPalette *pPalI = &pPal[*In++];
	*Out++ = pPalI->R;
	*Out++ = pPalI->G;
	*Out++ = pPalI->B;
      }  
    }
};


class ConvertVideoLine_01_RGB8: public AConvertVideoLine_U8
{
public:
    const TCameraPalette *pPal;    

    ConvertVideoLine_01_RGB8(const TCameraPalette *NewPal): pPal(NewPal) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const TCameraPalette *pPalI = &pPal[*In++];
	Out[0]=Out[1]=Out[2] = (pPalI->R+pPalI->G+pPalI->B) / 3;
        Out+=3;
      }  
    }
};


class ConvertVideoLine_02_RGB8: public AConvertVideoLine_U8
{
public:
    const TCameraPalette *pPal;
    uint16_t thr3;

    ConvertVideoLine_02_RGB8(const TCameraPalette *NewPal, unsigned threshold): pPal(NewPal), thr3(3*threshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const TCameraPalette *pPalI = &pPal[*In++];
	Out[0]=Out[1]=Out[2] = ((pPalI->R+pPalI->G+pPalI->B)>=thr3) ? 255 : 0;
        Out+=3;
      }  
    }
};


class ConvertVideoLine_11_RGB8: public AConvertVideoLine_U8
{
public:
    const TCameraPalette *pPal;    

    ConvertVideoLine_11_RGB8(const TCameraPalette *NewPal): pPal(NewPal) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const TCameraPalette *pPalI = &pPal[*In++];
	*Out++ = (pPalI->R+pPalI->G+pPalI->B) / 3;
      }  
    }
};


class ConvertVideoLine_12_RGB8: public AConvertVideoLine_U8
{
public:
    const TCameraPalette *pPal;
    uint16_t thr3;

    ConvertVideoLine_12_RGB8(const TCameraPalette *NewPal, unsigned threshold): pPal(NewPal), thr3(3*threshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	const TCameraPalette *pPalI = &pPal[*In++];
	*Out++ = ((pPalI->R+pPalI->G+pPalI->B)>=thr3) ? 255 : 0;
      }  
    }
};


//----------------------------------------------

class ConvertVideoLine_00_Gray8: public AConvertVideoLine_U8
{
public:
    const TCameraPalette *pPal;

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      Conv8_24(Out,In,LoopCount);
    }
};

class ConvertVideoLine_02_Gray8: public AConvertVideoLine_U8
{
public:
    unsigned char threshold;

    ConvertVideoLine_02_Gray8(unsigned char iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        Out[0]=Out[1]=Out[2] = (*(In++)>=threshold) ? 255 : 0;
	Out+=3;
      }
    }
};

class ConvertVideoLine_11_Gray8: public AConvertVideoLine_U8
{
public:
    const TCameraPalette *pPal;

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      memcpy(Out,In,LoopCount);
    }
};

class ConvertVideoLine_12_Gray8: public AConvertVideoLine_U8
{
public:
    unsigned char threshold;

    ConvertVideoLine_12_Gray8(unsigned char iniThreshold): threshold(iniThreshold) {};

    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        *Out++ = (*(In++)>=threshold) ? 255 : 0;
      }
    }
};


//---------------------------------------------------------

class AConvertVideoLine_U48: public AConvertVideoLine
{
public:
    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      return y*6*Width;
    }
};


class ConvertVideoLine_00_B16G16R16: public AConvertVideoLine_U48
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      Conv16_8(Out,(uint16_t*)In,3*LoopCount);
      RGB_BGR((char*)Out,LoopCount);
    }
};

class ConvertVideoLine_00_R16G16B16: public AConvertVideoLine_U48
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      Conv16_8(Out,(uint16_t*)In,3*LoopCount);
    }
};

class ConvertVideoLine_01_x16G16x16: public AConvertVideoLine_U48
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      Conv16_8(Out,(uint16_t*)In,3*LoopCount);      
      RGB_Gray24(Out,In,LoopCount);
    }
};


class ConvertVideoLine_02_x16G16x16: public AConvertVideoLine_U48
{
public:
  uint16_t thr3;

  ConvertVideoLine_02_x16G16x16(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    while(LoopCount-->0)
    {
      Out[2]=Out[1]=Out[0] = ((In[1]+In[3]+In[5])>=thr3) ? 255 : 0;
      Out+=3;
      In+=6;
    }
  }
};

class ConvertVideoLine_11_x16G16x16: public AConvertVideoLine_U48
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	*(Out++) = (In[1]+In[3]+In[5]) / 3;
        In += 6;
      }
    }
};

class ConvertVideoLine_12_x16G16x16: public AConvertVideoLine_U48
{
public:
  uint16_t thr3;

  ConvertVideoLine_12_x16G16x16(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    while(LoopCount-->0)
    {
      *(Out++) = ((In[1]+In[3]+In[5])>=thr3) ? 255 : 0;
      In+=6;
    }
  }
};


//---------------------------------------------------------

class AConvertVideoLine_U64: public AConvertVideoLine
{
public:
    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      return y*8*Width;
    }
};


class ConvertVideoLine_00_A16B16G16R16: public AConvertVideoLine_U64
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	Out[2] = In[1];
        Out[1] = In[3];
        Out[0] = In[5];
        Out+=3;
        In+=8;
      }
    }
};

class ConvertVideoLine_00_A16R16G16B16: public AConvertVideoLine_U64
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {				// Alo Ahi Rlo Rhi Glo Ghi Blo BHi
	Out[2] = In[5];		// Rhi
        Out[1] = In[3];		// Ghi
        Out[0] = In[1];		// Bhi
        Out+=3;
        In+=8;
      }
    }
};

class ConvertVideoLine_01_A16x16G16x16: public AConvertVideoLine_U64
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
        Out[2]=Out[1]=Out[0] = (In[1]+In[3]+In[5]) / 3;
        Out+=3;
        In+=8;
      }
    }
};


class ConvertVideoLine_02_A16x16G16x16: public AConvertVideoLine_U64
{
public:
  uint16_t thr3;

  ConvertVideoLine_02_A16x16G16x16(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    while(LoopCount-->0)
    {
      Out[2]=Out[1]=Out[0] = ((In[1]+In[3]+In[5])>=thr3) ? 255 : 0;
      Out+=3;
      In+=6;
    }
  }
};

class ConvertVideoLine_11_A16x16G16x16: public AConvertVideoLine_U64
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      while(LoopCount-->0)
      {
	*(Out++) = (In[1]+In[3]+In[5]) / 3;
        In += 8;
      }
    }
};

class ConvertVideoLine_12_A16x16G16x16: public AConvertVideoLine_U64
{
public:
  uint16_t thr3;

  ConvertVideoLine_12_A16x16G16x16(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    while(LoopCount-->0)
    {
      *(Out++) = ((In[1]+In[3]+In[5])>=thr3) ? 255 : 0;
      In+=8;
    }
  }
};


//---------------------------------------------------------

class AConvertVideoLine_U32i: public AConvertVideoLine_U32
{
public:
    AConvertVideoLine_U32i() {Orientation=1;}	//Windows defines that ARGB is vertically inverted.
};


class ConvertVideoLine_00_ARGB: public AConvertVideoLine_U32i
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      RGB32_BGR24(Out,In,LoopCount);	//converts from BGR32 to RGB24
    }
};

class ConvertVideoLine_01_ARGB: public AConvertVideoLine_U32i
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      BGR32_Gray24(Out,In,LoopCount);	//converts from BGR32 to RGB gray
    }
};


class ConvertVideoLine_02_ARGB: public AConvertVideoLine_U32i
{
public:
  uint16_t thr3;

  ConvertVideoLine_02_ARGB(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {				//converts from BGR32 to RGB mono
    while(LoopCount-->0)
    {
      Out[2]=Out[1]=Out[0] = ((*In + In[1] + In[2])>=thr3) ? 255 : 0;
      Out+=3;
      In+=4;
    }
  }
};

class ConvertVideoLine_11_ARGB: public AConvertVideoLine_U32i
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      RGB32_Gray(Out,In,LoopCount);	//converts from BGR32 to 8bit gray
    }
};

class ConvertVideoLine_12_ARGB: public AConvertVideoLine_U32i
{
public:
  uint16_t thr3;

  ConvertVideoLine_12_ARGB(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    while(LoopCount-->0)
    {
      *(Out++) = ((*In+In[1]+In[2]) >= thr3) ? 255 : 0;
      In+=4;
    }
  }
};


//---------------------------------------------------------

class AConvertVideoLine_U24i: public AConvertVideoLine
{
public:
    AConvertVideoLine_U24i() {Orientation=1;}	//Windows defines that RGB is vertically inverted.

    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      return y*3*Width;
    }
};


class ConvertVideoLine_00_RGB: public AConvertVideoLine_U24i
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {      
      RGB_BGR2(Out,In,LoopCount);		//converts from BGR to RGB
    }
};

class ConvertVideoLine_01_RGB: public AConvertVideoLine_U24i
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {    
      BGR_Gray24precise(Out,In,LoopCount);		//converts from BGR to RGB gray
    }
};


class ConvertVideoLine_02_RGB: public AConvertVideoLine_U24i
{
public:
  uint16_t thr3;

  ConvertVideoLine_02_RGB(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {				//converts from BGR32 to RGB mono
    while(LoopCount-->0)
    {
      Out[2]=Out[1]=Out[0] = ((*In + In[1] + In[2])>=thr3) ? 255 : 0;
      Out+=3;
      In+=3;
    }
  }
};

class ConvertVideoLine_11_RGB: public AConvertVideoLine_U24i
{
public:
    virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
    {
      RGB24_Gray8(Out,In,LoopCount);	//converts from BGR (does not matter RGB) to 8bit gray
    }
};

class ConvertVideoLine_12_RGB: public AConvertVideoLine_U24i
{
public:
  uint16_t thr3;

  ConvertVideoLine_12_RGB(unsigned char iniThreshold): thr3(3*iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    while(LoopCount-->0)
    {
      *(Out++) = ((*In+In[1]+In[2]) >= thr3) ? 255 : 0;
      In+=3;
    }
  }
};


//---------------------------------------------------------

class AConvertVideoLine_AYUV: public AConvertVideoLine
{
public:
    virtual unsigned RowStart(unsigned y, unsigned Width) const
    {
      return y*4*Width;
    }
};


class ConvertVideoLine_00_AYUV: public AConvertVideoLine_AYUV
{
public:
  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    int32_t X;
    while(LoopCount-->0)
    {
      const int32_t Y = 256 * In[1];
      const signed char U = In[2] - 128;      
      const signed char V = In[3] - 128;

      X = (Y + 291*V) >> 8;	// Y + 1.137*V;
      if(X>255) Out[0]=255;
      else if(X<0) Out[0]=0;
      else Out[0] = X;
      X = (Y -102*U - 148*V) >> 8; // Y - 0.397*U - 0.58*V;
      if(X>255) Out[1]=255;
      else if(X<0) Out[1]=0;
      else Out[1] = X;
      X = (Y + 521*U) >> 8;	// Y + 2.034*U;
      if(X>255) Out[2]=255;
      else if(X<0) Out[2]=0;
      else Out[2] = X;

      Out+=3;
      In+=4;
    }
  }
};

class ConvertVideoLine_01_AYUV: public AConvertVideoLine_AYUV
{
public:
  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {				//converts from AYUV to RGB mono
    In++;		// shift to Y compound
    while(LoopCount-->0)
    {
      Out[2]=Out[1]=Out[0] = *In;
      Out+=3;
      In+=4;
    }
  }
};

class ConvertVideoLine_02_AYUV: public AConvertVideoLine_AYUV
{
public:
  uint8_t thr;

  ConvertVideoLine_02_AYUV(unsigned char iniThreshold): thr(iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {				//converts from AYUV to RGB mono
    In++;		// shift to Y compound
    while(LoopCount-->0)
    {
      Out[2]=Out[1]=Out[0] = (*In>=thr) ? 255 : 0;
      Out+=3;
      In+=4;
    }
  }

};

class ConvertVideoLine_11_AYUV: public AConvertVideoLine_AYUV
{
public:
  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {				//converts from AYUV to gray 8 bits
    In++;		// shift to Y compound
    while(LoopCount-->0)
    {
      *(Out++) = *In;
      In+=4;
    }
  }
};

class ConvertVideoLine_12_AYUV: public AConvertVideoLine_AYUV
{
public:
  uint8_t thr;

  ConvertVideoLine_12_AYUV(unsigned char iniThreshold): thr(iniThreshold) {};

  virtual void ConvertData(unsigned char *Out, const unsigned char *In, unsigned LoopCount) const
  {
    In++;		// shift to Y compound
    while(LoopCount-->0)
    {
      *(Out++) = (*In >= thr) ? 255 : 0;
      In+=4;
    }
  }
};
