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
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
)
39 TRACE("AM_SAMPLE2_PROPERTIES: (null)\n");
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
;
59 ALLOCATOR_PROPERTIES
* pProps
;
60 CRITICAL_SECTION csState
;
61 HRESULT (* fnAlloc
) (IMemAllocator
*);
62 HRESULT (* fnFree
)(IMemAllocator
*);
67 struct list free_list
;
68 struct list used_list
;
71 typedef struct StdMediaSample2
73 const IMediaSample2Vtbl
* lpvtbl
;
76 AM_SAMPLE2_PROPERTIES props
;
77 IMemAllocator
* pParent
;
78 struct list listentry
;
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
;
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
);
112 static HRESULT WINAPI
BaseMemAllocator_QueryInterface(IMemAllocator
* iface
, REFIID riid
, LPVOID
* ppv
)
114 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
115 TRACE("(%p)->(%s, %p)\n", This
, qzdebugstr_guid(riid
), ppv
);
119 if (IsEqualIID(riid
, &IID_IUnknown
))
121 else if (IsEqualIID(riid
, &IID_IMemAllocator
))
126 IUnknown_AddRef((IUnknown
*)(*ppv
));
130 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
132 return E_NOINTERFACE
;
135 static ULONG WINAPI
BaseMemAllocator_AddRef(IMemAllocator
* iface
)
137 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
138 ULONG ref
= InterlockedIncrement(&This
->ref
);
140 TRACE("(%p)->() AddRef from %ld\n", iface
, ref
- 1);
145 static ULONG WINAPI
BaseMemAllocator_Release(IMemAllocator
* iface
)
147 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
148 ULONG ref
= InterlockedDecrement(&This
->ref
);
150 TRACE("(%p)->() Release from %ld\n", iface
, ref
+ 1);
154 CloseHandle(This
->hSemWaiting
);
155 if (This
->bCommitted
)
157 HeapFree(GetProcessHeap(), 0, This
->pProps
);
164 static HRESULT WINAPI
BaseMemAllocator_SetProperties(IMemAllocator
* iface
, ALLOCATOR_PROPERTIES
*pRequest
, ALLOCATOR_PROPERTIES
*pActual
)
166 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
169 TRACE("(%p)->(%p, %p)\n", This
, pRequest
, pActual
);
171 EnterCriticalSection(&This
->csState
);
173 if (!list_empty(&This
->used_list
))
174 hr
= VFW_E_BUFFERS_OUTSTANDING
;
175 else if (This
->bCommitted
)
176 hr
= VFW_E_ALREADY_COMMITTED
;
177 else if (pRequest
->cbAlign
== 0)
182 This
->pProps
= HeapAlloc(GetProcessHeap(), 0, sizeof(*This
->pProps
));
188 memcpy(This
->pProps
, pRequest
, sizeof(*This
->pProps
));
190 memcpy(pActual
, pRequest
, sizeof(*pActual
));
196 LeaveCriticalSection(&This
->csState
);
201 static HRESULT WINAPI
BaseMemAllocator_GetProperties(IMemAllocator
* iface
, ALLOCATOR_PROPERTIES
*pProps
)
203 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
206 TRACE("(%p)->(%p)\n", This
, pProps
);
208 EnterCriticalSection(&This
->csState
);
210 /* NOTE: this is different from the native version.
211 * It would silently succeed if the properties had
212 * not been set, but would fail further on down the
213 * line with some obscure error like having an
214 * invalid alignment. Whether or not our version
215 * will cause any problems remains to be seen */
217 hr
= VFW_E_SIZENOTSET
;
219 memcpy(pProps
, This
->pProps
, sizeof(*pProps
));
221 LeaveCriticalSection(&This
->csState
);
226 static HRESULT WINAPI
BaseMemAllocator_Commit(IMemAllocator
* iface
)
228 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
231 TRACE("(%p)->()\n", This
);
233 EnterCriticalSection(&This
->csState
);
236 hr
= VFW_E_SIZENOTSET
;
237 else if (This
->bCommitted
)
239 else if (This
->bDecommitQueued
)
241 This
->bDecommitQueued
= FALSE
;
246 if (!(This
->hSemWaiting
= CreateSemaphoreW(NULL
, This
->pProps
->cBuffers
, This
->pProps
->cBuffers
, NULL
)))
248 ERR("Couldn't create semaphore (error was %ld)\n", GetLastError());
249 hr
= HRESULT_FROM_WIN32(GetLastError());
253 hr
= This
->fnAlloc(iface
);
255 This
->bCommitted
= TRUE
;
257 ERR("fnAlloc failed with error 0x%lx\n", hr
);
261 LeaveCriticalSection(&This
->csState
);
266 static HRESULT WINAPI
BaseMemAllocator_Decommit(IMemAllocator
* iface
)
268 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
271 TRACE("(%p)->()\n", This
);
273 EnterCriticalSection(&This
->csState
);
275 if (!This
->bCommitted
)
279 if (!list_empty(&This
->used_list
))
281 This
->bDecommitQueued
= TRUE
;
282 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
283 ReleaseSemaphore(This
->hSemWaiting
, This
->lWaiting
, NULL
);
289 assert(This
->lWaiting
== 0);
291 This
->bCommitted
= FALSE
;
292 CloseHandle(This
->hSemWaiting
);
293 This
->hSemWaiting
= NULL
;
295 hr
= This
->fnFree(iface
);
297 ERR("fnFree failed with error 0x%lx\n", hr
);
301 LeaveCriticalSection(&This
->csState
);
306 static HRESULT WINAPI
BaseMemAllocator_GetBuffer(IMemAllocator
* iface
, IMediaSample
** pSample
, REFERENCE_TIME
*pStartTime
, REFERENCE_TIME
*pEndTime
, DWORD dwFlags
)
308 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
311 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
312 * The allocator might use these values to determine which buffer it retrieves */
314 TRACE("(%p)->(%p, %p, %p, %lx)\n", This
, pSample
, pStartTime
, pEndTime
, dwFlags
);
318 if (!This
->bCommitted
)
319 return VFW_E_NOT_COMMITTED
;
322 if (WaitForSingleObject(This
->hSemWaiting
, (dwFlags
& AM_GBF_NOWAIT
) ? 0 : INFINITE
) != WAIT_OBJECT_0
)
325 return VFW_E_TIMEOUT
;
329 EnterCriticalSection(&This
->csState
);
331 if (!This
->bCommitted
)
332 hr
= VFW_E_NOT_COMMITTED
;
333 else if (This
->bDecommitQueued
)
337 struct list
* free
= list_head(&This
->free_list
);
339 list_add_head(&This
->used_list
, free
);
341 *pSample
= (IMediaSample
*)LIST_ENTRY(free
, StdMediaSample2
, listentry
);
343 assert(((StdMediaSample2
*)*pSample
)->ref
== 0);
345 IMediaSample_AddRef(*pSample
);
348 LeaveCriticalSection(&This
->csState
);
353 static HRESULT WINAPI
BaseMemAllocator_ReleaseBuffer(IMemAllocator
* iface
, IMediaSample
* pSample
)
355 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
356 StdMediaSample2
* pStdSample
= (StdMediaSample2
*)pSample
;
359 TRACE("(%p)->(%p)\n", This
, pSample
);
361 /* FIXME: make sure that sample is currently on the used list */
363 /* FIXME: we should probably check the ref count on the sample before freeing
364 * it to make sure that it is not still in use */
365 EnterCriticalSection(&This
->csState
);
367 if (!This
->bCommitted
)
368 ERR("Releasing a buffer when the allocator is not committed?!?\n");
370 /* remove from used_list */
371 list_remove(&pStdSample
->listentry
);
373 list_add_head(&This
->free_list
, &pStdSample
->listentry
);
375 if (list_empty(&This
->used_list
) && This
->bDecommitQueued
&& This
->bCommitted
)
379 assert(This
->lWaiting
== 0);
381 This
->bCommitted
= FALSE
;
382 This
->bDecommitQueued
= FALSE
;
384 CloseHandle(This
->hSemWaiting
);
385 This
->hSemWaiting
= NULL
;
387 if (FAILED(hrfree
= This
->fnFree(iface
)))
388 ERR("fnFree failed with error 0x%lx\n", hrfree
);
391 LeaveCriticalSection(&This
->csState
);
393 /* notify a waiting thread that there is now a free buffer */
394 if (!ReleaseSemaphore(This
->hSemWaiting
, 1, NULL
))
396 ERR("ReleaseSemaphore failed with error %ld\n", GetLastError());
397 hr
= HRESULT_FROM_WIN32(GetLastError());
403 static const IMemAllocatorVtbl BaseMemAllocator_VTable
=
405 BaseMemAllocator_QueryInterface
,
406 BaseMemAllocator_AddRef
,
407 BaseMemAllocator_Release
,
408 BaseMemAllocator_SetProperties
,
409 BaseMemAllocator_GetProperties
,
410 BaseMemAllocator_Commit
,
411 BaseMemAllocator_Decommit
,
412 BaseMemAllocator_GetBuffer
,
413 BaseMemAllocator_ReleaseBuffer
416 static HRESULT
StdMediaSample2_Construct(BYTE
* pbBuffer
, LONG cbBuffer
, IMemAllocator
* pParent
, StdMediaSample2
** ppSample
)
418 assert(pbBuffer
&& pParent
&& (cbBuffer
> 0));
420 if (!(*ppSample
= CoTaskMemAlloc(sizeof(StdMediaSample2
))))
421 return E_OUTOFMEMORY
;
423 (*ppSample
)->lpvtbl
= &StdMediaSample2_VTable
;
424 (*ppSample
)->ref
= 0;
425 ZeroMemory(&(*ppSample
)->props
, sizeof((*ppSample
)->props
));
427 /* NOTE: no need to AddRef as the parent is guaranteed to be around
428 * at least as long as us and we don't want to create circular
429 * dependencies on the ref count */
430 (*ppSample
)->pParent
= pParent
;
431 (*ppSample
)->props
.cbData
= sizeof(AM_SAMPLE2_PROPERTIES
);
432 (*ppSample
)->props
.cbBuffer
= (*ppSample
)->props
.lActual
= cbBuffer
;
433 (*ppSample
)->props
.pbBuffer
= pbBuffer
;
434 (*ppSample
)->tMediaStart
= INVALID_MEDIA_TIME
;
435 (*ppSample
)->tMediaEnd
= 0;
440 static void StdMediaSample2_Delete(StdMediaSample2
* This
)
442 /* NOTE: does not remove itself from the list it belongs to */
446 static HRESULT WINAPI
StdMediaSample2_QueryInterface(IMediaSample2
* iface
, REFIID riid
, LPVOID
* ppv
)
448 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
449 TRACE("(%s, %p)\n", qzdebugstr_guid(riid
), ppv
);
453 if (IsEqualIID(riid
, &IID_IUnknown
))
455 else if (IsEqualIID(riid
, &IID_IMediaSample
))
457 else if (IsEqualIID(riid
, &IID_IMediaSample2
))
462 IUnknown_AddRef((IUnknown
*)(*ppv
));
466 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
468 return E_NOINTERFACE
;
471 static ULONG WINAPI
StdMediaSample2_AddRef(IMediaSample2
* iface
)
473 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
474 ULONG ref
= InterlockedIncrement(&This
->ref
);
476 TRACE("(%p)->() AddRef from %ld\n", iface
, ref
- 1);
481 static ULONG WINAPI
StdMediaSample2_Release(IMediaSample2
* iface
)
483 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
484 ULONG ref
= InterlockedDecrement(&This
->ref
);
486 TRACE("(%p)->() Release from %ld\n", iface
, ref
+ 1);
490 IMemAllocator_ReleaseBuffer(This
->pParent
, (IMediaSample
*)iface
);
496 static HRESULT WINAPI
StdMediaSample2_GetPointer(IMediaSample2
* iface
, BYTE
** ppBuffer
)
498 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
500 TRACE("(%p)\n", ppBuffer
);
502 *ppBuffer
= This
->props
.pbBuffer
;
507 static long WINAPI
StdMediaSample2_GetSize(IMediaSample2
* iface
)
509 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
511 TRACE("StdMediaSample2_GetSize()\n");
513 return This
->props
.cbBuffer
;
516 static HRESULT WINAPI
StdMediaSample2_GetTime(IMediaSample2
* iface
, REFERENCE_TIME
* pStart
, REFERENCE_TIME
* pEnd
)
519 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
521 TRACE("(%p, %p)\n", pStart
, pEnd
);
523 if (!(This
->props
.dwSampleFlags
& AM_SAMPLE_TIMEVALID
))
524 hr
= VFW_E_SAMPLE_TIME_NOT_SET
;
525 else if (!(This
->props
.dwSampleFlags
& AM_SAMPLE_STOPVALID
))
527 *pStart
= This
->props
.tStart
;
528 *pEnd
= This
->props
.tStart
+ 1;
530 hr
= VFW_S_NO_STOP_TIME
;
534 *pStart
= This
->props
.tStart
;
535 *pEnd
= This
->props
.tStop
;
543 static HRESULT WINAPI
StdMediaSample2_SetTime(IMediaSample2
* iface
, REFERENCE_TIME
* pStart
, REFERENCE_TIME
* pEnd
)
545 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
547 TRACE("(%p, %p)\n", pStart
, pEnd
);
551 This
->props
.tStart
= *pStart
;
552 This
->props
.dwSampleFlags
|= AM_SAMPLE_TIMEVALID
;
555 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_TIMEVALID
;
559 This
->props
.tStop
= *pEnd
;
560 This
->props
.dwSampleFlags
|= AM_SAMPLE_STOPVALID
;
563 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_STOPVALID
;
568 static HRESULT WINAPI
StdMediaSample2_IsSyncPoint(IMediaSample2
* iface
)
570 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
574 return (This
->props
.dwSampleFlags
& AM_SAMPLE_SPLICEPOINT
) ? S_OK
: S_FALSE
;
577 static HRESULT WINAPI
StdMediaSample2_SetSyncPoint(IMediaSample2
* iface
, BOOL bIsSyncPoint
)
579 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
581 TRACE("(%s)\n", bIsSyncPoint
? "TRUE" : "FALSE");
583 This
->props
.dwSampleFlags
= (This
->props
.dwSampleFlags
& ~AM_SAMPLE_SPLICEPOINT
) | bIsSyncPoint
? AM_SAMPLE_SPLICEPOINT
: 0;
588 static HRESULT WINAPI
StdMediaSample2_IsPreroll(IMediaSample2
* iface
)
590 StdMediaSample2
*This
= (StdMediaSample2
*)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("(%s)\n", bIsPreroll
? "TRUE" : "FALSE");
603 This
->props
.dwSampleFlags
= (This
->props
.dwSampleFlags
& ~AM_SAMPLE_PREROLL
) | bIsPreroll
? AM_SAMPLE_PREROLL
: 0;
608 static LONG WINAPI
StdMediaSample2_GetActualDataLength(IMediaSample2
* iface
)
610 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
614 return This
->props
.lActual
;
617 static HRESULT WINAPI
StdMediaSample2_SetActualDataLength(IMediaSample2
* iface
, LONG len
)
619 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
621 TRACE("(%ld)\n", len
);
623 if ((len
> This
->props
.cbBuffer
) || (len
< 0))
624 return VFW_E_BUFFER_OVERFLOW
;
627 This
->props
.lActual
= len
;
632 static HRESULT WINAPI
StdMediaSample2_GetMediaType(IMediaSample2
* iface
, AM_MEDIA_TYPE
** ppMediaType
)
634 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
636 TRACE("(%p)\n", ppMediaType
);
638 if (!This
->props
.pMediaType
) {
639 /* Make sure we return a NULL pointer (required by native Quartz dll) */
645 if (!(*ppMediaType
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
646 return E_OUTOFMEMORY
;
648 return CopyMediaType(*ppMediaType
, This
->props
.pMediaType
);
651 static HRESULT WINAPI
StdMediaSample2_SetMediaType(IMediaSample2
* iface
, AM_MEDIA_TYPE
* pMediaType
)
653 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
655 TRACE("(%p)\n", pMediaType
);
657 if (This
->props
.pMediaType
)
658 FreeMediaType(This
->props
.pMediaType
);
659 else if (!(This
->props
.pMediaType
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
660 return E_OUTOFMEMORY
;
662 return CopyMediaType(This
->props
.pMediaType
, pMediaType
);
665 static HRESULT WINAPI
StdMediaSample2_IsDiscontinuity(IMediaSample2
* iface
)
667 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
671 return (This
->props
.dwSampleFlags
& AM_SAMPLE_DATADISCONTINUITY
) ? S_OK
: S_FALSE
;
674 static HRESULT WINAPI
StdMediaSample2_SetDiscontinuity(IMediaSample2
* iface
, BOOL bIsDiscontinuity
)
676 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
678 TRACE("(%s)\n", bIsDiscontinuity
? "TRUE" : "FALSE");
680 This
->props
.dwSampleFlags
= (This
->props
.dwSampleFlags
& ~AM_SAMPLE_DATADISCONTINUITY
) | bIsDiscontinuity
? AM_SAMPLE_DATADISCONTINUITY
: 0;
685 static HRESULT WINAPI
StdMediaSample2_GetMediaTime(IMediaSample2
* iface
, LONGLONG
* pStart
, LONGLONG
* pEnd
)
687 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
689 TRACE("(%p, %p)\n", pStart
, pEnd
);
691 if (This
->tMediaStart
== INVALID_MEDIA_TIME
)
692 return VFW_E_MEDIA_TIME_NOT_SET
;
694 *pStart
= This
->tMediaStart
;
695 *pEnd
= This
->tMediaEnd
;
700 static HRESULT WINAPI
StdMediaSample2_SetMediaTime(IMediaSample2
* iface
, LONGLONG
* pStart
, LONGLONG
* pEnd
)
702 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
704 TRACE("(%p, %p)\n", pStart
, pEnd
);
707 This
->tMediaStart
= *pStart
;
709 This
->tMediaStart
= INVALID_MEDIA_TIME
;
712 This
->tMediaEnd
= *pEnd
;
719 static HRESULT WINAPI
StdMediaSample2_GetProperties(IMediaSample2
* iface
, DWORD cbProperties
, BYTE
* pbProperties
)
721 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
723 TRACE("(%ld, %p)\n", cbProperties
, pbProperties
);
725 memcpy(pbProperties
, &This
->props
, min(cbProperties
, sizeof(This
->props
)));
730 static HRESULT WINAPI
StdMediaSample2_SetProperties(IMediaSample2
* iface
, DWORD cbProperties
, const BYTE
* pbProperties
)
732 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
734 TRACE("(%ld, %p)\n", cbProperties
, pbProperties
);
736 /* NOTE: pbBuffer and cbBuffer are read-only */
737 memcpy(&This
->props
, pbProperties
, min(cbProperties
, AM_SAMPLE2_PROP_SIZE_WRITABLE
));
742 static const IMediaSample2Vtbl StdMediaSample2_VTable
=
744 StdMediaSample2_QueryInterface
,
745 StdMediaSample2_AddRef
,
746 StdMediaSample2_Release
,
747 StdMediaSample2_GetPointer
,
748 StdMediaSample2_GetSize
,
749 StdMediaSample2_GetTime
,
750 StdMediaSample2_SetTime
,
751 StdMediaSample2_IsSyncPoint
,
752 StdMediaSample2_SetSyncPoint
,
753 StdMediaSample2_IsPreroll
,
754 StdMediaSample2_SetPreroll
,
755 StdMediaSample2_GetActualDataLength
,
756 StdMediaSample2_SetActualDataLength
,
757 StdMediaSample2_GetMediaType
,
758 StdMediaSample2_SetMediaType
,
759 StdMediaSample2_IsDiscontinuity
,
760 StdMediaSample2_SetDiscontinuity
,
761 StdMediaSample2_GetMediaTime
,
762 StdMediaSample2_SetMediaTime
,
763 StdMediaSample2_GetProperties
,
764 StdMediaSample2_SetProperties
767 typedef struct StdMemAllocator
769 BaseMemAllocator base
;
773 static HRESULT
StdMemAllocator_Alloc(IMemAllocator
* iface
)
775 StdMemAllocator
*This
= (StdMemAllocator
*)iface
;
776 StdMediaSample2
* pSample
= NULL
;
780 assert(list_empty(&This
->base
.free_list
));
782 /* check alignment */
785 /* we do not allow a courser alignment than the OS page size */
786 if ((si
.dwPageSize
% This
->base
.pProps
->cbAlign
) != 0)
787 return VFW_E_BADALIGN
;
789 /* FIXME: each sample has to have its buffer start on the right alignment.
790 * We don't do this at the moment */
792 /* allocate memory */
793 This
->pMemory
= VirtualAlloc(NULL
, (This
->base
.pProps
->cbBuffer
+ This
->base
.pProps
->cbPrefix
) * This
->base
.pProps
->cBuffers
, MEM_COMMIT
, PAGE_READWRITE
);
795 for (i
= This
->base
.pProps
->cBuffers
- 1; i
>= 0; i
--)
797 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
798 BYTE
* pbBuffer
= (BYTE
*)This
->pMemory
+ i
* (This
->base
.pProps
->cbBuffer
+ This
->base
.pProps
->cbPrefix
) + This
->base
.pProps
->cbPrefix
;
800 StdMediaSample2_Construct(pbBuffer
, This
->base
.pProps
->cbBuffer
, iface
, &pSample
);
802 list_add_head(&This
->base
.free_list
, &pSample
->listentry
);
808 static HRESULT
StdMemAllocator_Free(IMemAllocator
* iface
)
810 StdMemAllocator
*This
= (StdMemAllocator
*)iface
;
811 struct list
* cursor
;
813 assert(list_empty(&This
->base
.used_list
));
815 while ((cursor
= list_head(&This
->base
.free_list
)) != NULL
)
818 StdMediaSample2_Delete(LIST_ENTRY(cursor
, StdMediaSample2
, listentry
));
822 if (!VirtualFree(This
->pMemory
, 0, MEM_RELEASE
))
824 ERR("Couldn't free memory. Error: %ld\n", GetLastError());
825 return HRESULT_FROM_WIN32(GetLastError());
831 HRESULT
StdMemAllocator_create(LPUNKNOWN lpUnkOuter
, LPVOID
* ppv
)
833 StdMemAllocator
* pMemAlloc
;
839 return CLASS_E_NOAGGREGATION
;
841 if (!(pMemAlloc
= CoTaskMemAlloc(sizeof(*pMemAlloc
))))
842 return E_OUTOFMEMORY
;
844 pMemAlloc
->pMemory
= NULL
;
846 if (SUCCEEDED(hr
= BaseMemAllocator_Init(StdMemAllocator_Alloc
, StdMemAllocator_Free
, &pMemAlloc
->base
)))
847 *ppv
= (LPVOID
)pMemAlloc
;
849 CoTaskMemFree(pMemAlloc
);