mirror of https://github.com/PCSX2/pcsx2.git
478 lines
11 KiB
C++
478 lines
11 KiB
C++
//------------------------------------------------------------------------------
|
|
// File: MType.cpp
|
|
//
|
|
// Desc: DirectShow base classes - implements a class that holds and
|
|
// manages media type information.
|
|
//
|
|
// Copyright (c) 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, HRESULT* phr)
|
|
{
|
|
HRESULT hr = CopyMediaType(this, &rt);
|
|
if (FAILED(hr) && (NULL != phr)) {
|
|
*phr = hr;
|
|
}
|
|
}
|
|
|
|
|
|
CMediaType::CMediaType(const CMediaType& rt, 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) ||
|
|
(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(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(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(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(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,
|
|
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)
|