/****************************************************************************
 * 
 *  $Id: exvsurf.cpp,v 1.1.1.1 1999/02/23 23:48:01 jordanb Exp $
 *  
 *  Copyright (C) 1995,1996,1997 Progressive Networks.
 *  All rights reserved.
 *
 *  This program contains proprietary 
 *  information of Progressive Networks, Inc, and is licensed
 *  subject to restrictions on use and distribution.
 *
 */

//
// Modifications History
//
//$LB (06/12/2003)  : YUV->RGB conversion is now managed with 24 bits, instead of 16
//
//$LB (07/12/2003) : call the REALcbState Callback in ExampleVideoSurface::OptimizedBlt if the pixel format
//                   doesn't match with what scol is able to process
//


#include <stdio.h>

#include "pncom.h"
#include "pntypes.h"
#include "pntypes.h"
#include "pnwintyp.h"

///#include "cpnxtype.h"

#include "rmapckts.h"
#include "rmawin.h"
#include "rmasite2.h"
//#include "rmavctrl.h"
#include "rmavsurf.h"
#include "rmacomm.h"

//#include "../x/scolplugin.h"
#include "Real.h"

#include "fivemlist.h"

#include "exvsurf.h"
#include "exnwsite.h"

#ifdef _DEBUG
#undef PN_THIS_FILE		
static char PN_THIS_FILE[] = __FILE__;
#endif



ExampleVideoSurface::ExampleVideoSurface(IUnknown* pContext, ExampleWindowlessSite* pSiteWindowless, myrealbuf p)
    : m_lRefCount(0)
    , m_pContext(pContext)
    , m_pSiteWindowless(pSiteWindowless)
    , m_pBitmapInfo(NULL)
	, m_myrealbuf (p)
{ 
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::ExampleVideoSurface");
#endif
/***************************************/

    if (m_pContext)
    {
	m_pContext->AddRef();
    }
//	MMechostr(MSKDEBUG,"j'y suis presque %d\n",m_myrealbuf->id);

    memset(&m_lastBitmapInfo, 0, sizeof(RMABitmapInfoHeader));

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::ExampleVideoSurface ok");
#endif
/***************************************/
}




ExampleVideoSurface::~ExampleVideoSurface()
{
    PN_RELEASE(m_pContext);
}

// *** IUnknown methods ***

/////////////////////////////////////////////////////////////////////////
//  Method:
//      IUnknown::QueryInterface
//  Purpose:
//      Implement this to export the interfaces supported by your 
//      object.
//
STDMETHODIMP 
ExampleVideoSurface::QueryInterface(REFIID riid, void** ppvObj)
{
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::QueryInterface");
#endif
/***************************************/


    if (IsEqualIID(riid, IID_IUnknown))
    {
        AddRef();
        *ppvObj = this;
        return PNR_OK;
    }
    else if (IsEqualIID(riid, IID_IRMAVideoSurface))
    {
        AddRef();
        *ppvObj = (IRMAVideoSurface*)this;
        return PNR_OK;
    }
    
    *ppvObj = NULL;


/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::QueryInterface ok");
#endif
/***************************************/
    return PNR_NOINTERFACE;
}






/////////////////////////////////////////////////////////////////////////
//  Method:
//      IUnknown::AddRef
//  Purpose:
//      Everyone usually implements this the same... feel free to use
//      this implementation.
//
STDMETHODIMP_(ULONG32) 
ExampleVideoSurface::AddRef()
{
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::AddRef");
#endif
/***************************************/

    return InterlockedIncrement(&m_lRefCount);
}




/////////////////////////////////////////////////////////////////////////
//  Method:
//      IUnknown::Release
//  Purpose:
//      Everyone usually implements this the same... feel free to use
//      this implementation.
//
STDMETHODIMP_(ULONG32) 
ExampleVideoSurface::Release()
{
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::Release");
#endif
/***************************************/

    if (InterlockedDecrement(&m_lRefCount) > 0)
    {
        return m_lRefCount;
    }

    delete this;

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::Release ok");
#endif
/***************************************/
    return 0;
}




