////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////
////																					////
////																					////
////					 - WmpRenderer.cpp -	    								    ////
////																					////
////																					////
////				Implementation of TextureRenderer Class             		    	////
////						Version  1.0	(August 2001)    			 				////
////																					////
////								  Nadège SONNET     								////
////																					////
////																					////
////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////

/****************************************************************************
 * Includes
 ****************************************************************************/
/*#include "../Main.h"
#include <initguid.h> 
#iclude "WmpRenderer.h"*/

#include "../Main.h"
#include <dshow.h>
#include <d3dx8.h>
#include "WmpRenderer.h"
#include <initguid.h> 

/****************************************************************************
 * Defines
 ****************************************************************************/

//6041fc8c-f864-40fc-a617-77ad189c4906
DEFINE_GUID(MY_RendererFilter,
0x6041fc8c, 0xf864, 0x40fc, 0xa6, 0x17, 0x77, 0xad, 0x18, 0x9c, 0x49, 0x6);




//-----------------------------------------------------------------------------
// Object creation template
//-----------------------------------------------------------------------------
CFactoryTemplate g_Templates[1] = {
    { L"RENDERFILTER"
  , &MY_RendererFilter
  , CTextureRenderer::CreateInstance
  
  }
};



int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

//-----------------------------------------------------------------------------
// Creation of a new instance of this class
//-----------------------------------------------------------------------------
CUnknown * WINAPI CTextureRenderer::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
{
    CTextureRenderer *punk = new CTextureRenderer(lpunk, phr);
    if (punk == NULL) {
        *phr = E_OUTOFMEMORY;
    }
	
	*phr = S_OK;

	
   return punk;

} 

//-----------------------------------------------------------------------------
// CTextureRenderer : constructor
//-----------------------------------------------------------------------------
CTextureRenderer::CTextureRenderer( LPUNKNOWN pUnk, HRESULT *phr)
                                   : CBaseVideoRenderer(MY_RendererFilter, 
                                   "RENDERFILTER", pUnk, phr)
								  

{
	
	if (pUnk)
	{
		m_pUnknown = pUnk;
		m_pUnknown->AddRef();
    }
	m_mywmpbuf=NULL;
	m_eState=Uninitialized;
  

}


//-----------------------------------------------------------------------------
// CTextureRenderer : destructor
//-----------------------------------------------------------------------------
CTextureRenderer::~CTextureRenderer()
{
    // Do nothing
	m_eState = Uninitialized ;
	if (m_pUnknown)
    {
		m_pUnknown->Release();
		m_pUnknown = NULL;
	}
	m_mywmpbuf=NULL;


}

//-----------------------------------------------------------------------------
// NonDelegatingQueryInterface : Query the IBaseFilter Interface
//-----------------------------------------------------------------------------
STDMETHODIMP CTextureRenderer::NonDelegatingQueryInterface(REFIID riid, void **ppv)
    {
        if (riid == IID_IBaseFilter) {
            return GetInterface((IBaseFilter *)this, ppv);
        } 
		else 
		{
            return CBaseVideoRenderer::NonDelegatingQueryInterface(riid, ppv);
        }


   }


//-----------------------------------------------------------------------------
// Initialisation of class parameters
//-----------------------------------------------------------------------------
void CTextureRenderer::Init(IUnknown* pUnknown, mywmpbuf p)
{
	m_mywmpbuf=p;
	m_mywmpbuf->buf=NULL;

}

//-----------------------------------------------------------------------------
// RenderFile: Builds a filter graph that renders the specified file.
//-----------------------------------------------------------------------------
HRESULT CTextureRenderer::RenderFile(IGraphBuilder *m_pGB, LPCWSTR lpwstrFile, LPCWSTR lpwstrPlayList)
{
	PostMessage (HScol,WMP_STATE,m_mywmpbuf->id,(LPARAM)WMP_CONTACTING);  
	return m_pGB->RenderFile(lpwstrFile,lpwstrPlayList);
	
}

