Tristan Matthews | 0a329cc | 2013-07-17 13:20:14 -0400 | [diff] [blame] | 1 | //------------------------------------------------------------------------------
|
| 2 | // File: MType.cpp
|
| 3 | //
|
| 4 | // Desc: DirectShow base classes - implements a class that holds and
|
| 5 | // manages media type information.
|
| 6 | //
|
| 7 | // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
|
| 8 | //------------------------------------------------------------------------------
|
| 9 |
|
| 10 | #include <pjmedia-videodev/config.h>
|
| 11 |
|
| 12 | #if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
|
| 13 |
|
| 14 | // helper class that derived pin objects can use to compare media
|
| 15 | // types etc. Has same data members as the struct AM_MEDIA_TYPE defined
|
| 16 | // in the streams IDL file, but also has (non-virtual) functions
|
| 17 |
|
| 18 | #include <streams.h>
|
| 19 | #include <mmreg.h>
|
| 20 |
|
| 21 | CMediaType::~CMediaType(){
|
| 22 | FreeMediaType(*this);
|
| 23 | }
|
| 24 |
|
| 25 |
|
| 26 | CMediaType::CMediaType()
|
| 27 | {
|
| 28 | InitMediaType();
|
| 29 | }
|
| 30 |
|
| 31 |
|
| 32 | CMediaType::CMediaType(const GUID * type)
|
| 33 | {
|
| 34 | InitMediaType();
|
| 35 | majortype = *type;
|
| 36 | }
|
| 37 |
|
| 38 |
|
| 39 | // copy constructor does a deep copy of the format block
|
| 40 |
|
| 41 | CMediaType::CMediaType(const AM_MEDIA_TYPE& rt, __out_opt HRESULT* phr)
|
| 42 | {
|
| 43 | HRESULT hr = CopyMediaType(this, &rt);
|
| 44 | if (FAILED(hr) && (NULL != phr)) {
|
| 45 | *phr = hr;
|
| 46 | }
|
| 47 | }
|
| 48 |
|
| 49 |
|
| 50 | CMediaType::CMediaType(const CMediaType& rt, __out_opt HRESULT* phr)
|
| 51 | {
|
| 52 | HRESULT hr = CopyMediaType(this, &rt);
|
| 53 | if (FAILED(hr) && (NULL != phr)) {
|
| 54 | *phr = hr;
|
| 55 | }
|
| 56 | }
|
| 57 |
|
| 58 |
|
| 59 | // this class inherits publicly from AM_MEDIA_TYPE so the compiler could generate
|
| 60 | // the following assignment operator itself, however it could introduce some
|
| 61 | // memory conflicts and leaks in the process because the structure contains
|
| 62 | // a dynamically allocated block (pbFormat) which it will not copy correctly
|
| 63 |
|
| 64 | CMediaType&
|
| 65 | CMediaType::operator=(const AM_MEDIA_TYPE& rt)
|
| 66 | {
|
| 67 | Set(rt);
|
| 68 | return *this;
|
| 69 | }
|
| 70 |
|
| 71 | CMediaType&
|
| 72 | CMediaType::operator=(const CMediaType& rt)
|
| 73 | {
|
| 74 | *this = (AM_MEDIA_TYPE &) rt;
|
| 75 | return *this;
|
| 76 | }
|
| 77 |
|
| 78 | BOOL
|
| 79 | CMediaType::operator == (const CMediaType& rt) const
|
| 80 | {
|
| 81 | // I don't believe we need to check sample size or
|
| 82 | // temporal compression flags, since I think these must
|
| 83 | // be represented in the type, subtype and format somehow. They
|
| 84 | // are pulled out as separate flags so that people who don't understand
|
| 85 | // the particular format representation can still see them, but
|
| 86 | // they should duplicate information in the format block.
|
| 87 |
|
| 88 | return ((IsEqualGUID(majortype,rt.majortype) == TRUE) &&
|
| 89 | (IsEqualGUID(subtype,rt.subtype) == TRUE) &&
|
| 90 | (IsEqualGUID(formattype,rt.formattype) == TRUE) &&
|
| 91 | (cbFormat == rt.cbFormat) &&
|
| 92 | ( (cbFormat == 0) ||
|
| 93 | pbFormat != NULL && rt.pbFormat != NULL &&
|
| 94 | (memcmp(pbFormat, rt.pbFormat, cbFormat) == 0)));
|
| 95 | }
|
| 96 |
|
| 97 |
|
| 98 | BOOL
|
| 99 | CMediaType::operator != (const CMediaType& rt) const
|
| 100 | {
|
| 101 | /* Check to see if they are equal */
|
| 102 |
|
| 103 | if (*this == rt) {
|
| 104 | return FALSE;
|
| 105 | }
|
| 106 | return TRUE;
|
| 107 | }
|
| 108 |
|
| 109 |
|
| 110 | HRESULT
|
| 111 | CMediaType::Set(const CMediaType& rt)
|
| 112 | {
|
| 113 | return Set((AM_MEDIA_TYPE &) rt);
|
| 114 | }
|
| 115 |
|
| 116 |
|
| 117 | HRESULT
|
| 118 | CMediaType::Set(const AM_MEDIA_TYPE& rt)
|
| 119 | {
|
| 120 | if (&rt != this) {
|
| 121 | FreeMediaType(*this);
|
| 122 | HRESULT hr = CopyMediaType(this, &rt);
|
| 123 | if (FAILED(hr)) {
|
| 124 | return E_OUTOFMEMORY;
|
| 125 | }
|
| 126 | }
|
| 127 |
|
| 128 | return S_OK;
|
| 129 | }
|
| 130 |
|
| 131 |
|
| 132 | BOOL
|
| 133 | CMediaType::IsValid() const
|
| 134 | {
|
| 135 | return (!IsEqualGUID(majortype,GUID_NULL));
|
| 136 | }
|
| 137 |
|
| 138 |
|
| 139 | void
|
| 140 | CMediaType::SetType(const GUID* ptype)
|
| 141 | {
|
| 142 | majortype = *ptype;
|
| 143 | }
|
| 144 |
|
| 145 |
|
| 146 | void
|
| 147 | CMediaType::SetSubtype(const GUID* ptype)
|
| 148 | {
|
| 149 | subtype = *ptype;
|
| 150 | }
|
| 151 |
|
| 152 |
|
| 153 | ULONG
|
| 154 | CMediaType::GetSampleSize() const {
|
| 155 | if (IsFixedSize()) {
|
| 156 | return lSampleSize;
|
| 157 | } else {
|
| 158 | return 0;
|
| 159 | }
|
| 160 | }
|
| 161 |
|
| 162 |
|
| 163 | void
|
| 164 | CMediaType::SetSampleSize(ULONG sz) {
|
| 165 | if (sz == 0) {
|
| 166 | SetVariableSize();
|
| 167 | } else {
|
| 168 | bFixedSizeSamples = TRUE;
|
| 169 | lSampleSize = sz;
|
| 170 | }
|
| 171 | }
|
| 172 |
|
| 173 |
|
| 174 | void
|
| 175 | CMediaType::SetVariableSize() {
|
| 176 | bFixedSizeSamples = FALSE;
|
| 177 | }
|
| 178 |
|
| 179 |
|
| 180 | void
|
| 181 | CMediaType::SetTemporalCompression(BOOL bCompressed) {
|
| 182 | bTemporalCompression = bCompressed;
|
| 183 | }
|
| 184 |
|
| 185 | BOOL
|
| 186 | CMediaType::SetFormat(__in_bcount(cb) BYTE * pformat, ULONG cb)
|
| 187 | {
|
| 188 | if (NULL == AllocFormatBuffer(cb))
|
| 189 | return(FALSE);
|
| 190 |
|
| 191 | ASSERT(pbFormat);
|
| 192 | memcpy(pbFormat, pformat, cb);
|
| 193 | return(TRUE);
|
| 194 | }
|
| 195 |
|
| 196 |
|
| 197 | // set the type of the media type format block, this type defines what you
|
| 198 | // will actually find in the format pointer. For example FORMAT_VideoInfo or
|
| 199 | // FORMAT_WaveFormatEx. In the future this may be an interface pointer to a
|
| 200 | // property set. Before sending out media types this should be filled in.
|
| 201 |
|
| 202 | void
|
| 203 | CMediaType::SetFormatType(const GUID *pformattype)
|
| 204 | {
|
| 205 | formattype = *pformattype;
|
| 206 | }
|
| 207 |
|
| 208 |
|
| 209 | // reset the format buffer
|
| 210 |
|
| 211 | void CMediaType::ResetFormatBuffer()
|
| 212 | {
|
| 213 | if (cbFormat) {
|
| 214 | CoTaskMemFree((PVOID)pbFormat);
|
| 215 | }
|
| 216 | cbFormat = 0;
|
| 217 | pbFormat = NULL;
|
| 218 | }
|
| 219 |
|
| 220 |
|
| 221 | // allocate length bytes for the format and return a read/write pointer
|
| 222 | // If we cannot allocate the new block of memory we return NULL leaving
|
| 223 | // the original block of memory untouched (as does ReallocFormatBuffer)
|
| 224 |
|
| 225 | BYTE*
|
| 226 | CMediaType::AllocFormatBuffer(ULONG length)
|
| 227 | {
|
| 228 | ASSERT(length);
|
| 229 |
|
| 230 | // do the types have the same buffer size
|
| 231 |
|
| 232 | if (cbFormat == length) {
|
| 233 | return pbFormat;
|
| 234 | }
|
| 235 |
|
| 236 | // allocate the new format buffer
|
| 237 |
|
| 238 | BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
| 239 | if (pNewFormat == NULL) {
|
| 240 | if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
| 241 | return NULL;
|
| 242 | }
|
| 243 |
|
| 244 | // delete the old format
|
| 245 |
|
| 246 | if (cbFormat != 0) {
|
| 247 | ASSERT(pbFormat);
|
| 248 | CoTaskMemFree((PVOID)pbFormat);
|
| 249 | }
|
| 250 |
|
| 251 | cbFormat = length;
|
| 252 | pbFormat = pNewFormat;
|
| 253 | return pbFormat;
|
| 254 | }
|
| 255 |
|
| 256 |
|
| 257 | // reallocate length bytes for the format and return a read/write pointer
|
| 258 | // to it. We keep as much information as we can given the new buffer size
|
| 259 | // if this fails the original format buffer is left untouched. The caller
|
| 260 | // is responsible for ensuring the size of memory required is non zero
|
| 261 |
|
| 262 | BYTE*
|
| 263 | CMediaType::ReallocFormatBuffer(ULONG length)
|
| 264 | {
|
| 265 | ASSERT(length);
|
| 266 |
|
| 267 | // do the types have the same buffer size
|
| 268 |
|
| 269 | if (cbFormat == length) {
|
| 270 | return pbFormat;
|
| 271 | }
|
| 272 |
|
| 273 | // allocate the new format buffer
|
| 274 |
|
| 275 | BYTE *pNewFormat = (PBYTE)CoTaskMemAlloc(length);
|
| 276 | if (pNewFormat == NULL) {
|
| 277 | if (length <= cbFormat) return pbFormat; //reuse the old block anyway.
|
| 278 | return NULL;
|
| 279 | }
|
| 280 |
|
| 281 | // copy any previous format (or part of if new is smaller)
|
| 282 | // delete the old format and replace with the new one
|
| 283 |
|
| 284 | if (cbFormat != 0) {
|
| 285 | ASSERT(pbFormat);
|
| 286 | memcpy(pNewFormat,pbFormat,min(length,cbFormat));
|
| 287 | CoTaskMemFree((PVOID)pbFormat);
|
| 288 | }
|
| 289 |
|
| 290 | cbFormat = length;
|
| 291 | pbFormat = pNewFormat;
|
| 292 | return pNewFormat;
|
| 293 | }
|
| 294 |
|
| 295 | // initialise a media type structure
|
| 296 |
|
| 297 | void CMediaType::InitMediaType()
|
| 298 | {
|
| 299 | ZeroMemory((PVOID)this, sizeof(*this));
|
| 300 | lSampleSize = 1;
|
| 301 | bFixedSizeSamples = TRUE;
|
| 302 | }
|
| 303 |
|
| 304 |
|
| 305 | // a partially specified media type can be passed to IPin::Connect
|
| 306 | // as a constraint on the media type used in the connection.
|
| 307 | // the type, subtype or format type can be null.
|
| 308 | BOOL
|
| 309 | CMediaType::IsPartiallySpecified(void) const
|
| 310 | {
|
| 311 | if ((majortype == GUID_NULL) ||
|
| 312 | (formattype == GUID_NULL)) {
|
| 313 | return TRUE;
|
| 314 | } else {
|
| 315 | return FALSE;
|
| 316 | }
|
| 317 | }
|
| 318 |
|
| 319 | BOOL
|
| 320 | CMediaType::MatchesPartial(const CMediaType* ppartial) const
|
| 321 | {
|
| 322 | if ((ppartial->majortype != GUID_NULL) &&
|
| 323 | (majortype != ppartial->majortype)) {
|
| 324 | return FALSE;
|
| 325 | }
|
| 326 | if ((ppartial->subtype != GUID_NULL) &&
|
| 327 | (subtype != ppartial->subtype)) {
|
| 328 | return FALSE;
|
| 329 | }
|
| 330 |
|
| 331 | if (ppartial->formattype != GUID_NULL) {
|
| 332 | // if the format block is specified then it must match exactly
|
| 333 | if (formattype != ppartial->formattype) {
|
| 334 | return FALSE;
|
| 335 | }
|
| 336 | if (cbFormat != ppartial->cbFormat) {
|
| 337 | return FALSE;
|
| 338 | }
|
| 339 | if ((cbFormat != 0) &&
|
| 340 | (memcmp(pbFormat, ppartial->pbFormat, cbFormat) != 0)) {
|
| 341 | return FALSE;
|
| 342 | }
|
| 343 | }
|
| 344 |
|
| 345 | return TRUE;
|
| 346 |
|
| 347 | }
|
| 348 |
|
| 349 |
|
| 350 |
|
| 351 | // general purpose function to delete a heap allocated AM_MEDIA_TYPE structure
|
| 352 | // which is useful when calling IEnumMediaTypes::Next as the interface
|
| 353 | // implementation allocates the structures which you must later delete
|
| 354 | // the format block may also be a pointer to an interface to release
|
| 355 |
|
| 356 | void WINAPI DeleteMediaType(__inout_opt AM_MEDIA_TYPE *pmt)
|
| 357 | {
|
| 358 | // allow NULL pointers for coding simplicity
|
| 359 |
|
| 360 | if (pmt == NULL) {
|
| 361 | return;
|
| 362 | }
|
| 363 |
|
| 364 | FreeMediaType(*pmt);
|
| 365 | CoTaskMemFree((PVOID)pmt);
|
| 366 | }
|
| 367 |
|
| 368 |
|
| 369 | // this also comes in useful when using the IEnumMediaTypes interface so
|
| 370 | // that you can copy a media type, you can do nearly the same by creating
|
| 371 | // a CMediaType object but as soon as it goes out of scope the destructor
|
| 372 | // will delete the memory it allocated (this takes a copy of the memory)
|
| 373 |
|
| 374 | AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const *pSrc)
|
| 375 | {
|
| 376 | ASSERT(pSrc);
|
| 377 |
|
| 378 | // Allocate a block of memory for the media type
|
| 379 |
|
| 380 | AM_MEDIA_TYPE *pMediaType =
|
| 381 | (AM_MEDIA_TYPE *)CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
|
| 382 |
|
| 383 | if (pMediaType == NULL) {
|
| 384 | return NULL;
|
| 385 | }
|
| 386 | // Copy the variable length format block
|
| 387 |
|
| 388 | HRESULT hr = CopyMediaType(pMediaType,pSrc);
|
| 389 | if (FAILED(hr)) {
|
| 390 | CoTaskMemFree((PVOID)pMediaType);
|
| 391 | return NULL;
|
| 392 | }
|
| 393 |
|
| 394 | return pMediaType;
|
| 395 | }
|
| 396 |
|
| 397 |
|
| 398 | // Copy 1 media type to another
|
| 399 |
|
| 400 | HRESULT WINAPI CopyMediaType(__out AM_MEDIA_TYPE *pmtTarget, const AM_MEDIA_TYPE *pmtSource)
|
| 401 | {
|
| 402 | // We'll leak if we copy onto one that already exists - there's one
|
| 403 | // case we can check like that - copying to itself.
|
| 404 | ASSERT(pmtSource != pmtTarget);
|
| 405 | *pmtTarget = *pmtSource;
|
| 406 | if (pmtSource->cbFormat != 0) {
|
| 407 | ASSERT(pmtSource->pbFormat != NULL);
|
| 408 | pmtTarget->pbFormat = (PBYTE)CoTaskMemAlloc(pmtSource->cbFormat);
|
| 409 | if (pmtTarget->pbFormat == NULL) {
|
| 410 | pmtTarget->cbFormat = 0;
|
| 411 | return E_OUTOFMEMORY;
|
| 412 | } else {
|
| 413 | CopyMemory((PVOID)pmtTarget->pbFormat, (PVOID)pmtSource->pbFormat,
|
| 414 | pmtTarget->cbFormat);
|
| 415 | }
|
| 416 | }
|
| 417 | if (pmtTarget->pUnk != NULL) {
|
| 418 | pmtTarget->pUnk->AddRef();
|
| 419 | }
|
| 420 |
|
| 421 | return S_OK;
|
| 422 | }
|
| 423 |
|
| 424 | // Free an existing media type (ie free resources it holds)
|
| 425 |
|
| 426 | void WINAPI FreeMediaType(__inout AM_MEDIA_TYPE& mt)
|
| 427 | {
|
| 428 | if (mt.cbFormat != 0) {
|
| 429 | CoTaskMemFree((PVOID)mt.pbFormat);
|
| 430 |
|
| 431 | // Strictly unnecessary but tidier
|
| 432 | mt.cbFormat = 0;
|
| 433 | mt.pbFormat = NULL;
|
| 434 | }
|
| 435 | if (mt.pUnk != NULL) {
|
| 436 | mt.pUnk->Release();
|
| 437 | mt.pUnk = NULL;
|
| 438 | }
|
| 439 | }
|
| 440 |
|
| 441 | // Initialize a media type from a WAVEFORMATEX
|
| 442 |
|
| 443 | STDAPI CreateAudioMediaType(
|
| 444 | const WAVEFORMATEX *pwfx,
|
| 445 | __out AM_MEDIA_TYPE *pmt,
|
| 446 | BOOL bSetFormat
|
| 447 | )
|
| 448 | {
|
| 449 | pmt->majortype = MEDIATYPE_Audio;
|
| 450 | if (pwfx->wFormatTag == WAVE_FORMAT_EXTENSIBLE) {
|
| 451 | pmt->subtype = ((PWAVEFORMATEXTENSIBLE)pwfx)->SubFormat;
|
| 452 | } else {
|
| 453 | pmt->subtype = FOURCCMap(pwfx->wFormatTag);
|
| 454 | }
|
| 455 | pmt->formattype = FORMAT_WaveFormatEx;
|
| 456 | pmt->bFixedSizeSamples = TRUE;
|
| 457 | pmt->bTemporalCompression = FALSE;
|
| 458 | pmt->lSampleSize = pwfx->nBlockAlign;
|
| 459 | pmt->pUnk = NULL;
|
| 460 | if (bSetFormat) {
|
| 461 | if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
| 462 | pmt->cbFormat = sizeof(WAVEFORMATEX);
|
| 463 | } else {
|
| 464 | pmt->cbFormat = sizeof(WAVEFORMATEX) + pwfx->cbSize;
|
| 465 | }
|
| 466 | pmt->pbFormat = (PBYTE)CoTaskMemAlloc(pmt->cbFormat);
|
| 467 | if (pmt->pbFormat == NULL) {
|
| 468 | return E_OUTOFMEMORY;
|
| 469 | }
|
| 470 | if (pwfx->wFormatTag == WAVE_FORMAT_PCM) {
|
| 471 | CopyMemory(pmt->pbFormat, pwfx, sizeof(PCMWAVEFORMAT));
|
| 472 | ((WAVEFORMATEX *)pmt->pbFormat)->cbSize = 0;
|
| 473 | } else {
|
| 474 | CopyMemory(pmt->pbFormat, pwfx, pmt->cbFormat);
|
| 475 | }
|
| 476 | }
|
| 477 | return S_OK;
|
| 478 | }
|
| 479 |
|
| 480 | // eliminate very many spurious warnings from MS compiler
|
| 481 | #pragma warning(disable:4514)
|
| 482 |
|
| 483 | #endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */
|