PN_RESULT	
ExampleVideoSurface::Init()
{
    return PNR_OK;
}


STDMETHODIMP
ExampleVideoSurface::Blt(UCHAR*		    pImageData,
			     RMABitmapInfoHeader*   pBitmapInfo,
			     REF(PNxRect)	    inDestRect,
			     REF(PNxRect)	    inSrcRect)
{
int k;
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::Blt");
#endif
/***************************************/

    BeginOptimizedBlt(pBitmapInfo);
	k = OptimizedBlt(pImageData, inDestRect, inSrcRect);

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::Blt ok");
#endif
/***************************************/
    return k;
}





STDMETHODIMP
ExampleVideoSurface::BeginOptimizedBlt(RMABitmapInfoHeader* pBitmapInfo)
{
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::BeginOptimizedBlt");
#endif
/***************************************/

    PN_RESULT res = PNR_FAIL;
                                                                                
    if ((!pBitmapInfo)||(!pBitmapInfo->biCompression))
    {                                                                           
        return res;
    }

    m_pBitmapInfo = pBitmapInfo;
	m_myrealbuf->width=pBitmapInfo->biWidth;
	m_myrealbuf->height=pBitmapInfo->biHeight;
	if (m_myrealbuf->buf)
	{
		free((void*)m_myrealbuf->buf);
		m_myrealbuf->buf=NULL;
	}
    MMechostr(MSKDEBUG,">>%d-%d\n",m_myrealbuf->width,m_myrealbuf->height);
    MMechostr(MSKDEBUG,"(%d) %d\n",pBitmapInfo->biBitCount,pBitmapInfo->biSizeImage);
	char buf[16];
	*(int*)buf=m_pBitmapInfo->biCompression;
	buf[4]=0;
	MMechostr(MSKDEBUG,"format %x %s!\n",m_pBitmapInfo->biCompression,buf);


/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::BeginOptimizedBlt ok");
#endif
/***************************************/
    return PNR_OK;
}



//$LB (06/12/2003) short* YUVtab=NULL;
OBJBITMAP_BUFFER YUVtab;

int fillYUVtab()
{
	int y,u,v;
	int y2,u2,v2;
	float r,g,b;
	int ri,gi,bi;
	//$LB (06/12/2003) short* p;
	OBJBITMAP_BUFFER p;

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL fillYUVtab");
#endif
/***************************************/

	if (YUVtab) return 0;
	//$LB (06/12/2003) YUVtab=(short*)malloc(32768*2*4);
	YUVtab = (OBJBITMAP_BUFFER) malloc (64*128*128 * 3); // (Lum. steps) * (Chr. Red steps) * (Chr. Blue steps) * (nb bytes per pix)
	if (!YUVtab) return -1;

	p=YUVtab;
	for(y=0;y<256;y+=4)
	for(u=0;u<256;u+=2)
	for(v=0;v<256;v+=2)
	{
		y2=(255*(y-16))/219; 
		u2=(127*(u-128))/112;
		v2=(127*(v-128))/112; 
				
		r = (float)(1.402*v2 + y2 + .5);
		g = (float)(y2 - .7143*v2 - .3437*u2 + .5);
		b = (float)(1.77*u2 + y2 + .5);
		ri=(int)r; gi=(int)g; bi=(int)b;
		if (ri<0) ri=0;
		if (ri>255) ri=255;
		if (gi<0) gi=0;
		if (gi>255) gi=255;
		if (bi<0) bi=0;
		if (bi>255) bi=255;

		//$LB (06/12/2003) *(p++)=(bi>>3)+((gi<<2)&0x3e0)+((ri<<7)&0x7c00);
		*(p++) = bi; *(p++) = gi; *(p++) = ri;

//		MMechostr(MSKDEBUG,"col(%d,%d,%d) %x\n",y,u,v,*(p-1));
	}

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL fillYUVtab ok");
#endif
/***************************************/

	return 0;
}




