quartz: Make the memory allocator emit more warnings and fix race condition.
[wine/wine64.git] / dlls / quartz / memallocator.c
blob2ee8d71cc8c8842edd5dd20f489102f57358629e
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 void dump_AM_SAMPLE2_PROPERTIES(const AM_SAMPLE2_PROPERTIES * pProps)
36 if (!pProps)
38 TRACE("AM_SAMPLE2_PROPERTIES: (null)\n");
39 return;
41 TRACE("\tcbData: %d\n", pProps->cbData);
42 TRACE("\tdwTypeSpecificFlags: 0x%8x\n", pProps->dwTypeSpecificFlags);
43 TRACE("\tdwSampleFlags: 0x%8x\n", pProps->dwSampleFlags);
44 TRACE("\tlActual: %d\n", pProps->lActual);
45 TRACE("\ttStart: %x%08x%s\n", (LONG)(pProps->tStart >> 32), (LONG)pProps->tStart, pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? "" : " (not valid)");
46 TRACE("\ttStop: %x%08x%s\n", (LONG)(pProps->tStop >> 32), (LONG)pProps->tStop, pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? "" : " (not valid)");
47 TRACE("\tdwStreamId: 0x%x\n", pProps->dwStreamId);
48 TRACE("\tpMediaType: %p\n", pProps->pMediaType);
49 TRACE("\tpbBuffer: %p\n", pProps->pbBuffer);
50 TRACE("\tcbBuffer: %d\n", pProps->cbBuffer);
53 static const IMemAllocatorVtbl BaseMemAllocator_VTable;
54 static const IMediaSample2Vtbl StdMediaSample2_VTable;
56 #define AM_SAMPLE2_PROP_SIZE_WRITABLE (unsigned int)(&((AM_SAMPLE2_PROPERTIES *)0)->pbBuffer)
58 #define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff)
60 HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *),
61 HRESULT (* fnFree)(IMemAllocator *),
62 HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *),
63 HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD),
64 HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *),
65 void (* fnDestroyed)(IMemAllocator *),
66 CRITICAL_SECTION *pCritSect,
67 BaseMemAllocator * pMemAlloc)
69 assert(fnAlloc && fnFree && fnDestroyed);
71 pMemAlloc->lpVtbl = &BaseMemAllocator_VTable;
73 pMemAlloc->ref = 1;
74 ZeroMemory(&pMemAlloc->props, sizeof(pMemAlloc->props));
75 list_init(&pMemAlloc->free_list);
76 list_init(&pMemAlloc->used_list);
77 pMemAlloc->fnAlloc = fnAlloc;
78 pMemAlloc->fnFree = fnFree;
79 pMemAlloc->fnVerify = fnVerify;
80 pMemAlloc->fnBufferPrepare = fnBufferPrepare;
81 pMemAlloc->fnBufferReleased = fnBufferReleased;
82 pMemAlloc->fnDestroyed = fnDestroyed;
83 pMemAlloc->bDecommitQueued = FALSE;
84 pMemAlloc->bCommitted = FALSE;
85 pMemAlloc->hSemWaiting = NULL;
86 pMemAlloc->lWaiting = 0;
87 pMemAlloc->pCritSect = pCritSect;
89 return S_OK;
92 static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv)
94 BaseMemAllocator *This = (BaseMemAllocator *)iface;
95 TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv);
97 *ppv = NULL;
99 if (IsEqualIID(riid, &IID_IUnknown))
100 *ppv = (LPVOID)This;
101 else if (IsEqualIID(riid, &IID_IMemAllocator))
102 *ppv = (LPVOID)This;
104 if (*ppv)
106 IUnknown_AddRef((IUnknown *)(*ppv));
107 return S_OK;
110 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
112 return E_NOINTERFACE;
115 static ULONG WINAPI BaseMemAllocator_AddRef(IMemAllocator * iface)
117 BaseMemAllocator *This = (BaseMemAllocator *)iface;
118 ULONG ref = InterlockedIncrement(&This->ref);
120 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
122 return ref;
125 static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface)
127 BaseMemAllocator *This = (BaseMemAllocator *)iface;
128 ULONG ref = InterlockedDecrement(&This->ref);
130 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
132 if (!ref)
134 CloseHandle(This->hSemWaiting);
135 if (This->bCommitted)
136 This->fnFree(iface);
138 This->fnDestroyed(iface);
139 return 0;
141 return ref;
144 static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual)
146 BaseMemAllocator *This = (BaseMemAllocator *)iface;
147 HRESULT hr;
149 TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual);
151 EnterCriticalSection(This->pCritSect);
153 if (!list_empty(&This->used_list))
154 hr = VFW_E_BUFFERS_OUTSTANDING;
155 else if (This->bCommitted)
156 hr = VFW_E_ALREADY_COMMITTED;
157 else if (pRequest->cbAlign == 0)
158 hr = VFW_E_BADALIGN;
159 else
161 if (This->fnVerify)
162 hr = This->fnVerify(iface, pRequest);
163 else
164 hr = S_OK;
166 if (SUCCEEDED(hr))
167 This->props = *pRequest;
169 *pActual = This->props;
172 LeaveCriticalSection(This->pCritSect);
174 return hr;
177 static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps)
179 BaseMemAllocator *This = (BaseMemAllocator *)iface;
180 HRESULT hr = S_OK;
182 TRACE("(%p)->(%p)\n", This, pProps);
184 EnterCriticalSection(This->pCritSect);
186 memcpy(pProps, &This->props, sizeof(*pProps));
188 LeaveCriticalSection(This->pCritSect);
190 return hr;
193 static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface)
195 BaseMemAllocator *This = (BaseMemAllocator *)iface;
196 HRESULT hr;
198 TRACE("(%p)->()\n", This);
200 EnterCriticalSection(This->pCritSect);
202 if (!This->props.cbAlign)
203 hr = VFW_E_BADALIGN;
204 else if (!This->props.cbBuffer)
205 hr = VFW_E_SIZENOTSET;
206 else if (!This->props.cBuffers)
207 hr = VFW_E_BUFFER_NOTSET;
208 else if (This->bDecommitQueued && This->bCommitted)
210 This->bDecommitQueued = FALSE;
211 hr = S_OK;
213 else if (This->bCommitted)
214 hr = S_OK;
215 else
217 if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->props.cBuffers, This->props.cBuffers, NULL)))
219 ERR("Couldn't create semaphore (error was %u)\n", GetLastError());
220 hr = HRESULT_FROM_WIN32(GetLastError());
222 else
224 hr = This->fnAlloc(iface);
225 if (SUCCEEDED(hr))
226 This->bCommitted = TRUE;
227 else
228 ERR("fnAlloc failed with error 0x%x\n", hr);
232 LeaveCriticalSection(This->pCritSect);
234 return hr;
237 static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface)
239 BaseMemAllocator *This = (BaseMemAllocator *)iface;
240 HRESULT hr;
242 TRACE("(%p)->()\n", This);
244 EnterCriticalSection(This->pCritSect);
246 if (!This->bCommitted)
247 hr = S_OK;
248 else
250 if (!list_empty(&This->used_list))
252 This->bDecommitQueued = TRUE;
253 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
254 ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL);
256 hr = S_OK;
258 else
260 if (This->lWaiting != 0)
261 ERR("Waiting: %d\n", This->lWaiting);
263 This->bCommitted = FALSE;
264 CloseHandle(This->hSemWaiting);
265 This->hSemWaiting = NULL;
267 hr = This->fnFree(iface);
268 if (FAILED(hr))
269 ERR("fnFree failed with error 0x%x\n", hr);
273 LeaveCriticalSection(This->pCritSect);
275 return hr;
278 static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags)
280 BaseMemAllocator *This = (BaseMemAllocator *)iface;
281 HRESULT hr = S_OK;
283 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
284 * The allocator might use these values to determine which buffer it retrieves */
286 TRACE("(%p)->(%p, %p, %p, %x)\n", This, pSample, pStartTime, pEndTime, dwFlags);
288 *pSample = NULL;
290 EnterCriticalSection(This->pCritSect);
291 if (!This->bCommitted || This->bDecommitQueued)
293 WARN("Not committed\n");
294 hr = VFW_E_NOT_COMMITTED;
296 else
297 ++This->lWaiting;
298 LeaveCriticalSection(This->pCritSect);
299 if (FAILED(hr))
300 return hr;
302 if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0)
304 EnterCriticalSection(This->pCritSect);
305 --This->lWaiting;
306 LeaveCriticalSection(This->pCritSect);
307 WARN("Timed out\n");
308 return VFW_E_TIMEOUT;
311 EnterCriticalSection(This->pCritSect);
313 --This->lWaiting;
314 if (!This->bCommitted)
315 hr = VFW_E_NOT_COMMITTED;
316 else if (This->bDecommitQueued)
317 hr = VFW_E_TIMEOUT;
318 else
320 struct list * free = list_head(&This->free_list);
321 list_remove(free);
322 list_add_head(&This->used_list, free);
324 *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry);
326 assert(((StdMediaSample2 *)*pSample)->ref == 0);
328 IMediaSample_AddRef(*pSample);
331 LeaveCriticalSection(This->pCritSect);
333 if (hr != S_OK)
334 WARN("%08x\n", hr);
335 return hr;
338 static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample)
340 BaseMemAllocator *This = (BaseMemAllocator *)iface;
341 StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample;
342 HRESULT hr = S_OK;
344 TRACE("(%p)->(%p)\n", This, pSample);
346 /* FIXME: make sure that sample is currently on the used list */
348 /* FIXME: we should probably check the ref count on the sample before freeing
349 * it to make sure that it is not still in use */
350 EnterCriticalSection(This->pCritSect);
352 if (!This->bCommitted)
353 ERR("Releasing a buffer when the allocator is not committed?!?\n");
355 /* remove from used_list */
356 list_remove(&pStdSample->listentry);
358 list_add_head(&This->free_list, &pStdSample->listentry);
360 if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted)
362 HRESULT hrfree;
364 if (This->lWaiting != 0)
365 ERR("Waiting: %d\n", This->lWaiting);
367 This->bCommitted = FALSE;
368 This->bDecommitQueued = FALSE;
370 CloseHandle(This->hSemWaiting);
371 This->hSemWaiting = NULL;
373 if (FAILED(hrfree = This->fnFree(iface)))
374 ERR("fnFree failed with error 0x%x\n", hrfree);
377 LeaveCriticalSection(This->pCritSect);
379 /* notify a waiting thread that there is now a free buffer */
380 if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL))
382 ERR("ReleaseSemaphore failed with error %u\n", GetLastError());
383 hr = HRESULT_FROM_WIN32(GetLastError());
386 return hr;
389 static const IMemAllocatorVtbl BaseMemAllocator_VTable =
391 BaseMemAllocator_QueryInterface,
392 BaseMemAllocator_AddRef,
393 BaseMemAllocator_Release,
394 BaseMemAllocator_SetProperties,
395 BaseMemAllocator_GetProperties,
396 BaseMemAllocator_Commit,
397 BaseMemAllocator_Decommit,
398 BaseMemAllocator_GetBuffer,
399 BaseMemAllocator_ReleaseBuffer
402 HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample)
404 assert(pbBuffer && pParent && (cbBuffer > 0));
406 if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2))))
407 return E_OUTOFMEMORY;
409 (*ppSample)->lpvtbl = &StdMediaSample2_VTable;
410 (*ppSample)->ref = 0;
411 ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props));
413 /* NOTE: no need to AddRef as the parent is guaranteed to be around
414 * at least as long as us and we don't want to create circular
415 * dependencies on the ref count */
416 (*ppSample)->pParent = pParent;
417 (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
418 (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer;
419 (*ppSample)->props.pbBuffer = pbBuffer;
420 (*ppSample)->tMediaStart = INVALID_MEDIA_TIME;
421 (*ppSample)->tMediaEnd = 0;
423 return S_OK;
426 void StdMediaSample2_Delete(StdMediaSample2 * This)
428 /* NOTE: does not remove itself from the list it belongs to */
429 CoTaskMemFree(This);
432 static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv)
434 StdMediaSample2 *This = (StdMediaSample2 *)iface;
435 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
437 *ppv = NULL;
439 if (IsEqualIID(riid, &IID_IUnknown))
440 *ppv = (LPVOID)This;
441 else if (IsEqualIID(riid, &IID_IMediaSample))
442 *ppv = (LPVOID)This;
443 else if (IsEqualIID(riid, &IID_IMediaSample2))
444 *ppv = (LPVOID)This;
446 if (*ppv)
448 IUnknown_AddRef((IUnknown *)(*ppv));
449 return S_OK;
452 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
454 return E_NOINTERFACE;
457 static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface)
459 StdMediaSample2 *This = (StdMediaSample2 *)iface;
460 ULONG ref = InterlockedIncrement(&This->ref);
462 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
464 return ref;
467 static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface)
469 StdMediaSample2 *This = (StdMediaSample2 *)iface;
470 ULONG ref = InterlockedDecrement(&This->ref);
472 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
474 if (!ref)
476 if (This->pParent)
477 IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface);
478 else
479 StdMediaSample2_Delete(This);
480 return 0;
482 return ref;
485 static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer)
487 StdMediaSample2 *This = (StdMediaSample2 *)iface;
489 TRACE("(%p)\n", ppBuffer);
491 *ppBuffer = This->props.pbBuffer;
493 if (!*ppBuffer)
495 ERR("Requested an unlocked surface and trying to lock regardless\n");
496 return E_FAIL;
499 return S_OK;
502 static long WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface)
504 StdMediaSample2 *This = (StdMediaSample2 *)iface;
506 TRACE("StdMediaSample2_GetSize()\n");
508 return This->props.cbBuffer;
511 static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
513 HRESULT hr;
514 StdMediaSample2 *This = (StdMediaSample2 *)iface;
516 TRACE("(%p, %p)\n", pStart, pEnd);
518 if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID))
519 hr = VFW_E_SAMPLE_TIME_NOT_SET;
520 else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID))
522 *pStart = This->props.tStart;
523 *pEnd = This->props.tStart + 1;
525 hr = VFW_S_NO_STOP_TIME;
527 else
529 *pStart = This->props.tStart;
530 *pEnd = This->props.tStop;
532 hr = S_OK;
535 return S_OK;
538 static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
540 StdMediaSample2 *This = (StdMediaSample2 *)iface;
542 TRACE("(%p, %p)\n", pStart, pEnd);
544 if (pStart)
546 This->props.tStart = *pStart;
547 This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID;
549 else
550 This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID;
552 if (pEnd)
554 This->props.tStop = *pEnd;
555 This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID;
557 else
558 This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID;
560 return S_OK;
563 static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface)
565 StdMediaSample2 *This = (StdMediaSample2 *)iface;
567 TRACE("()\n");
569 return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE;
572 static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint)
574 StdMediaSample2 *This = (StdMediaSample2 *)iface;
576 TRACE("(%s)\n", bIsSyncPoint ? "TRUE" : "FALSE");
578 if (bIsSyncPoint)
579 This->props.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
580 else
581 This->props.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT;
583 return S_OK;
586 static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface)
588 StdMediaSample2 *This = (StdMediaSample2 *)iface;
590 TRACE("()\n");
592 return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE;
595 static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll)
597 StdMediaSample2 *This = (StdMediaSample2 *)iface;
599 TRACE("(%s)\n", bIsPreroll ? "TRUE" : "FALSE");
601 if (bIsPreroll)
602 This->props.dwSampleFlags |= AM_SAMPLE_PREROLL;
603 else
604 This->props.dwSampleFlags &= ~AM_SAMPLE_PREROLL;
606 return S_OK;
609 static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface)
611 StdMediaSample2 *This = (StdMediaSample2 *)iface;
613 TRACE("()\n");
615 return This->props.lActual;
618 static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len)
620 StdMediaSample2 *This = (StdMediaSample2 *)iface;
622 TRACE("(%d)\n", len);
624 if ((len > This->props.cbBuffer) || (len < 0))
626 WARN("Tried to set length to %d, while max is %d\n", len, This->props.cbBuffer);
627 return VFW_E_BUFFER_OVERFLOW;
629 else
631 This->props.lActual = len;
632 return S_OK;
636 static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType)
638 StdMediaSample2 *This = (StdMediaSample2 *)iface;
640 TRACE("(%p)\n", ppMediaType);
642 if (!This->props.pMediaType) {
643 /* Make sure we return a NULL pointer (required by native Quartz dll) */
644 if (ppMediaType)
645 *ppMediaType = NULL;
646 return S_FALSE;
649 if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
650 return E_OUTOFMEMORY;
652 return CopyMediaType(*ppMediaType, This->props.pMediaType);
655 static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType)
657 StdMediaSample2 *This = (StdMediaSample2 *)iface;
659 TRACE("(%p)\n", pMediaType);
661 if (This->props.pMediaType)
662 FreeMediaType(This->props.pMediaType);
663 else if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
664 return E_OUTOFMEMORY;
666 return CopyMediaType(This->props.pMediaType, pMediaType);
669 static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface)
671 StdMediaSample2 *This = (StdMediaSample2 *)iface;
673 TRACE("()\n");
675 return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE;
678 static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity)
680 StdMediaSample2 *This = (StdMediaSample2 *)iface;
682 TRACE("(%s)\n", bIsDiscontinuity ? "TRUE" : "FALSE");
684 if (bIsDiscontinuity)
685 This->props.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
686 else
687 This->props.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY;
689 return S_OK;
692 static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
694 StdMediaSample2 *This = (StdMediaSample2 *)iface;
696 TRACE("(%p, %p)\n", pStart, pEnd);
698 if (This->tMediaStart == INVALID_MEDIA_TIME)
699 return VFW_E_MEDIA_TIME_NOT_SET;
701 *pStart = This->tMediaStart;
702 *pEnd = This->tMediaEnd;
704 return E_NOTIMPL;
707 static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
709 StdMediaSample2 *This = (StdMediaSample2 *)iface;
711 TRACE("(%p, %p)\n", pStart, pEnd);
713 if (pStart)
714 This->tMediaStart = *pStart;
715 else
716 This->tMediaStart = INVALID_MEDIA_TIME;
718 if (pEnd)
719 This->tMediaEnd = *pEnd;
720 else
721 This->tMediaEnd = 0;
723 return S_OK;
726 static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties)
728 StdMediaSample2 *This = (StdMediaSample2 *)iface;
730 TRACE("(%d, %p)\n", cbProperties, pbProperties);
732 memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props)));
734 return S_OK;
737 static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties)
739 StdMediaSample2 *This = (StdMediaSample2 *)iface;
741 TRACE("(%d, %p)\n", cbProperties, pbProperties);
743 /* NOTE: pbBuffer and cbBuffer are read-only */
744 memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE));
746 return S_OK;
749 static const IMediaSample2Vtbl StdMediaSample2_VTable =
751 StdMediaSample2_QueryInterface,
752 StdMediaSample2_AddRef,
753 StdMediaSample2_Release,
754 StdMediaSample2_GetPointer,
755 StdMediaSample2_GetSize,
756 StdMediaSample2_GetTime,
757 StdMediaSample2_SetTime,
758 StdMediaSample2_IsSyncPoint,
759 StdMediaSample2_SetSyncPoint,
760 StdMediaSample2_IsPreroll,
761 StdMediaSample2_SetPreroll,
762 StdMediaSample2_GetActualDataLength,
763 StdMediaSample2_SetActualDataLength,
764 StdMediaSample2_GetMediaType,
765 StdMediaSample2_SetMediaType,
766 StdMediaSample2_IsDiscontinuity,
767 StdMediaSample2_SetDiscontinuity,
768 StdMediaSample2_GetMediaTime,
769 StdMediaSample2_SetMediaTime,
770 StdMediaSample2_GetProperties,
771 StdMediaSample2_SetProperties
774 typedef struct StdMemAllocator
776 BaseMemAllocator base;
777 CRITICAL_SECTION csState;
778 LPVOID pMemory;
779 } StdMemAllocator;
781 static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface)
783 StdMemAllocator *This = (StdMemAllocator *)iface;
784 StdMediaSample2 * pSample = NULL;
785 SYSTEM_INFO si;
786 long i;
788 assert(list_empty(&This->base.free_list));
790 /* check alignment */
791 GetSystemInfo(&si);
793 /* we do not allow a courser alignment than the OS page size */
794 if ((si.dwPageSize % This->base.props.cbAlign) != 0)
795 return VFW_E_BADALIGN;
797 /* FIXME: each sample has to have its buffer start on the right alignment.
798 * We don't do this at the moment */
800 /* allocate memory */
801 This->pMemory = VirtualAlloc(NULL, (This->base.props.cbBuffer + This->base.props.cbPrefix) * This->base.props.cBuffers, MEM_COMMIT, PAGE_READWRITE);
803 for (i = This->base.props.cBuffers - 1; i >= 0; i--)
805 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
806 BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.props.cbBuffer + This->base.props.cbPrefix) + This->base.props.cbPrefix;
808 StdMediaSample2_Construct(pbBuffer, This->base.props.cbBuffer, iface, &pSample);
810 list_add_head(&This->base.free_list, &pSample->listentry);
813 return S_OK;
816 static HRESULT StdMemAllocator_Free(IMemAllocator * iface)
818 StdMemAllocator *This = (StdMemAllocator *)iface;
819 struct list * cursor;
821 if (!list_empty(&This->base.used_list))
823 WARN("Freeing allocator with outstanding samples!\n");
824 while ((cursor = list_head(&This->base.used_list)) != NULL)
826 StdMediaSample2 *pSample;
827 list_remove(cursor);
828 pSample = LIST_ENTRY(cursor, StdMediaSample2, listentry);
829 pSample->pParent = NULL;
833 while ((cursor = list_head(&This->base.free_list)) != NULL)
835 list_remove(cursor);
836 StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry));
839 /* free memory */
840 if (!VirtualFree(This->pMemory, 0, MEM_RELEASE))
842 ERR("Couldn't free memory. Error: %u\n", GetLastError());
843 return HRESULT_FROM_WIN32(GetLastError());
846 return S_OK;
849 static void StdMemAllocator_Destroy(IMemAllocator *iface)
851 StdMemAllocator *This = (StdMemAllocator *)iface;
853 This->csState.DebugInfo->Spare[0] = 0;
854 DeleteCriticalSection(&This->csState);
856 CoTaskMemFree(This);
859 HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv)
861 StdMemAllocator * pMemAlloc;
862 HRESULT hr;
864 *ppv = NULL;
866 if (lpUnkOuter)
867 return CLASS_E_NOAGGREGATION;
869 if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc))))
870 return E_OUTOFMEMORY;
872 InitializeCriticalSection(&pMemAlloc->csState);
873 pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StdMemAllocator.csState");
875 pMemAlloc->pMemory = NULL;
877 if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, NULL, NULL, NULL, StdMemAllocator_Destroy, &pMemAlloc->csState, &pMemAlloc->base)))
878 *ppv = (LPVOID)pMemAlloc;
879 else
880 CoTaskMemFree(pMemAlloc);
882 return hr;