 
#include <XBApp.h>
#include <XBFont.h>
#include <XBHelp.h>
#include <xgraphics.h>

#include <xmv.h>
#include "XMVHelper.h"


class CXBoxSample
{
    enum READ_METHOD
    {
        READ_FROM_FILE,     // Read from a file using CreateDecoderForFile
        READ_FROM_PACKETS,  // Read from a file using CreateDecoderForPackets
        READ_FROM_MEMORY,   // Read from a block of memory
        READ_METHOD_COUNT   // Number of READ_METHOD enums
    };

    CXBFont         m_Font;                 // Font object
    CXMVPlayer      m_player;               // Movie player object
    READ_METHOD     m_readMethod;           // Controls how the movie data is read.
    BOOL            m_bYUV;                 // Unpack to a YUV or RGB texture - using an overlay requires YUV
    BOOL            m_bUseTextures;         // Render to a texture or an overlay - using Play() requires an overlay
    BOOL            m_bUsePlay;             // Use the Play() or GetNextFrame() method to play the movie
    BOOL            m_bUseColorKey;         // Use a colorkey - requires an overlay
    BOOL            m_bFullScreen;          // Should we play full screen or just partial?

    HRESULT PlayVideoWithPlay( const CHAR* strFilename );
    HRESULT PlayVideoWithGetNextFrame( const CHAR* strFilename );
    BOOL    PlayVideoFrame();           // Play a frame from a video, if one is playing.
    HRESULT OpenMovie( const CHAR* strFilename, D3DFORMAT format, BOOL allocateTextures );

public:
    virtual HRESULT Initialize();
    virtual HRESULT Render();
    virtual HRESULT FrameMove();

    CXBoxSample();
};

CXBoxSample::CXBoxSample() 
{
    m_bFullScreen =         FALSE;
    m_readMethod =          READ_FROM_FILE;
    m_bYUV =                FALSE;
    m_bUseTextures =        TRUE;
    m_bUsePlay =            TRUE;
    m_bUseColorKey =        FALSE;

}

HRESULT CXBoxSample::Initialize()
{
    return S_OK;
}

HRESULT CXBoxSample::FrameMove()
{
	const char* strMovieName = "D:\\Test.xmv";
	PlayVideoWithGetNextFrame( strMovieName );
    return S_OK;
}

HRESULT CXBoxSample::OpenMovie( const CHAR* strFilename, D3DFORMAT format, BOOL bAllocateTextures )
{
    HRESULT hr = E_FAIL;
   
    hr = m_player.OpenFile( strFilename, format, m_pd3dDevice, bAllocateTextures );
          
    
    return hr;
}


//-----------------------------------------------------------------------------
// Name: TexturePlayVideo()
// Desc: Plays specified video file on a texture.
//-----------------------------------------------------------------------------
HRESULT CXBoxSample::PlayVideoWithGetNextFrame( const CHAR* strFilename )
{
    
   // If we're not currently playing a movie then start playing one.
    D3DFORMAT format = D3DFMT_YUY2;
            // The only non-YUV formats allowed are D3DFMT_LIN_A8R8G8B8 and D3DFMT_LIN_X8R8G8B8
    format = D3DFMT_LIN_A8R8G8B8;
   
    // We can use the file or memory or packet interface - it doesn't matter.
    HRESULT hr = OpenMovie( strFilename, format, TRUE );

    return hr;
}


