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 typedef struct StdMediaSample2
36 IMediaSample2 IMediaSample2_iface
;
38 AM_SAMPLE2_PROPERTIES props
;
39 IMemAllocator
* pParent
;
40 struct list listentry
;
43 BOOL media_time_valid
;
46 typedef struct BaseMemAllocator
48 IMemAllocator IMemAllocator_iface
;
51 ALLOCATOR_PROPERTIES props
;
52 HRESULT (* fnAlloc
) (IMemAllocator
*);
53 HRESULT (* fnFree
)(IMemAllocator
*);
54 HRESULT (* fnVerify
)(IMemAllocator
*, ALLOCATOR_PROPERTIES
*);
55 HRESULT (* fnBufferPrepare
)(IMemAllocator
*, StdMediaSample2
*, DWORD flags
);
56 HRESULT (* fnBufferReleased
)(IMemAllocator
*, StdMediaSample2
*);
57 void (* fnDestroyed
)(IMemAllocator
*);
62 struct list free_list
;
63 struct list used_list
;
64 CRITICAL_SECTION
*pCritSect
;
67 static inline BaseMemAllocator
*impl_from_IMemAllocator(IMemAllocator
*iface
)
69 return CONTAINING_RECORD(iface
, BaseMemAllocator
, IMemAllocator_iface
);
72 static const IMemAllocatorVtbl BaseMemAllocator_VTable
;
73 static const IMediaSample2Vtbl StdMediaSample2_VTable
;
74 static inline StdMediaSample2
*unsafe_impl_from_IMediaSample(IMediaSample
* iface
);
76 #define AM_SAMPLE2_PROP_SIZE_WRITABLE FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer)
78 static HRESULT
BaseMemAllocator_Init(HRESULT (* fnAlloc
)(IMemAllocator
*),
79 HRESULT (* fnFree
)(IMemAllocator
*),
80 HRESULT (* fnVerify
)(IMemAllocator
*, ALLOCATOR_PROPERTIES
*),
81 HRESULT (* fnBufferPrepare
)(IMemAllocator
*, StdMediaSample2
*, DWORD
),
82 HRESULT (* fnBufferReleased
)(IMemAllocator
*, StdMediaSample2
*),
83 void (* fnDestroyed
)(IMemAllocator
*),
84 CRITICAL_SECTION
*pCritSect
,
85 BaseMemAllocator
* pMemAlloc
)
87 assert(fnAlloc
&& fnFree
&& fnDestroyed
);
89 pMemAlloc
->IMemAllocator_iface
.lpVtbl
= &BaseMemAllocator_VTable
;
92 ZeroMemory(&pMemAlloc
->props
, sizeof(pMemAlloc
->props
));
93 list_init(&pMemAlloc
->free_list
);
94 list_init(&pMemAlloc
->used_list
);
95 pMemAlloc
->fnAlloc
= fnAlloc
;
96 pMemAlloc
->fnFree
= fnFree
;
97 pMemAlloc
->fnVerify
= fnVerify
;
98 pMemAlloc
->fnBufferPrepare
= fnBufferPrepare
;
99 pMemAlloc
->fnBufferReleased
= fnBufferReleased
;
100 pMemAlloc
->fnDestroyed
= fnDestroyed
;
101 pMemAlloc
->bDecommitQueued
= FALSE
;
102 pMemAlloc
->bCommitted
= FALSE
;
103 pMemAlloc
->hSemWaiting
= NULL
;
104 pMemAlloc
->lWaiting
= 0;
105 pMemAlloc
->pCritSect
= pCritSect
;
110 static HRESULT WINAPI
BaseMemAllocator_QueryInterface(IMemAllocator
* iface
, REFIID riid
, LPVOID
* ppv
)
112 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
113 TRACE("(%p)->(%s, %p)\n", This
, qzdebugstr_guid(riid
), ppv
);
117 if (IsEqualIID(riid
, &IID_IUnknown
))
118 *ppv
= &This
->IMemAllocator_iface
;
119 else if (IsEqualIID(riid
, &IID_IMemAllocator
))
120 *ppv
= &This
->IMemAllocator_iface
;
124 IUnknown_AddRef((IUnknown
*)(*ppv
));
128 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
130 return E_NOINTERFACE
;
133 static ULONG WINAPI
BaseMemAllocator_AddRef(IMemAllocator
* iface
)
135 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
136 ULONG ref
= InterlockedIncrement(&This
->ref
);
138 TRACE("(%p)->() AddRef from %d\n", iface
, ref
- 1);
143 static ULONG WINAPI
BaseMemAllocator_Release(IMemAllocator
* iface
)
145 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
146 ULONG ref
= InterlockedDecrement(&This
->ref
);
148 TRACE("(%p)->() Release from %d\n", iface
, ref
+ 1);
152 CloseHandle(This
->hSemWaiting
);
153 if (This
->bCommitted
)
156 This
->fnDestroyed(iface
);
162 static HRESULT WINAPI
BaseMemAllocator_SetProperties(IMemAllocator
* iface
, ALLOCATOR_PROPERTIES
*pRequest
, ALLOCATOR_PROPERTIES
*pActual
)
164 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
167 TRACE("(%p)->(%p, %p)\n", This
, pRequest
, pActual
);
169 TRACE("Requested %d buffers, size %d, alignment %d, prefix %d.\n",
170 pRequest
->cBuffers
, pRequest
->cbBuffer
, pRequest
->cbAlign
, pRequest
->cbPrefix
);
172 EnterCriticalSection(This
->pCritSect
);
174 if (!list_empty(&This
->used_list
))
175 hr
= VFW_E_BUFFERS_OUTSTANDING
;
176 else if (This
->bCommitted
)
177 hr
= VFW_E_ALREADY_COMMITTED
;
178 else if (pRequest
->cbAlign
== 0)
183 hr
= This
->fnVerify(iface
, pRequest
);
188 This
->props
= *pRequest
;
190 *pActual
= This
->props
;
193 LeaveCriticalSection(This
->pCritSect
);
198 static HRESULT WINAPI
BaseMemAllocator_GetProperties(IMemAllocator
* iface
, ALLOCATOR_PROPERTIES
*pProps
)
200 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
202 TRACE("(%p)->(%p)\n", This
, pProps
);
204 EnterCriticalSection(This
->pCritSect
);
206 memcpy(pProps
, &This
->props
, sizeof(*pProps
));
208 LeaveCriticalSection(This
->pCritSect
);
213 static HRESULT WINAPI
BaseMemAllocator_Commit(IMemAllocator
* iface
)
215 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
218 TRACE("(%p)->()\n", This
);
220 EnterCriticalSection(This
->pCritSect
);
222 if (!This
->props
.cbAlign
)
224 else if (!This
->props
.cbBuffer
)
225 hr
= VFW_E_SIZENOTSET
;
226 else if (!This
->props
.cBuffers
)
227 hr
= VFW_E_BUFFER_NOTSET
;
228 else if (This
->bDecommitQueued
&& This
->bCommitted
)
230 This
->bDecommitQueued
= FALSE
;
233 else if (This
->bCommitted
)
237 if (!(This
->hSemWaiting
= CreateSemaphoreW(NULL
, This
->props
.cBuffers
, This
->props
.cBuffers
, NULL
)))
239 ERR("Couldn't create semaphore (error was %u)\n", GetLastError());
240 hr
= HRESULT_FROM_WIN32(GetLastError());
244 hr
= This
->fnAlloc(iface
);
246 This
->bCommitted
= TRUE
;
248 ERR("fnAlloc failed with error 0x%x\n", hr
);
252 LeaveCriticalSection(This
->pCritSect
);
257 static HRESULT WINAPI
BaseMemAllocator_Decommit(IMemAllocator
* iface
)
259 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
262 TRACE("(%p)->()\n", This
);
264 EnterCriticalSection(This
->pCritSect
);
266 if (!This
->bCommitted
)
270 if (!list_empty(&This
->used_list
))
272 This
->bDecommitQueued
= TRUE
;
273 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
274 ReleaseSemaphore(This
->hSemWaiting
, This
->lWaiting
, NULL
);
280 if (This
->lWaiting
!= 0)
281 ERR("Waiting: %d\n", This
->lWaiting
);
283 This
->bCommitted
= FALSE
;
284 CloseHandle(This
->hSemWaiting
);
285 This
->hSemWaiting
= NULL
;
287 hr
= This
->fnFree(iface
);
289 ERR("fnFree failed with error 0x%x\n", hr
);
293 LeaveCriticalSection(This
->pCritSect
);
298 static HRESULT WINAPI
BaseMemAllocator_GetBuffer(IMemAllocator
* iface
, IMediaSample
** pSample
, REFERENCE_TIME
*pStartTime
, REFERENCE_TIME
*pEndTime
, DWORD dwFlags
)
300 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
303 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
304 * The allocator might use these values to determine which buffer it retrieves */
306 TRACE("(%p)->(%p, %p, %p, %x)\n", This
, pSample
, pStartTime
, pEndTime
, dwFlags
);
310 EnterCriticalSection(This
->pCritSect
);
311 if (!This
->bCommitted
|| This
->bDecommitQueued
)
313 WARN("Not committed\n");
314 hr
= VFW_E_NOT_COMMITTED
;
318 LeaveCriticalSection(This
->pCritSect
);
322 if (WaitForSingleObject(This
->hSemWaiting
, (dwFlags
& AM_GBF_NOWAIT
) ? 0 : INFINITE
) != WAIT_OBJECT_0
)
324 EnterCriticalSection(This
->pCritSect
);
326 LeaveCriticalSection(This
->pCritSect
);
328 return VFW_E_TIMEOUT
;
331 EnterCriticalSection(This
->pCritSect
);
334 if (!This
->bCommitted
)
335 hr
= VFW_E_NOT_COMMITTED
;
336 else if (This
->bDecommitQueued
)
341 struct list
* free
= list_head(&This
->free_list
);
343 list_add_head(&This
->used_list
, free
);
345 ms
= LIST_ENTRY(free
, StdMediaSample2
, listentry
);
346 assert(ms
->ref
== 0);
347 *pSample
= (IMediaSample
*)&ms
->IMediaSample2_iface
;
348 IMediaSample_AddRef(*pSample
);
351 LeaveCriticalSection(This
->pCritSect
);
358 static HRESULT WINAPI
BaseMemAllocator_ReleaseBuffer(IMemAllocator
* iface
, IMediaSample
* pSample
)
360 BaseMemAllocator
*This
= impl_from_IMemAllocator(iface
);
361 StdMediaSample2
* pStdSample
= unsafe_impl_from_IMediaSample(pSample
);
364 TRACE("(%p)->(%p)\n", This
, pSample
);
366 /* FIXME: make sure that sample is currently on the used list */
368 /* FIXME: we should probably check the ref count on the sample before freeing
369 * it to make sure that it is not still in use */
370 EnterCriticalSection(This
->pCritSect
);
372 if (!This
->bCommitted
)
373 ERR("Releasing a buffer when the allocator is not committed?!?\n");
375 /* remove from used_list */
376 list_remove(&pStdSample
->listentry
);
378 list_add_head(&This
->free_list
, &pStdSample
->listentry
);
380 if (list_empty(&This
->used_list
) && This
->bDecommitQueued
&& This
->bCommitted
)
384 if (This
->lWaiting
!= 0)
385 ERR("Waiting: %d\n", This
->lWaiting
);
387 This
->bCommitted
= FALSE
;
388 This
->bDecommitQueued
= FALSE
;
390 CloseHandle(This
->hSemWaiting
);
391 This
->hSemWaiting
= NULL
;
393 if (FAILED(hrfree
= This
->fnFree(iface
)))
394 ERR("fnFree failed with error 0x%x\n", hrfree
);
397 LeaveCriticalSection(This
->pCritSect
);
399 /* notify a waiting thread that there is now a free buffer */
400 if (This
->hSemWaiting
&& !ReleaseSemaphore(This
->hSemWaiting
, 1, NULL
))
402 ERR("ReleaseSemaphore failed with error %u\n", GetLastError());
403 hr
= HRESULT_FROM_WIN32(GetLastError());
409 static const IMemAllocatorVtbl BaseMemAllocator_VTable
=
411 BaseMemAllocator_QueryInterface
,
412 BaseMemAllocator_AddRef
,
413 BaseMemAllocator_Release
,
414 BaseMemAllocator_SetProperties
,
415 BaseMemAllocator_GetProperties
,
416 BaseMemAllocator_Commit
,
417 BaseMemAllocator_Decommit
,
418 BaseMemAllocator_GetBuffer
,
419 BaseMemAllocator_ReleaseBuffer
422 static HRESULT
StdMediaSample2_Construct(BYTE
* pbBuffer
, LONG cbBuffer
, IMemAllocator
* pParent
, StdMediaSample2
** ppSample
)
424 assert(pbBuffer
&& pParent
&& (cbBuffer
> 0));
426 if (!(*ppSample
= CoTaskMemAlloc(sizeof(StdMediaSample2
))))
427 return E_OUTOFMEMORY
;
429 (*ppSample
)->IMediaSample2_iface
.lpVtbl
= &StdMediaSample2_VTable
;
430 (*ppSample
)->ref
= 0;
431 ZeroMemory(&(*ppSample
)->props
, sizeof((*ppSample
)->props
));
433 /* NOTE: no need to AddRef as the parent is guaranteed to be around
434 * at least as long as us and we don't want to create circular
435 * dependencies on the ref count */
436 (*ppSample
)->pParent
= pParent
;
437 (*ppSample
)->props
.cbData
= sizeof(AM_SAMPLE2_PROPERTIES
);
438 (*ppSample
)->props
.cbBuffer
= (*ppSample
)->props
.lActual
= cbBuffer
;
439 (*ppSample
)->props
.pbBuffer
= pbBuffer
;
440 (*ppSample
)->media_time_valid
= FALSE
;
445 static void StdMediaSample2_Delete(StdMediaSample2
* This
)
447 if (This
->props
.pMediaType
)
448 DeleteMediaType(This
->props
.pMediaType
);
450 /* NOTE: does not remove itself from the list it belongs to */
454 static inline StdMediaSample2
*impl_from_IMediaSample2(IMediaSample2
* iface
)
456 return CONTAINING_RECORD(iface
, StdMediaSample2
, IMediaSample2_iface
);
459 static HRESULT WINAPI
StdMediaSample2_QueryInterface(IMediaSample2
* iface
, REFIID riid
, void ** ppv
)
461 TRACE("(%s, %p)\n", qzdebugstr_guid(riid
), ppv
);
465 if (IsEqualIID(riid
, &IID_IUnknown
) || IsEqualIID(riid
, &IID_IMediaSample
) ||
466 IsEqualIID(riid
, &IID_IMediaSample2
))
469 IMediaSample2_AddRef(iface
);
473 FIXME("No interface for %s!\n", qzdebugstr_guid(riid
));
474 return E_NOINTERFACE
;
477 static ULONG WINAPI
StdMediaSample2_AddRef(IMediaSample2
* iface
)
479 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
480 ULONG ref
= InterlockedIncrement(&This
->ref
);
482 TRACE("(%p)->(): new ref = %d\n", This
, ref
);
487 static ULONG WINAPI
StdMediaSample2_Release(IMediaSample2
* iface
)
489 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
490 ULONG ref
= InterlockedDecrement(&This
->ref
);
492 TRACE("(%p)->(): new ref = %d\n", This
, ref
);
496 if (This
->props
.pMediaType
)
497 DeleteMediaType(This
->props
.pMediaType
);
498 This
->props
.pMediaType
= NULL
;
499 This
->props
.dwSampleFlags
= 0;
500 This
->media_time_valid
= FALSE
;
503 IMemAllocator_ReleaseBuffer(This
->pParent
, (IMediaSample
*)iface
);
505 StdMediaSample2_Delete(This
);
510 static HRESULT WINAPI
StdMediaSample2_GetPointer(IMediaSample2
* iface
, BYTE
** ppBuffer
)
512 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
514 TRACE("(%p)->(%p)\n", iface
, ppBuffer
);
516 *ppBuffer
= This
->props
.pbBuffer
;
520 ERR("Requested an unlocked surface and trying to lock regardless\n");
527 static LONG WINAPI
StdMediaSample2_GetSize(IMediaSample2
* iface
)
529 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
531 TRACE("StdMediaSample2_GetSize()\n");
533 return This
->props
.cbBuffer
;
536 static HRESULT WINAPI
StdMediaSample2_GetTime(IMediaSample2
* iface
, REFERENCE_TIME
* pStart
, REFERENCE_TIME
* pEnd
)
538 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
541 TRACE("(%p)->(%p, %p)\n", iface
, pStart
, pEnd
);
543 if (!(This
->props
.dwSampleFlags
& AM_SAMPLE_TIMEVALID
))
544 hr
= VFW_E_SAMPLE_TIME_NOT_SET
;
545 else if (!(This
->props
.dwSampleFlags
& AM_SAMPLE_STOPVALID
))
547 *pStart
= This
->props
.tStart
;
548 *pEnd
= This
->props
.tStart
+ 1;
550 hr
= VFW_S_NO_STOP_TIME
;
554 *pStart
= This
->props
.tStart
;
555 *pEnd
= This
->props
.tStop
;
563 static HRESULT WINAPI
StdMediaSample2_SetTime(IMediaSample2
*iface
, REFERENCE_TIME
*start
, REFERENCE_TIME
*end
)
565 StdMediaSample2
*sample
= impl_from_IMediaSample2(iface
);
567 TRACE("sample %p, start %s, end %s.\n", sample
, start
? debugstr_time(*start
) : "(null)",
568 end
? debugstr_time(*end
) : "(null)");
572 sample
->props
.tStart
= *start
;
573 sample
->props
.dwSampleFlags
|= AM_SAMPLE_TIMEVALID
;
577 sample
->props
.tStop
= *end
;
578 sample
->props
.dwSampleFlags
|= AM_SAMPLE_STOPVALID
;
581 sample
->props
.dwSampleFlags
&= ~AM_SAMPLE_STOPVALID
;
584 sample
->props
.dwSampleFlags
&= ~(AM_SAMPLE_TIMEVALID
| AM_SAMPLE_STOPVALID
);
589 static HRESULT WINAPI
StdMediaSample2_IsSyncPoint(IMediaSample2
* iface
)
591 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
593 TRACE("(%p)->()\n", iface
);
595 return (This
->props
.dwSampleFlags
& AM_SAMPLE_SPLICEPOINT
) ? S_OK
: S_FALSE
;
598 static HRESULT WINAPI
StdMediaSample2_SetSyncPoint(IMediaSample2
* iface
, BOOL bIsSyncPoint
)
600 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
602 TRACE("(%p)->(%s)\n", iface
, bIsSyncPoint
? "TRUE" : "FALSE");
605 This
->props
.dwSampleFlags
|= AM_SAMPLE_SPLICEPOINT
;
607 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_SPLICEPOINT
;
612 static HRESULT WINAPI
StdMediaSample2_IsPreroll(IMediaSample2
* iface
)
614 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
616 TRACE("(%p)->()\n", iface
);
618 return (This
->props
.dwSampleFlags
& AM_SAMPLE_PREROLL
) ? S_OK
: S_FALSE
;
621 static HRESULT WINAPI
StdMediaSample2_SetPreroll(IMediaSample2
* iface
, BOOL bIsPreroll
)
623 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
625 TRACE("(%p)->(%s)\n", iface
, bIsPreroll
? "TRUE" : "FALSE");
628 This
->props
.dwSampleFlags
|= AM_SAMPLE_PREROLL
;
630 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_PREROLL
;
635 static LONG WINAPI
StdMediaSample2_GetActualDataLength(IMediaSample2
* iface
)
637 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
639 TRACE("(%p)->()\n", iface
);
641 return This
->props
.lActual
;
644 static HRESULT WINAPI
StdMediaSample2_SetActualDataLength(IMediaSample2
* iface
, LONG len
)
646 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
648 TRACE("(%p)->(%d)\n", iface
, len
);
650 if ((len
> This
->props
.cbBuffer
) || (len
< 0))
652 WARN("Tried to set length to %d, while max is %d\n", len
, This
->props
.cbBuffer
);
653 return VFW_E_BUFFER_OVERFLOW
;
657 This
->props
.lActual
= len
;
662 static HRESULT WINAPI
StdMediaSample2_GetMediaType(IMediaSample2
* iface
, AM_MEDIA_TYPE
** ppMediaType
)
664 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
666 TRACE("(%p)->(%p)\n", iface
, ppMediaType
);
668 if (!This
->props
.pMediaType
) {
669 /* Make sure we return a NULL pointer (required by native Quartz dll) */
675 if (!(*ppMediaType
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
676 return E_OUTOFMEMORY
;
678 return CopyMediaType(*ppMediaType
, This
->props
.pMediaType
);
681 static HRESULT WINAPI
StdMediaSample2_SetMediaType(IMediaSample2
* iface
, AM_MEDIA_TYPE
* pMediaType
)
683 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
685 TRACE("(%p)->(%p)\n", iface
, pMediaType
);
687 if (This
->props
.pMediaType
)
689 DeleteMediaType(This
->props
.pMediaType
);
690 This
->props
.pMediaType
= NULL
;
695 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_TYPECHANGED
;
699 This
->props
.dwSampleFlags
|= AM_SAMPLE_TYPECHANGED
;
701 if (!(This
->props
.pMediaType
= CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE
))))
702 return E_OUTOFMEMORY
;
704 return CopyMediaType(This
->props
.pMediaType
, pMediaType
);
707 static HRESULT WINAPI
StdMediaSample2_IsDiscontinuity(IMediaSample2
* iface
)
709 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
711 TRACE("(%p)->()\n", iface
);
713 return (This
->props
.dwSampleFlags
& AM_SAMPLE_DATADISCONTINUITY
) ? S_OK
: S_FALSE
;
716 static HRESULT WINAPI
StdMediaSample2_SetDiscontinuity(IMediaSample2
* iface
, BOOL bIsDiscontinuity
)
718 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
720 TRACE("(%p)->(%s)\n", iface
, bIsDiscontinuity
? "TRUE" : "FALSE");
722 if (bIsDiscontinuity
)
723 This
->props
.dwSampleFlags
|= AM_SAMPLE_DATADISCONTINUITY
;
725 This
->props
.dwSampleFlags
&= ~AM_SAMPLE_DATADISCONTINUITY
;
730 static HRESULT WINAPI
StdMediaSample2_GetMediaTime(IMediaSample2
* iface
, LONGLONG
* pStart
, LONGLONG
* pEnd
)
732 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
734 TRACE("(%p)->(%p, %p)\n", iface
, pStart
, pEnd
);
736 if (!This
->media_time_valid
)
737 return VFW_E_MEDIA_TIME_NOT_SET
;
739 *pStart
= This
->tMediaStart
;
740 *pEnd
= This
->tMediaEnd
;
745 static HRESULT WINAPI
StdMediaSample2_SetMediaTime(IMediaSample2
*iface
, LONGLONG
*start
, LONGLONG
*end
)
747 StdMediaSample2
*sample
= impl_from_IMediaSample2(iface
);
749 TRACE("sample %p, start %s, end %s.\n", sample
, start
? debugstr_time(*start
) : "(null)",
750 end
? debugstr_time(*end
) : "(null)");
754 if (!end
) return E_POINTER
;
755 sample
->tMediaStart
= *start
;
756 sample
->tMediaEnd
= *end
;
757 sample
->media_time_valid
= TRUE
;
760 sample
->media_time_valid
= FALSE
;
765 static HRESULT WINAPI
StdMediaSample2_GetProperties(IMediaSample2
* iface
, DWORD cbProperties
, BYTE
* pbProperties
)
767 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
769 TRACE("(%p)->(%d, %p)\n", iface
, cbProperties
, pbProperties
);
771 memcpy(pbProperties
, &This
->props
, min(cbProperties
, sizeof(This
->props
)));
776 static HRESULT WINAPI
StdMediaSample2_SetProperties(IMediaSample2
* iface
, DWORD cbProperties
, const BYTE
* pbProperties
)
778 StdMediaSample2
*This
= impl_from_IMediaSample2(iface
);
780 TRACE("(%p)->(%d, %p)\n", iface
, cbProperties
, pbProperties
);
782 /* NOTE: pbBuffer and cbBuffer are read-only */
783 memcpy(&This
->props
, pbProperties
, min(cbProperties
, AM_SAMPLE2_PROP_SIZE_WRITABLE
));
788 static const IMediaSample2Vtbl StdMediaSample2_VTable
=
790 StdMediaSample2_QueryInterface
,
791 StdMediaSample2_AddRef
,
792 StdMediaSample2_Release
,
793 StdMediaSample2_GetPointer
,
794 StdMediaSample2_GetSize
,
795 StdMediaSample2_GetTime
,
796 StdMediaSample2_SetTime
,
797 StdMediaSample2_IsSyncPoint
,
798 StdMediaSample2_SetSyncPoint
,
799 StdMediaSample2_IsPreroll
,
800 StdMediaSample2_SetPreroll
,
801 StdMediaSample2_GetActualDataLength
,
802 StdMediaSample2_SetActualDataLength
,
803 StdMediaSample2_GetMediaType
,
804 StdMediaSample2_SetMediaType
,
805 StdMediaSample2_IsDiscontinuity
,
806 StdMediaSample2_SetDiscontinuity
,
807 StdMediaSample2_GetMediaTime
,
808 StdMediaSample2_SetMediaTime
,
809 StdMediaSample2_GetProperties
,
810 StdMediaSample2_SetProperties
813 static inline StdMediaSample2
*unsafe_impl_from_IMediaSample(IMediaSample
* iface
)
815 IMediaSample2
*iface2
= (IMediaSample2
*)iface
;
819 assert(iface2
->lpVtbl
== &StdMediaSample2_VTable
);
820 return impl_from_IMediaSample2(iface2
);
823 typedef struct StdMemAllocator
825 BaseMemAllocator base
;
826 CRITICAL_SECTION csState
;
830 static inline StdMemAllocator
*StdMemAllocator_from_IMemAllocator(IMemAllocator
* iface
)
832 return CONTAINING_RECORD(iface
, StdMemAllocator
, base
.IMemAllocator_iface
);
835 static HRESULT
StdMemAllocator_Alloc(IMemAllocator
* iface
)
837 StdMemAllocator
*This
= StdMemAllocator_from_IMemAllocator(iface
);
838 StdMediaSample2
* pSample
= NULL
;
842 assert(list_empty(&This
->base
.free_list
));
844 /* check alignment */
847 /* we do not allow a courser alignment than the OS page size */
848 if ((si
.dwPageSize
% This
->base
.props
.cbAlign
) != 0)
849 return VFW_E_BADALIGN
;
851 /* FIXME: each sample has to have its buffer start on the right alignment.
852 * We don't do this at the moment */
854 /* allocate memory */
855 This
->pMemory
= VirtualAlloc(NULL
, (This
->base
.props
.cbBuffer
+ This
->base
.props
.cbPrefix
) * This
->base
.props
.cBuffers
, MEM_COMMIT
, PAGE_READWRITE
);
858 return E_OUTOFMEMORY
;
860 for (i
= This
->base
.props
.cBuffers
- 1; i
>= 0; i
--)
862 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
863 BYTE
* pbBuffer
= (BYTE
*)This
->pMemory
+ i
* (This
->base
.props
.cbBuffer
+ This
->base
.props
.cbPrefix
) + This
->base
.props
.cbPrefix
;
865 StdMediaSample2_Construct(pbBuffer
, This
->base
.props
.cbBuffer
, iface
, &pSample
);
867 list_add_head(&This
->base
.free_list
, &pSample
->listentry
);
873 static HRESULT
StdMemAllocator_Free(IMemAllocator
* iface
)
875 StdMemAllocator
*This
= StdMemAllocator_from_IMemAllocator(iface
);
876 struct list
* cursor
;
878 if (!list_empty(&This
->base
.used_list
))
880 WARN("Freeing allocator with outstanding samples!\n");
881 while ((cursor
= list_head(&This
->base
.used_list
)) != NULL
)
883 StdMediaSample2
*pSample
;
885 pSample
= LIST_ENTRY(cursor
, StdMediaSample2
, listentry
);
886 pSample
->pParent
= NULL
;
890 while ((cursor
= list_head(&This
->base
.free_list
)) != NULL
)
893 StdMediaSample2_Delete(LIST_ENTRY(cursor
, StdMediaSample2
, listentry
));
897 if (!VirtualFree(This
->pMemory
, 0, MEM_RELEASE
))
899 ERR("Couldn't free memory. Error: %u\n", GetLastError());
900 return HRESULT_FROM_WIN32(GetLastError());
906 static void StdMemAllocator_Destroy(IMemAllocator
*iface
)
908 StdMemAllocator
*This
= StdMemAllocator_from_IMemAllocator(iface
);
910 This
->csState
.DebugInfo
->Spare
[0] = 0;
911 DeleteCriticalSection(&This
->csState
);
915 InterlockedDecrement(&object_locks
);
918 HRESULT
mem_allocator_create(IUnknown
*lpUnkOuter
, IUnknown
**out
)
920 StdMemAllocator
* pMemAlloc
;
924 return CLASS_E_NOAGGREGATION
;
926 if (!(pMemAlloc
= CoTaskMemAlloc(sizeof(*pMemAlloc
))))
927 return E_OUTOFMEMORY
;
929 InitializeCriticalSection(&pMemAlloc
->csState
);
930 pMemAlloc
->csState
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": StdMemAllocator.csState");
932 pMemAlloc
->pMemory
= NULL
;
934 if (SUCCEEDED(hr
= BaseMemAllocator_Init(StdMemAllocator_Alloc
, StdMemAllocator_Free
, NULL
, NULL
, NULL
, StdMemAllocator_Destroy
, &pMemAlloc
->csState
, &pMemAlloc
->base
)))
935 *out
= (IUnknown
*)&pMemAlloc
->base
.IMemAllocator_iface
;
937 CoTaskMemFree(pMemAlloc
);