//-----------------------------------------------------------------------------
// CheckMediaType: This method forces the graph to give us an R8G8B8 video
// type, making our copy to texture memory trivial.
//-----------------------------------------------------------------------------
HRESULT CTextureRenderer::CheckMediaType(const CMediaType *pmt)
{
    HRESULT   hr = E_FAIL;
    VIDEOINFO *pvi;
  		
    
    // Reject the connection if this is not a video type
    if( *pmt->FormatType() != FORMAT_VideoInfo ) 
	{
        return E_INVALIDARG;
    }
    
    // Only accept RGB24
    pvi = (VIDEOINFO *)pmt->Format();
    if(IsEqualGUID( *pmt->Type(),    MEDIATYPE_Video)  &&
       IsEqualGUID( *pmt->Subtype(), MEDIASUBTYPE_RGB24))
    {
        hr = S_OK;
    }
    
    return hr;
}


//-----------------------------------------------------------------------------
// SetMediaType: Graph connection has been made. 
//-----------------------------------------------------------------------------
HRESULT CTextureRenderer::SetMediaType(const CMediaType *pmt)
{
	

    // Retrieve the size of this media type
    VIDEOINFO *pviBmp;                      // Bitmap info header
    pviBmp = (VIDEOINFO *)pmt->Format();

	
	//m_pBitmapInfo = &(pviBmp->bmiHeader);
    m_lVidWidth  = pviBmp->bmiHeader.biWidth;
    m_lVidHeight = abs(pviBmp->bmiHeader.biHeight);
    m_lVidPitch = (m_lVidWidth * 3 + 3) & ~(3); // We are forcing RGB24

	 
	//Initialisation of video buffer 
	m_mywmpbuf->width=m_lVidWidth;
	m_mywmpbuf->height=m_lVidHeight;
	if (m_mywmpbuf->buf)
	{
		free((void*)m_mywmpbuf->buf);
		m_mywmpbuf->buf=NULL;
	}
	
	int l;
	l=m_lVidWidth*m_lVidHeight;
	if (m_mywmpbuf->buf==NULL)
	{
		m_mywmpbuf->buf=(short*)malloc(l*2);
		m_mywmpbuf->size=l*2;
		if (m_mywmpbuf->buf==NULL)
		{
			(MSKDEBUG,"\nWARNING >>> Could not create buffer for wmp");
			return S_FALSE;
		}
	}

    return S_OK;
}


//-----------------------------------------------------------------------------
// DoRenderSample: A sample has been delivered. Copy it to the texture.
//-----------------------------------------------------------------------------
HRESULT CTextureRenderer::DoRenderSample( IMediaSample * pSample )
{


	int i,j;
    BYTE  *pBmpBuffer=NULL;     // Bitmap buffer

	if (m_mywmpbuf->buf==NULL)
	{
		//MMechostr(MSKDEBUG,"\nWARNING >>> Could not create buffer for wmp");
		return S_FALSE;
	}
	
	if ((m_eState == Stopped) || (m_eState == Paused)|| (m_eState == Uninitialized))
	{
		return S_FALSE;
	}
	    
    // Get the video bitmap buffer
    pSample->GetPointer( &pBmpBuffer );
  

	short *pTxtBuffer = m_mywmpbuf->buf;//Texture buffer
	pBmpBuffer+=m_lVidPitch*(m_lVidHeight-1);

	for(i=0;i<m_lVidHeight;i++)
	{

		for(j=0;j<m_lVidWidth;j++)
		{
			pTxtBuffer[j]=((pBmpBuffer[3*j]>>3)&0x1f)+((pBmpBuffer[3*j+1]<<2)&0x3e0)+((pBmpBuffer[3*j+2]<<7)&0x7c00);		
		
		}
		pTxtBuffer+=m_lVidWidth;
		pBmpBuffer-=m_lVidPitch;
	}

 
	//We replace the callback call by an event posting on the main scol window to avoid problems do 
	//to the fact that DirectShow use his own thread
	if(m_mywmpbuf->msgPosted==false )
	{
		m_mywmpbuf->msgPosted = true;
		PostMessage (HScol,WMP_BLIT,m_mywmpbuf->id,(LPARAM)m_mywmpbuf);
	}
	else return S_FALSE;//-1;

	
    return S_OK;
}


