[STRMBASE]
[reactos.git] / reactos / lib / 3rdparty / strmbase / mediatype.c
1 /*
2 * Implementation of MedaType utility functions
3 *
4 * Copyright 2003 Robert Shearman
5 * Copyright 2010 Aric Stewart, CodeWeavers
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "strmbase_private.h"
23
24 HRESULT WINAPI CopyMediaType(AM_MEDIA_TYPE *dest, const AM_MEDIA_TYPE *src)
25 {
26 *dest = *src;
27 if (src->pbFormat)
28 {
29 dest->pbFormat = CoTaskMemAlloc(src->cbFormat);
30 if (!dest->pbFormat)
31 return E_OUTOFMEMORY;
32 memcpy(dest->pbFormat, src->pbFormat, src->cbFormat);
33 }
34 if (dest->pUnk)
35 IUnknown_AddRef(dest->pUnk);
36 return S_OK;
37 }
38
39 void WINAPI FreeMediaType(AM_MEDIA_TYPE * pMediaType)
40 {
41 if (pMediaType->pbFormat)
42 {
43 CoTaskMemFree(pMediaType->pbFormat);
44 pMediaType->pbFormat = NULL;
45 }
46 if (pMediaType->pUnk)
47 {
48 IUnknown_Release(pMediaType->pUnk);
49 pMediaType->pUnk = NULL;
50 }
51 }
52
53 AM_MEDIA_TYPE * WINAPI CreateMediaType(AM_MEDIA_TYPE const * pSrc)
54 {
55 AM_MEDIA_TYPE * pDest;
56
57 pDest = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE));
58 if (!pDest)
59 return NULL;
60
61 if (FAILED(CopyMediaType(pDest, pSrc)))
62 {
63 CoTaskMemFree(pDest);
64 return NULL;
65 }
66
67 return pDest;
68 }
69
70 void WINAPI DeleteMediaType(AM_MEDIA_TYPE * pMediaType)
71 {
72 FreeMediaType(pMediaType);
73 CoTaskMemFree(pMediaType);
74 }
75
76 typedef struct tagENUMEDIADETAILS
77 {
78 ULONG cMediaTypes;
79 AM_MEDIA_TYPE * pMediaTypes;
80 } ENUMMEDIADETAILS;
81
82 typedef struct IEnumMediaTypesImpl
83 {
84 IEnumMediaTypes IEnumMediaTypes_iface;
85 LONG refCount;
86 BasePin *basePin;
87 BasePin_GetMediaType enumMediaFunction;
88 BasePin_GetMediaTypeVersion mediaVersionFunction;
89 LONG currentVersion;
90 ENUMMEDIADETAILS enumMediaDetails;
91 ULONG uIndex;
92 } IEnumMediaTypesImpl;
93
94 static inline IEnumMediaTypesImpl *impl_from_IEnumMediaTypes(IEnumMediaTypes *iface)
95 {
96 return CONTAINING_RECORD(iface, IEnumMediaTypesImpl, IEnumMediaTypes_iface);
97 }
98
99 static const struct IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl;
100
101 HRESULT WINAPI EnumMediaTypes_Construct(BasePin *basePin, BasePin_GetMediaType enumFunc, BasePin_GetMediaTypeVersion versionFunc, IEnumMediaTypes ** ppEnum)
102 {
103 ULONG i;
104 IEnumMediaTypesImpl * pEnumMediaTypes = CoTaskMemAlloc(sizeof(IEnumMediaTypesImpl));
105 AM_MEDIA_TYPE amt;
106
107 if (!pEnumMediaTypes)
108 {
109 *ppEnum = NULL;
110 return E_OUTOFMEMORY;
111 }
112 pEnumMediaTypes->IEnumMediaTypes_iface.lpVtbl = &IEnumMediaTypesImpl_Vtbl;
113 pEnumMediaTypes->refCount = 1;
114 pEnumMediaTypes->uIndex = 0;
115 pEnumMediaTypes->enumMediaFunction = enumFunc;
116 pEnumMediaTypes->mediaVersionFunction = versionFunc;
117 IPin_AddRef(&basePin->IPin_iface);
118 pEnumMediaTypes->basePin = basePin;
119
120 i = 0;
121 while (enumFunc(basePin, i, &amt) == S_OK) i++;
122
123 pEnumMediaTypes->enumMediaDetails.cMediaTypes = i;
124 pEnumMediaTypes->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * i);
125 for (i = 0; i < pEnumMediaTypes->enumMediaDetails.cMediaTypes; i++)
126 {
127 enumFunc(basePin,i,&amt);
128 if (FAILED(CopyMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i], &amt)))
129 {
130 while (i--)
131 FreeMediaType(&pEnumMediaTypes->enumMediaDetails.pMediaTypes[i]);
132 CoTaskMemFree(pEnumMediaTypes->enumMediaDetails.pMediaTypes);
133 return E_OUTOFMEMORY;
134 }
135 }
136 *ppEnum = &pEnumMediaTypes->IEnumMediaTypes_iface;
137 pEnumMediaTypes->currentVersion = versionFunc(basePin);
138 return S_OK;
139 }
140
141 static HRESULT WINAPI IEnumMediaTypesImpl_QueryInterface(IEnumMediaTypes * iface, REFIID riid, void ** ret_iface)
142 {
143 TRACE("(%p)->(%s, %p)\n", iface, debugstr_guid(riid), ret_iface);
144
145 if (IsEqualIID(riid, &IID_IUnknown) ||
146 IsEqualIID(riid, &IID_IEnumMediaTypes))
147 {
148 IEnumMediaTypes_AddRef(iface);
149 *ret_iface = iface;
150 return S_OK;
151 }
152
153 *ret_iface = NULL;
154
155 WARN("No interface for %s\n", debugstr_guid(riid));
156
157 return E_NOINTERFACE;
158 }
159
160 static ULONG WINAPI IEnumMediaTypesImpl_AddRef(IEnumMediaTypes * iface)
161 {
162 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
163 ULONG ref = InterlockedIncrement(&This->refCount);
164
165 TRACE("(%p)->(): new ref = %u\n", iface, ref);
166
167 return ref;
168 }
169
170 static ULONG WINAPI IEnumMediaTypesImpl_Release(IEnumMediaTypes * iface)
171 {
172 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
173 ULONG ref = InterlockedDecrement(&This->refCount);
174
175 TRACE("(%p)->(): new ref = %u\n", iface, ref);
176
177 if (!ref)
178 {
179 ULONG i;
180 for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
181 FreeMediaType(&This->enumMediaDetails.pMediaTypes[i]);
182 CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
183 IPin_Release(&This->basePin->IPin_iface);
184 CoTaskMemFree(This);
185 }
186 return ref;
187 }
188
189 static HRESULT WINAPI IEnumMediaTypesImpl_Next(IEnumMediaTypes * iface, ULONG cMediaTypes, AM_MEDIA_TYPE ** ppMediaTypes, ULONG * pcFetched)
190 {
191 ULONG cFetched;
192 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
193
194 TRACE("(%p)->(%u, %p, %p)\n", iface, cMediaTypes, ppMediaTypes, pcFetched);
195
196 cFetched = min(This->enumMediaDetails.cMediaTypes, This->uIndex + cMediaTypes) - This->uIndex;
197
198 if (This->currentVersion != This->mediaVersionFunction(This->basePin))
199 return VFW_E_ENUM_OUT_OF_SYNC;
200
201 TRACE("Next uIndex: %u, cFetched: %u\n", This->uIndex, cFetched);
202
203 if (cFetched > 0)
204 {
205 ULONG i;
206 for (i = 0; i < cFetched; i++)
207 if (!(ppMediaTypes[i] = CreateMediaType(&This->enumMediaDetails.pMediaTypes[This->uIndex + i])))
208 {
209 while (i--)
210 DeleteMediaType(ppMediaTypes[i]);
211 *pcFetched = 0;
212 return E_OUTOFMEMORY;
213 }
214 }
215
216 if ((cMediaTypes != 1) || pcFetched)
217 *pcFetched = cFetched;
218
219 This->uIndex += cFetched;
220
221 if (cFetched != cMediaTypes)
222 return S_FALSE;
223 return S_OK;
224 }
225
226 static HRESULT WINAPI IEnumMediaTypesImpl_Skip(IEnumMediaTypes * iface, ULONG cMediaTypes)
227 {
228 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
229
230 TRACE("(%p)->(%u)\n", iface, cMediaTypes);
231
232 if (This->currentVersion != This->mediaVersionFunction(This->basePin))
233 return VFW_E_ENUM_OUT_OF_SYNC;
234
235 if (This->uIndex + cMediaTypes < This->enumMediaDetails.cMediaTypes)
236 {
237 This->uIndex += cMediaTypes;
238 return S_OK;
239 }
240 return S_FALSE;
241 }
242
243 static HRESULT WINAPI IEnumMediaTypesImpl_Reset(IEnumMediaTypes * iface)
244 {
245 ULONG i;
246 AM_MEDIA_TYPE amt;
247 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
248
249 TRACE("(%p)->()\n", iface);
250
251 for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
252 FreeMediaType(&This->enumMediaDetails.pMediaTypes[i]);
253 CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
254
255 i = 0;
256 while (This->enumMediaFunction(This->basePin, i, &amt) == S_OK) i++;
257
258 This->enumMediaDetails.cMediaTypes = i;
259 This->enumMediaDetails.pMediaTypes = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE) * i);
260 for (i = 0; i < This->enumMediaDetails.cMediaTypes; i++)
261 {
262 This->enumMediaFunction(This->basePin, i,&amt);
263 if (FAILED(CopyMediaType(&This->enumMediaDetails.pMediaTypes[i], &amt)))
264 {
265 while (i--)
266 FreeMediaType(&This->enumMediaDetails.pMediaTypes[i]);
267 CoTaskMemFree(This->enumMediaDetails.pMediaTypes);
268 return E_OUTOFMEMORY;
269 }
270 }
271
272 This->currentVersion = This->mediaVersionFunction(This->basePin);
273 This->uIndex = 0;
274
275 return S_OK;
276 }
277
278 static HRESULT WINAPI IEnumMediaTypesImpl_Clone(IEnumMediaTypes * iface, IEnumMediaTypes ** ppEnum)
279 {
280 HRESULT hr;
281 IEnumMediaTypesImpl *This = impl_from_IEnumMediaTypes(iface);
282
283 TRACE("(%p)->(%p)\n", iface, ppEnum);
284
285 hr = EnumMediaTypes_Construct(This->basePin, This->enumMediaFunction, This->mediaVersionFunction, ppEnum);
286 if (FAILED(hr))
287 return hr;
288 return IEnumMediaTypes_Skip(*ppEnum, This->uIndex);
289 }
290
291 static const IEnumMediaTypesVtbl IEnumMediaTypesImpl_Vtbl =
292 {
293 IEnumMediaTypesImpl_QueryInterface,
294 IEnumMediaTypesImpl_AddRef,
295 IEnumMediaTypesImpl_Release,
296 IEnumMediaTypesImpl_Next,
297 IEnumMediaTypesImpl_Skip,
298 IEnumMediaTypesImpl_Reset,
299 IEnumMediaTypesImpl_Clone
300 };