michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* vim:set ts=2 sw=2 sts=2 et cindent: */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: #if !defined(WMFByteStream_h_) michael@0: #define WMFByteStream_h_ michael@0: michael@0: #include "WMF.h" michael@0: michael@0: #include "nsISupportsImpl.h" michael@0: #include "nsCOMPtr.h" michael@0: #include "mozilla/ReentrantMonitor.h" michael@0: #include "mozilla/Attributes.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "mozilla/RefPtr.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: class MediaResource; michael@0: class ReadRequest; michael@0: class WMFSourceReaderCallback; michael@0: class SharedThreadPool; michael@0: michael@0: // Wraps a MediaResource around an IMFByteStream interface, so that it can michael@0: // be used by the IMFSourceReader. Each WMFByteStream creates a WMF Work Queue michael@0: // on which blocking I/O is performed. The SourceReader requests reads michael@0: // asynchronously using {Begin,End}Read(), and more rarely synchronously michael@0: // using Read(). michael@0: // michael@0: // Note: This implementation attempts to be bug-compatible with Windows Media michael@0: // Foundation's implementation of IMFByteStream. The behaviour of WMF's michael@0: // IMFByteStream was determined by creating it and testing the edge cases. michael@0: // For details see the test code at: michael@0: // https://github.com/cpearce/IMFByteStreamBehaviour/ michael@0: class WMFByteStream MOZ_FINAL : public IMFByteStream michael@0: , public IMFAttributes michael@0: { michael@0: public: michael@0: WMFByteStream(MediaResource* aResource, WMFSourceReaderCallback* aCallback); michael@0: ~WMFByteStream(); michael@0: michael@0: nsresult Init(); michael@0: nsresult Shutdown(); michael@0: michael@0: // IUnknown Methods. michael@0: STDMETHODIMP QueryInterface(REFIID aIId, LPVOID *aInterface); michael@0: STDMETHODIMP_(ULONG) AddRef(); michael@0: STDMETHODIMP_(ULONG) Release(); michael@0: michael@0: // IMFByteStream Methods. michael@0: STDMETHODIMP BeginRead(BYTE *aBuffer, michael@0: ULONG aLength, michael@0: IMFAsyncCallback *aCallback, michael@0: IUnknown *aCallerState); michael@0: STDMETHODIMP BeginWrite(const BYTE *, ULONG , michael@0: IMFAsyncCallback *, michael@0: IUnknown *); michael@0: STDMETHODIMP Close(); michael@0: STDMETHODIMP EndRead(IMFAsyncResult* aResult, ULONG *aBytesRead); michael@0: STDMETHODIMP EndWrite(IMFAsyncResult *, ULONG *); michael@0: STDMETHODIMP Flush(); michael@0: STDMETHODIMP GetCapabilities(DWORD *aCapabilities); michael@0: STDMETHODIMP GetCurrentPosition(QWORD *aPosition); michael@0: STDMETHODIMP GetLength(QWORD *pqwLength); michael@0: STDMETHODIMP IsEndOfStream(BOOL *aIsEndOfStream); michael@0: STDMETHODIMP Read(BYTE *, ULONG, ULONG *); michael@0: STDMETHODIMP Seek(MFBYTESTREAM_SEEK_ORIGIN aSeekOrigin, michael@0: LONGLONG aSeekOffset, michael@0: DWORD aSeekFlags, michael@0: QWORD *aCurrentPosition); michael@0: STDMETHODIMP SetCurrentPosition(QWORD aPosition); michael@0: STDMETHODIMP SetLength(QWORD); michael@0: STDMETHODIMP Write(const BYTE *, ULONG, ULONG *); michael@0: michael@0: // IMFAttributes methods michael@0: STDMETHODIMP GetItem(REFGUID guidKey, PROPVARIANT* pValue); michael@0: STDMETHODIMP GetItemType(REFGUID guidKey, MF_ATTRIBUTE_TYPE* pType); michael@0: STDMETHODIMP CompareItem(REFGUID guidKey, REFPROPVARIANT Value, BOOL* pbResult); michael@0: STDMETHODIMP Compare(IMFAttributes* pTheirs, MF_ATTRIBUTES_MATCH_TYPE MatchType, BOOL* pbResult); michael@0: STDMETHODIMP GetUINT32(REFGUID guidKey, UINT32* punValue); michael@0: STDMETHODIMP GetUINT64(REFGUID guidKey, UINT64* punValue); michael@0: STDMETHODIMP GetDouble(REFGUID guidKey, double* pfValue); michael@0: STDMETHODIMP GetGUID(REFGUID guidKey, GUID* pguidValue); michael@0: STDMETHODIMP GetStringLength(REFGUID guidKey, UINT32* pcchLength); michael@0: STDMETHODIMP GetString(REFGUID guidKey, LPWSTR pwszValue, UINT32 cchBufSize, UINT32* pcchLength); michael@0: STDMETHODIMP GetAllocatedString(REFGUID guidKey, LPWSTR* ppwszValue, UINT32* pcchLength); michael@0: STDMETHODIMP GetBlobSize(REFGUID guidKey, UINT32* pcbBlobSize); michael@0: STDMETHODIMP GetBlob(REFGUID guidKey, UINT8* pBuf, UINT32 cbBufSize, UINT32* pcbBlobSize); michael@0: STDMETHODIMP GetAllocatedBlob(REFGUID guidKey, UINT8** ppBuf, UINT32* pcbSize); michael@0: STDMETHODIMP GetUnknown(REFGUID guidKey, REFIID riid, LPVOID* ppv); michael@0: STDMETHODIMP SetItem(REFGUID guidKey, REFPROPVARIANT Value); michael@0: STDMETHODIMP DeleteItem(REFGUID guidKey); michael@0: STDMETHODIMP DeleteAllItems(); michael@0: STDMETHODIMP SetUINT32(REFGUID guidKey, UINT32 unValue); michael@0: STDMETHODIMP SetUINT64(REFGUID guidKey,UINT64 unValue); michael@0: STDMETHODIMP SetDouble(REFGUID guidKey, double fValue); michael@0: STDMETHODIMP SetGUID(REFGUID guidKey, REFGUID guidValue); michael@0: STDMETHODIMP SetString(REFGUID guidKey, LPCWSTR wszValue); michael@0: STDMETHODIMP SetBlob(REFGUID guidKey, const UINT8* pBuf, UINT32 cbBufSize); michael@0: STDMETHODIMP SetUnknown(REFGUID guidKey, IUnknown* pUnknown); michael@0: STDMETHODIMP LockStore(); michael@0: STDMETHODIMP UnlockStore(); michael@0: STDMETHODIMP GetCount(UINT32* pcItems); michael@0: STDMETHODIMP GetItemByIndex(UINT32 unIndex, GUID* pguidKey, PROPVARIANT* pValue); michael@0: STDMETHODIMP CopyAllItems(IMFAttributes* pDest); michael@0: michael@0: // We perform an async read operation in this callback implementation. michael@0: // Processes an async read request, storing the result in aResult, and michael@0: // notifying the caller when the read operation is complete. michael@0: void ProcessReadRequest(IMFAsyncResult* aResult, michael@0: ReadRequest* aRequestState); michael@0: michael@0: private: michael@0: michael@0: // Locks the MediaResource and performs the read. The other read methods michael@0: // call this function. michael@0: nsresult Read(ReadRequest* aRequestState); michael@0: michael@0: // Returns true if the current position of the stream is at end of stream. michael@0: bool IsEOS(); michael@0: michael@0: // Reference to the thread pool in which we perform the reads asynchronously. michael@0: // Note this is pool is shared amongst all active WMFByteStreams. michael@0: RefPtr mThreadPool; michael@0: michael@0: // Reference to the source reader's callback. We use this reference to michael@0: // notify threads waiting on a ReadSample() callback to stop waiting michael@0: // if the stream is closed, which happens when the media element is michael@0: // shutdown. michael@0: RefPtr mSourceReaderCallback; michael@0: michael@0: // Resource we're wrapping. michael@0: nsRefPtr mResource; michael@0: michael@0: // Protects mOffset, which is accessed by the SourceReaders thread(s), and michael@0: // on the work queue thread. michael@0: ReentrantMonitor mReentrantMonitor; michael@0: michael@0: // Current offset of the logical read cursor. We maintain this separately michael@0: // from the media resource's offset since a partially complete read (in Invoke()) michael@0: // would leave the resource's offset at a value unexpected by the caller, michael@0: // since the read hadn't yet completed. michael@0: int64_t mOffset; michael@0: michael@0: // We implement IMFAttributes by forwarding all calls to an instance of the michael@0: // standard IMFAttributes class, which we store a reference to here. michael@0: RefPtr mAttributes; michael@0: michael@0: // True if the resource has been shutdown, either because the WMFReader is michael@0: // shutting down, or because the underlying MediaResource has closed. michael@0: bool mIsShutdown; michael@0: michael@0: // IUnknown ref counting. michael@0: ThreadSafeAutoRefCnt mRefCnt; michael@0: NS_DECL_OWNINGTHREAD michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif