blob: 8d99697eee2e81548bd6d9391f4ef5837f9b4fb4 [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001//------------------------------------------------------------------------------
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
21CMediaType::~CMediaType(){
22 FreeMediaType(*this);
23}
24
25
26CMediaType::CMediaType()
27{
28 InitMediaType();
29}
30
31
32CMediaType::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
41CMediaType::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
50CMediaType::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
64CMediaType&
65CMediaType::operator=(const AM_MEDIA_TYPE& rt)
66{
67 Set(rt);
68 return *this;
69}
70
71CMediaType&
72CMediaType::operator=(const CMediaType& rt)
73{
74 *this = (AM_MEDIA_TYPE &) rt;
75 return *this;
76}
77
78BOOL
79CMediaType::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
98BOOL
99CMediaType::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
110HRESULT
111CMediaType::Set(const CMediaType& rt)
112{
113 return Set((AM_MEDIA_TYPE &) rt);
114}
115
116
117HRESULT
118CMediaType::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
132BOOL
133CMediaType::IsValid() const
134{
135 return (!IsEqualGUID(majortype,GUID_NULL));
136}
137
138
139void
140CMediaType::SetType(const GUID* ptype)
141{
142 majortype = *ptype;
143}
144
145
146void
147CMediaType::SetSubtype(const GUID* ptype)
148{
149 subtype = *ptype;
150}
151
152
153ULONG
154CMediaType::GetSampleSize() const {
155 if (IsFixedSize()) {
156 return lSampleSize;
157 } else {
158 return 0;
159 }
160}
161
162
163void
164CMediaType::SetSampleSize(ULONG sz) {
165 if (sz == 0) {
166 SetVariableSize();
167 } else {
168 bFixedSizeSamples = TRUE;
169 lSampleSize = sz;
170 }
171}
172
173
174void
175CMediaType::SetVariableSize() {
176 bFixedSizeSamples = FALSE;
177}
178
179
180void
181CMediaType::SetTemporalCompression(BOOL bCompressed) {
182 bTemporalCompression = bCompressed;
183}
184
185BOOL
186CMediaType::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
202void
203CMediaType::SetFormatType(const GUID *pformattype)
204{
205 formattype = *pformattype;
206}
207
208
209// reset the format buffer
210
211void 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
225BYTE*
226CMediaType::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
262BYTE*
263CMediaType::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
297void 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.
308BOOL
309CMediaType::IsPartiallySpecified(void) const
310{
311 if ((majortype == GUID_NULL) ||
312 (formattype == GUID_NULL)) {
313 return TRUE;
314 } else {
315 return FALSE;
316 }
317}
318
319BOOL
320CMediaType::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
356void 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
374AM_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
400HRESULT 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
426void 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
443STDAPI 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 */