winepulse.drv: add a pulseaudio driver
[wine/hacks.git] / dlls / quartz / memallocator.c
bloba1c4473238fdad38f5bca1c65dc5cddd603faa0d
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 const IMemAllocatorVtbl * lpVtbl;
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 const IMemAllocatorVtbl BaseMemAllocator_VTable;
56 static const IMediaSample2Vtbl StdMediaSample2_VTable;
58 #define AM_SAMPLE2_PROP_SIZE_WRITABLE FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer)
60 #define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff)
62 static HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *),
63 HRESULT (* fnFree)(IMemAllocator *),
64 HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *),
65 HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD),
66 HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *),
67 void (* fnDestroyed)(IMemAllocator *),
68 CRITICAL_SECTION *pCritSect,
69 BaseMemAllocator * pMemAlloc)
71 assert(fnAlloc && fnFree && fnDestroyed);
73 pMemAlloc->lpVtbl = &BaseMemAllocator_VTable;
75 pMemAlloc->ref = 1;
76 ZeroMemory(&pMemAlloc->props, sizeof(pMemAlloc->props));
77 list_init(&pMemAlloc->free_list);
78 list_init(&pMemAlloc->used_list);
79 pMemAlloc->fnAlloc = fnAlloc;
80 pMemAlloc->fnFree = fnFree;
81 pMemAlloc->fnVerify = fnVerify;
82 pMemAlloc->fnBufferPrepare = fnBufferPrepare;
83 pMemAlloc->fnBufferReleased = fnBufferReleased;
84 pMemAlloc->fnDestroyed = fnDestroyed;
85 pMemAlloc->bDecommitQueued = FALSE;
86 pMemAlloc->bCommitted = FALSE;
87 pMemAlloc->hSemWaiting = NULL;
88 pMemAlloc->lWaiting = 0;
89 pMemAlloc->pCritSect = pCritSect;
91 return S_OK;
94 static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv)
96 BaseMemAllocator *This = (BaseMemAllocator *)iface;
97 TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv);
99 *ppv = NULL;
101 if (IsEqualIID(riid, &IID_IUnknown))
102 *ppv = This;
103 else if (IsEqualIID(riid, &IID_IMemAllocator))
104 *ppv = This;
106 if (*ppv)
108 IUnknown_AddRef((IUnknown *)(*ppv));
109 return S_OK;
112 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
114 return E_NOINTERFACE;
117 static ULONG WINAPI BaseMemAllocator_AddRef(IMemAllocator * iface)
119 BaseMemAllocator *This = (BaseMemAllocator *)iface;
120 ULONG ref = InterlockedIncrement(&This->ref);
122 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
124 return ref;
127 static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface)
129 BaseMemAllocator *This = (BaseMemAllocator *)iface;
130 ULONG ref = InterlockedDecrement(&This->ref);
132 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
134 if (!ref)
136 CloseHandle(This->hSemWaiting);
137 if (This->bCommitted)
138 This->fnFree(iface);
140 This->fnDestroyed(iface);
141 return 0;
143 return ref;
146 static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual)
148 BaseMemAllocator *This = (BaseMemAllocator *)iface;
149 HRESULT hr;
151 TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual);
153 EnterCriticalSection(This->pCritSect);
155 if (!list_empty(&This->used_list))
156 hr = VFW_E_BUFFERS_OUTSTANDING;
157 else if (This->bCommitted)
158 hr = VFW_E_ALREADY_COMMITTED;
159 else if (pRequest->cbAlign == 0)
160 hr = VFW_E_BADALIGN;
161 else
163 if (This->fnVerify)
164 hr = This->fnVerify(iface, pRequest);
165 else
166 hr = S_OK;
168 if (SUCCEEDED(hr))
169 This->props = *pRequest;
171 *pActual = This->props;
174 LeaveCriticalSection(This->pCritSect);
176 return hr;
179 static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps)
181 BaseMemAllocator *This = (BaseMemAllocator *)iface;
182 HRESULT hr = S_OK;
184 TRACE("(%p)->(%p)\n", This, pProps);
186 EnterCriticalSection(This->pCritSect);
188 memcpy(pProps, &This->props, sizeof(*pProps));
190 LeaveCriticalSection(This->pCritSect);
192 return hr;
195 static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface)
197 BaseMemAllocator *This = (BaseMemAllocator *)iface;
198 HRESULT hr;
200 TRACE("(%p)->()\n", This);
202 EnterCriticalSection(This->pCritSect);
204 if (!This->props.cbAlign)
205 hr = VFW_E_BADALIGN;
206 else if (!This->props.cbBuffer)
207 hr = VFW_E_SIZENOTSET;
208 else if (!This->props.cBuffers)
209 hr = VFW_E_BUFFER_NOTSET;
210 else if (This->bDecommitQueued && This->bCommitted)
212 This->bDecommitQueued = FALSE;
213 hr = S_OK;
215 else if (This->bCommitted)
216 hr = S_OK;
217 else
219 if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->props.cBuffers, This->props.cBuffers, NULL)))
221 ERR("Couldn't create semaphore (error was %u)\n", GetLastError());
222 hr = HRESULT_FROM_WIN32(GetLastError());
224 else
226 hr = This->fnAlloc(iface);
227 if (SUCCEEDED(hr))
228 This->bCommitted = TRUE;
229 else
230 ERR("fnAlloc failed with error 0x%x\n", hr);
234 LeaveCriticalSection(This->pCritSect);
236 return hr;
239 static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface)
241 BaseMemAllocator *This = (BaseMemAllocator *)iface;
242 HRESULT hr;
244 TRACE("(%p)->()\n", This);
246 EnterCriticalSection(This->pCritSect);
248 if (!This->bCommitted)
249 hr = S_OK;
250 else
252 if (!list_empty(&This->used_list))
254 This->bDecommitQueued = TRUE;
255 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
256 ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL);
258 hr = S_OK;
260 else
262 if (This->lWaiting != 0)
263 ERR("Waiting: %d\n", This->lWaiting);
265 This->bCommitted = FALSE;
266 CloseHandle(This->hSemWaiting);
267 This->hSemWaiting = NULL;
269 hr = This->fnFree(iface);
270 if (FAILED(hr))
271 ERR("fnFree failed with error 0x%x\n", hr);
275 LeaveCriticalSection(This->pCritSect);
277 return hr;
280 static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags)
282 BaseMemAllocator *This = (BaseMemAllocator *)iface;
283 HRESULT hr = S_OK;
285 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
286 * The allocator might use these values to determine which buffer it retrieves */
288 TRACE("(%p)->(%p, %p, %p, %x)\n", This, pSample, pStartTime, pEndTime, dwFlags);
290 *pSample = NULL;
292 EnterCriticalSection(This->pCritSect);
293 if (!This->bCommitted || This->bDecommitQueued)
295 WARN("Not committed\n");
296 hr = VFW_E_NOT_COMMITTED;
298 else
299 ++This->lWaiting;
300 LeaveCriticalSection(This->pCritSect);
301 if (FAILED(hr))
302 return hr;
304 if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0)
306 EnterCriticalSection(This->pCritSect);
307 --This->lWaiting;
308 LeaveCriticalSection(This->pCritSect);
309 WARN("Timed out\n");
310 return VFW_E_TIMEOUT;
313 EnterCriticalSection(This->pCritSect);
315 --This->lWaiting;
316 if (!This->bCommitted)
317 hr = VFW_E_NOT_COMMITTED;
318 else if (This->bDecommitQueued)
319 hr = VFW_E_TIMEOUT;
320 else
322 struct list * free = list_head(&This->free_list);
323 list_remove(free);
324 list_add_head(&This->used_list, free);
326 *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry);
328 assert(((StdMediaSample2 *)*pSample)->ref == 0);
330 IMediaSample_AddRef(*pSample);
333 LeaveCriticalSection(This->pCritSect);
335 if (hr != S_OK)
336 WARN("%08x\n", hr);
337 return hr;
340 static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample)
342 BaseMemAllocator *This = (BaseMemAllocator *)iface;
343 StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample;
344 HRESULT hr = S_OK;
346 TRACE("(%p)->(%p)\n", This, pSample);
348 /* FIXME: make sure that sample is currently on the used list */
350 /* FIXME: we should probably check the ref count on the sample before freeing
351 * it to make sure that it is not still in use */
352 EnterCriticalSection(This->pCritSect);
354 if (!This->bCommitted)
355 ERR("Releasing a buffer when the allocator is not committed?!?\n");
357 /* remove from used_list */
358 list_remove(&pStdSample->listentry);
360 list_add_head(&This->free_list, &pStdSample->listentry);
362 if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted)
364 HRESULT hrfree;
366 if (This->lWaiting != 0)
367 ERR("Waiting: %d\n", This->lWaiting);
369 This->bCommitted = FALSE;
370 This->bDecommitQueued = FALSE;
372 CloseHandle(This->hSemWaiting);
373 This->hSemWaiting = NULL;
375 if (FAILED(hrfree = This->fnFree(iface)))
376 ERR("fnFree failed with error 0x%x\n", hrfree);
379 LeaveCriticalSection(This->pCritSect);
381 /* notify a waiting thread that there is now a free buffer */
382 if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL))
384 ERR("ReleaseSemaphore failed with error %u\n", GetLastError());
385 hr = HRESULT_FROM_WIN32(GetLastError());
388 return hr;
391 static const IMemAllocatorVtbl BaseMemAllocator_VTable =
393 BaseMemAllocator_QueryInterface,
394 BaseMemAllocator_AddRef,
395 BaseMemAllocator_Release,
396 BaseMemAllocator_SetProperties,
397 BaseMemAllocator_GetProperties,
398 BaseMemAllocator_Commit,
399 BaseMemAllocator_Decommit,
400 BaseMemAllocator_GetBuffer,
401 BaseMemAllocator_ReleaseBuffer
404 static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample)
406 assert(pbBuffer && pParent && (cbBuffer > 0));
408 if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2))))
409 return E_OUTOFMEMORY;
411 (*ppSample)->lpvtbl = &StdMediaSample2_VTable;
412 (*ppSample)->ref = 0;
413 ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props));
415 /* NOTE: no need to AddRef as the parent is guaranteed to be around
416 * at least as long as us and we don't want to create circular
417 * dependencies on the ref count */
418 (*ppSample)->pParent = pParent;
419 (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
420 (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer;
421 (*ppSample)->props.pbBuffer = pbBuffer;
422 (*ppSample)->tMediaStart = INVALID_MEDIA_TIME;
423 (*ppSample)->tMediaEnd = 0;
425 return S_OK;
428 static void StdMediaSample2_Delete(StdMediaSample2 * This)
430 /* NOTE: does not remove itself from the list it belongs to */
431 CoTaskMemFree(This);
434 static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv)
436 StdMediaSample2 *This = (StdMediaSample2 *)iface;
437 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
439 *ppv = NULL;
441 if (IsEqualIID(riid, &IID_IUnknown))
442 *ppv = This;
443 else if (IsEqualIID(riid, &IID_IMediaSample))
444 *ppv = This;
445 else if (IsEqualIID(riid, &IID_IMediaSample2))
446 *ppv = This;
448 if (*ppv)
450 IUnknown_AddRef((IUnknown *)(*ppv));
451 return S_OK;
454 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
456 return E_NOINTERFACE;
459 static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface)
461 StdMediaSample2 *This = (StdMediaSample2 *)iface;
462 ULONG ref = InterlockedIncrement(&This->ref);
464 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
466 return ref;
469 static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface)
471 StdMediaSample2 *This = (StdMediaSample2 *)iface;
472 ULONG ref = InterlockedDecrement(&This->ref);
474 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
476 if (!ref)
478 if (This->pParent)
479 IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface);
480 else
481 StdMediaSample2_Delete(This);
482 return 0;
484 return ref;
487 static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer)
489 StdMediaSample2 *This = (StdMediaSample2 *)iface;
491 TRACE("(%p)->(%p)\n", iface, ppBuffer);
493 *ppBuffer = This->props.pbBuffer;
495 if (!*ppBuffer)
497 ERR("Requested an unlocked surface and trying to lock regardless\n");
498 return E_FAIL;
501 return S_OK;
504 static LONG WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface)
506 StdMediaSample2 *This = (StdMediaSample2 *)iface;
508 TRACE("StdMediaSample2_GetSize()\n");
510 return This->props.cbBuffer;
513 static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
515 HRESULT hr;
516 StdMediaSample2 *This = (StdMediaSample2 *)iface;
518 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
520 if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID))
521 hr = VFW_E_SAMPLE_TIME_NOT_SET;
522 else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID))
524 *pStart = This->props.tStart;
525 *pEnd = This->props.tStart + 1;
527 hr = VFW_S_NO_STOP_TIME;
529 else
531 *pStart = This->props.tStart;
532 *pEnd = This->props.tStop;
534 hr = S_OK;
537 return hr;
540 static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
542 StdMediaSample2 *This = (StdMediaSample2 *)iface;
544 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
546 if (pStart)
548 This->props.tStart = *pStart;
549 This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID;
551 else
552 This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID;
554 if (pEnd)
556 This->props.tStop = *pEnd;
557 This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID;
559 else
560 This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID;
562 return S_OK;
565 static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface)
567 StdMediaSample2 *This = (StdMediaSample2 *)iface;
569 TRACE("(%p)->()\n", iface);
571 return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE;
574 static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint)
576 StdMediaSample2 *This = (StdMediaSample2 *)iface;
578 TRACE("(%p)->(%s)\n", iface, bIsSyncPoint ? "TRUE" : "FALSE");
580 if (bIsSyncPoint)
581 This->props.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
582 else
583 This->props.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT;
585 return S_OK;
588 static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface)
590 StdMediaSample2 *This = (StdMediaSample2 *)iface;
592 TRACE("(%p)->()\n", iface);
594 return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE;
597 static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll)
599 StdMediaSample2 *This = (StdMediaSample2 *)iface;
601 TRACE("(%p)->(%s)\n", iface, bIsPreroll ? "TRUE" : "FALSE");
603 if (bIsPreroll)
604 This->props.dwSampleFlags |= AM_SAMPLE_PREROLL;
605 else
606 This->props.dwSampleFlags &= ~AM_SAMPLE_PREROLL;
608 return S_OK;
611 static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface)
613 StdMediaSample2 *This = (StdMediaSample2 *)iface;
615 TRACE("(%p)->()\n", iface);
617 return This->props.lActual;
620 static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len)
622 StdMediaSample2 *This = (StdMediaSample2 *)iface;
624 TRACE("(%p)->(%d)\n", iface, len);
626 if ((len > This->props.cbBuffer) || (len < 0))
628 WARN("Tried to set length to %d, while max is %d\n", len, This->props.cbBuffer);
629 return VFW_E_BUFFER_OVERFLOW;
631 else
633 This->props.lActual = len;
634 return S_OK;
638 static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType)
640 StdMediaSample2 *This = (StdMediaSample2 *)iface;
642 TRACE("(%p)->(%p)\n", iface, ppMediaType);
644 if (!This->props.pMediaType) {
645 /* Make sure we return a NULL pointer (required by native Quartz dll) */
646 if (ppMediaType)
647 *ppMediaType = NULL;
648 return S_FALSE;
651 if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
652 return E_OUTOFMEMORY;
654 return CopyMediaType(*ppMediaType, This->props.pMediaType);
657 static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType)
659 StdMediaSample2 *This = (StdMediaSample2 *)iface;
661 TRACE("(%p)->(%p)\n", iface, pMediaType);
663 if (This->props.pMediaType)
664 FreeMediaType(This->props.pMediaType);
665 else if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
666 return E_OUTOFMEMORY;
668 return CopyMediaType(This->props.pMediaType, pMediaType);
671 static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface)
673 StdMediaSample2 *This = (StdMediaSample2 *)iface;
675 TRACE("(%p)->()\n", iface);
677 return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE;
680 static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity)
682 StdMediaSample2 *This = (StdMediaSample2 *)iface;
684 TRACE("(%p)->(%s)\n", iface, bIsDiscontinuity ? "TRUE" : "FALSE");
686 if (bIsDiscontinuity)
687 This->props.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
688 else
689 This->props.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY;
691 return S_OK;
694 static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
696 StdMediaSample2 *This = (StdMediaSample2 *)iface;
698 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
700 if (This->tMediaStart == INVALID_MEDIA_TIME)
701 return VFW_E_MEDIA_TIME_NOT_SET;
703 *pStart = This->tMediaStart;
704 *pEnd = This->tMediaEnd;
706 return E_NOTIMPL;
709 static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
711 StdMediaSample2 *This = (StdMediaSample2 *)iface;
713 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd);
715 if (pStart)
716 This->tMediaStart = *pStart;
717 else
718 This->tMediaStart = INVALID_MEDIA_TIME;
720 if (pEnd)
721 This->tMediaEnd = *pEnd;
722 else
723 This->tMediaEnd = 0;
725 return S_OK;
728 static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties)
730 StdMediaSample2 *This = (StdMediaSample2 *)iface;
732 TRACE("(%p)->(%d, %p)\n", iface, cbProperties, pbProperties);
734 memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props)));
736 return S_OK;
739 static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties)
741 StdMediaSample2 *This = (StdMediaSample2 *)iface;
743 TRACE("(%p)->(%d, %p)\n", iface, cbProperties, pbProperties);
745 /* NOTE: pbBuffer and cbBuffer are read-only */
746 memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE));
748 return S_OK;
751 static const IMediaSample2Vtbl StdMediaSample2_VTable =
753 StdMediaSample2_QueryInterface,
754 StdMediaSample2_AddRef,
755 StdMediaSample2_Release,
756 StdMediaSample2_GetPointer,
757 StdMediaSample2_GetSize,
758 StdMediaSample2_GetTime,
759 StdMediaSample2_SetTime,
760 StdMediaSample2_IsSyncPoint,
761 StdMediaSample2_SetSyncPoint,
762 StdMediaSample2_IsPreroll,
763 StdMediaSample2_SetPreroll,
764 StdMediaSample2_GetActualDataLength,
765 StdMediaSample2_SetActualDataLength,
766 StdMediaSample2_GetMediaType,
767 StdMediaSample2_SetMediaType,
768 StdMediaSample2_IsDiscontinuity,
769 StdMediaSample2_SetDiscontinuity,
770 StdMediaSample2_GetMediaTime,
771 StdMediaSample2_SetMediaTime,
772 StdMediaSample2_GetProperties,
773 StdMediaSample2_SetProperties
776 typedef struct StdMemAllocator
778 BaseMemAllocator base;
779 CRITICAL_SECTION csState;
780 LPVOID pMemory;
781 } StdMemAllocator;
783 static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface)
785 StdMemAllocator *This = (StdMemAllocator *)iface;
786 StdMediaSample2 * pSample = NULL;
787 SYSTEM_INFO si;
788 LONG i;
790 assert(list_empty(&This->base.free_list));
792 /* check alignment */
793 GetSystemInfo(&si);
795 /* we do not allow a courser alignment than the OS page size */
796 if ((si.dwPageSize % This->base.props.cbAlign) != 0)
797 return VFW_E_BADALIGN;
799 /* FIXME: each sample has to have its buffer start on the right alignment.
800 * We don't do this at the moment */
802 /* allocate memory */
803 This->pMemory = VirtualAlloc(NULL, (This->base.props.cbBuffer + This->base.props.cbPrefix) * This->base.props.cBuffers, MEM_COMMIT, PAGE_READWRITE);
805 for (i = This->base.props.cBuffers - 1; i >= 0; i--)
807 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
808 BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.props.cbBuffer + This->base.props.cbPrefix) + This->base.props.cbPrefix;
810 StdMediaSample2_Construct(pbBuffer, This->base.props.cbBuffer, iface, &pSample);
812 list_add_head(&This->base.free_list, &pSample->listentry);
815 return S_OK;
818 static HRESULT StdMemAllocator_Free(IMemAllocator * iface)
820 StdMemAllocator *This = (StdMemAllocator *)iface;
821 struct list * cursor;
823 if (!list_empty(&This->base.used_list))
825 WARN("Freeing allocator with outstanding samples!\n");
826 while ((cursor = list_head(&This->base.used_list)) != NULL)
828 StdMediaSample2 *pSample;
829 list_remove(cursor);
830 pSample = LIST_ENTRY(cursor, StdMediaSample2, listentry);
831 pSample->pParent = NULL;
835 while ((cursor = list_head(&This->base.free_list)) != NULL)
837 list_remove(cursor);
838 StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry));
841 /* free memory */
842 if (!VirtualFree(This->pMemory, 0, MEM_RELEASE))
844 ERR("Couldn't free memory. Error: %u\n", GetLastError());
845 return HRESULT_FROM_WIN32(GetLastError());
848 return S_OK;
851 static void StdMemAllocator_Destroy(IMemAllocator *iface)
853 StdMemAllocator *This = (StdMemAllocator *)iface;
855 This->csState.DebugInfo->Spare[0] = 0;
856 DeleteCriticalSection(&This->csState);
858 CoTaskMemFree(This);
861 HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv)
863 StdMemAllocator * pMemAlloc;
864 HRESULT hr;
866 *ppv = NULL;
868 if (lpUnkOuter)
869 return CLASS_E_NOAGGREGATION;
871 if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc))))
872 return E_OUTOFMEMORY;
874 InitializeCriticalSection(&pMemAlloc->csState);
875 pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StdMemAllocator.csState");
877 pMemAlloc->pMemory = NULL;
879 if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, NULL, NULL, NULL, StdMemAllocator_Destroy, &pMemAlloc->csState, &pMemAlloc->base)))
880 *ppv = pMemAlloc;
881 else
882 CoTaskMemFree(pMemAlloc);
884 return hr;