//$LB (07/12/2003) 
void
ExampleVideoSurface::GetCompressionString (char* string)
{
RMABitmapInfoHeader* bi = this->GetBitmapInfoHeader();

  if (!bi)
  {
    sprintf (string, "BitmapInfoHeader data is undefined : can't give you any video information! sorry...");		
	return;
  }


  switch (bi->biCompression)
  {
	case RMA_RGB         : sprintf(string, "REAL FORMAT RMA_RGB"); break;   
	case RMA_RLE8        : sprintf(string, "REAL FORMAT RMA_RLE8"); break; 
	case RMA_RLE4        : sprintf(string, "REAL FORMAT RMA_RLE4"); break;
	case RMA_BITFIELDS   : sprintf(string, "REAL FORMAT RMA_BITFIELDS"); break;
	case RMA_I420        : sprintf(string, "REAL FORMAT RMA_I420"); break;
	case RMA_YV12        : sprintf(string, "REAL FORMAT RMA_YV12"); break;
	case RMA_YUY2        : sprintf(string, "REAL FORMAT RMA_YUY2"); break;
	case RMA_UYVY        : sprintf(string, "REAL FORMAT RMA_UYVY"); break;
	case RMA_YVU9        : sprintf(string, "REAL FORMAT RMA_YVU9"); break;
	case RMA_RGB3_ID     : sprintf(string, "REAL FORMAT RMA_RGB3_ID"); break;
	case RMA_RGB24_ID    : sprintf(string, "REAL FORMAT RMA_RGB24_ID"); break;
	case RMA_RGB565_ID   : sprintf(string, "REAL FORMAT RMA_RGB565_ID"); break;
	case RMA_RGB555_ID   : sprintf(string, "REAL FORMAT RMA_RGB555_ID"); break;
	case RMA_8BIT_ID     : sprintf(string, "REAL FORMAT RMA_8BIT_ID"); break;
	case RMA_YUV420_ID   : sprintf(string, "REAL FORMAT RMA_YUV420_ID"); break;
	case RMA_YUV411_ID   : sprintf(string, "REAL FORMAT RMA_YUV411_ID"); break;
	case RMA_YUVRAW_ID   : sprintf(string, "REAL FORMAT RMA_YUVRAW_ID"); break;
	default              : sprintf(string, "REAL FORMAT unknown"); break;
  }

}




