www.pudn.com > avi_file_source.rar > asyncio.h


//------------------------------------------------------------------------------ 
// File: AsyncIo.h 
// 
// Desc: DirectShow sample code - base library for I/O functionality. 
// 
// Copyright (c) Microsoft Corporation.  All rights reserved. 
//------------------------------------------------------------------------------ 
 
 
#ifndef __ASYNCIO_H__ 
#define __ASYNCIO_H__ 
 
// 
// definition of CAsyncFile object that performs file access. It provides 
// asynchronous, unbuffered, aligned reads from a file, using a worker thread 
// on win95 and potentially overlapped i/o if available. 
 
// !!! Need to use real overlapped i/o if available 
// currently only uses worker thread, not overlapped i/o 
 
 
class CAsyncIo; 
class CAsyncStream; 
 
// 
//  Model the stream we read from based on a file-like interface 
// 
class CAsyncStream 
{ 
public: 
    virtual ~CAsyncStream() {}; 
    virtual HRESULT SetPointer(LONGLONG llPos) = 0; 
    virtual HRESULT Read(PBYTE pbBuffer, 
                         DWORD dwBytesToRead, 
                         BOOL bAlign, 
                         LPDWORD pdwBytesRead) = 0; 
 
    virtual LONGLONG Size(LONGLONG *pSizeAvailable = NULL) = 0; 
    virtual DWORD Alignment() = 0; 
    virtual void Lock() = 0; 
    virtual void Unlock() = 0; 
    //virtual void SetStopHandle(HANDLE hevStop) {} 
}; 
 
// represents a single request and performs the i/o. Can be called on either 
// worker thread or app thread, but must hold pcsFile across file accesses. 
// (ie across SetFilePointer/ReadFile pairs) 
class CAsyncRequest 
{ 
    CAsyncIo     *m_pIo; 
    CAsyncStream *m_pStream; 
    LONGLONG      m_llPos; 
    BOOL          m_bAligned; 
    LONG    m_lLength; 
    BYTE*   m_pBuffer; 
    LPVOID  m_pContext; 
    DWORD   m_dwUser; 
    HRESULT m_hr; 
 
public: 
    // init the params for this request. Issue the i/o 
    // if overlapped i/o is possible. 
    HRESULT Request( 
        CAsyncIo *pIo, 
        CAsyncStream *pStream, 
        LONGLONG llPos, 
        LONG lLength, 
        BOOL bAligned, 
        BYTE* pBuffer, 
        LPVOID pContext,    // filter's context 
        DWORD dwUser);      // downstream filter's context 
 
    // issue the i/o if not overlapped, and block until i/o complete. 
    // returns error code of file i/o 
    HRESULT Complete(); 
 
    // cancels the i/o. blocks until i/o is no longer pending 
    HRESULT Cancel() 
    { 
        return S_OK; 
    }; 
 
    // accessor functions 
    LPVOID GetContext() 
    { 
        return m_pContext; 
    }; 
 
    DWORD GetUser() 
    { 
        return m_dwUser; 
    }; 
 
    HRESULT GetHResult() { 
        return m_hr; 
    }; 
 
    // we set m_lLength to the actual length 
    LONG GetActualLength() { 
        return m_lLength; 
    }; 
 
    LONGLONG GetStart() { 
        return m_llPos; 
    }; 
}; 
 
 
typedef CGenericList CRequestList; 
 
// this class needs a worker thread, but the ones defined in classes\base 
// are not suitable (they assume you have one message sent or posted per 
// request, whereas here for efficiency we want just to set an event when 
// there is work on the queue). 
// 
// we create CAsyncRequest objects and queue them on m_listWork. The worker 
// thread pulls them off, completes them and puts them on m_listDone. 
// The events m_evWork and m_evDone are set when the corresponding lists are 
// not empty. 
// 
// Synchronous requests are done on the caller thread. These should be 
// synchronised by the caller, but to make sure we hold m_csFile across 
// the SetFilePointer/ReadFile code. 
// 
// Flush by calling BeginFlush. This rejects all further requests (by 
// setting m_bFlushing within m_csLists), cancels all requests and moves them 
// to the done list, and sets m_evDone to ensure that no WaitForNext operations 
// will block. Call EndFlush to cancel this state. 
// 
// we support unaligned calls to SyncRead. This is done by opening the file 
// twice if we are using unbuffered i/o (m_dwAlign > 1). 
// !!!fix this to buffer on top of existing file handle? 
class CAsyncIo 
{ 
 