//-----------------------------------------------------------------------------
// OnReceiveFirstSample: The first sample has been delivered. Copy it to the texture.
//-----------------------------------------------------------------------------
void CTextureRenderer::OnReceiveFirstSample(IMediaSample *pMediaSample)
{
	DoRenderSample(pMediaSample);
}




//-------------------------------------------------------------------------------
// CTextureRenderer::WaitForState(): Wait for the state to change to the given one.
//-------------------------------------------------------------------------------
void CTextureRenderer::WaitForState(FILTER_STATE State,IMediaControl *m_pMC)
{
    // Make sure we have switched to the required state
    LONG   lfs ;
    do
    {
        m_pMC->GetState(0, &lfs) ;
    } while (State != lfs);
}

//-------------------------------------------------------------------------------
// CTextureRenderer::Stop(): Stops the filter graph (and waits to really stop)
//-------------------------------------------------------------------------------
STDMETHODIMP CTextureRenderer::Stop(IMediaControl *m_pMC)
{
    HRESULT  hr;

	if (m_eState==Stopped)
		return S_OK ;
    
	if (! IsGraphReady() )
    {
		MMechostr(MSKDEBUG,"\nCTextureRenderer video playback graph hasn't been built yet");
        return S_FALSE ;
    }


    if (FAILED(hr=m_pMC->Stop()))
	{
		MMechostr(MSKDEBUG,"\nWARNING >>> Could not stop the filter graph");
		DisplayWmpErrorMessage(hr);
        return S_FALSE ;
    }
    WaitForState(State_Stopped,m_pMC) ;
	
    
    // Some state changes now
    m_eState = Stopped ;
    
    return S_OK ;  // success
}


//-------------------------------------------------------------------------------
// CTextureRenderer::Pause(): Pauses/Cues the filter graph (and waits to really pause)
//-------------------------------------------------------------------------------
STDMETHODIMP CTextureRenderer::Pause(IMediaControl *m_pMC)
{

    HRESULT  hr;
    
	if (m_eState==Paused)
		return S_OK ;

    if (! IsGraphReady() )
    {
		MMechostr(MSKDEBUG,"\nCTextureRenderer video playback graph hasn't been built yet");
        return S_FALSE ;
    }

	//StopStreaming();

    if (FAILED(hr=m_pMC->Pause()))
    {
		MMechostr(MSKDEBUG,"\nWARNING >>> Could not pause the filter graph");
		DisplayWmpErrorMessage(hr);
        return S_FALSE ;
    }
    WaitForState(State_Paused,m_pMC) ;
    
    // Some state changes now
    m_eState = Paused ;
    
    return S_OK ;  // success
}

//-------------------------------------------------------------------------------
// CTextureRenderer::Run(): Plays the filter graph (and waits to really start playing)
//-------------------------------------------------------------------------------
STDMETHODIMP
CTextureRenderer::Run(IMediaControl *m_pMC)
{
 
	HRESULT  hr;

	if (m_eState==Playing)
		return S_OK ;


	//StartStreaming();
    if (FAILED(hr=m_pMC->Run()))
    {
		MMechostr(MSKDEBUG,"\nWARNING >>> Could not run the filter graph");
		DisplayWmpErrorMessage(hr);
        return S_FALSE ;
    }
    WaitForState(State_Running,m_pMC) ;
    

    // Some state changes now
    m_eState = Playing ;


    
    return S_OK ;  // success
}

