HRESULT CMediaController::CreateInstance(CMediaController **ppMediaController)
{
    HRESULT hr = S_OK;

    //Instantiate the class
    CMediaController *pMediaController = new CMediaController(&hr);

    if (!pMediaController)
    {
        LOG_MSG_IF_FAILED(L"CMediaController creation failed.\n", E_OUTOFMEMORY);
        
        return E_OUTOFMEMORY;       
    }

    //Return the pointer to the caller
    if (SUCCEEDED (hr))
    {
        *ppMediaController = pMediaController;
        (*ppMediaController)->AddRef();
                
        TRACE((L"CMediaController created.\n"));
    }
                
    LOG_MSG_IF_FAILED(L"CMediaController creation failed.\n", E_FAIL);

    SAFE_RELEASE (pMediaController);

    return hr;
}
HRESULT D3DPresentEngine::PresentSwapChain(IDirect3DSwapChain9* pSwapChain, IDirect3DSurface9* pSurface)
{
    HRESULT hr = S_OK;


	//pSwapChain->GetFrontBufferData(d3d_shared_surface);
	IDirect3DSurface9 *surface;
	pSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&surface);
    if (m_pDevice->StretchRect(surface,NULL,d3d_shared_surface,NULL,D3DTEXF_NONE) != D3D_OK)
	{
		printf("ofxWMFVideoPlayer: Error while copying texture to gl context \n");
	}
	SAFE_RELEASE(surface);

    if (m_hwnd == NULL)
    {
        return MF_E_INVALIDREQUEST;
    }
	
    hr = pSwapChain->Present(NULL, &m_rcDestRect, m_hwnd, NULL, 0);

	

    LOG_MSG_IF_FAILED(L"D3DPresentEngine::PresentSwapChain, IDirect3DSwapChain9::Present failed.", hr);


    return hr;
}
HRESULT CASFManager::CreateInstance(CASFManager **ppASFManager)
{

    // Note: CASFManager constructor sets the ref count to zero.
    // Create method calls AddRef.

    HRESULT hr = S_OK;

    CASFManager *pASFManager = new (std::nothrow) CASFManager(&hr);

    if (!pASFManager)
    {
        return E_OUTOFMEMORY;
    }

    if (SUCCEEDED(hr))
    {
        *ppASFManager = pASFManager;
        (*ppASFManager)->AddRef();

        TRACE((L"CASFManager created.\n"));
    }

    LOG_MSG_IF_FAILED(L"CASFManager creation failed.\n", hr);

    SAFE_RELEASE (pASFManager);
    return hr;
}
HRESULT CASFManager::SelectStream (WORD wStreamNumber,
                                   GUID* pguidCurrentMediaType)
{
    HRESULT hr = S_OK;

    if (wStreamNumber == 0 || !pguidCurrentMediaType)
    {
        return E_INVALIDARG;
    }

    if (! m_pSplitter || ! m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    //Select the stream you want to parse. This sample allows you to select only one stream at a time
    CHECK_HR(hr  =  m_pSplitter->SelectStreams(&wStreamNumber, 1));

    //Load the appropriate stream decoder
    CHECK_HR(hr = SetupStreamDecoder(wStreamNumber, pguidCurrentMediaType));
    
    m_CurrentStreamID = wStreamNumber;

    m_guidCurrentMediaType = *pguidCurrentMediaType;

    TRACE((L"Stream selected.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::SelectStreams failed.\n", hr);

    return hr;
}
HRESULT CASFManager::GetSeekPosition (MFTIME* hnsSeekTime, 
                                      QWORD *pcbDataOffset, 
                                      MFTIME* phnsApproxSeekTime)
{
    HRESULT hr = S_OK;


    //if the media type is audio, or doesn't have an indexed data
    //calculate the offset manually
    if (( m_guidCurrentMediaType == MFMediaType_Audio) || (!m_pIndexer))
    {
        CHECK_HR(hr =  GetSeekPositionManually(*hnsSeekTime, pcbDataOffset));
    }

    //if the type is video, get the position with the indexer
    if (( m_guidCurrentMediaType == MFMediaType_Video))
    {
        CHECK_HR(hr =  GetSeekPositionWithIndexer(*hnsSeekTime, pcbDataOffset, phnsApproxSeekTime));        
    }


    TRACE((L"Offset calculated.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::GetSeekPosition failed.\n", hr);

    return hr;
}
HRESULT D3DPresentEngine::PresentSwapChain(IDirect3DSwapChain9* pSwapChain, IDirect3DSurface9* pSurface)
{
	//-----------------------------------------------------------------------------
	// Copy latest D3D frame to our OpenGL/D3D shared surface...

	//pSwapChain->GetFrontBufferData(d3d_shared_surface);
	IDirect3DSurface9 *surface;
	pSwapChain->GetBackBuffer(0,D3DBACKBUFFER_TYPE_MONO,&surface);
    if (m_pDevice->StretchRect(surface,NULL,d3d_shared_surface,NULL,D3DTEXF_NONE) != D3D_OK)
	{
		CI_LOG_E("Error while copying texture to gl context");
		//printf("ciWMFVideoplayer: Error while copying texture to gl context \n");
	}
	SAFE_RELEASE(surface);

	//-----------------------------------------------------------------------------
	// Original code from the WMF EVRpresenter sample code...

	HRESULT hr = S_OK;
	
	if (m_hwnd == NULL)
    {
        return MF_E_INVALIDREQUEST;
    }
	
    hr = pSwapChain->Present(NULL, &m_rcDestRect, m_hwnd, NULL, 0);
	
    LOG_MSG_IF_FAILED(L"D3DPresentEngine::PresentSwapChain, IDirect3DSwapChain9::Present failed.", hr);
	
    return hr;
}
HRESULT WebHelper::Init(DispatchCallback *pCallback)
{
    m_pDispatchCB = pCallback;

    IConnectionPointContainer *pCPContainer = NULL;
    HWND hwndBrowser = NULL;

    // Create the InternetExplorer object.
    HRESULT hr = CoCreateInstance(CLSID_InternetExplorer, NULL,
        CLSCTX_ALL, IID_IWebBrowser2, (void**)&m_pBrowser);
    LOG_MSG_IF_FAILED(L"CoCreateInstance(CLSID_InternetExplorer)", hr);

    // Set up the connection point so that we receive events.
    if (SUCCEEDED(hr))
    {
        hr = m_pBrowser->QueryInterface(IID_IConnectionPointContainer, (void**)&pCPContainer);
        LOG_MSG_IF_FAILED(L"QueryInterface for IConnectionPointContainer)", hr);
    }

    if (SUCCEEDED(hr))
    {
        hr = pCPContainer->FindConnectionPoint(DIID_DWebBrowserEvents2, &m_pCP);
        LOG_MSG_IF_FAILED(L"FindConnectionPoint)", hr);
    }

    if (SUCCEEDED(hr))
    {
        hr = m_pCP->Advise(this, &m_dwCookie);
        LOG_MSG_IF_FAILED(L"Advise)", hr);
    }

    if (SUCCEEDED(hr))
    {
        hr = m_pBrowser->get_HWND((SHANDLE_PTR*)&hwndBrowser);
    }

    // Move the browser window to the front.
    if (SUCCEEDED(hr))
    {
        SetWindowPos(hwndBrowser, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    }

    SAFE_RELEASE(pCPContainer);

    return hr;
}
HRESULT CASFManager::CreateASFSplitter (IMFByteStream *pContentByteStream,
                                        IMFASFSplitter **ppSplitter)
{
    if (!pContentByteStream || !ppSplitter)
    {
        return E_INVALIDARG;
    }

    if (!m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    HRESULT hr = S_OK;
    
    IMFASFSplitter *pSplitter = NULL;
    IMFPresentationDescriptor* pPD = NULL;

    UINT64 cbDataOffset = 0, cbDataLength = 0;

    CHECK_HR(hr = MFCreateASFSplitter(&pSplitter));
    
    CHECK_HR(hr = pSplitter->Initialize(m_pContentInfo));

    //Generate the presentation descriptor
    CHECK_HR(hr =  m_pContentInfo->GeneratePresentationDescriptor(&pPD));

    //Get the offset to the start of the Data Object
    CHECK_HR(hr = pPD->GetUINT64(MF_PD_ASF_DATA_START_OFFSET, &cbDataOffset));

    //Get the length of the Data Object
    CHECK_HR(hr = pPD->GetUINT64(MF_PD_ASF_DATA_LENGTH, &cbDataLength));

    m_pByteStream = pContentByteStream;
    m_pByteStream->AddRef();

    m_cbDataOffset = cbDataOffset;
    m_cbDataLength = cbDataLength;

    // Return the pointer to the caller.
    *ppSplitter = pSplitter;
    (*ppSplitter)->AddRef();

    TRACE((L"Created Splitter object.\n"));


done:

    LOG_MSG_IF_FAILED(L"CASFManager::CreateASFSplitter failed.\n", hr);

    SAFE_RELEASE(pSplitter);
    SAFE_RELEASE(pPD);

    return hr;
}
HRESULT CASFManager::ReadDataIntoBuffer(
    IMFByteStream *pStream,     // Pointer to the byte stream.
    DWORD cbOffset,             // Offset at which to start reading
    DWORD cbToRead,             // Number of bytes to read
    IMFMediaBuffer **ppBuffer   // Receives a pointer to the buffer.
    )
{
    HRESULT hr = S_OK;
    BYTE *pData = NULL;
    DWORD cbRead = 0;   // Actual amount of data read

    IMFMediaBuffer *pBuffer = NULL;

    // Create the media buffer. This function allocates the memory.
    CHECK_HR(hr = MFCreateMemoryBuffer(cbToRead, &pBuffer));

    // Access the buffer.
    CHECK_HR(hr = pBuffer->Lock(&pData, NULL, NULL));

    //Set the offset
    CHECK_HR(hr = pStream->SetCurrentPosition(cbOffset));

    // Read the data from the byte stream.
    CHECK_HR(hr = pStream->Read(pData, cbToRead, &cbRead));

    CHECK_HR(hr = pBuffer->Unlock());
    pData = NULL;

    // Update the size of the valid data.
    CHECK_HR(hr = pBuffer->SetCurrentLength(cbRead));

    // Return the pointer to the caller.
    *ppBuffer = pBuffer;
    (*ppBuffer)->AddRef();

    TRACE((L"Read data from the ASF file into a media buffer.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::ReadDataIntoBuffer failed.\n", hr);
    
    if (pData)
    {
        pBuffer->Unlock();
    }
    SAFE_RELEASE(pBuffer);
    return hr;
}
HRESULT CASFManager::CreateASFContentInfo (IMFByteStream *pContentByteStream,
                                           IMFASFContentInfo **ppContentInfo)
{
    if (!pContentByteStream || !ppContentInfo)
    {
        return E_INVALIDARG;
    }
 
    HRESULT hr = S_OK;
    QWORD cbHeader = 0;

   
    IMFASFContentInfo *pContentInfo = NULL;
    IMFMediaBuffer *pBuffer = NULL;

    // Create the ASF content information object.
    CHECK_HR(hr = MFCreateASFContentInfo(&pContentInfo));
    
    // Read the first 30 bytes to find the total header size.
    CHECK_HR(hr = ReadDataIntoBuffer(
        pContentByteStream, 0, MIN_ASF_HEADER_SIZE, &pBuffer));

    CHECK_HR(hr = pContentInfo->GetHeaderSize(pBuffer, &cbHeader));

    SAFE_RELEASE(pBuffer);
    
    //Read the header into a buffer
    CHECK_HR(hr = ReadDataIntoBuffer(
        pContentByteStream, 0, (DWORD)cbHeader, &pBuffer));

    // Pass the buffer for the header object.
    CHECK_HR(hr = pContentInfo->ParseHeader(pBuffer, 0));


    // Return the pointer to the caller.
    *ppContentInfo = pContentInfo;
    (*ppContentInfo)->AddRef();

    TRACE((L"Created ContentInfo object.\n"));

done:
    
    LOG_MSG_IF_FAILED(L"CASFManager::CreateASFContentInfo failed.\n", hr);

    SAFE_RELEASE(pBuffer);
    SAFE_RELEASE(pContentInfo);
    return hr;
}
HRESULT D3DPresentEngine::PresentSwapChain(IDirect3DSwapChain9* pSwapChain, IDirect3DSurface9* pSurface)
{
    HRESULT hr = S_OK;

    if (m_hwnd == NULL)
    {
        return MF_E_INVALIDREQUEST;
    }

    hr = pSwapChain->Present(NULL, &m_rcDestRect, m_hwnd, NULL, 0);

    LOG_MSG_IF_FAILED(L"D3DPresentEngine::PresentSwapChain, IDirect3DSwapChain9::Present failed.", hr);


    return hr;
}
HRESULT CASFManager::GetSeekPositionManually(MFTIME hnsSeekTime, 
                                    QWORD *cbDataOffset) 
{
    //Get average packet size
    UINT32 averagepacketsize = ( m_fileinfo->cbMaxPacketSize+ m_fileinfo->cbMinPacketSize)/2;

    DWORD dwFlags = 0;

    double fraction = 0;

    HRESULT hr = S_OK;
    
    //Check if the reverse flag is set, if so, offset is calculated from the end of the presentation
    CHECK_HR(hr = this->m_pSplitter->GetFlags(&dwFlags));

    if (dwFlags & MFASF_SPLITTER_REVERSE)
    {
        fraction = ((double) (m_fileinfo->cbPresentationDuration) - (double) (hnsSeekTime))/(double) (m_fileinfo->cbPresentationDuration);
    }
    else
    {
        fraction = (double)(hnsSeekTime)/(double) (m_fileinfo->cbPresentationDuration);
    }
    
    //calculate the number of packets passed
    int seeked_packets = (int)( m_fileinfo->cbPackets * fraction);
    
    //get the offset
    *cbDataOffset = (QWORD)averagepacketsize * seeked_packets;



    if (*cbDataOffset >= 0)
    {
        return S_OK;
    }

    TRACE((L"Offset calculated through fraction.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::GetSeekPositionManually failed.\n", hr);
    return hr;
}
HRESULT Scheduler::ScheduleSample(IMFSample *pSample, BOOL bPresentNow)
{
    if (m_pCB == NULL)
    {
        return MF_E_NOT_INITIALIZED;
    }

    if (m_hSchedulerThread == NULL)
    {
        return MF_E_NOT_INITIALIZED;
    }

    HRESULT hr = S_OK;
    DWORD dwExitCode = 0;

    GetExitCodeThread(m_hSchedulerThread, &dwExitCode);
    if (dwExitCode != STILL_ACTIVE)
    {
        return E_FAIL;
    }

    if (bPresentNow || (m_pClock == NULL))
    {
        // Present the sample immediately.
        m_pCB->PresentSample(pSample, 0);
    }
    else
    {
        // Queue the sample and ask the scheduler thread to wake up.
        hr = m_ScheduledSamples.Queue(pSample);

        if (SUCCEEDED(hr))
        {
            PostThreadMessage(m_dwThreadID, eSchedule, 0, 0);
        }
    }

    LOG_MSG_IF_FAILED(L"Scheduler::ScheduleSample failed", hr);

    return hr;
}
HRESULT CMediaController::CreateBitmapForKeyFrame(BYTE* pPixelData, IMFMediaType* pMediaType)
{
    if(!pPixelData || !pMediaType)
    {
        return E_INVALIDARG;
    }

    HRESULT hr = S_OK;

    INT32 stride = 0;

    //Get the Frame size and stride through Media Type attributes

    CHECK_HR (hr = MFGetAttributeSize(pMediaType, MF_MT_FRAME_SIZE, &m_Width, &m_Height));

    CHECK_HR (pMediaType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&stride)); 

    SAFE_DELETE(m_pBitmap);

    //Create the bitmap with the given size
    m_pBitmap = new Bitmap(m_Width, m_Height, (INT32)stride, PixelFormat32bppRGB, pPixelData);

    if(!m_pBitmap)
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }
    else
    {
        //Bitmap was created, set the flag
        m_fHasTestMedia = TRUE;
        TRACE((L"Bitmap for the key frame created.\n"));
    }

done:
    LOG_MSG_IF_FAILED(L"Bitmap could not be created.\n", hr);

    return hr;
}
HRESULT CASFManager::OpenASFFile(const WCHAR *sFileName)
{
    HRESULT hr = S_OK;

    IMFByteStream* pStream = NULL;

    // Open a byte stream for the file.
    CHECK_HR(hr = MFCreateFile(
        MF_ACCESSMODE_READ, 
        MF_OPENMODE_FAIL_IF_NOT_EXIST,
        MF_FILEFLAGS_NONE,
        sFileName,
        &pStream
        ));


    TRACE((L"Opened ASF File\n"));

    //Reset the ASF components.
    Reset();

    // Create the Media Foundation ASF objects.
    CHECK_HR(hr = CreateASFContentInfo(pStream, &m_pContentInfo));

    CHECK_HR(hr = CreateASFSplitter(pStream, &m_pSplitter));

    CHECK_HR(hr = CreateASFIndexer(pStream, &m_pIndexer));

done:
    
    LOG_MSG_IF_FAILED(L"CASFManager::OpenASFFile failed.\n", hr);

    SAFE_RELEASE(pStream);

    return hr;
}
//-----------------------------------------------------------------------------
// PresentSwapChain
//
// Presents a swap chain that contains a video frame by doing a callback
// via the sink.
//
// pSwapChain: Pointer to the swap chain.
// pSurface: Pointer to the swap chain's back buffer surface.
//-----------------------------------------------------------------------------
HRESULT D3DPresentEngine::PresentSwapChain(IDirect3DSwapChain9* pSwapChain, IDirect3DSurface9* pSurface)
{
    HRESULT hr = S_OK;

    if (m_hwnd == NULL)
    {
        return MF_E_INVALIDREQUEST;
    }
	
	if(!m_pRenderSurface)
	{
		D3DSURFACE_DESC desc;
		
		// Get the surface description
		pSurface->GetDesc(&desc);

		// Create a surface the same size as our sample
		hr = this->m_pDevice->CreateRenderTarget(desc.Width, 
												 desc.Height, 
												 desc.Format, 
												 desc.MultiSampleType, 
												 desc.MultiSampleQuality, 
												 true, 
												 &m_pRenderSurface, 
												 NULL);
		if(hr != S_OK)
			goto bottom;
	}

	if(m_pRenderSurface)
	{
		D3DSURFACE_DESC originalDesc;
		// Get the surface description of this sample
		pSurface->GetDesc(&originalDesc);

		D3DSURFACE_DESC renderDesc;
		// Get the surface description of the render surface
		m_pRenderSurface->GetDesc(&renderDesc);

		// Compare the descriptions to make sure they match
		if(originalDesc.Width != renderDesc.Width || 
		   originalDesc.Height != renderDesc.Height ||
		   originalDesc.Format != renderDesc.Format)
		{
			// Release the old render surface
			SAFE_RELEASE(m_pRenderSurface);
			
			// Create a new render surface that matches the size of this surface 
			hr = this->m_pDevice->CreateRenderTarget(originalDesc.Width, 
													 originalDesc.Height, 
													 originalDesc.Format, 
													 originalDesc.MultiSampleType, 
													 originalDesc.MultiSampleQuality, 
													 true, 
													 &m_pRenderSurface, 
													 NULL);
		if(hr != S_OK)
			goto bottom;
		}
	}

	if(m_pRenderSurface)
	{
		// Copy the passed surface to our rendered surface
		hr = D3DXLoadSurfaceFromSurface(m_pRenderSurface,
										NULL,
										NULL,
										pSurface,
										NULL,
										NULL,
										D3DX_FILTER_NONE,
										0);
	}

	if(hr != S_OK)
			goto bottom;

	// Do the callback, passing the rendered surface
	if(m_pCallback)
		hr = m_pCallback->PresentSurfaceCB(m_pRenderSurface);

    LOG_MSG_IF_FAILED(L"D3DPresentEngine::PresentSwapChain failed.", hr);

bottom:

    return hr;
}
HRESULT CASFManager::GenerateSamples(
    MFTIME hnsSeekTime, 
    DWORD dwFlags,
    SAMPLE_INFO* pSampleInfo,
    void (*FuncPtrToDisplaySampleInfo)(SAMPLE_INFO*)
    )
{
    if (! m_pSplitter)
    {
        return MF_E_NOT_INITIALIZED;
    }

    HRESULT hr = S_OK;
    QWORD   cbStartOffset = 0;
    DWORD   cbReadLen = 0;
    MFTIME  hnsApproxTime =0;
    MFTIME  hnsTestSampleDuration =0;
    BOOL    bReverse = FALSE;

    // Flush the splitter to remove any samples that were delivered
    // to the ASF splitter during a previous call to this method.
    CHECK_HR(hr = m_pSplitter->Flush());

    //set the reverse flag if applicable
    hr = m_pSplitter->SetFlags(dwFlags);

    if (FAILED (hr))
    {
        dwFlags = 0;
        hr = S_OK;
    }

    bReverse = ((dwFlags & MFASF_SPLITTER_REVERSE) == MFASF_SPLITTER_REVERSE);

    // Get the offset from the start of the ASF Data Object to the desired seek time.
    CHECK_HR(hr =  GetSeekPosition(&hnsSeekTime, &cbStartOffset, &hnsApproxTime));

    // Get the audio playback duration. (The duration is TEST_AUDIO_DURATION or up to
    // the end of the file, whichever is shorter.)
    if (m_guidCurrentMediaType == MFMediaType_Audio)
    {
        GetTestDuration(hnsSeekTime, bReverse, &hnsTestSampleDuration);
    }

    // Notify the MFT we are about to start.
    if (m_pDecoder)
    {
        if ( m_pDecoder->GetDecoderStatus() != STREAMING)
        {
            hr =  m_pDecoder->StartDecoding();
        }

        if (FAILED(hr))
        {
            SAFE_RELEASE(m_pDecoder);
        }
    }
        
    cbReadLen = (DWORD)(m_cbDataLength - cbStartOffset);

    if (bReverse)
    {
        // Reverse playback: Read from the offset back to zero. 
        
        CHECK_HR(hr = GenerateSamplesLoop(
            hnsSeekTime,
            hnsTestSampleDuration,
            bReverse,
            (DWORD)(m_cbDataLength + m_cbDataOffset - cbStartOffset), //DWORD cbDataOffset
            cbReadLen,              //DWORD cbDataLen
            pSampleInfo,
            FuncPtrToDisplaySampleInfo
            ));

    }
    else
    {
        // Forward playback: Read from the offset to the end.
            
        CHECK_HR(hr = GenerateSamplesLoop(
            hnsSeekTime,
            hnsTestSampleDuration,
            bReverse,
            (DWORD)(m_cbDataOffset + cbStartOffset), //DWORD cbDataOffset, 
            cbReadLen,                              //DWORD cbDataLen
            pSampleInfo,
            FuncPtrToDisplaySampleInfo
            ));
    }

    // Note: cbStartOffset is relative to the start of the data object.
    // GenerateSamplesLoop expects the offset relative to the start of the file.

        
done:
    LOG_MSG_IF_FAILED(L"CASFManager::GenerateSamples failed.\n", hr);
    return hr;
}
HRESULT CASFManager::GetSeekPositionWithIndexer ( 
                        MFTIME hnsSeekTime, 
                        QWORD *cbDataOffset, 
                        MFTIME* hnsApproxSeekTime)
{
    if (! m_pIndexer)
    {
        return MF_E_ASF_NOINDEX;
    }

    HRESULT hr = S_OK;

    PROPVARIANT var;
    PropVariantInit(&var);
    
    var.vt = VT_I8;
    var.hVal.QuadPart = hnsSeekTime;

    ASF_INDEX_IDENTIFIER IndexIdentifier;

    BOOL fIsIndexed = FALSE;
    DWORD cbIndexDescriptor = 0;

    DWORD dwFlags = 0;

    //currently only time index is supported, set to GUID_NULL
    IndexIdentifier.guidIndexType = GUID_NULL;
    IndexIdentifier.wStreamNumber =  m_CurrentStreamID;

    //Is the stream indexed? Get the value of cbIndexDescriptor
    hr = m_pIndexer->GetIndexStatus( &IndexIdentifier,
        &fIsIndexed,
        NULL,
        &cbIndexDescriptor );

    if (hr == MF_E_BUFFERTOOSMALL)
    {
        hr = S_OK;
    }

    CHECK_HR(hr);

    //check if the reverse flag needs to be set on the indexer
    CHECK_HR (hr = m_pSplitter->GetFlags(&dwFlags));

    if (dwFlags & MFASF_SPLITTER_REVERSE)
    {
        CHECK_HR (hr = m_pIndexer->SetFlags(MFASF_INDEXER_READ_FOR_REVERSEPLAYBACK));
    }

    //Get the offset from the indexer
    if (fIsIndexed)
    {
        CHECK_HR(hr = m_pIndexer->GetSeekPositionForValue(
            &var, 
            &IndexIdentifier, 
            cbDataOffset, 
            hnsApproxSeekTime, 
            0 ));
    }
    else
    {
        hr = MF_E_ASF_NOINDEX;
    }

    TRACE((L"Offset calculated through the Indexer.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::GetSeekPositionWithIndexer failed.\n", hr);

    //release memory
    PropVariantClear(&var);

    return hr;
}
HRESULT CASFManager::SetupStreamDecoder (WORD wStreamNumber, 
                                         GUID* pguidCurrentMediaType)
{
    if (! m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    if (wStreamNumber == 0)
    {
        return E_INVALIDARG;
    }

    IMFASFProfile* pProfile = NULL;
    IMFMediaType* pMediaType = NULL;
    IMFASFStreamConfig *pStream = NULL;

    GUID    guidMajorType = GUID_NULL;
    GUID    guidSubType = GUID_NULL;
    GUID    guidDecoderCategory = GUID_NULL;

    BOOL fIsCompressed = TRUE;

    CLSID *pDecoderCLSIDs = NULL;   // Pointer to an array of CLISDs. 
    UINT32 cDecoderCLSIDs = 0;   // Size of the array.
    
    HRESULT hr = S_OK;

    //Get the profile object that stores stream information
    CHECK_HR(hr =  m_pContentInfo->GetProfile(&pProfile));

    //Get stream configuration object from the profile
    CHECK_HR(hr = pProfile->GetStreamByNumber(wStreamNumber, &pStream));

    //Get the media type
    CHECK_HR(hr = pStream->GetMediaType(&pMediaType));

    //Get the major media type
    CHECK_HR(hr = pMediaType->GetMajorType(&guidMajorType));
        
    //Get the sub media type
    CHECK_HR(hr = pMediaType->GetGUID(MF_MT_SUBTYPE, &guidSubType));
    
    //find out if the media type is compressed
    CHECK_HR(hr = pMediaType->IsCompressedFormat(&fIsCompressed));

    if (fIsCompressed)
    {
        //get decoder category
        if (guidMajorType == MFMediaType_Video)
        {
            guidDecoderCategory = MFT_CATEGORY_VIDEO_DECODER;
        }
        else if (guidMajorType == MFMediaType_Audio)
        {
            guidDecoderCategory = MFT_CATEGORY_AUDIO_DECODER;
        }
        else
        {
            CHECK_HR(hr = MF_E_INVALIDMEDIATYPE);
        }

        // Look for a decoder.
        MFT_REGISTER_TYPE_INFO tinfo;
        tinfo.guidMajorType = guidMajorType;
        tinfo.guidSubtype = guidSubType;

        CHECK_HR(hr = MFTEnum(
            guidDecoderCategory,
            0,                  // Reserved
            &tinfo,             // Input type to match. (Encoded type.)
            NULL,               // Output type to match. (Don't care.)
            NULL,               // Attributes to match. (None.)
            &pDecoderCLSIDs,    // Receives a pointer to an array of CLSIDs.
            &cDecoderCLSIDs     // Receives the size of the array.
            ));

        // MFTEnum can return zero matches.
        if (cDecoderCLSIDs == 0)
        {
            hr = MF_E_TOPO_CODEC_NOT_FOUND;
        }
        else
        {
            //if the CDecoder instance does not exist, create one.
            if (!m_pDecoder)
            {
                CHECK_HR(hr = CDecoder::CreateInstance(&m_pDecoder));
            }
            
            //Load the first MFT in the array for the current media type
            CHECK_HR(hr = m_pDecoder->Initialize(pDecoderCLSIDs[0], pMediaType));
        }
        *pguidCurrentMediaType = guidMajorType;
    }
    else
    {
        // Not compressed. Don't need a decoder. 
         CHECK_HR(hr = MF_E_INVALIDREQUEST);
    }


    TRACE((L"Stream decoder loaded.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::SetupStreamDecoder failed.\n", hr);
    
    SAFE_RELEASE(pProfile);
    SAFE_RELEASE(pMediaType);
    SAFE_RELEASE(pStream);

    CoTaskMemFree(pDecoderCLSIDs);

    return hr;
}
HRESULT CASFManager::EnumerateStreams (WORD** ppwStreamNumbers, 
                                       GUID** ppguidMajorType, 
                                       DWORD* pcbTotalStreams)
{
    if (!ppwStreamNumbers || !ppguidMajorType || !pcbTotalStreams)
    {
        return E_INVALIDARG;
    }

    if (!m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    HRESULT hr = S_OK;

    IMFASFStreamConfig* pStream = NULL;
    IMFASFProfile* pProfile = NULL;

    *pcbTotalStreams =0;

    WORD* pwStreamNumbers; 
    GUID* pguidMajorType;   

    CHECK_HR(hr =  m_pContentInfo->GetProfile(&pProfile));

    CHECK_HR(hr = pProfile->GetStreamCount(pcbTotalStreams));

    if (*pcbTotalStreams == 0)
    {
        SAFE_RELEASE(pProfile);

        return E_FAIL;
    }

    //create an array of stream numbers and initialize elements swith 0
    pwStreamNumbers = new WORD[*pcbTotalStreams*sizeof(WORD)];

    if (!pwStreamNumbers)
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    ZeroMemory (pwStreamNumbers, *pcbTotalStreams*sizeof(WORD));

    //create an array of guids and initialize elements with GUID_NULL.
    pguidMajorType = new GUID[*pcbTotalStreams*sizeof(GUID)];
    
    if (!pguidMajorType)
    {
        hr = E_OUTOFMEMORY;
        goto done;
    }

    ZeroMemory (pguidMajorType, *pcbTotalStreams*sizeof(GUID));

    //populate the arrays with stream numbers and guids from the profile object
    for (unsigned index = 0; index < *pcbTotalStreams; index++)
    {
        CHECK_HR(hr = pProfile->GetStream(index, &pwStreamNumbers[index], &pStream));

        CHECK_HR(hr = pStream->GetStreamType(&pguidMajorType[index]));

        SAFE_RELEASE(pStream);
    }


    *ppwStreamNumbers = pwStreamNumbers;
    *ppguidMajorType = pguidMajorType;

    TRACE((L"Enumerated streams.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::EnumerateStreams failed.\n", hr);

    SAFE_RELEASE(pProfile);
    SAFE_RELEASE(pStream);

    if (FAILED (hr))
    {
        SAFE_ARRAY_DELETE(pwStreamNumbers);
        SAFE_ARRAY_DELETE(pguidMajorType);
    }

    return hr;
}
HRESULT CASFManager::CreateASFIndexer (IMFByteStream *pContentByteStream,
                                       IMFASFIndexer **ppIndexer)
{
    if (!pContentByteStream || !ppIndexer)
    {
        return E_INVALIDARG;
    }

    if (!m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    HRESULT hr = S_OK;

    IMFASFIndexer *pIndexer = NULL;
    IMFByteStream *pIndexerByteStream = NULL;

    QWORD qwLength = 0, qwIndexOffset = 0, qwBytestreamLength = 0;
    DWORD dwByteStreamsNeeded = 0;

    // Create the indexer.
    CHECK_HR(hr = MFCreateASFIndexer(&pIndexer));

    //Initialize the indexer to work with this ASF library
    CHECK_HR(hr =  pIndexer->Initialize(m_pContentInfo));


    //Check if the index exists. 
    //you can only do this after creating the indexer

    //Get byte stream length
    CHECK_HR(hr = pContentByteStream->GetLength(&qwLength));

    //Get index offset
    CHECK_HR(hr = pIndexer->GetIndexPosition( m_pContentInfo, &qwIndexOffset ));
    
    if ( qwIndexOffset >= qwLength)
    {
        //index object does not exist, release the indexer
        goto done;
    }
    else
    {
        // initialize the indexer
        // Create a byte stream that the Indexer will use to read in
        // and parse the indexers.
         CHECK_HR(hr = MFCreateASFIndexerByteStream( pContentByteStream,
                                qwIndexOffset,
                                &pIndexerByteStream ));
    }

    CHECK_HR(hr = pIndexer->GetIndexByteStreamCount( &dwByteStreamsNeeded ));

    if (dwByteStreamsNeeded == 1)
    {
        CHECK_HR(hr = pIndexer->SetIndexByteStreams( &pIndexerByteStream, dwByteStreamsNeeded ));
    }
    
    // Return the pointer to the caller.
    *ppIndexer = pIndexer;
    (*ppIndexer)->AddRef();

    TRACE((L"Created Indexer object.\n"));


done:

    LOG_MSG_IF_FAILED(L"CASFManager::CreateASFIndexer failed.\n", hr);
    SAFE_RELEASE(pIndexer);
    SAFE_RELEASE(pIndexerByteStream);

    return hr;
}
HRESULT WebHelper::OpenURLWithData(const WCHAR *wszURL, const BYTE *pbPostData, DWORD cbData)
{
    // This string is the header needed for HTTP POST actions.
    const LPWSTR POST_HEADER_DATA = L"Content-Type: application/x-www-form-urlencoded\r\n";

    if (!wszURL)
    {
        return E_INVALIDARG;
    }

    if (!m_pBrowser)
    {
        return E_UNEXPECTED;
    }
    
    HRESULT hr = S_OK;
    BSTR    bstrURL = NULL;
    VARIANT vtEmpty;
    VARIANT vtHeader;
    VARIANT vtPostData;

    VariantInit(&vtEmpty);
    VariantInit(&vtHeader);
    VariantInit(&vtPostData);

    // Allocate a BSTR for the URL.
    bstrURL = SysAllocString(wszURL);
    if (bstrURL == NULL)
    {
        hr = E_OUTOFMEMORY;
    }

    // Allocate a BSTR for the header.
    if (SUCCEEDED(hr))
    {
        vtHeader.bstrVal = SysAllocString(POST_HEADER_DATA);
        if (vtHeader.bstrVal == NULL)
        {
            hr = E_OUTOFMEMORY;
        }
        else
        {
            vtHeader.vt = VT_BSTR;
        }
    }


    if (SUCCEEDED(hr))
    {
        if ( pbPostData )
        {
            // Convert the POST data to a safe array in a variant. The safe array type is VT_UI1.

            void *pvData = NULL;
            SAFEARRAY *saPostData = SafeArrayCreateVector(VT_UI1, 0, cbData);
            if (saPostData == NULL)
            {
                hr = E_OUTOFMEMORY;
            }

            if (SUCCEEDED(hr))
            {
                hr = SafeArrayAccessData(saPostData, &pvData);
            }

            if (SUCCEEDED(hr))
            {
                CopyMemory((BYTE*)pvData, pbPostData, cbData);
                hr = SafeArrayUnaccessData(saPostData);
            }

            if (SUCCEEDED(hr))
            {
                vtPostData.vt = VT_ARRAY | VT_UI1;
                vtPostData.parray = saPostData;
            }
        }
    }



    // Make the IE window visible.
    if (SUCCEEDED(hr))
    {
        hr = m_pBrowser->put_Visible(VARIANT_TRUE);
        LOG_MSG_IF_FAILED(L"put_Visible)", hr);
    }

    // Navigate to the URL.
    if (SUCCEEDED(hr))
    {
        hr = m_pBrowser->Navigate(bstrURL, &vtEmpty, &vtEmpty, &vtPostData, &vtHeader);
        LOG_MSG_IF_FAILED(L"Navigate", hr);
    }

    SysFreeString(bstrURL);

    VariantClear(&vtEmpty);
    VariantClear(&vtHeader);
    VariantClear(&vtPostData);

    return hr;
}
HRESULT CASFManager::SetFilePropertiesObject(FILE_PROPERTIES_OBJECT* fileinfo)
{
    if (! m_pContentInfo)
    {
        return MF_E_NOT_INITIALIZED;
    }

    HRESULT hr = S_OK;

    IMFPresentationDescriptor *pPD = NULL;

    UINT32 cbBlobSize = 0;

    CHECK_HR( hr =  m_pContentInfo->GeneratePresentationDescriptor(&pPD));

    //get File ID
    hr = pPD->GetGUID(MF_PD_ASF_FILEPROPERTIES_FILE_ID, &fileinfo->guidFileID);

    // get Creation Time
    hr = pPD->GetBlob(MF_PD_ASF_FILEPROPERTIES_CREATION_TIME, (BYTE *)&fileinfo->ftCreationTime, sizeof(FILETIME), &cbBlobSize);

    //get Data Packets Count
    hr = pPD->GetUINT32(MF_PD_ASF_FILEPROPERTIES_PACKETS, &fileinfo->cbPackets);

    //get Play Duration
    hr = pPD->GetUINT64(MF_PD_ASF_FILEPROPERTIES_PLAY_DURATION, &fileinfo->cbPlayDuration);

    //get presentation duration 
    hr = pPD->GetUINT64(MF_PD_DURATION, &fileinfo->cbPresentationDuration);

    //get Send Duration
    hr = pPD->GetUINT64(MF_PD_ASF_FILEPROPERTIES_SEND_DURATION, &fileinfo->cbSendDuration);

    //get preroll
    UINT64 msecspreroll = 0, hnspreroll =0;
    hr = pPD->GetUINT64(MF_PD_ASF_FILEPROPERTIES_PREROLL, &msecspreroll);
    hnspreroll = msecspreroll*10000;
    fileinfo->cbPreroll = hnspreroll;

    //get Flags
    hr = pPD->GetUINT32(MF_PD_ASF_FILEPROPERTIES_FLAGS, &fileinfo->cbFlags);

    //get Maximum Data Packet Size
    hr = pPD->GetUINT32(MF_PD_ASF_FILEPROPERTIES_MAX_PACKET_SIZE, &fileinfo->cbMaxPacketSize);

    //get Minimum Data Packet Size
    hr = pPD->GetUINT32(MF_PD_ASF_FILEPROPERTIES_MIN_PACKET_SIZE, &fileinfo->cbMinPacketSize);
    
    // get Maximum Bit rate
    hr = pPD->GetUINT32(MF_PD_ASF_FILEPROPERTIES_MAX_BITRATE, &fileinfo->cbMaxBitRate);
    

    this->m_fileinfo = fileinfo;

    TRACE((L"Read File Properties Object from the ASF Header Object.\n"));

done:

    LOG_MSG_IF_FAILED(L"CASFManager::SetFilePropertiesObject failed.\n", hr);

    SAFE_RELEASE(pPD);

    return hr;

}