wined3d: In window mode (!pbuffer) we want both a window drawable format and double...
[wine.git] / dlls / quartz / memallocator.c
blob12effbb1fb9bc64cf865b8bc709d72217bd40d5b
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/list.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
35 void dump_AM_SAMPLE2_PROPERTIES(const AM_SAMPLE2_PROPERTIES * pProps)
37 if (!pProps)
39 TRACE("AM_SAMPLE2_PROPERTIES: (null)\n");
40 return;
42 TRACE("\tcbData: %d\n", pProps->cbData);
43 TRACE("\tdwTypeSpecificFlags: 0x%8x\n", pProps->dwTypeSpecificFlags);
44 TRACE("\tdwSampleFlags: 0x%8x\n", pProps->dwSampleFlags);
45 TRACE("\tlActual: %d\n", pProps->lActual);
46 TRACE("\ttStart: %x%08x%s\n", (LONG)(pProps->tStart >> 32), (LONG)pProps->tStart, pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? "" : " (not valid)");
47 TRACE("\ttStop: %x%08x%s\n", (LONG)(pProps->tStop >> 32), (LONG)pProps->tStop, pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? "" : " (not valid)");
48 TRACE("\tdwStreamId: 0x%x\n", pProps->dwStreamId);
49 TRACE("\tpMediaType: %p\n", pProps->pMediaType);
50 TRACE("\tpbBuffer: %p\n", pProps->pbBuffer);
51 TRACE("\tcbBuffer: %d\n", pProps->cbBuffer);
54 typedef struct BaseMemAllocator
56 const IMemAllocatorVtbl * lpVtbl;
58 LONG ref;
59 ALLOCATOR_PROPERTIES * pProps;
60 CRITICAL_SECTION csState;
61 HRESULT (* fnAlloc) (IMemAllocator *);
62 HRESULT (* fnFree)(IMemAllocator *);
63 HANDLE hSemWaiting;
64 BOOL bDecommitQueued;
65 BOOL bCommitted;
66 LONG lWaiting;
67 struct list free_list;
68 struct list used_list;
69 } BaseMemAllocator;
71 typedef struct StdMediaSample2
73 const IMediaSample2Vtbl * lpvtbl;
75 LONG ref;
76 AM_SAMPLE2_PROPERTIES props;
77 IMemAllocator * pParent;
78 struct list listentry;
79 LONGLONG tMediaStart;
80 LONGLONG tMediaEnd;
81 } StdMediaSample2;
83 static const IMemAllocatorVtbl BaseMemAllocator_VTable;
84 static const IMediaSample2Vtbl StdMediaSample2_VTable;
86 #define AM_SAMPLE2_PROP_SIZE_WRITABLE (unsigned int)(&((AM_SAMPLE2_PROPERTIES *)0)->pbBuffer)
88 #define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff)
90 static HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), HRESULT (* fnFree)(IMemAllocator *), BaseMemAllocator * pMemAlloc)
92 assert(fnAlloc && fnFree);
94 pMemAlloc->lpVtbl = &BaseMemAllocator_VTable;
96 pMemAlloc->ref = 1;
97 pMemAlloc->pProps = NULL;
98 list_init(&pMemAlloc->free_list);
99 list_init(&pMemAlloc->used_list);
100 pMemAlloc->fnAlloc = fnAlloc;
101 pMemAlloc->fnFree = fnFree;
102 pMemAlloc->bDecommitQueued = FALSE;
103 pMemAlloc->bCommitted = FALSE;
104 pMemAlloc->hSemWaiting = NULL;
105 pMemAlloc->lWaiting = 0;
107 InitializeCriticalSection(&pMemAlloc->csState);
108 pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": BaseMemAllocator.csState");
110 return S_OK;
113 static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv)
115 BaseMemAllocator *This = (BaseMemAllocator *)iface;
116 TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv);
118 *ppv = NULL;
120 if (IsEqualIID(riid, &IID_IUnknown))
121 *ppv = (LPVOID)This;
122 else if (IsEqualIID(riid, &IID_IMemAllocator))
123 *ppv = (LPVOID)This;
125 if (*ppv)
127 IUnknown_AddRef((IUnknown *)(*ppv));
128 return S_OK;
131 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
133 return E_NOINTERFACE;
136 static ULONG WINAPI BaseMemAllocator_AddRef(IMemAllocator * iface)
138 BaseMemAllocator *This = (BaseMemAllocator *)iface;
139 ULONG ref = InterlockedIncrement(&This->ref);
141 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
143 return ref;
146 static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface)
148 BaseMemAllocator *This = (BaseMemAllocator *)iface;
149 ULONG ref = InterlockedDecrement(&This->ref);
151 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
153 if (!ref)
155 CloseHandle(This->hSemWaiting);
156 if (This->bCommitted)
157 This->fnFree(iface);
158 CoTaskMemFree(This->pProps);
159 This->csState.DebugInfo->Spare[0] = 0;
160 DeleteCriticalSection(&This->csState);
161 CoTaskMemFree(This);
162 return 0;
164 return ref;
167 static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual)
169 BaseMemAllocator *This = (BaseMemAllocator *)iface;
170 HRESULT hr;
172 TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual);
174 EnterCriticalSection(&This->csState);
176 if (!list_empty(&This->used_list))
177 hr = VFW_E_BUFFERS_OUTSTANDING;
178 else if (This->bCommitted)
179 hr = VFW_E_ALREADY_COMMITTED;
180 else if (pRequest->cbAlign == 0)
181 hr = VFW_E_BADALIGN;
182 else
184 if (!This->pProps)
185 This->pProps = CoTaskMemAlloc(sizeof(*This->pProps));
187 if (!This->pProps)
188 hr = E_OUTOFMEMORY;
189 else
191 *This->pProps = *pRequest;
193 *pActual = *pRequest;
195 hr = S_OK;
199 LeaveCriticalSection(&This->csState);
201 return hr;
204 static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps)
206 BaseMemAllocator *This = (BaseMemAllocator *)iface;
207 HRESULT hr = S_OK;
209 TRACE("(%p)->(%p)\n", This, pProps);
211 EnterCriticalSection(&This->csState);
213 /* NOTE: this is different from the native version.
214 * It would silently succeed if the properties had
215 * not been set, but would fail further on down the
216 * line with some obscure error like having an
217 * invalid alignment. Whether or not our version
218 * will cause any problems remains to be seen */
219 if (!This->pProps)
220 hr = VFW_E_SIZENOTSET;
221 else
222 memcpy(pProps, This->pProps, sizeof(*pProps));
224 LeaveCriticalSection(&This->csState);
226 return hr;
229 static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface)
231 BaseMemAllocator *This = (BaseMemAllocator *)iface;
232 HRESULT hr;
234 TRACE("(%p)->()\n", This);
236 EnterCriticalSection(&This->csState);
238 if (!This->pProps)
239 hr = VFW_E_SIZENOTSET;
240 else if (This->bDecommitQueued && This->bCommitted)
242 This->bDecommitQueued = FALSE;
243 hr = S_OK;
245 else if (This->bCommitted)
246 hr = S_OK;
247 else
249 if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->pProps->cBuffers, This->pProps->cBuffers, NULL)))
251 ERR("Couldn't create semaphore (error was %u)\n", GetLastError());
252 hr = HRESULT_FROM_WIN32(GetLastError());
254 else
256 hr = This->fnAlloc(iface);
257 if (SUCCEEDED(hr))
258 This->bCommitted = TRUE;
259 else
260 ERR("fnAlloc failed with error 0x%x\n", hr);
264 LeaveCriticalSection(&This->csState);
266 return hr;
269 static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface)
271 BaseMemAllocator *This = (BaseMemAllocator *)iface;
272 HRESULT hr;
274 TRACE("(%p)->()\n", This);
276 EnterCriticalSection(&This->csState);
278 if (!This->bCommitted)
279 hr = S_OK;
280 else
282 if (!list_empty(&This->used_list))
284 This->bDecommitQueued = TRUE;
285 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
286 ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL);
288 hr = S_OK;
290 else
292 assert(This->lWaiting == 0);
294 This->bCommitted = FALSE;
295 CloseHandle(This->hSemWaiting);
296 This->hSemWaiting = NULL;
298 hr = This->fnFree(iface);
299 if (FAILED(hr))
300 ERR("fnFree failed with error 0x%x\n", hr);
304 LeaveCriticalSection(&This->csState);
306 return hr;
309 static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags)
311 BaseMemAllocator *This = (BaseMemAllocator *)iface;
312 HRESULT hr = S_OK;
314 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
315 * The allocator might use these values to determine which buffer it retrieves */
317 TRACE("(%p)->(%p, %p, %p, %x)\n", This, pSample, pStartTime, pEndTime, dwFlags);
319 *pSample = NULL;
321 if (!This->bCommitted)
322 return VFW_E_NOT_COMMITTED;
324 This->lWaiting++;
325 if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0)
327 This->lWaiting--;
328 return VFW_E_TIMEOUT;
330 This->lWaiting--;
332 EnterCriticalSection(&This->csState);
334 if (!This->bCommitted)
335 hr = VFW_E_NOT_COMMITTED;
336 else if (This->bDecommitQueued)
337 hr = VFW_E_TIMEOUT;
338 else
340 struct list * free = list_head(&This->free_list);
341 list_remove(free);
342 list_add_head(&This->used_list, free);
344 *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry);
346 assert(((StdMediaSample2 *)*pSample)->ref == 0);
348 IMediaSample_AddRef(*pSample);
351 LeaveCriticalSection(&This->csState);
353 return hr;
356 static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample)
358 BaseMemAllocator *This = (BaseMemAllocator *)iface;
359 StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample;
360 HRESULT hr = S_OK;
362 TRACE("(%p)->(%p)\n", This, pSample);
364 /* FIXME: make sure that sample is currently on the used list */
366 /* FIXME: we should probably check the ref count on the sample before freeing
367 * it to make sure that it is not still in use */
368 EnterCriticalSection(&This->csState);
370 if (!This->bCommitted)
371 ERR("Releasing a buffer when the allocator is not committed?!?\n");
373 /* remove from used_list */
374 list_remove(&pStdSample->listentry);
376 list_add_head(&This->free_list, &pStdSample->listentry);
378 if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted)
380 HRESULT hrfree;
382 assert(This->lWaiting == 0);
384 This->bCommitted = FALSE;
385 This->bDecommitQueued = FALSE;
387 CloseHandle(This->hSemWaiting);
388 This->hSemWaiting = NULL;
390 if (FAILED(hrfree = This->fnFree(iface)))
391 ERR("fnFree failed with error 0x%x\n", hrfree);
394 LeaveCriticalSection(&This->csState);
396 /* notify a waiting thread that there is now a free buffer */
397 if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL))
399 ERR("ReleaseSemaphore failed with error %u\n", GetLastError());
400 hr = HRESULT_FROM_WIN32(GetLastError());
403 return hr;
406 static const IMemAllocatorVtbl BaseMemAllocator_VTable =
408 BaseMemAllocator_QueryInterface,
409 BaseMemAllocator_AddRef,
410 BaseMemAllocator_Release,
411 BaseMemAllocator_SetProperties,
412 BaseMemAllocator_GetProperties,
413 BaseMemAllocator_Commit,
414 BaseMemAllocator_Decommit,
415 BaseMemAllocator_GetBuffer,
416 BaseMemAllocator_ReleaseBuffer
419 static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample)
421 assert(pbBuffer && pParent && (cbBuffer > 0));
423 if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2))))
424 return E_OUTOFMEMORY;
426 (*ppSample)->lpvtbl = &StdMediaSample2_VTable;
427 (*ppSample)->ref = 0;
428 ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props));
430 /* NOTE: no need to AddRef as the parent is guaranteed to be around
431 * at least as long as us and we don't want to create circular
432 * dependencies on the ref count */
433 (*ppSample)->pParent = pParent;
434 (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
435 (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer;
436 (*ppSample)->props.pbBuffer = pbBuffer;
437 (*ppSample)->tMediaStart = INVALID_MEDIA_TIME;
438 (*ppSample)->tMediaEnd = 0;
440 return S_OK;
443 static void StdMediaSample2_Delete(StdMediaSample2 * This)
445 /* NOTE: does not remove itself from the list it belongs to */
446 CoTaskMemFree(This);
449 static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv)
451 StdMediaSample2 *This = (StdMediaSample2 *)iface;
452 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
454 *ppv = NULL;
456 if (IsEqualIID(riid, &IID_IUnknown))
457 *ppv = (LPVOID)This;
458 else if (IsEqualIID(riid, &IID_IMediaSample))
459 *ppv = (LPVOID)This;
460 else if (IsEqualIID(riid, &IID_IMediaSample2))
461 *ppv = (LPVOID)This;
463 if (*ppv)
465 IUnknown_AddRef((IUnknown *)(*ppv));
466 return S_OK;
469 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
471 return E_NOINTERFACE;
474 static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface)
476 StdMediaSample2 *This = (StdMediaSample2 *)iface;
477 ULONG ref = InterlockedIncrement(&This->ref);
479 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1);
481 return ref;
484 static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface)
486 StdMediaSample2 *This = (StdMediaSample2 *)iface;
487 ULONG ref = InterlockedDecrement(&This->ref);
489 TRACE("(%p)->() Release from %d\n", iface, ref + 1);
491 if (!ref)
493 if (This->pParent)
494 IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface);
495 else
496 StdMediaSample2_Delete(This);
497 return 0;
499 return ref;
502 static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer)
504 StdMediaSample2 *This = (StdMediaSample2 *)iface;
506 TRACE("(%p)\n", ppBuffer);
508 *ppBuffer = This->props.pbBuffer;
510 return S_OK;
513 static long WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface)
515 StdMediaSample2 *This = (StdMediaSample2 *)iface;
517 TRACE("StdMediaSample2_GetSize()\n");
519 return This->props.cbBuffer;
522 static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
524 HRESULT hr;
525 StdMediaSample2 *This = (StdMediaSample2 *)iface;
527 TRACE("(%p, %p)\n", pStart, pEnd);
529 if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID))
530 hr = VFW_E_SAMPLE_TIME_NOT_SET;
531 else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID))
533 *pStart = This->props.tStart;
534 *pEnd = This->props.tStart + 1;
536 hr = VFW_S_NO_STOP_TIME;
538 else
540 *pStart = This->props.tStart;
541 *pEnd = This->props.tStop;
543 hr = S_OK;
546 return S_OK;
549 static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
551 StdMediaSample2 *This = (StdMediaSample2 *)iface;
553 TRACE("(%p, %p)\n", pStart, pEnd);
555 if (pStart)
557 This->props.tStart = *pStart;
558 This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID;
560 else
561 This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID;
563 if (pEnd)
565 This->props.tStop = *pEnd;
566 This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID;
568 else
569 This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID;
571 return S_OK;
574 static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface)
576 StdMediaSample2 *This = (StdMediaSample2 *)iface;
578 TRACE("()\n");
580 return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE;
583 static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint)
585 StdMediaSample2 *This = (StdMediaSample2 *)iface;
587 TRACE("(%s)\n", bIsSyncPoint ? "TRUE" : "FALSE");
589 if (bIsSyncPoint)
590 This->props.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT;
591 else
592 This->props.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT;
594 return S_OK;
597 static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface)
599 StdMediaSample2 *This = (StdMediaSample2 *)iface;
601 TRACE("()\n");
603 return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE;
606 static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll)
608 StdMediaSample2 *This = (StdMediaSample2 *)iface;
610 TRACE("(%s)\n", bIsPreroll ? "TRUE" : "FALSE");
612 if (bIsPreroll)
613 This->props.dwSampleFlags |= AM_SAMPLE_PREROLL;
614 else
615 This->props.dwSampleFlags &= ~AM_SAMPLE_PREROLL;
617 return S_OK;
620 static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface)
622 StdMediaSample2 *This = (StdMediaSample2 *)iface;
624 TRACE("()\n");
626 return This->props.lActual;
629 static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len)
631 StdMediaSample2 *This = (StdMediaSample2 *)iface;
633 TRACE("(%d)\n", len);
635 if ((len > This->props.cbBuffer) || (len < 0))
636 return VFW_E_BUFFER_OVERFLOW;
637 else
639 This->props.lActual = len;
640 return S_OK;
644 static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType)
646 StdMediaSample2 *This = (StdMediaSample2 *)iface;
648 TRACE("(%p)\n", ppMediaType);
650 if (!This->props.pMediaType) {
651 /* Make sure we return a NULL pointer (required by native Quartz dll) */
652 if (ppMediaType)
653 *ppMediaType = NULL;
654 return S_FALSE;
657 if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
658 return E_OUTOFMEMORY;
660 return CopyMediaType(*ppMediaType, This->props.pMediaType);
663 static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType)
665 StdMediaSample2 *This = (StdMediaSample2 *)iface;
667 TRACE("(%p)\n", pMediaType);
669 if (This->props.pMediaType)
670 FreeMediaType(This->props.pMediaType);
671 else if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
672 return E_OUTOFMEMORY;
674 return CopyMediaType(This->props.pMediaType, pMediaType);
677 static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface)
679 StdMediaSample2 *This = (StdMediaSample2 *)iface;
681 TRACE("()\n");
683 return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE;
686 static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity)
688 StdMediaSample2 *This = (StdMediaSample2 *)iface;
690 TRACE("(%s)\n", bIsDiscontinuity ? "TRUE" : "FALSE");
692 if (bIsDiscontinuity)
693 This->props.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY;
694 else
695 This->props.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY;
697 return S_OK;
700 static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
702 StdMediaSample2 *This = (StdMediaSample2 *)iface;
704 TRACE("(%p, %p)\n", pStart, pEnd);
706 if (This->tMediaStart == INVALID_MEDIA_TIME)
707 return VFW_E_MEDIA_TIME_NOT_SET;
709 *pStart = This->tMediaStart;
710 *pEnd = This->tMediaEnd;
712 return E_NOTIMPL;
715 static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
717 StdMediaSample2 *This = (StdMediaSample2 *)iface;
719 TRACE("(%p, %p)\n", pStart, pEnd);
721 if (pStart)
722 This->tMediaStart = *pStart;
723 else
724 This->tMediaStart = INVALID_MEDIA_TIME;
726 if (pEnd)
727 This->tMediaEnd = *pEnd;
728 else
729 This->tMediaEnd = 0;
731 return S_OK;
734 static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties)
736 StdMediaSample2 *This = (StdMediaSample2 *)iface;
738 TRACE("(%d, %p)\n", cbProperties, pbProperties);
740 memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props)));
742 return S_OK;
745 static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties)
747 StdMediaSample2 *This = (StdMediaSample2 *)iface;
749 TRACE("(%d, %p)\n", cbProperties, pbProperties);
751 /* NOTE: pbBuffer and cbBuffer are read-only */
752 memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE));
754 return S_OK;
757 static const IMediaSample2Vtbl StdMediaSample2_VTable =
759 StdMediaSample2_QueryInterface,
760 StdMediaSample2_AddRef,
761 StdMediaSample2_Release,
762 StdMediaSample2_GetPointer,
763 StdMediaSample2_GetSize,
764 StdMediaSample2_GetTime,
765 StdMediaSample2_SetTime,
766 StdMediaSample2_IsSyncPoint,
767 StdMediaSample2_SetSyncPoint,
768 StdMediaSample2_IsPreroll,
769 StdMediaSample2_SetPreroll,
770 StdMediaSample2_GetActualDataLength,
771 StdMediaSample2_SetActualDataLength,
772 StdMediaSample2_GetMediaType,
773 StdMediaSample2_SetMediaType,
774 StdMediaSample2_IsDiscontinuity,
775 StdMediaSample2_SetDiscontinuity,
776 StdMediaSample2_GetMediaTime,
777 StdMediaSample2_SetMediaTime,
778 StdMediaSample2_GetProperties,
779 StdMediaSample2_SetProperties
782 typedef struct StdMemAllocator
784 BaseMemAllocator base;
785 LPVOID pMemory;
786 } StdMemAllocator;
788 static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface)
790 StdMemAllocator *This = (StdMemAllocator *)iface;
791 StdMediaSample2 * pSample = NULL;
792 SYSTEM_INFO si;
793 long i;
795 assert(list_empty(&This->base.free_list));
797 /* check alignment */
798 GetSystemInfo(&si);
800 /* we do not allow a courser alignment than the OS page size */
801 if ((si.dwPageSize % This->base.pProps->cbAlign) != 0)
802 return VFW_E_BADALIGN;
804 /* FIXME: each sample has to have its buffer start on the right alignment.
805 * We don't do this at the moment */
807 /* allocate memory */
808 This->pMemory = VirtualAlloc(NULL, (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) * This->base.pProps->cBuffers, MEM_COMMIT, PAGE_READWRITE);
810 for (i = This->base.pProps->cBuffers - 1; i >= 0; i--)
812 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
813 BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) + This->base.pProps->cbPrefix;
815 StdMediaSample2_Construct(pbBuffer, This->base.pProps->cbBuffer, iface, &pSample);
817 list_add_head(&This->base.free_list, &pSample->listentry);
820 return S_OK;
823 static HRESULT StdMemAllocator_Free(IMemAllocator * iface)
825 StdMemAllocator *This = (StdMemAllocator *)iface;
826 struct list * cursor;
828 if (!list_empty(&This->base.used_list))
830 WARN("Freeing allocator with outstanding samples!\n");
831 while ((cursor = list_head(&This->base.used_list)) != NULL)
833 StdMediaSample2 *pSample;
834 list_remove(cursor);
835 pSample = LIST_ENTRY(cursor, StdMediaSample2, listentry);
836 pSample->pParent = NULL;
840 while ((cursor = list_head(&This->base.free_list)) != NULL)
842 list_remove(cursor);
843 StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry));
846 /* free memory */
847 if (!VirtualFree(This->pMemory, 0, MEM_RELEASE))
849 ERR("Couldn't free memory. Error: %u\n", GetLastError());
850 return HRESULT_FROM_WIN32(GetLastError());
853 return S_OK;
856 HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv)
858 StdMemAllocator * pMemAlloc;
859 HRESULT hr;
861 *ppv = NULL;
863 if (lpUnkOuter)
864 return CLASS_E_NOAGGREGATION;
866 if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc))))
867 return E_OUTOFMEMORY;
869 pMemAlloc->pMemory = NULL;
871 if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, &pMemAlloc->base)))
872 *ppv = (LPVOID)pMemAlloc;
873 else
874 CoTaskMemFree(pMemAlloc);
876 return hr;