    CCritSec m_csReader; 
    CAsyncStream *m_pStream; 
 
    CCritSec m_csLists;      // locks access to the list and events 
    BOOL m_bFlushing;        // true if between BeginFlush/EndFlush 
 
    CRequestList m_listWork; 
    CRequestList m_listDone; 
 
    CAMEvent m_evWork;      // set when list is not empty 
    CAMEvent m_evDone; 
 
    // for correct flush behaviour: all protected by m_csLists 
    LONG    m_cItemsOut;    // nr of items not on listDone or listWork 
    BOOL    m_bWaiting;     // TRUE if someone waiting for m_evAllDone 
    CAMEvent m_evAllDone;   // signal when m_cItemsOut goes to 0 if m_cWaiting 
 
 
    CAMEvent m_evStop;         // set when thread should exit 
    HANDLE m_hThread; 
 
    LONGLONG Size() { 
        ASSERT(m_pStream != NULL); 
        return m_pStream->Size(); 
    }; 
 
    // start the thread 
    HRESULT StartThread(void); 
 
    // stop the thread and close the handle 
    HRESULT CloseThread(void); 
 
    // manage the list of requests. hold m_csLists and ensure 
    // that the (manual reset) event hevList is set when things on 
    // the list but reset when the list is empty. 
    // returns null if list empty 
    CAsyncRequest* GetWorkItem(); 
 
    // get an item from the done list 
    CAsyncRequest* GetDoneItem(); 
 
    // put an item on the work list 
    HRESULT PutWorkItem(CAsyncRequest* pRequest); 
 
    // put an item on the done list 
    HRESULT PutDoneItem(CAsyncRequest* pRequest); 
 
    // called on thread to process any active requests 
    void ProcessRequests(void); 
 
    // initial static thread proc calls ThreadProc with DWORD 
    // param as this 
    static DWORD WINAPI InitialThreadProc(LPVOID pv) { 
        CAsyncIo * pThis = (CAsyncIo*) pv; 
        return pThis->ThreadProc(); 
    }; 
 
    DWORD ThreadProc(void); 
 
public: 
 
    CAsyncIo(CAsyncStream *pStream); 
    ~CAsyncIo(); 
 
    // open the file 
    HRESULT Open(LPCTSTR pName); 
 
    // ready for async activity - call this before 
    // calling Request 
    HRESULT AsyncActive(void); 
 
    // call this when no more async activity will happen before 
    // the next AsyncActive call 
    HRESULT AsyncInactive(void); 
 
    // queue a requested read. must be aligned. 
    HRESULT Request( 
            LONGLONG llPos, 
            LONG lLength, 
            BOOL bAligned, 
            BYTE* pBuffer, 
            LPVOID pContext, 
            DWORD dwUser); 
 
    // wait for the next read to complete 
    HRESULT WaitForNext( 
            DWORD dwTimeout, 
            LPVOID *ppContext, 
            DWORD * pdwUser, 
            LONG * pcbActual); 
 
    // perform a read of an already aligned buffer 
    HRESULT SyncReadAligned( 
            LONGLONG llPos, 
            LONG lLength, 
            BYTE* pBuffer, 
            LONG* pcbActual, 
            PVOID pvContext); 
 
    // perform a synchronous read. will be buffered 
    // if not aligned. 
    HRESULT SyncRead( 
            LONGLONG llPos, 
            LONG lLength, 
            BYTE* pBuffer); 
 
    // return length 
    HRESULT Length(LONGLONG *pllTotal, LONGLONG* pllAvailable); 
 
    // all Reader positions, read lengths and memory locations must 
    // be aligned to this. 
    HRESULT Alignment(LONG* pl); 
 
    HRESULT BeginFlush(); 
    HRESULT EndFlush(); 
 
    LONG Alignment() 
    { 
        return m_pStream->Alignment(); 
    }; 
 
    BOOL IsAligned(LONG l) { 
    if ((l & (Alignment() -1)) == 0) { 
        return TRUE; 
    } else { 
        return FALSE; 
    } 
    }; 
 
    BOOL IsAligned(LONGLONG ll) { 
        return IsAligned( (LONG) (ll & 0xffffffff)); 
    }; 
 
    //  Accessor 
    HANDLE StopEvent() const { return m_evDone; } 
}; 
 
#endif // __ASYNCIO_H__