#pragma once

#include <windows.h>
#include <mmsystem.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfreadwrite.h>
#include <evr.h>

#include "kpi_decoder.h"
#include "kpi_impl.h"
#include "kbdshow_decoder_base.h"

class KbMFDecoder :  public KbDShowDecoderBase, public KbKpiUnknownImpl<IMFAsyncCallback>
{
private:
    enum {
        COMMAND_RUN,
        COMMAND_QUIT,
        COMMAND_SETVIDEOPOS,
    };

public:
private:
    static bool          s_bInitialized;
    IMFByteStream       *m_pByteStream;
    //for audio
    IMFSourceReader     *m_pSourceReader;
    IMFSample           *m_pSample;
    IMFMediaBuffer      *m_pMediaBuffer;
    //for video
    IMFMediaSession     *m_pMediaSession;
    IMFMediaSource      *m_pMediaSource;
    IMFTopology         *m_pTopology;
    IMFVideoDisplayControl *m_pVideoDisplayControl;
    IMFPresentationClock   *m_pPresentationClock;
    HANDLE                  m_hMFEvent;
    //
    DWORD                m_dwBlockAlign;
    DWORD                m_dwPointer;
    void __fastcall CreateVideoWindow(void);

    void __stdcall ThreadProc(void);
    void __fastcall MessageLoop(void);
    LRESULT CALLBACK VideoWindowProcInternal(HWND hWnd,
        UINT message,
        WPARAM wParam, LPARAM lParam);

    HRESULT CreateMediaSinkActivate(IMFStreamDescriptor* stream_desc, IMFActivate** activate);
    void AddSourceNode(IMFPresentationDescriptor* pres_desc, IMFStreamDescriptor* stream_desc, IMFTopologyNode** node);
    void AddOutputNode(IMFActivate* activate, IMFTopologyNode** node);

    //IMFAsyncCallback
    HRESULT STDMETHODCALLTYPE GetParameters(DWORD* pdwFlags, DWORD* pdwQueue) { return E_NOTIMPL; }
    HRESULT STDMETHODCALLTYPE Invoke(IMFAsyncResult* pAsyncResult);

public:
    BOOL __fastcall Open(const KPI_MEDIAINFO *cpRequest,
                         IKpiConfig *pConfig,
                         IKpiFile *pFile, 
                         IKpiFolder *pFolder);
    DWORD  WINAPI Select(DWORD dwNumber,
                         const KPI_MEDIAINFO **ppMediaInfo,
                         IKpiTagInfo *pTagInfo,
                         DWORD dwTagGetFlags);
    DWORD  WINAPI Render(BYTE *pBuffer, DWORD dwSizeSample);
    UINT64 WINAPI Seek(UINT64 qwPosSample, DWORD dwFlag);
    DWORD  WINAPI UpdateConfig(void* pvReserved);
    static bool __fastcall Initialize(void);
    static void __fastcall Uninitialize(void);
    KbMFDecoder(void);
    ~KbMFDecoder(void);
};
