msxml3: Leading space chars are allowed in SelectionNamespaces value string.
[wine/multimedia.git] / dlls / quartz / memallocator.c
blob4858c02bcd34317c4baef04a39f2bf09b5f1009b
1 /*
2 * Memory Allocator and Media Sample Implementation
4 * Copyright 2003 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <assert.h>
22 #include <limits.h>
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "vfwmsgs.h"
29 #include "quartz_private.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
34 typedef struct BaseMemAllocator
36 IMemAllocator IMemAllocator_iface;
38 LONG ref;
39 ALLOCATOR_PROPERTIES props;
40 HRESULT (* fnAlloc) (IMemAllocator *);
41 HRESULT (* fnFree)(IMemAllocator *);
42 HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *);
43 HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD flags);
44 HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *);
45 void (* fnDestroyed)(IMemAllocator *);
46 HANDLE hSemWaiting;
47 BOOL bDecommitQueued;
48 BOOL bCommitted;
49 LONG lWaiting;
50 struct list free_list;
51 struct list used_list;
52 CRITICAL_SECTION *pCritSect;
53 } BaseMemAllocator;
55 static inline BaseMemAllocator *impl_from_IMemAllocator(IMemAllocator *iface)
57 return CONTAINING_RECORD(iface, BaseMemAllocator, IMemAllocator_iface);
60 static const IMemAllocatorVtbl BaseMemAllocator_VTable;
61 static const IMediaSample2Vtbl StdMediaSample2_VTable;
63 #define AM_SAMPLE2_PROP_SIZE_WRITABLE FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer)
65 #define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff)
67 static HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *),
68 HRESULT (* fnFree)(IMemAllocator *),
69 HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *),
70 HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD),
71 HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *),
72 void (* fnDestroyed)(IMemAllocator *),
73 CRITICAL_SECTION *pCritSect,
74 BaseMemAllocator * pMemAlloc)
76 assert(fnAlloc && fnFree && fnDestroyed);
78 pMemAlloc->IMemAllocator_iface.lpVtbl = &BaseMemAllocator_VTable;
80 pMemAlloc->ref = 1;
81 ZeroMemory(&pMemAlloc->props, sizeof(pMemAlloc->props));
82 list_init(&pMemAlloc->free_list);
83 list_init(&pMemAlloc->used_list);
84 pMemAlloc->fnAlloc = fnAlloc;
85 pMemAlloc->fnFree = fnFree;
86 pMemAlloc->fnVerify = fnVerify;
87 pMemAlloc->fnBufferPrepare = fnBufferPrepare;
88 pMemAlloc->fnBufferReleased = fnBufferReleased;
89 pMemAlloc->fnDestroyed = fnDestroyed;
90 pMemAlloc->bDecommitQueued = FALSE;
91 pMemAlloc->bCommitted = FALSE;
92 pMemAlloc->hSemWaiting = NULL;
93 pMemAlloc->lWaiting = 0;
94 pMemAlloc->pCritSect = pCritSect;
96 return S_OK;
99 static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv)
101 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
102 TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv);
104 *ppv = NULL;
106 if (IsEqualIID(riid, &IID_IUnknown))
107 *ppv = This;
108 else if (IsEqualIID(riid, &IID_IMemAllocator))
109 *ppv = This;
111 if (*ppv)
113 IUnknown_AddRef((IUnknown *)(*ppv));
114 return S_OK;
117 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
119 return E_NOINTERFACE;
122 static ULONG WINAPI BaseMemAllocator_AddRef(IMemAllocator * iface)
124 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
125 ULONG ref = InterlockedIncrement(&This->ref);
127 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
129 return ref;
132 static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface)
134 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
135 ULONG ref = InterlockedDecrement(&This->ref);
137 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
139 if (!ref)
141 CloseHandle(This->hSemWaiting);
142 if (This->bCommitted)
143 This->fnFree(iface);
145 This->fnDestroyed(iface);
146 return 0;
148 return ref;
151 static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual)
153 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
154 HRESULT hr;
156 TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual);
158 EnterCriticalSection(This->pCritSect);
160 if (!list_empty(&This->used_list))
161 hr = VFW_E_BUFFERS_OUTSTANDING;
162 else if (This->bCommitted)
163 hr = VFW_E_ALREADY_COMMITTED;
164 else if (pRequest->cbAlign == 0)
165 hr = VFW_E_BADALIGN;
166 else
168 if (This->fnVerify)
169 hr = This->fnVerify(iface, pRequest);
170 else
171 hr = S_OK;
173 if (SUCCEEDED(hr))
174 This->props = *pRequest;
176 *pActual = This->props;
179 LeaveCriticalSection(This->pCritSect);
181 return hr;
184 static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps)
186 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
187 HRESULT hr = S_OK;
189 TRACE("(%p)->(%p)\n", This, pProps);
191 EnterCriticalSection(This->pCritSect);
193 memcpy(pProps, &This->props, sizeof(*pProps));
195 LeaveCriticalSection(This->pCritSect);
197 return hr;
200 static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface)
202 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
203 HRESULT hr;
205 TRACE("(%p)->()\n", This);
207 EnterCriticalSection(This->pCritSect);
209 if (!This->props.cbAlign)
210 hr = VFW_E_BADALIGN;
211 else if (!This->props.cbBuffer)
212 hr = VFW_E_SIZENOTSET;
213 else if (!This->props.cBuffers)
214 hr = VFW_E_BUFFER_NOTSET;
215 else if (This->bDecommitQueued && This->bCommitted)
217 This->bDecommitQueued = FALSE;
218 hr = S_OK;
220 else if (This->bCommitted)
221 hr = S_OK;
222 else
224 if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->props.cBuffers, This->props.cBuffers, NULL)))
226 ERR("Couldn't create semaphore (error was %u)\n", GetLastError());
227 hr = HRESULT_FROM_WIN32(GetLastError());
229 else
231 hr = This->fnAlloc(iface);
232 if (SUCCEEDED(hr))
233 This->bCommitted = TRUE;
234 else
235 ERR("fnAlloc failed with error 0x%x\n", hr);
239 LeaveCriticalSection(This->pCritSect);
241 return hr;
244 static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface)
246 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
247 HRESULT hr;
249 TRACE("(%p)->()\n", This);
251 EnterCriticalSection(This->pCritSect);
253 if (!This->bCommitted)
254 hr = S_OK;
255 else
257 if (!list_empty(&This->used_list))
259 This->bDecommitQueued = TRUE;
260 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
261 ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL);
263 hr = S_OK;
265 else
267 if (This->lWaiting != 0)
268 ERR("Waiting: %d\n", This->lWaiting);
270 This->bCommitted = FALSE;
271 CloseHandle(This->hSemWaiting);
272 This->hSemWaiting = NULL;
274 hr = This->fnFree(iface);
275 if (FAILED(hr))
276 ERR("fnFree failed with error 0x%x\n", hr);
280 LeaveCriticalSection(This->pCritSect);
282 return hr;
285 static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags)
287 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
288 HRESULT hr = S_OK;
290 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
291 * The allocator might use these values to determine which buffer it retrieves */
293 TRACE("(%p)->(%p, %p, %p, %x)\n", This, pSample, pStartTime, pEndTime, dwFlags);
295 *pSample = NULL;
297 EnterCriticalSection(This->pCritSect);
298 if (!This->bCommitted || This->bDecommitQueued)
300 WARN("Not committed\n");
301 hr = VFW_E_NOT_COMMITTED;
303 else
304 ++This->lWaiting;
305 LeaveCriticalSection(This->pCritSect);
306 if (FAILED(hr))
307 return hr;
309 if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0)
311 EnterCriticalSection(This->pCritSect);
312 --This->lWaiting;
313 LeaveCriticalSection(This->pCritSect);
314 WARN("Timed out\n");
315 return VFW_E_TIMEOUT;
318 EnterCriticalSection(This->pCritSect);
320 --This->lWaiting;
321 if (!This->bCommitted)
322 hr = VFW_E_NOT_COMMITTED;
323 else if (This->bDecommitQueued)
324 hr = VFW_E_TIMEOUT;
325 else
327 struct list * free = list_head(&This->free_list);
328 list_remove(free);
329 list_add_head(&This->used_list, free);
331 *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry);
333 assert(((StdMediaSample2 *)*pSample)->ref == 0);
335 IMediaSample_AddRef(*pSample);
338 LeaveCriticalSection(This->pCritSect);
340 if (hr != S_OK)
341 WARN("%08x\n", hr);
342 return hr;
345 static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample)
347 BaseMemAllocator *This = impl_from_IMemAllocator(iface);
348 StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample;
349 HRESULT hr = S_OK;
351 TRACE("(%p)->(%p)\n", This, pSample);
353 /* FIXME: make sure that sample is currently on the used list */
355 /* FIXME: we should probably check the ref count on the sample before freeing
356 * it to make sure that it is not still in use */
357 EnterCriticalSection(This->pCritSect);
359 if (!This->bCommitted)
360 ERR("Releasing a buffer when the allocator is not committed?!?\n");
362 /* remove from used_list */
363 list_remove(&pStdSample->listentry);
365 list_add_head(&This->free_list, &pStdSample->listentry);
367 if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted)
369 HRESULT hrfree;
371 if (This->lWaiting != 0)
372 ERR("Waiting: %d\n", This->lWaiting);
374 This->bCommitted = FALSE;
375 This->bDecommitQueued = FALSE;
377 CloseHandle(This->hSemWaiting);
378 This->hSemWaiting = NULL;
380 if (FAILED(hrfree = This->fnFree(iface)))
381 ERR("fnFree failed with error 0x%x\n", hrfree);
384 LeaveCriticalSection(This->pCritSect);
386 /* notify a waiting thread that there is now a free buffer */
387 if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL))
389 ERR("ReleaseSemaphore failed with error %u\n", GetLastError());
390 hr = HRESULT_FROM_WIN32(GetLastError());
393 return hr;
396 static const IMemAllocatorVtbl BaseMemAllocator_VTable =
398 BaseMemAllocator_QueryInterface,
399 BaseMemAllocator_AddRef,
400 BaseMemAllocator_Release,
401 BaseMemAllocator_SetProperties,
402 BaseMemAllocator_GetProperties,
403 BaseMemAllocator_Commit,
404 BaseMemAllocator_Decommit,
405 BaseMemAllocator_GetBuffer,
406 BaseMemAllocator_ReleaseBuffer
409 static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample)
411 assert(pbBuffer && pParent && (cbBuffer > 0));
413 if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2))))
414 return E_OUTOFMEMORY;
416 (*ppSample)->lpvtbl = &StdMediaSample2_VTable;
417 (*ppSample)->ref = 0;
418 ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props));
420 /* NOTE: no need to AddRef as the parent is guaranteed to be around
421 * at least as long as us and we don't want to create circular
422 * dependencies on the ref count */
423 (*ppSample)->pParent = pParent;
424 (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
425 (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer;
426 (*ppSample)->props.pbBuffer = pbBuffer;
427 (*ppSample)->tMediaStart = INVALID_MEDIA_TIME;
428 (*ppSample)->tMediaEnd = 0;
430 return S_OK;
433 static void StdMediaSample2_Delete(StdMediaSample2 * This)
435 /* NOTE: does not remove itself from the list it belongs to */
436 CoTaskMemFree(This);
439 static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv)
441 StdMediaSample2 *This = (StdMediaSample2 *)iface;
442 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
444 *ppv = NULL;
446 if (IsEqualIID(riid, &IID_IUnknown))
447 *ppv = This;
448 else if (IsEqualIID(riid, &IID_IMediaSample))
449 *ppv = This;
450 else if (IsEqualIID(riid, &IID_IMediaSample2))
451 *ppv = This;
453 if (*ppv)
455 IUnknown_AddRef((IUnknown *)(*ppv));
456 return S_OK;
459 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
461 return E_NOINTERFACE;
464 static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface)
466 StdMediaSample2 *This = (StdMediaSample2 *)iface;
467 ULONG ref = InterlockedIncrement(&This->ref);
469 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
471 return ref;
474 static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface)
476 StdMediaSample2 *This = (StdMediaSample2 *)iface;
477 ULONG ref = InterlockedDecrement(&This->ref);
479 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
481 if (!ref)
483 if (This->pParent)
484 IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface);
485 else
486 StdMediaSample2_Delete(This);
487 return 0;
489 return ref;
492 static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer)
494 StdMediaSample2 *This = (StdMediaSample2 *)iface;
496 TRACE("(%p)->(%p)\n", iface, ppBuffer);
498 *ppBuffer = This->props.pbBuffer;
500 if (!*ppBuffer)
502 ERR("Requested an unlocked surface and trying to lock regardless\n");
503 return E_FAIL;
506 return S_OK;
509 static LONG WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface)
511 StdMediaSample2 *This = (StdMediaSample2 *)iface;
513 TRACE("StdMediaSample2_GetSize()\n");
515 return This->props.cbBuffer;
518 static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
520 HRESULT hr;
521 StdMediaSample2 *This = (StdMediaSample2 *)iface;
523 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
525 if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID))
526 hr = VFW_E_SAMPLE_TIME_NOT_SET;
527 else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID))
529 *pStart = This->props.tStart;
530 *pEnd = This->props.tStart + 1;
532 hr = VFW_S_NO_STOP_TIME;
534 else
536 *pStart = This->props.tStart;
537 *pEnd = This->props.tStop;
539 hr = S_OK;
542 return hr;
545 static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
547 StdMediaSample2 *This = (StdMediaSample2 *)iface;
549 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
551 if (pStart)
553 This->props.tStart = *pStart;
554 This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID;
556 else
557 This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID;
559 if (pEnd)
561 This->props.tStop = *pEnd;
562 This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID;
564 else
565 This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID;
567 return S_OK;
570 static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface)
572 StdMediaSample2 *This = (StdMediaSample2 *)iface;
574 TRACE("(%p)->()\n", iface);
576 return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE;
579 static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint)
581 StdMediaSample2 *This = (StdMediaSample2 *)iface;
583 TRACE("(%p)->(%s)\n", iface, bIsSyncPoint ? "TRUE" : "FALSE");
585 if (bIsSyncPoint)
586 This->props.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
587 else
588 This->props.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT;
590 return S_OK;
593 static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface)
595 StdMediaSample2 *This = (StdMediaSample2 *)iface;
597 TRACE("(%p)->()\n", iface);
599 return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE;
602 static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll)
604 StdMediaSample2 *This = (StdMediaSample2 *)iface;
606 TRACE("(%p)->(%s)\n", iface, bIsPreroll ? "TRUE" : "FALSE");
608 if (bIsPreroll)
609 This->props.dwSampleFlags |= AM_SAMPLE_PREROLL;
610 else
611 This->props.dwSampleFlags &= ~AM_SAMPLE_PREROLL;
613 return S_OK;
616 static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface)
618 StdMediaSample2 *This = (StdMediaSample2 *)iface;
620 TRACE("(%p)->()\n", iface);
622 return This->props.lActual;
625 static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len)
627 StdMediaSample2 *This = (StdMediaSample2 *)iface;
629 TRACE("(%p)->(%d)\n", iface, len);
631 if ((len > This->props.cbBuffer) || (len < 0))
633 WARN("Tried to set length to %d, while max is %d\n", len, This->props.cbBuffer);
634 return VFW_E_BUFFER_OVERFLOW;
636 else
638 This->props.lActual = len;
639 return S_OK;
643 static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType)
645 StdMediaSample2 *This = (StdMediaSample2 *)iface;
647 TRACE("(%p)->(%p)\n", iface, ppMediaType);
649 if (!This->props.pMediaType) {
650 /* Make sure we return a NULL pointer (required by native Quartz dll) */
651 if (ppMediaType)
652 *ppMediaType = NULL;
653 return S_FALSE;
656 if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
657 return E_OUTOFMEMORY;
659 return CopyMediaType(*ppMediaType, This->props.pMediaType);
662 static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType)
664 StdMediaSample2 *This = (StdMediaSample2 *)iface;
666 TRACE("(%p)->(%p)\n", iface, pMediaType);
668 if (This->props.pMediaType)
670 FreeMediaType(This->props.pMediaType);
671 This->props.pMediaType = NULL;
673 if (!pMediaType)
674 return S_FALSE;
675 if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
676 return E_OUTOFMEMORY;
678 return CopyMediaType(This->props.pMediaType, pMediaType);
681 static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface)
683 StdMediaSample2 *This = (StdMediaSample2 *)iface;
685 TRACE("(%p)->()\n", iface);
687 return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE;
690 static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity)
692 StdMediaSample2 *This = (StdMediaSample2 *)iface;
694 TRACE("(%p)->(%s)\n", iface, bIsDiscontinuity ? "TRUE" : "FALSE");
696 if (bIsDiscontinuity)
697 This->props.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
698 else
699 This->props.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY;
701 return S_OK;
704 static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
706 StdMediaSample2 *This = (StdMediaSample2 *)iface;
708 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
710 if (This->tMediaStart == INVALID_MEDIA_TIME)
711 return VFW_E_MEDIA_TIME_NOT_SET;
713 *pStart = This->tMediaStart;
714 *pEnd = This->tMediaEnd;
716 return S_OK;
719 static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
721 StdMediaSample2 *This = (StdMediaSample2 *)iface;
723 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
725 if (pStart)
726 This->tMediaStart = *pStart;
727 else
728 This->tMediaStart = INVALID_MEDIA_TIME;
730 if (pEnd)
731 This->tMediaEnd = *pEnd;
732 else
733 This->tMediaEnd = 0;
735 return S_OK;
738 static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties)
740 StdMediaSample2 *This = (StdMediaSample2 *)iface;
742 TRACE("(%p)->(%d, %p)\n", iface, cbProperties, pbProperties);
744 memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props)));
746 return S_OK;
749 static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties)
751 StdMediaSample2 *This = (StdMediaSample2 *)iface;
753 TRACE("(%p)->(%d, %p)\n", iface, cbProperties, pbProperties);
755 /* NOTE: pbBuffer and cbBuffer are read-only */
756 memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE));
758 return S_OK;
761 static const IMediaSample2Vtbl StdMediaSample2_VTable =
763 StdMediaSample2_QueryInterface,
764 StdMediaSample2_AddRef,
765 StdMediaSample2_Release,
766 StdMediaSample2_GetPointer,
767 StdMediaSample2_GetSize,
768 StdMediaSample2_GetTime,
769 StdMediaSample2_SetTime,
770 StdMediaSample2_IsSyncPoint,
771 StdMediaSample2_SetSyncPoint,
772 StdMediaSample2_IsPreroll,
773 StdMediaSample2_SetPreroll,
774 StdMediaSample2_GetActualDataLength,
775 StdMediaSample2_SetActualDataLength,
776 StdMediaSample2_GetMediaType,
777 StdMediaSample2_SetMediaType,
778 StdMediaSample2_IsDiscontinuity,
779 StdMediaSample2_SetDiscontinuity,
780 StdMediaSample2_GetMediaTime,
781 StdMediaSample2_SetMediaTime,
782 StdMediaSample2_GetProperties,
783 StdMediaSample2_SetProperties
786 typedef struct StdMemAllocator
788 BaseMemAllocator base;
789 CRITICAL_SECTION csState;
790 LPVOID pMemory;
791 } StdMemAllocator;
793 static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface)
795 StdMemAllocator *This = (StdMemAllocator *)iface;
796 StdMediaSample2 * pSample = NULL;
797 SYSTEM_INFO si;
798 LONG i;
800 assert(list_empty(&This->base.free_list));
802 /* check alignment */
803 GetSystemInfo(&si);
805 /* we do not allow a courser alignment than the OS page size */
806 if ((si.dwPageSize % This->base.props.cbAlign) != 0)
807 return VFW_E_BADALIGN;
809 /* FIXME: each sample has to have its buffer start on the right alignment.
810 * We don't do this at the moment */
812 /* allocate memory */
813 This->pMemory = VirtualAlloc(NULL, (This->base.props.cbBuffer + This->base.props.cbPrefix) * This->base.props.cBuffers, MEM_COMMIT, PAGE_READWRITE);
815 if (!This->pMemory)
816 return E_OUTOFMEMORY;
818 for (i = This->base.props.cBuffers - 1; i >= 0; i--)
820 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
821 BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.props.cbBuffer + This->base.props.cbPrefix) + This->base.props.cbPrefix;
823 StdMediaSample2_Construct(pbBuffer, This->base.props.cbBuffer, iface, &pSample);
825 list_add_head(&This->base.free_list, &pSample->listentry);
828 return S_OK;
831 static HRESULT StdMemAllocator_Free(IMemAllocator * iface)
833 StdMemAllocator *This = (StdMemAllocator *)iface;
834 struct list * cursor;
836 if (!list_empty(&This->base.used_list))
838 WARN("Freeing allocator with outstanding samples!\n");
839 while ((cursor = list_head(&This->base.used_list)) != NULL)
841 StdMediaSample2 *pSample;
842 list_remove(cursor);
843 pSample = LIST_ENTRY(cursor, StdMediaSample2, listentry);
844 pSample->pParent = NULL;
848 while ((cursor = list_head(&This->base.free_list)) != NULL)
850 list_remove(cursor);
851 StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry));
854 /* free memory */
855 if (!VirtualFree(This->pMemory, 0, MEM_RELEASE))
857 ERR("Couldn't free memory. Error: %u\n", GetLastError());
858 return HRESULT_FROM_WIN32(GetLastError());
861 return S_OK;
864 static void StdMemAllocator_Destroy(IMemAllocator *iface)
866 StdMemAllocator *This = (StdMemAllocator *)iface;
868 This->csState.DebugInfo->Spare[0] = 0;
869 DeleteCriticalSection(&This->csState);
871 CoTaskMemFree(This);
874 HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv)
876 StdMemAllocator * pMemAlloc;
877 HRESULT hr;
879 *ppv = NULL;
881 if (lpUnkOuter)
882 return CLASS_E_NOAGGREGATION;
884 if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc))))
885 return E_OUTOFMEMORY;
887 InitializeCriticalSection(&pMemAlloc->csState);
888 pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StdMemAllocator.csState");
890 pMemAlloc->pMemory = NULL;
892 if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, NULL, NULL, NULL, StdMemAllocator_Destroy, &pMemAlloc->csState, &pMemAlloc->base)))
893 *ppv = pMemAlloc;
894 else
895 CoTaskMemFree(pMemAlloc);
897 return hr;