| //------------------------------------------------------------------------------ | |
| // File: MType.cpp | |
| // | |
| // Desc: DirectShow base classes - implements a class that holds and | |
| // manages media type information. | |
| // | |
| // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. | |
| //------------------------------------------------------------------------------ | |
| // helper class that derived pin objects can use to compare media | |
| // types etc. Has same data members as the struct AM_MEDIA_TYPE defined | |
| // in the streams IDL file, but also has (non-virtual) functions | |
| #include <streams.h> | |
| #include <mmreg.h> | |
| CMediaType::~CMediaType(){ | |
| FreeMediaType(*this); | |
| } | |
| CMediaType::CMediaType() | |
| { | |
| InitMediaType(); | |
| } | |
| CMediaType::CMediaType(const GUID * type) | |
| { | |
| InitMediaType(); | |
| majortype = *type; | |
| } | |
| // copy constructor does a deep copy of the format block | |
| CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, __out_opt HRESULT* phr) | |
| { | |
| HRESULT hr = CopyMediaType(this, &rt); | |
| if (FAILED(hr) && (NULL != phr)) { | |
| *phr = hr; | |
| } | |
| } | |
| CMediaType::CMediaType(const CMediaType& rt, __out_opt HRESULT* phr) | |
| { | |
| HRESULT hr = CopyMediaType(this, &rt); | |
| if (FAILED(hr) && (NULL != phr)) { | |
| *phr = hr; | |
| } | |
| } | |
| // this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate | |
| // the following assignment operator itself, however it could introduce some | |
| // memory conflicts and leaks in the process because the structure contains | |
| // a dynamically allocated block (pbFormat) which it will not copy correctly | |
| CMediaType& | |
| CMediaType::operator=(const AM_MEDIA_TYPE& rt) | |
| { | |
| Set(rt); | |
| return *this; | |
| } | |
| CMediaType& | |
| CMediaType::operator=(const CMediaType& rt) | |
| { | |
| *this = (AM_MEDIA_TYPE &) rt; | |
| return *this; | |
| } | |
| BOOL | |
| CMediaType::operator == (const CMediaType& rt) const | |
| { | |
| // I don't believe we need to check sample size or | |
| // temporal compression flags, since I think these must | |
| // be represented in the type, subtype and format somehow. They | |
| // are pulled out as separate flags so that people who don't understand | |
| // the particular format representation can still see them, but | |
| // they should duplicate information in the format block. | |
| return ((IsEqualGUID(majortype,rt.majortype) == TRUE) && | |
| (IsEqualGUID(subtype,rt.subtype) == TRUE) && | |
| (IsEqualGUID(formattype,rt.formattype) == TRUE) && | |
| (cbFormat == rt.cbFormat) && | |
| ( (cbFormat == 0) || | |
| pbFormat != NULL && rt.pbFormat != NULL && | |
| (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0))); | |
| } | |
| BOOL | |
| CMediaType::operator != (const CMediaType& rt) const | |
| { | |
| /* Check to see if they are equal */ | |
| if (*this == rt) { | |
| return FALSE; | |
| } | |
| return TRUE; | |
| } | |
| HRESULT | |
| CMediaType::Set(const CMediaType& rt) | |
| { | |
| return Set((AM_MEDIA_TYPE &) rt); | |
| } | |
| HRESULT | |
| CMediaType::Set(const AM_MEDIA_TYPE& rt) | |
| { | |
| if (&rt != this) { | |
| FreeMediaType(*this); | |
| HRESULT hr = CopyMediaType(this, &rt); | |
| if (FAILED(hr)) { | |
| return E_OUTOFMEMORY; | |
| } | |
| } | |
| return S_OK; | |
| } | |
| BOOL | |
| CMediaType::IsValid() const | |
| { | |
| return (!IsEqualGUID(majortype,GUID_NULL)); | |
| } | |
| void | |
| CMediaType::SetType(const GUID* ptype) | |
| { | |
| majortype = *ptype; | |
| } | |
| void | |
| CMediaType::SetSubtype(const GUID* ptype) | |
| { | |
| subtype = *ptype; | |
| } | |
| ULONG | |
| CMediaType::GetSampleSize() const { | |
| if (IsFixedSize()) { | |
| return lSampleSize; | |
| } else { | |
| return 0; | |
| } | |
| } | |
| void | |
| CMediaType::SetSampleSize(ULONG sz) { | |
| if (sz == 0) { | |
| SetVariableSize(); | |
| } else { | |
| bFixedSizeSamples = TRUE; | |
| lSampleSize = sz; | |
| } | |
| } | |
| void | |
| CMediaType::SetVariableSize() { | |
| bFixedSizeSamples = FALSE; | |
| } | |
| void | |
| CMediaType::SetTemporalCompression(BOOL bCompressed) { | |
| bTemporalCompression = bCompressed; | |
| } | |
| BOOL | |
| CMediaType::SetFormat(__in_bcount(cb) BYTE * pformat, ULONG cb) | |
| { | |
| if (NULL == AllocFormatBuffer(cb)) | |
| return(FALSE); | |
| ASSERT(pbFormat); | |
| memcpy(pbFormat, pformat, cb); | |
| return(TRUE); | |
| } | |
| // set the type of the media type format block, this type defines what you | |
| // will actually find in the format pointer. For example FORMAT_VideoInfo or | |
| // FORMAT_WaveFormatEx. In the future this may be an interface pointer to a | |
| // property set. Before sending out media types this should be filled in. | |
| void | |
| CMediaType::SetFormatType(const GUID *pformattype) | |
| { | |
| formattype = *pformattype; | |
| } | |
| // reset the format buffer | |
| void CMediaType::ResetFormatBuffer() | |
| { | |
| if (cbFormat) { | |
| CoTaskMemFree((PVOID)pbFormat); | |
| } | |
| cbFormat = 0; | |
| pbFormat = NULL; | |
| } | |
| // allocate length bytes for the format and return a read/write pointer | |
| // If we cannot allocate the new block of memory we return NULL leaving | |
| // the original block of memory untouched (as does ReallocFormatBuffer) | |
| BYTE* | |
| CMediaType::AllocFormatBuffer(ULONG length) | |
| { | |
| ASSERT(length); | |
| // do the types have the same buffer size | |
| if (cbFormat == length) { | |
| return pbFormat; | |
| } | |
| // allocate the new format buffer | |
| BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); | |
| if (pNewFormat == NULL) { | |
| if (length <= cbFormat) return pbFormat; //reuse the old block anyway. | |
| return NULL; | |
| } | |
| // delete the old format | |
| if (cbFormat != 0) { | |
| ASSERT(pbFormat); | |
| CoTaskMemFree((PVOID)pbFormat); | |
| } | |
| cbFormat = length; | |
| pbFormat = pNewFormat; | |
| return pbFormat; | |
| } | |
| // reallocate length bytes for the format and return a read/write pointer | |
| // to it. We keep as much information as we can given the new buffer size | |
| // if this fails the original format buffer is left untouched. The caller | |
| // is responsible for ensuring the size of memory required is non zero | |
| BYTE* | |
| CMediaType::ReallocFormatBuffer(ULONG length) | |
| { | |
| ASSERT(length); | |
| // do the types have the same buffer size | |
| if (cbFormat == length) { | |
| return pbFormat; | |
| } | |
| // allocate the new format buffer | |
| BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length); | |
| if (pNewFormat == NULL) { | |
| if (length <= cbFormat) return pbFormat; //reuse the old block anyway. | |
| return NULL; | |
| } | |
| // copy any previous format (or part of if new is smaller) | |
| // delete the old format and replace with the new one | |
| if (cbFormat != 0) { | |
| ASSERT(pbFormat); | |
| memcpy(pNewFormat,pbFormat,min(length,cbFormat)); | |
| CoTaskMemFree((PVOID)pbFormat); | |
| } | |
| cbFormat = length; | |
| pbFormat = pNewFormat; | |
| return pNewFormat; | |
| } | |
| // initialise a media type structure | |
| void CMediaType::InitMediaType() | |
| { | |
| ZeroMemory((PVOID)this, sizeof(*this)); | |
| lSampleSize = 1; | |
| bFixedSizeSamples = TRUE; | |
| } | |
| // a partially specified media type can be passed to IPin::Connect | |
| // as a constraint on the media type used in the connection. | |
| // the type, subtype or format type can be null. | |
| BOOL | |
| CMediaType::IsPartiallySpecified(void) const | |
| { | |
| if ((majortype == GUID_NULL) || | |
| (formattype == GUID_NULL)) { | |
| return TRUE; | |
| } else { | |
| return FALSE; | |
| } | |
| } | |
| BOOL | |
| CMediaType::MatchesPartial(const CMediaType* ppartial) const | |
| { | |
| if ((ppartial->majortype != GUID_NULL) && | |
| (majortype != ppartial->majortype)) { | |
| return FALSE; | |
| } | |
| if ((ppartial->subtype != GUID_NULL) && | |
| (subtype != ppartial->subtype)) { | |
| return FALSE; | |
| } | |
| if (ppartial->formattype != GUID_NULL) { | |
| // if the format block is specified then it must match exactly | |
| if (formattype != ppartial->formattype) { | |
| return FALSE; | |
| } | |
| if (cbFormat != ppartial->cbFormat) { | |
| return FALSE; | |
| } | |
| if ((cbFormat != 0) && | |
| (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) { | |
| return FALSE; | |
| } | |
| } | |
| return TRUE; | |
| } | |
| // general purpose function to delete a heap allocated AM_MEDIA_TYPE structure | |
| // which is useful when calling IEnumMediaTypes::Next as the interface | |
| // implementation allocates the structures which you must later delete | |
| // the format block may also be a pointer to an interface to release | |
| void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt) | |
| { | |
| // allow NULL pointers for coding simplicity | |
| if (pmt == NULL) { | |
| return; | |
| } | |
| FreeMediaType(*pmt); | |
| CoTaskMemFree((PVOID)pmt); | |
| } | |
| // this also comes in useful when using the IEnumMediaTypes interface so | |
| // that you can copy a media type, you can do nearly the same by creating | |
| // a CMediaType object but as soon as it goes out of scope the destructor | |
| // will delete the memory it allocated (this takes a copy of the memory) | |
| AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc) | |
| { | |
| ASSERT(pSrc); | |
| // Allocate a block of memory for the media type | |
| AM_MEDIA_TYPE *pMediaType = | |
| (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); | |
| if (pMediaType == NULL) { | |
| return NULL; | |
| } | |
| // Copy the variable length format block | |
| HRESULT hr = CopyMediaType(pMediaType,pSrc); | |
| if (FAILED(hr)) { | |
| CoTaskMemFree((PVOID)pMediaType); | |
| return NULL; | |
| } | |
| return pMediaType; | |
| } | |
| // Copy 1 media type to another | |
| HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource) | |
| { | |
| // We'll leak if we copy onto one that already exists - there's one | |
| // case we can check like that - copying to itself. | |
| ASSERT(pmtSource != pmtTarget); | |
| *pmtTarget = *pmtSource; | |
| if (pmtSource->cbFormat != 0) { | |
| ASSERT(pmtSource->pbFormat != NULL); | |
| pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat); | |
| if (pmtTarget->pbFormat == NULL) { | |
| pmtTarget->cbFormat = 0; | |
| return E_OUTOFMEMORY; | |
| } else { | |
| CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat, | |
| pmtTarget->cbFormat); | |
| } | |
| } | |
| if (pmtTarget->pUnk != NULL) { | |
| pmtTarget->pUnk->AddRef(); | |
| } | |
| return S_OK; | |
| } | |
| // Free an existing media type (ie free resources it holds) | |
| void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt) | |
| { | |
| if (mt.cbFormat != 0) { | |
| CoTaskMemFree((PVOID)mt.pbFormat); | |
| // Strictly unnecessary but tidier | |
| mt.cbFormat = 0; | |
| mt.pbFormat = NULL; | |
| } | |
| if (mt.pUnk != NULL) { | |
| mt.pUnk->Release(); | |
| mt.pUnk = NULL; | |
| } | |
| } | |
| // Initialize a media type from a WAVEFORMATEX | |
| STDAPI CreateAudioMediaType( | |
| const WAVEFORMATEX *pwfx, | |
| __out AM_MEDIA_TYPE *pmt, | |
| BOOL bSetFormat | |
| ) | |
| { | |
| pmt->majortype = MEDIATYPE_Audio; | |
| if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) { | |
| pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat; | |
| } else { | |
| pmt->subtype = FOURCCMap(pwfx->wFormatTag); | |
| } | |
| pmt->formattype = FORMAT_WaveFormatEx; | |
| pmt->bFixedSizeSamples = TRUE; | |
| pmt->bTemporalCompression = FALSE; | |
| pmt->lSampleSize = pwfx->nBlockAlign; | |
| pmt->pUnk = NULL; | |
| if (bSetFormat) { | |
| if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { | |
| pmt->cbFormat = sizeof(WAVEFORMATEX); | |
| } else { | |
| pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize; | |
| } | |
| pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat); | |
| if (pmt->pbFormat == NULL) { | |
| return E_OUTOFMEMORY; | |
| } | |
| if (pwfx->wFormatTag == WAVE_FORMAT_PCM) { | |
| CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT)); | |
| ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0; | |
| } else { | |
| CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat); | |
| } | |
| } | |
| return S_OK; | |
| } | |
| // eliminate very many spurious warnings from MS compiler | |
| #pragma warning(disable:4514) |