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/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(quartz
);
34 void dump_AM_SAMPLE2_PROPERTIES(const AM_SAMPLE2_PROPERTIES
* pProps
)
38 TRACE("AM_SAMPLE2_PROPERTIES: (null)\n");
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
;
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
;
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
);
99 if (IsEqualIID(riid
, &IID_IUnknown
))
101 else if (IsEqualIID(riid
, &IID_IMemAllocator
))
106 IUnknown_AddRef((IUnknown
*)(*ppv
));
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);
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);
134 CloseHandle(This
->hSemWaiting
);
135 if (This
->bCommitted
)
138 This
->fnDestroyed(iface
);
144 static HRESULT WINAPI
BaseMemAllocator_SetProperties(IMemAllocator
* iface
, ALLOCATOR_PROPERTIES
*pRequest
, ALLOCATOR_PROPERTIES
*pActual
)
146 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
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)
162 hr
= This
->fnVerify(iface
, pRequest
);
167 This
->props
= *pRequest
;
169 *pActual
= This
->props
;
172 LeaveCriticalSection(This
->pCritSect
);
177 static HRESULT WINAPI
BaseMemAllocator_GetProperties(IMemAllocator
* iface
, ALLOCATOR_PROPERTIES
*pProps
)
179 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
182 TRACE("(%p)->(%p)\n", This
, pProps
);
184 EnterCriticalSection(This
->pCritSect
);
186 memcpy(pProps
, &This
->props
, sizeof(*pProps
));
188 LeaveCriticalSection(This
->pCritSect
);
193 static HRESULT WINAPI
BaseMemAllocator_Commit(IMemAllocator
* iface
)
195 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
198 TRACE("(%p)->()\n", This
);
200 EnterCriticalSection(This
->pCritSect
);
202 if (!This
->props
.cbAlign
)
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
;
213 else if (This
->bCommitted
)
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());
224 hr
= This
->fnAlloc(iface
);
226 This
->bCommitted
= TRUE
;
228 ERR("fnAlloc failed with error 0x%x\n", hr
);
232 LeaveCriticalSection(This
->pCritSect
);
237 static HRESULT WINAPI
BaseMemAllocator_Decommit(IMemAllocator
* iface
)
239 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
242 TRACE("(%p)->()\n", This
);
244 EnterCriticalSection(This
->pCritSect
);
246 if (!This
->bCommitted
)
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
);
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
);
269 ERR("fnFree failed with error 0x%x\n", hr
);
273 LeaveCriticalSection(This
->pCritSect
);
278 static HRESULT WINAPI
BaseMemAllocator_GetBuffer(IMemAllocator
* iface
, IMediaSample
** pSample
, REFERENCE_TIME
*pStartTime
, REFERENCE_TIME
*pEndTime
, DWORD dwFlags
)
280 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
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
);
290 EnterCriticalSection(This
->pCritSect
);
291 if (!This
->bCommitted
|| This
->bDecommitQueued
)
293 WARN("Not committed\n");
294 hr
= VFW_E_NOT_COMMITTED
;
298 LeaveCriticalSection(This
->pCritSect
);
302 if (WaitForSingleObject(This
->hSemWaiting
, (dwFlags
& AM_GBF_NOWAIT
) ? 0 : INFINITE
) != WAIT_OBJECT_0
)
304 EnterCriticalSection(This
->pCritSect
);
306 LeaveCriticalSection(This
->pCritSect
);
308 return VFW_E_TIMEOUT
;
311 EnterCriticalSection(This
->pCritSect
);
314 if (!This
->bCommitted
)
315 hr
= VFW_E_NOT_COMMITTED
;
316 else if (This
->bDecommitQueued
)
320 struct list
* free
= list_head(&This
->free_list
);
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
);
338 static HRESULT WINAPI
BaseMemAllocator_ReleaseBuffer(IMemAllocator
* iface
, IMediaSample
* pSample
)
340 BaseMemAllocator
*This
= (BaseMemAllocator
*)iface
;
341 StdMediaSample2
* pStdSample
= (StdMediaSample2
*)pSample
;
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
)
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());
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;
426 void StdMediaSample2_Delete(StdMediaSample2
* This
)
428 /* NOTE: does not remove itself from the list it belongs to */
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
);
439 if (IsEqualIID(riid
, &IID_IUnknown
))
441 else if (IsEqualIID(riid
, &IID_IMediaSample
))
443 else if (IsEqualIID(riid
, &IID_IMediaSample2
))
448 IUnknown_AddRef((IUnknown
*)(*ppv
));
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);
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);
477 IMemAllocator_ReleaseBuffer(This
->pParent
, (IMediaSample
*)iface
);
479 StdMediaSample2_Delete(This
);
485 static HRESULT WINAPI
StdMediaSample2_GetPointer(IMediaSample2
* iface
, BYTE
** ppBuffer
)
487 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
489 TRACE("(%p)->(%p)\n", iface
, ppBuffer
);
491 *ppBuffer
= This
->props
.pbBuffer
;
495 ERR("Requested an unlocked surface and trying to lock regardless\n");
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
)
514 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
516 TRACE("(%p)->(%p, %p)\n", iface
, 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
;
529 *pStart
= This
->props
.tStart
;
530 *pEnd
= This
->props
.tStop
;
538 static HRESULT WINAPI
StdMediaSample2_SetTime(IMediaSample2
* iface
, REFERENCE_TIME
* pStart
, REFERENCE_TIME
* pEnd
)
540 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
542 TRACE("(%p)->(%p, %p)\n", iface
, pStart
, pEnd
);
546 This
->props
.tStart
= *pStart
;
547 This
->props
.dwSampleFlags
|= AM_SAMPLE_TIMEVALID
;
550 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_TIMEVALID
;
554 This
->props
.tStop
= *pEnd
;
555 This
->props
.dwSampleFlags
|= AM_SAMPLE_STOPVALID
;
558 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_STOPVALID
;
563 static HRESULT WINAPI
StdMediaSample2_IsSyncPoint(IMediaSample2
* iface
)
565 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
567 TRACE("(%p)->()\n", iface
);
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("(%p)->(%s)\n", iface
, bIsSyncPoint
? "TRUE" : "FALSE");
579 This
->props
.dwSampleFlags
|= AM_SAMPLE_SPLICEPOINT
;
581 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_SPLICEPOINT
;
586 static HRESULT WINAPI
StdMediaSample2_IsPreroll(IMediaSample2
* iface
)
588 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
590 TRACE("(%p)->()\n", iface
);
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("(%p)->(%s)\n", iface
, bIsPreroll
? "TRUE" : "FALSE");
602 This
->props
.dwSampleFlags
|= AM_SAMPLE_PREROLL
;
604 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_PREROLL
;
609 static LONG WINAPI
StdMediaSample2_GetActualDataLength(IMediaSample2
* iface
)
611 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
613 TRACE("(%p)->()\n", iface
);
615 return This
->props
.lActual
;
618 static HRESULT WINAPI
StdMediaSample2_SetActualDataLength(IMediaSample2
* iface
, LONG len
)
620 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
622 TRACE("(%p)->(%d)\n", iface
, 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
;
631 This
->props
.lActual
= len
;
636 static HRESULT WINAPI
StdMediaSample2_GetMediaType(IMediaSample2
* iface
, AM_MEDIA_TYPE
** ppMediaType
)
638 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
640 TRACE("(%p)->(%p)\n", iface
, ppMediaType
);
642 if (!This
->props
.pMediaType
) {
643 /* Make sure we return a NULL pointer (required by native Quartz dll) */
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)->(%p)\n", iface
, 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("(%p)->()\n", iface
);
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("(%p)->(%s)\n", iface
, bIsDiscontinuity
? "TRUE" : "FALSE");
684 if (bIsDiscontinuity
)
685 This
->props
.dwSampleFlags
|= AM_SAMPLE_DATADISCONTINUITY
;
687 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_DATADISCONTINUITY
;
692 static HRESULT WINAPI
StdMediaSample2_GetMediaTime(IMediaSample2
* iface
, LONGLONG
* pStart
, LONGLONG
* pEnd
)
694 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
696 TRACE("(%p)->(%p, %p)\n", iface
, 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
;
707 static HRESULT WINAPI
StdMediaSample2_SetMediaTime(IMediaSample2
* iface
, LONGLONG
* pStart
, LONGLONG
* pEnd
)
709 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
711 TRACE("(%p)->(%p, %p)\n", iface
, pStart
, pEnd
);
714 This
->tMediaStart
= *pStart
;
716 This
->tMediaStart
= INVALID_MEDIA_TIME
;
719 This
->tMediaEnd
= *pEnd
;
726 static HRESULT WINAPI
StdMediaSample2_GetProperties(IMediaSample2
* iface
, DWORD cbProperties
, BYTE
* pbProperties
)
728 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
730 TRACE("(%p)->(%d, %p)\n", iface
, cbProperties
, pbProperties
);
732 memcpy(pbProperties
, &This
->props
, min(cbProperties
, sizeof(This
->props
)));
737 static HRESULT WINAPI
StdMediaSample2_SetProperties(IMediaSample2
* iface
, DWORD cbProperties
, const BYTE
* pbProperties
)
739 StdMediaSample2
*This
= (StdMediaSample2
*)iface
;
741 TRACE("(%p)->(%d, %p)\n", iface
, cbProperties
, pbProperties
);
743 /* NOTE: pbBuffer and cbBuffer are read-only */
744 memcpy(&This
->props
, pbProperties
, min(cbProperties
, AM_SAMPLE2_PROP_SIZE_WRITABLE
));
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
;
781 static HRESULT
StdMemAllocator_Alloc(IMemAllocator
* iface
)
783 StdMemAllocator
*This
= (StdMemAllocator
*)iface
;
784 StdMediaSample2
* pSample
= NULL
;
788 assert(list_empty(&This
->base
.free_list
));
790 /* check alignment */
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
);
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
;
828 pSample
= LIST_ENTRY(cursor
, StdMediaSample2
, listentry
);
829 pSample
->pParent
= NULL
;
833 while ((cursor
= list_head(&This
->base
.free_list
)) != NULL
)
836 StdMediaSample2_Delete(LIST_ENTRY(cursor
, StdMediaSample2
, listentry
));
840 if (!VirtualFree(This
->pMemory
, 0, MEM_RELEASE
))
842 ERR("Couldn't free memory. Error: %u\n", GetLastError());
843 return HRESULT_FROM_WIN32(GetLastError());
849 static void StdMemAllocator_Destroy(IMemAllocator
*iface
)
851 StdMemAllocator
*This
= (StdMemAllocator
*)iface
;
853 This
->csState
.DebugInfo
->Spare
[0] = 0;
854 DeleteCriticalSection(&This
->csState
);
859 HRESULT
StdMemAllocator_create(LPUNKNOWN lpUnkOuter
, LPVOID
* ppv
)
861 StdMemAllocator
* pMemAlloc
;
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
;
880 CoTaskMemFree(pMemAlloc
);