//-----------------------------------------------------------------------------
// Name: PlayVideoFrame()
// Desc: Plays one frame of video if a movie is currently open and if there is
// a frame available. This function is safe to call at any time.
//-----------------------------------------------------------------------------
BOOL CXBoxSample::PlayVideoFrame()
{

    if ( !m_player.IsPlaying() )
        return FALSE;

    const FLOAT fMovieWidth = FLOAT( m_player.GetWidth() );
    const FLOAT fMovieHeight = FLOAT( m_player.GetHeight() );

    // Move to the next frame.
    LPDIRECT3DTEXTURE8 pTexture = 0;
    if ( m_bUseTextures )
        pTexture = m_player.AdvanceFrameForTexturing( m_pd3dDevice );
    else
        pTexture = m_player.AdvanceFrameForOverlays( m_pd3dDevice );

    // See if the movie is over now.
    if ( !m_player.IsPlaying() )
    {
        // Clean up the movie, then return.
        m_player.Destroy();
        return FALSE;
    }

    // If no texture is ready, return TRUE to indicate that a movie is playing,
    // but don't render anything yet.
    if ( !pTexture )
        return TRUE;

    if ( m_bUseTextures )
    {

        // Have the texture start small and scale up, just to prove it's on
        // a texture.
        const DWORD FRAMES_TO_EASE_IN = 40;
        FLOAT fRatio = 1.0;
        if ( m_player.GetCurrentFrame() < FRAMES_TO_EASE_IN )
            fRatio = FLOAT( m_player.GetCurrentFrame() ) / FRAMES_TO_EASE_IN;

        const FLOAT fSizeY    = ( m_bFullScreen ? 480.0f : 240.0f) * fRatio;
        const FLOAT fOriginX =  320.0f - ( fSizeY * .5f * fMovieWidth / fMovieHeight );
        const FLOAT fOriginY = 240.0f - fSizeY * .5f;

        // Draw the texture.
        m_pd3dDevice->SetRenderState( D3DRS_FILLMODE,         D3DFILL_SOLID );
        m_pd3dDevice->SetRenderState( D3DRS_CULLMODE,         D3DCULL_CCW );
        m_pd3dDevice->SetRenderState( D3DRS_ZENABLE,          FALSE );

        // Draw the texture as a quad.
        m_pd3dDevice->SetTexture( 0, pTexture );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP,   D3DTOP_SELECTARG1 );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );

        // Wrapping isn't allowed on linear textures.
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSU,  D3DTADDRESS_CLAMP );
        m_pd3dDevice->SetTextureStageState( 0, D3DTSS_ADDRESSV,  D3DTADDRESS_CLAMP );

        // If we're unpacking to a YUV surface we have to tell the hardware that we
        // are rendering from a YUV surface.
        if ( m_bYUV )
            m_pd3dDevice->SetRenderState( D3DRS_YUVENABLE, TRUE );

        FLOAT fLeft   = fOriginX;
        FLOAT fRight  = fOriginX + ( fSizeY * fMovieWidth) / fMovieHeight;
        FLOAT fTop    = fOriginY;
        FLOAT fBottom = fOriginY + fSizeY;

        // On linear textures the texture coordinate range is from 0,0 to width,height, instead
        // of 0,0 to 1,1.
        m_pd3dDevice->SetVertexShader( D3DFVF_XYZRHW|D3DFVF_TEX1 );
        m_pd3dDevice->Begin( D3DPT_QUADLIST );
        m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, fMovieHeight );
        m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fLeft,  fBottom, 0.0f, 1.0f );
        m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, 0, 0 );
        m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fLeft,  fTop,    0.0f, 1.0f );
        m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, 0 );
        m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fRight, fTop,    0.0f, 1.0f );
        m_pd3dDevice->SetVertexData2f( D3DVSDE_TEXCOORD0, fMovieWidth, fMovieHeight );
        m_pd3dDevice->SetVertexData4f( D3DVSDE_VERTEX, fRight, fBottom, 0.0f, 1.0f );
        m_pd3dDevice->End();

        // If we switched to YUV texturing then we need to switch back.
        if ( m_bYUV )
            m_pd3dDevice->SetRenderState( D3DRS_YUVENABLE, FALSE );
    }
    else
    {
        // Setup the source and destination rectangles.
        RECT srcRect = { 0, 0, m_player.GetWidth(), m_player.GetHeight() };
        RECT dstRect = g_partialScreenRect;
        if ( m_bFullScreen )
            dstRect = g_fullScreenRect;

        // Get the surface from the texture.
        IDirect3DSurface8* pSurface;
        pTexture->GetSurfaceLevel( 0, &pSurface );

        // Display the frame of data as an overlay, enabling color keying if requested.
        if ( m_bUseColorKey )
            m_pd3dDevice->UpdateOverlay( pSurface, &srcRect, &dstRect, TRUE, g_colorKey );
        else
            m_pd3dDevice->UpdateOverlay( pSurface, &srcRect, &dstRect, FALSE, 0 );
    }

    return TRUE;
}

CXBoxSample xbApp;