STDMETHODIMP
ExampleVideoSurface::OptimizedBlt(UCHAR* pImageBits,			
				      REF(PNxRect) rDestRect, 
				      REF(PNxRect) rSrcRect)
{
	int k,l;
	//$LB (06/12/2003)
	int BPL, BSize;

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::OptimizedBlt");
#endif
/***************************************/

    if (!m_pBitmapInfo)
    {
	return PNR_UNEXPECTED;
    }


	l = m_pBitmapInfo->biWidth * m_pBitmapInfo->biHeight;

	//$LB (06/12/2003) 
	BPL =  m_pBitmapInfo->biWidth * 3;
	if ((BPL % 4) != 0) BPL += (BPL % 4); // 32 bits aligned
	BSize = BPL * m_pBitmapInfo->biHeight;


	//$LB (06/12/2003) 
	if ((m_myrealbuf->buf)&&(m_myrealbuf->size != BSize))
	{
		free(m_myrealbuf->buf);
		m_myrealbuf->buf=NULL;
	}


	if (m_myrealbuf->buf==NULL)
	{
		//$LB (06/12/2003)  m_myrealbuf->buf = (short*)malloc(l*2);
		//                  m_myrealbuf->size=l*2;
		m_myrealbuf->buf  = (OBJBITMAP_BUFFER) malloc(BSize);
		m_myrealbuf->size = BSize;


		if (m_myrealbuf->buf==NULL)
		{
			MMechostr(MSKDEBUG,"unable to create buffer for real\n");
			return PNR_OK;
		}
	}





	if (((m_pBitmapInfo->biCompression==RMA_YUV420_ID) || (m_pBitmapInfo->biCompression==RMA_I420)) &&(m_pBitmapInfo->biBitCount==12))
	{
		UCHAR* cy;
		UCHAR* cr;
		UCHAR* cb;
		int i,j,i0,j0, offset;
		//$LB (06/12/2003)  short *p;
		OBJBITMAP_BUFFER p;

		if (fillYUVtab()) return PNR_OK;

		p=m_myrealbuf->buf;
		cy=pImageBits;
		cr=pImageBits+l;
		cb=cr+(l>>2);

		for(i=0; i<m_pBitmapInfo->biHeight; i++)
		{
			i0 = (i>>2) * m_pBitmapInfo->biWidth;

			for(j=0; j<m_pBitmapInfo->biWidth; j++) 
			{
				j0 = (j>>1)+i0;

				//$LB (06/12/2003) 
				//offset = (((*(cy++))&0xf8)<<9) | ((cr[j0]&0xfc)<<4) | ((cb[j0]&0xfc)>>2);
				offset = (((*(cy++))&0xfc)<<12) | ((cr[j0]&0xfc)<<6) | ((cb[j0]&0xfc)>>1); 

				offset *= 3;

				*(p++) = YUVtab[offset + 0];
				*(p++) = YUVtab[offset + 1];
				*(p++) = YUVtab[offset + 2];
			} 
		}

	k=OBJbeginreflex(m_myrealbuf->m,typeReal,m_myrealbuf->id,RFLREAL_IMAGE);
	if (k==0) OBJcallreflex(m_myrealbuf->m,0);
	}


    else
	{
		char tmp[64];
		char buf[16];
		*(int*)buf=m_pBitmapInfo->biCompression;
		buf[4]=0;

		MMechostr(MSKDEBUG,"Unknown format %x %s\n",m_pBitmapInfo->biCompression,buf);

		this->GetCompressionString (&tmp[0]);

		//$LB (07/12/2003) : call the REALcbState Callback to warn the user he can't read the video
		k = OBJbeginreflex (m_myrealbuf->m, typeReal, m_myrealbuf->id, RFLREAL_STATE);
		if (k==0)
		{
 		  if (MMpush (m_myrealbuf->m, REALerror)) return PNR_OK; 
		  if (MMpush (m_myrealbuf->m, 1<<1)) return PNR_OK;                 // error code
		  if (Mpushstrbloc(m_myrealbuf->m,(char*)tmp)) return PNR_OK; // error string
		  if (MMpush (m_myrealbuf->m, 2<<1)) return PNR_OK;
		  if (k = MBdeftab(m_myrealbuf->m)) return PNR_OK; 
		  if (MMpush (m_myrealbuf->m, 2<<1)) return PNR_OK;
		  if (k = MBdeftab(m_myrealbuf->m)) return PNR_OK;
		  OBJcallreflex (m_myrealbuf->m, 1);
		}

	}






/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::OptimizedBlt ok");
#endif
/***************************************/

    return PNR_OK;
 }









STDMETHODIMP
ExampleVideoSurface::EndOptimizedBlt(void)
{
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::EndOptimizedBlt");
#endif
/***************************************/

    m_pBitmapInfo = NULL;


/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::EndOptimizedBlt ok");
#endif
/***************************************/
    return PNR_OK;
}


STDMETHODIMP
ExampleVideoSurface::GetOptimizedFormat(REF(RMA_COMPRESSION_TYPE) ulType)
{
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::GetOptimizedFormat");
#endif
/***************************************/

    if (m_pBitmapInfo)
    {
        ulType =  m_pBitmapInfo->biCompression;
    }

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::GetOptimizedFormat ok");
#endif
/***************************************/

    return PNR_NOTIMPL;
}


STDMETHODIMP
ExampleVideoSurface::GetPreferredFormat(REF(RMA_COMPRESSION_TYPE) ulType)
{
/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::GetPreferredFormat");
#endif
/***************************************/

    ulType = RMA_RGB;

/***************************************/
#ifdef _DEBUG_MMEDIA_
	MMechostr(MSKDEBUG, "\nREAL ExampleVideoSurface::GetPreferredFormat ok");
#endif
/***************************************/
    return PNR_OK;
}
 