Added YUV routines needed for v4l driver, and in the future possibly
[wine/gsoc-2012-control.git] / dlls / quartz / memallocator.c
blob9f3d9ddcd0848444b0d7c63830874fd1188dbd20
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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(AM_SAMPLE2_PROPERTIES * pProps)
37 if (!pProps)
39 TRACE("AM_SAMPLE2_PROPERTIES: (null)\n");
40 return;
42 TRACE("\tcbData: %ld\n", pProps->cbData);
43 TRACE("\tdwTypeSpecificFlags: 0x%8lx\n", pProps->dwTypeSpecificFlags);
44 TRACE("\tdwSampleFlags: 0x%8lx\n", pProps->dwSampleFlags);
45 TRACE("\tlActual: %ld\n", pProps->lActual);
46 TRACE("\ttStart: %lx%08lx%s\n", (LONG)(pProps->tStart >> 32), (LONG)pProps->tStart, pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? "" : " (not valid)");
47 TRACE("\ttStop: %lx%08lx%s\n", (LONG)(pProps->tStop >> 32), (LONG)pProps->tStop, pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? "" : " (not valid)");
48 TRACE("\tdwStreamId: 0x%lx\n", pProps->dwStreamId);
49 TRACE("\tpMediaType: %p\n", pProps->pMediaType);
50 TRACE("\tpbBuffer: %p\n", pProps->pbBuffer);
51 TRACE("\tcbBuffer: %ld\n", pProps->cbBuffer);
54 typedef struct BaseMemAllocator
56 const IMemAllocatorVtbl * lpVtbl;
58 ULONG 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 ULONG ref;
76 AM_SAMPLE2_PROPERTIES props;
77 IMemAllocator * pParent;
78 struct list listentry;
79 LONGLONG tMediaStart;
80 LONGLONG tMediaEnd;
81 } StdMediaSample2;
83 static const struct IMemAllocatorVtbl BaseMemAllocator_VTable;
84 static const struct IMediaSample2Vtbl StdMediaSample2_VTable;
86 #define AM_SAMPLE2_PROP_SIZE_WRITABLE (unsigned int)(&((AM_SAMPLE2_PROPERTIES *)0)->pbBuffer)
88 #ifdef _I64_MAX
89 #define INVALID_MEDIA_TIME _I64_MAX
90 #else
91 #define INVALID_MEDIA_TIME ((long long)(~0ull >> 1))
92 #endif
94 static HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), HRESULT (* fnFree)(IMemAllocator *), BaseMemAllocator * pMemAlloc)
96 assert(fnAlloc && fnFree);
98 pMemAlloc->lpVtbl = &BaseMemAllocator_VTable;
100 pMemAlloc->ref = 1;
101 pMemAlloc->pProps = NULL;
102 list_init(&pMemAlloc->free_list);
103 list_init(&pMemAlloc->used_list);
104 pMemAlloc->fnAlloc = fnAlloc;
105 pMemAlloc->fnFree = fnFree;
106 pMemAlloc->bDecommitQueued = FALSE;
107 pMemAlloc->bCommitted = FALSE;
108 pMemAlloc->hSemWaiting = NULL;
109 pMemAlloc->lWaiting = 0;
111 InitializeCriticalSection(&pMemAlloc->csState);
113 return S_OK;
116 static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv)
118 BaseMemAllocator *This = (BaseMemAllocator *)iface;
119 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
121 *ppv = NULL;
123 if (IsEqualIID(riid, &IID_IUnknown))
124 *ppv = (LPVOID)This;
125 else if (IsEqualIID(riid, &IID_IMemAllocator))
126 *ppv = (LPVOID)This;
128 if (*ppv)
130 IUnknown_AddRef((IUnknown *)(*ppv));
131 return S_OK;
134 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
136 return E_NOINTERFACE;
139 static ULONG WINAPI BaseMemAllocator_AddRef(IMemAllocator * iface)
141 BaseMemAllocator *This = (BaseMemAllocator *)iface;
142 ULONG ref = InterlockedIncrement(&This->ref);
144 TRACE("(%p)->() AddRef from %ld\n", iface, ref - 1);
146 return ref;
149 static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface)
151 BaseMemAllocator *This = (BaseMemAllocator *)iface;
152 ULONG ref = InterlockedDecrement(&This->ref);
154 TRACE("(%p)->() Release from %ld\n", iface, ref + 1);
156 if (!ref)
158 CloseHandle(This->hSemWaiting);
159 if (This->bCommitted)
160 This->fnFree(iface);
161 HeapFree(GetProcessHeap(), 0, This->pProps);
162 CoTaskMemFree(This);
163 return 0;
165 return ref;
168 static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual)
170 BaseMemAllocator *This = (BaseMemAllocator *)iface;
171 HRESULT hr;
173 TRACE("(%p, %p)\n", pRequest, pActual);
175 EnterCriticalSection(&This->csState);
177 if (!list_empty(&This->used_list))
178 hr = VFW_E_BUFFERS_OUTSTANDING;
179 else if (This->bCommitted)
180 hr = VFW_E_ALREADY_COMMITTED;
181 else if (pRequest->cbAlign == 0)
182 hr = VFW_E_BADALIGN;
183 else
185 if (!This->pProps)
186 This->pProps = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->pProps));
188 if (!This->pProps)
189 hr = E_OUTOFMEMORY;
190 else
192 memcpy(This->pProps, pRequest, sizeof(*This->pProps));
194 memcpy(pActual, pRequest, sizeof(*pActual));
196 hr = S_OK;
200 LeaveCriticalSection(&This->csState);
202 return hr;
205 static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps)
207 BaseMemAllocator *This = (BaseMemAllocator *)iface;
208 HRESULT hr = S_OK;
210 TRACE("(%p)\n", pProps);
212 EnterCriticalSection(&This->csState);
214 /* NOTE: this is different from the native version.
215 * It would silently succeed if the properties had
216 * not been set, but would fail further on down the
217 * line with some obscure error like having an
218 * invalid alignment. Whether or not our version
219 * will cause any problems remains to be seen */
220 if (!This->pProps)
221 hr = VFW_E_SIZENOTSET;
222 else
223 memcpy(pProps, This->pProps, sizeof(*pProps));
225 LeaveCriticalSection(&This->csState);
227 return hr;
230 static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface)
232 BaseMemAllocator *This = (BaseMemAllocator *)iface;
233 HRESULT hr;
235 TRACE("()\n");
237 EnterCriticalSection(&This->csState);
239 if (!This->pProps)
240 hr = VFW_E_SIZENOTSET;
241 else if (This->bCommitted)
242 hr = VFW_E_ALREADY_COMMITTED;
243 else if (This->bDecommitQueued)
245 This->bDecommitQueued = FALSE;
246 hr = S_OK;
248 else
250 if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->pProps->cBuffers, This->pProps->cBuffers, NULL)))
252 ERR("Couldn't create semaphore (error was %ld)\n", GetLastError());
253 hr = HRESULT_FROM_WIN32(GetLastError());
255 else
257 hr = This->fnAlloc(iface);
258 if (SUCCEEDED(hr))
259 This->bCommitted = TRUE;
260 else
261 ERR("fnAlloc failed with error 0x%lx\n", hr);
265 LeaveCriticalSection(&This->csState);
267 return hr;
270 static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface)
272 BaseMemAllocator *This = (BaseMemAllocator *)iface;
273 HRESULT hr;
275 TRACE("()\n");
277 EnterCriticalSection(&This->csState);
279 if (!This->bCommitted)
280 hr = VFW_E_NOT_COMMITTED;
281 else
283 if (!list_empty(&This->used_list))
285 This->bDecommitQueued = TRUE;
286 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
287 ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL);
289 hr = S_OK;
291 else
293 assert(This->lWaiting == 0);
295 This->bCommitted = FALSE;
296 CloseHandle(This->hSemWaiting);
297 This->hSemWaiting = NULL;
299 hr = This->fnFree(iface);
300 if (FAILED(hr))
301 ERR("fnFree failed with error 0x%lx\n", hr);
305 LeaveCriticalSection(&This->csState);
307 return hr;
310 static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags)
312 BaseMemAllocator *This = (BaseMemAllocator *)iface;
313 HRESULT hr = S_OK;
315 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
316 * The allocator might use these values to determine which buffer it retrieves */
318 TRACE("(%p, %p, %p, %lx)\n", pSample, pStartTime, pEndTime, dwFlags);
320 *pSample = NULL;
322 if (!This->bCommitted)
323 return VFW_E_NOT_COMMITTED;
325 This->lWaiting++;
326 if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0)
328 This->lWaiting--;
329 return VFW_E_TIMEOUT;
331 This->lWaiting--;
333 EnterCriticalSection(&This->csState);
335 if (!This->bCommitted)
336 hr = VFW_E_NOT_COMMITTED;
337 else if (This->bDecommitQueued)
338 hr = VFW_E_TIMEOUT;
339 else
341 struct list * free = list_head(&This->free_list);
342 list_remove(free);
343 list_add_head(&This->used_list, free);
345 *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry);
347 assert(((StdMediaSample2 *)*pSample)->ref == 0);
349 IMediaSample_AddRef(*pSample);
352 LeaveCriticalSection(&This->csState);
354 return hr;
357 static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample)
359 BaseMemAllocator *This = (BaseMemAllocator *)iface;
360 StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample;
361 HRESULT hr = S_OK;
363 TRACE("(%p)\n", pSample);
365 /* FIXME: make sure that sample is currently on the used list */
367 /* FIXME: we should probably check the ref count on the sample before freeing
368 * it to make sure that it is not still in use */
369 EnterCriticalSection(&This->csState);
371 if (!This->bCommitted)
372 ERR("Releasing a buffer when the allocator is not committed?!?\n");
374 /* remove from used_list */
375 list_remove(&pStdSample->listentry);
377 list_add_head(&This->free_list, &pStdSample->listentry);
379 if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted)
381 HRESULT hrfree;
383 assert(This->lWaiting == 0);
385 This->bCommitted = FALSE;
386 This->bDecommitQueued = FALSE;
388 CloseHandle(This->hSemWaiting);
389 This->hSemWaiting = NULL;
391 if (FAILED(hrfree = This->fnFree(iface)))
392 ERR("fnFree failed with error 0x%lx\n", hrfree);
395 LeaveCriticalSection(&This->csState);
397 /* notify a waiting thread that there is now a free buffer */
398 if (!ReleaseSemaphore(This->hSemWaiting, 1, NULL))
400 ERR("ReleaseSemaphore failed with error %ld\n", GetLastError());
401 hr = HRESULT_FROM_WIN32(GetLastError());
404 return hr;
407 static const IMemAllocatorVtbl BaseMemAllocator_VTable =
409 BaseMemAllocator_QueryInterface,
410 BaseMemAllocator_AddRef,
411 BaseMemAllocator_Release,
412 BaseMemAllocator_SetProperties,
413 BaseMemAllocator_GetProperties,
414 BaseMemAllocator_Commit,
415 BaseMemAllocator_Decommit,
416 BaseMemAllocator_GetBuffer,
417 BaseMemAllocator_ReleaseBuffer
420 static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample)
422 assert(pbBuffer && pParent && (cbBuffer > 0));
424 if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2))))
425 return E_OUTOFMEMORY;
427 (*ppSample)->lpvtbl = &StdMediaSample2_VTable;
428 (*ppSample)->ref = 0;
429 ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props));
431 /* NOTE: no need to AddRef as the parent is guaranteed to be around
432 * at least as long as us and we don't want to create circular
433 * dependencies on the ref count */
434 (*ppSample)->pParent = pParent;
435 (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
436 (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer;
437 (*ppSample)->props.pbBuffer = pbBuffer;
438 (*ppSample)->tMediaStart = INVALID_MEDIA_TIME;
439 (*ppSample)->tMediaEnd = 0;
441 return S_OK;
444 static void StdMediaSample2_Delete(StdMediaSample2 * This)
446 /* NOTE: does not remove itself from the list it belongs to */
447 CoTaskMemFree(This);
450 static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv)
452 StdMediaSample2 *This = (StdMediaSample2 *)iface;
453 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
455 *ppv = NULL;
457 if (IsEqualIID(riid, &IID_IUnknown))
458 *ppv = (LPVOID)This;
459 else if (IsEqualIID(riid, &IID_IMediaSample))
460 *ppv = (LPVOID)This;
461 else if (IsEqualIID(riid, &IID_IMediaSample2))
462 *ppv = (LPVOID)This;
464 if (*ppv)
466 IUnknown_AddRef((IUnknown *)(*ppv));
467 return S_OK;
470 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
472 return E_NOINTERFACE;
475 static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface)
477 StdMediaSample2 *This = (StdMediaSample2 *)iface;
478 ULONG ref = InterlockedIncrement(&This->ref);
480 TRACE("(%p)->() AddRef from %ld\n", iface, ref - 1);
482 return ref;
485 static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface)
487 StdMediaSample2 *This = (StdMediaSample2 *)iface;
488 ULONG ref = InterlockedDecrement(&This->ref);
490 TRACE("(%p)->() Release from %ld\n", iface, ref + 1);
492 if (!ref)
494 IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface);
495 return 0;
497 return ref;
500 static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer)
502 StdMediaSample2 *This = (StdMediaSample2 *)iface;
504 TRACE("(%p)\n", ppBuffer);
506 *ppBuffer = This->props.pbBuffer;
508 return S_OK;
511 static long WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface)
513 StdMediaSample2 *This = (StdMediaSample2 *)iface;
515 TRACE("StdMediaSample2_GetSize()\n");
517 return This->props.cbBuffer;
520 static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
522 HRESULT hr;
523 StdMediaSample2 *This = (StdMediaSample2 *)iface;
525 TRACE("(%p, %p)\n", pStart, pEnd);
527 if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID))
528 hr = VFW_E_SAMPLE_TIME_NOT_SET;
529 else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID))
531 *pStart = This->props.tStart;
532 *pEnd = This->props.tStart + 1;
534 hr = VFW_S_NO_STOP_TIME;
536 else
538 *pStart = This->props.tStart;
539 *pEnd = This->props.tStop;
541 hr = S_OK;
544 return S_OK;
547 static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
549 StdMediaSample2 *This = (StdMediaSample2 *)iface;
551 TRACE("(%p, %p)\n", pStart, pEnd);
553 if (pStart)
555 This->props.tStart = *pStart;
556 This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID;
558 else
559 This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID;
561 if (pEnd)
563 This->props.tStop = *pEnd;
564 This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID;
566 else
567 This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID;
569 return S_OK;
572 static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface)
574 StdMediaSample2 *This = (StdMediaSample2 *)iface;
576 TRACE("()\n");
578 return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE;
581 static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint)
583 StdMediaSample2 *This = (StdMediaSample2 *)iface;
585 TRACE("(%s)\n", bIsSyncPoint ? "TRUE" : "FALSE");
587 This->props.dwSampleFlags = (This->props.dwSampleFlags & ~AM_SAMPLE_SPLICEPOINT) | bIsSyncPoint ? AM_SAMPLE_SPLICEPOINT : 0;
589 return S_OK;
592 static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface)
594 StdMediaSample2 *This = (StdMediaSample2 *)iface;
596 TRACE("()\n");
598 return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE;
601 static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll)
603 StdMediaSample2 *This = (StdMediaSample2 *)iface;
605 TRACE("(%s)\n", bIsPreroll ? "TRUE" : "FALSE");
607 This->props.dwSampleFlags = (This->props.dwSampleFlags & ~AM_SAMPLE_PREROLL) | bIsPreroll ? AM_SAMPLE_PREROLL : 0;
609 return S_OK;
612 static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface)
614 StdMediaSample2 *This = (StdMediaSample2 *)iface;
616 TRACE("()\n");
618 return This->props.lActual;
621 static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len)
623 StdMediaSample2 *This = (StdMediaSample2 *)iface;
625 TRACE("(%ld)\n", len);
627 if ((len > This->props.cbBuffer) || (len < 0))
628 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 This->props.dwSampleFlags = (This->props.dwSampleFlags & ~AM_SAMPLE_DATADISCONTINUITY) | bIsDiscontinuity ? AM_SAMPLE_DATADISCONTINUITY : 0;
686 return S_OK;
689 static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
691 StdMediaSample2 *This = (StdMediaSample2 *)iface;
693 TRACE("(%p, %p)\n", pStart, pEnd);
695 if (This->tMediaStart == INVALID_MEDIA_TIME)
696 return VFW_E_MEDIA_TIME_NOT_SET;
698 *pStart = This->tMediaStart;
699 *pEnd = This->tMediaEnd;
701 return E_NOTIMPL;
704 static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
706 StdMediaSample2 *This = (StdMediaSample2 *)iface;
708 TRACE("(%p, %p)\n", pStart, pEnd);
710 if (pStart)
711 This->tMediaStart = *pStart;
712 else
713 This->tMediaStart = INVALID_MEDIA_TIME;
715 if (pEnd)
716 This->tMediaEnd = *pEnd;
717 else
718 This->tMediaEnd = 0;
720 return S_OK;
723 static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties)
725 StdMediaSample2 *This = (StdMediaSample2 *)iface;
727 TRACE("(%ld, %p)\n", cbProperties, pbProperties);
729 memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props)));
731 return S_OK;
734 static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties)
736 StdMediaSample2 *This = (StdMediaSample2 *)iface;
738 TRACE("(%ld, %p)\n", cbProperties, pbProperties);
740 /* NOTE: pbBuffer and cbBuffer are read-only */
741 memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE));
743 return S_OK;
746 static const IMediaSample2Vtbl StdMediaSample2_VTable =
748 StdMediaSample2_QueryInterface,
749 StdMediaSample2_AddRef,
750 StdMediaSample2_Release,
751 StdMediaSample2_GetPointer,
752 StdMediaSample2_GetSize,
753 StdMediaSample2_GetTime,
754 StdMediaSample2_SetTime,
755 StdMediaSample2_IsSyncPoint,
756 StdMediaSample2_SetSyncPoint,
757 StdMediaSample2_IsPreroll,
758 StdMediaSample2_SetPreroll,
759 StdMediaSample2_GetActualDataLength,
760 StdMediaSample2_SetActualDataLength,
761 StdMediaSample2_GetMediaType,
762 StdMediaSample2_SetMediaType,
763 StdMediaSample2_IsDiscontinuity,
764 StdMediaSample2_SetDiscontinuity,
765 StdMediaSample2_GetMediaTime,
766 StdMediaSample2_SetMediaTime,
767 StdMediaSample2_GetProperties,
768 StdMediaSample2_SetProperties
771 typedef struct StdMemAllocator
773 BaseMemAllocator base;
774 LPVOID pMemory;
775 } StdMemAllocator;
777 static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface)
779 StdMemAllocator *This = (StdMemAllocator *)iface;
780 StdMediaSample2 * pSample = NULL;
781 SYSTEM_INFO si;
782 long i;
784 assert(list_empty(&This->base.free_list));
786 /* check alignment */
787 GetSystemInfo(&si);
789 /* we do not allow a courser alignment than the OS page size */
790 if ((si.dwPageSize % This->base.pProps->cbAlign) != 0)
791 return VFW_E_BADALIGN;
793 /* FIXME: each sample has to have its buffer start on the right alignment.
794 * We don't do this at the moment */
796 /* allocate memory */
797 This->pMemory = VirtualAlloc(NULL, (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) * This->base.pProps->cBuffers, MEM_COMMIT, PAGE_READWRITE);
799 for (i = This->base.pProps->cBuffers - 1; i >= 0; i--)
801 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
802 BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) + This->base.pProps->cbPrefix;
804 StdMediaSample2_Construct(pbBuffer, This->base.pProps->cbBuffer, iface, &pSample);
806 list_add_head(&This->base.free_list, &pSample->listentry);
809 return S_OK;
812 static HRESULT StdMemAllocator_Free(IMemAllocator * iface)
814 StdMemAllocator *This = (StdMemAllocator *)iface;
815 struct list * cursor;
817 assert(list_empty(&This->base.used_list));
819 while ((cursor = list_head(&This->base.free_list)) != NULL)
821 list_remove(cursor);
822 StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry));
825 /* free memory */
826 if (!VirtualFree(This->pMemory, 0, MEM_RELEASE))
828 ERR("Couldn't free memory. Error: %ld\n", GetLastError());
829 return HRESULT_FROM_WIN32(GetLastError());
832 return S_OK;
835 HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv)
837 StdMemAllocator * pMemAlloc;
838 HRESULT hr;
840 *ppv = NULL;
842 if (lpUnkOuter)
843 return CLASS_E_NOAGGREGATION;
845 if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc))))
846 return E_OUTOFMEMORY;
848 pMemAlloc->pMemory = NULL;
850 if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, &pMemAlloc->base)))
851 *ppv = (LPVOID)pMemAlloc;
852 else
853 CoTaskMemFree(pMemAlloc);
855 return hr;