2 * Implementation of CLSID_MemoryAllocator.
4 * Copyright (C) Hidenori TAKESHIMA <hidenori@a2.ctktv.ne.jp>
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
32 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(quartz);
35 #include "quartz_private.h"
39 /***************************************************************************
41 * new/delete for CLSID_MemoryAllocator.
45 /* can I use offsetof safely? - FIXME? */
46 static QUARTZ_IFEntry IFEntries[] =
48 { &IID_IMemAllocator, offsetof(CMemoryAllocator,memalloc)-offsetof(CMemoryAllocator,unk) },
51 static void QUARTZ_DestroyMemoryAllocator(IUnknown* punk)
53 CMemoryAllocator_THIS(punk,unk);
55 CMemoryAllocator_UninitIMemAllocator( This );
58 HRESULT QUARTZ_CreateMemoryAllocator(IUnknown* punkOuter,void** ppobj)
60 CMemoryAllocator* pma;
63 TRACE("(%p,%p)\n",punkOuter,ppobj);
65 pma = (CMemoryAllocator*)QUARTZ_AllocObj( sizeof(CMemoryAllocator) );
69 QUARTZ_IUnkInit( &pma->unk, punkOuter );
70 hr = CMemoryAllocator_InitIMemAllocator( pma );
73 QUARTZ_FreeObj( pma );
77 pma->unk.pEntries = IFEntries;
78 pma->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
79 pma->unk.pOnFinalRelease = QUARTZ_DestroyMemoryAllocator;
81 *ppobj = (void*)(&pma->unk);
87 /***************************************************************************
89 * CMemoryAllocator::IMemAllocator
94 IMemAllocator_LockUnusedBuffer(CMemoryAllocator* This,IMediaSample** ppSample)
99 TRACE("(%p) try to enter critical section\n",This);
100 EnterCriticalSection( &This->csMem );
101 TRACE("(%p) enter critical section\n",This);
103 if ( This->pData == NULL || This->ppSamples == NULL ||
104 This->prop.cBuffers <= 0 )
106 hr = VFW_E_NOT_COMMITTED;
111 for ( i = 0; i < This->prop.cBuffers; i++ )
113 if ( This->ppSamples[i] == NULL )
115 hr = VFW_E_NOT_COMMITTED;
118 if ( This->ppSamples[i]->ref == 0 )
120 *ppSample = (IMediaSample*)(This->ppSamples[i]);
121 IMediaSample_AddRef( *ppSample );
129 LeaveCriticalSection( &This->csMem );
130 TRACE("(%p) leave critical section\n",This);
135 /* TRUE = all samples are released */
137 IMemAllocator_ReleaseUnusedBuffer(CMemoryAllocator* This)
142 TRACE("(%p) try to enter critical section\n",This);
143 EnterCriticalSection( &This->csMem );
144 TRACE("(%p) enter critical section\n",This);
146 if ( This->pData == NULL || This->ppSamples == NULL ||
147 This->prop.cBuffers <= 0 )
150 for ( i = 0; i < This->prop.cBuffers; i++ )
152 if ( This->ppSamples[i]->ref == 0 )
154 QUARTZ_DestroyMemMediaSample( This->ppSamples[i] );
155 This->ppSamples[i] = NULL;
165 QUARTZ_FreeMem(This->ppSamples);
166 This->ppSamples = NULL;
167 QUARTZ_FreeMem(This->pData);
172 LeaveCriticalSection( &This->csMem );
173 TRACE("(%p) leave critical section\n",This);
179 static HRESULT WINAPI
180 IMemAllocator_fnQueryInterface(IMemAllocator* iface,REFIID riid,void** ppobj)
182 CMemoryAllocator_THIS(iface,memalloc);
184 TRACE("(%p)->()\n",This);
186 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
190 IMemAllocator_fnAddRef(IMemAllocator* iface)
192 CMemoryAllocator_THIS(iface,memalloc);
194 TRACE("(%p)->()\n",This);
196 return IUnknown_AddRef(This->unk.punkControl);
200 IMemAllocator_fnRelease(IMemAllocator* iface)
202 CMemoryAllocator_THIS(iface,memalloc);
204 TRACE("(%p)->()\n",This);
206 return IUnknown_Release(This->unk.punkControl);
209 static HRESULT WINAPI
210 IMemAllocator_fnSetProperties(IMemAllocator* iface,ALLOCATOR_PROPERTIES* pPropReq,ALLOCATOR_PROPERTIES* pPropActual)
212 CMemoryAllocator_THIS(iface,memalloc);
216 TRACE( "(%p)->(%p,%p)\n", This, pPropReq, pPropActual );
218 if ( pPropReq == NULL || pPropActual == NULL )
220 if ( pPropReq->cBuffers < 0 ||
221 pPropReq->cbBuffer < 0 ||
222 pPropReq->cbAlign < 0 ||
223 pPropReq->cbPrefix < 0 )
225 TRACE("pPropReq is invalid\n");
229 if ( pPropReq->cbAlign == 0 ||
230 ( pPropReq->cbAlign & (pPropReq->cbAlign-1) ) != 0 )
232 WARN("cbAlign is invalid - %ld\n",pPropReq->cbAlign);
233 return VFW_E_BADALIGN;
238 EnterCriticalSection( &This->csMem );
240 if ( This->pData != NULL || This->ppSamples != NULL )
242 /* if commited, properties must not be changed. */
243 TRACE("already commited\n");
248 This->prop.cBuffers = pPropReq->cBuffers;
249 This->prop.cbBuffer = pPropReq->cbBuffer;
250 This->prop.cbAlign = pPropReq->cbAlign;
251 This->prop.cbPrefix = pPropReq->cbPrefix;
253 if ( This->prop.cbAlign == 0 )
254 This->prop.cbAlign = 1;
255 padding = This->prop.cbAlign -
256 ( (This->prop.cbBuffer+This->prop.cbPrefix) % This->prop.cbAlign );
258 This->prop.cbBuffer += padding;
260 memcpy( pPropActual, &This->prop, sizeof(ALLOCATOR_PROPERTIES) );
263 LeaveCriticalSection( &This->csMem );
265 TRACE("returned successfully.\n");
270 static HRESULT WINAPI
271 IMemAllocator_fnGetProperties(IMemAllocator* iface,ALLOCATOR_PROPERTIES* pProp)
273 CMemoryAllocator_THIS(iface,memalloc);
275 TRACE( "(%p)->(%p)\n", This, pProp );
280 EnterCriticalSection( &This->csMem );
282 memcpy( pProp, &This->prop, sizeof(ALLOCATOR_PROPERTIES) );
284 LeaveCriticalSection( &This->csMem );
289 static HRESULT WINAPI
290 IMemAllocator_fnCommit(IMemAllocator* iface)
292 CMemoryAllocator_THIS(iface,memalloc);
298 TRACE( "(%p)->()\n", This );
300 EnterCriticalSection( &This->csMem );
303 /* FIXME - handle in Decommitting */
304 if ( This->pData != NULL || This->ppSamples != NULL ||
305 This->prop.cBuffers <= 0 )
308 lBufSize = This->prop.cBuffers *
309 (This->prop.cbBuffer + This->prop.cbPrefix) +
314 This->pData = (BYTE*)QUARTZ_AllocMem( lBufSize );
315 if ( This->pData == NULL )
321 This->ppSamples = (CMemMediaSample**)QUARTZ_AllocMem(
322 sizeof(CMemMediaSample*) * This->prop.cBuffers );
323 if ( This->ppSamples == NULL )
329 for ( i = 0; i < This->prop.cBuffers; i++ )
330 This->ppSamples[i] = NULL;
332 pCur = This->pData + This->prop.cbAlign - ((This->pData-(BYTE*)NULL) & (This->prop.cbAlign-1));
334 for ( i = 0; i < This->prop.cBuffers; i++ )
336 hr = QUARTZ_CreateMemMediaSample(
337 pCur, (This->prop.cbBuffer + This->prop.cbPrefix),
338 iface, &This->ppSamples[i] );
341 pCur += (This->prop.cbBuffer + This->prop.cbPrefix);
347 IMemAllocator_Decommit(iface);
349 LeaveCriticalSection( &This->csMem );
354 static HRESULT WINAPI
355 IMemAllocator_fnDecommit(IMemAllocator* iface)
357 CMemoryAllocator_THIS(iface,memalloc);
359 TRACE( "(%p)->()\n", This );
363 ResetEvent( This->hEventSample );
365 /* to avoid deadlock, don't hold critical section while blocking */
366 if ( IMemAllocator_ReleaseUnusedBuffer(This) )
369 WaitForSingleObject( This->hEventSample, INFINITE );
375 static HRESULT WINAPI
376 IMemAllocator_fnGetBuffer(IMemAllocator* iface,IMediaSample** ppSample,REFERENCE_TIME* prtStart,REFERENCE_TIME* prtEnd,DWORD dwFlags)
378 CMemoryAllocator_THIS(iface,memalloc);
381 TRACE( "(%p)->(%p,%p,%p,%lu)\n", This, ppSample, prtStart, prtEnd, dwFlags );
383 if ( ppSample == NULL )
388 ResetEvent( This->hEventSample );
390 /* to avoid deadlock, don't hold critical section while blocking */
391 hr = IMemAllocator_LockUnusedBuffer(This,ppSample);
392 if ( ( hr != VFW_E_TIMEOUT ) || ( dwFlags & AM_GBF_NOWAIT ) )
395 WaitForSingleObject( This->hEventSample, INFINITE );
403 static HRESULT WINAPI
404 IMemAllocator_fnReleaseBuffer(IMemAllocator* iface,IMediaSample* pSample)
406 CMemoryAllocator_THIS(iface,memalloc);
408 TRACE( "(%p)->(%p)\n", This, pSample );
409 SetEvent( This->hEventSample );
416 static ICOM_VTABLE(IMemAllocator) imemalloc =
418 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
419 /* IUnknown fields */
420 IMemAllocator_fnQueryInterface,
421 IMemAllocator_fnAddRef,
422 IMemAllocator_fnRelease,
423 /* IMemAllocator fields */
424 IMemAllocator_fnSetProperties,
425 IMemAllocator_fnGetProperties,
426 IMemAllocator_fnCommit,
427 IMemAllocator_fnDecommit,
428 IMemAllocator_fnGetBuffer,
429 IMemAllocator_fnReleaseBuffer,
433 HRESULT CMemoryAllocator_InitIMemAllocator( CMemoryAllocator* pma )
437 ICOM_VTBL(&pma->memalloc) = &imemalloc;
439 ZeroMemory( &pma->prop, sizeof(pma->prop) );
440 pma->hEventSample = (HANDLE)NULL;
442 pma->ppSamples = NULL;
444 pma->hEventSample = CreateEventA( NULL, TRUE, FALSE, NULL );
445 if ( pma->hEventSample == (HANDLE)NULL )
446 return E_OUTOFMEMORY;
448 InitializeCriticalSection( &pma->csMem );
453 void CMemoryAllocator_UninitIMemAllocator( CMemoryAllocator* pma )
457 IMemAllocator_Decommit( (IMemAllocator*)(&pma->memalloc) );
459 DeleteCriticalSection( &pma->csMem );
461 if ( pma->hEventSample != (HANDLE)NULL )
462 CloseHandle( pma->hEventSample );