For a radio button even if the initial style includes WS_TABSTOP the
[wine/wine64.git] / dlls / quartz / memalloc.c
blob3f6ecf410d7e373343863a3c4af0c04718e7ec61
1 /*
2 * Implementation of CLSID_MemoryAllocator.
4 * hidenori@a2.ctktv.ne.jp
5 */
7 #include "config.h"
9 #include "windef.h"
10 #include "winbase.h"
11 #include "wingdi.h"
12 #include "winuser.h"
13 #include "winerror.h"
14 #include "strmif.h"
15 #include "uuids.h"
16 #include "vfwmsgs.h"
18 #include "debugtools.h"
19 DEFAULT_DEBUG_CHANNEL(quartz);
21 #include "quartz_private.h"
22 #include "memalloc.h"
25 /***************************************************************************
27 * new/delete for CLSID_MemoryAllocator.
31 /* can I use offsetof safely? - FIXME? */
32 static QUARTZ_IFEntry IFEntries[] =
34 { &IID_IMemAllocator, offsetof(CMemoryAllocator,memalloc)-offsetof(CMemoryAllocator,unk) },
37 static void QUARTZ_DestroyMemoryAllocator(IUnknown* punk)
39 CMemoryAllocator_THIS(punk,unk);
41 CMemoryAllocator_UninitIMemAllocator( This );
44 HRESULT QUARTZ_CreateMemoryAllocator(IUnknown* punkOuter,void** ppobj)
46 CMemoryAllocator* pma;
47 HRESULT hr;
49 TRACE("(%p,%p)\n",punkOuter,ppobj);
51 pma = (CMemoryAllocator*)QUARTZ_AllocObj( sizeof(CMemoryAllocator) );
52 if ( pma == NULL )
53 return E_OUTOFMEMORY;
55 QUARTZ_IUnkInit( &pma->unk, punkOuter );
56 hr = CMemoryAllocator_InitIMemAllocator( pma );
57 if ( FAILED(hr) )
59 QUARTZ_FreeObj( pma );
60 return hr;
63 pma->unk.pEntries = IFEntries;
64 pma->unk.dwEntries = sizeof(IFEntries)/sizeof(IFEntries[0]);
65 pma->unk.pOnFinalRelease = QUARTZ_DestroyMemoryAllocator;
67 *ppobj = (void*)(&pma->unk);
69 return S_OK;
73 /***************************************************************************
75 * CMemoryAllocator::IMemAllocator
79 static HRESULT
80 IMemAllocator_LockUnusedBuffer(CMemoryAllocator* This,IMediaSample** ppSample)
82 HRESULT hr = E_FAIL;
83 LONG i;
85 TRACE("(%p) try to enter critical section\n",This);
86 EnterCriticalSection( &This->csMem );
87 TRACE("(%p) enter critical section\n",This);
89 if ( This->pData == NULL || This->ppSamples == NULL ||
90 This->prop.cBuffers <= 0 )
92 hr = VFW_E_NOT_COMMITTED;
93 goto end;
97 for ( i = 0; i < This->prop.cBuffers; i++ )
99 if ( This->ppSamples[i] == NULL )
101 hr = VFW_E_NOT_COMMITTED;
102 goto end;
104 if ( This->ppSamples[i]->ref == 0 )
106 *ppSample = (IMediaSample*)(This->ppSamples[i]);
107 IMediaSample_AddRef( *ppSample );
108 hr = NOERROR;
109 goto end;
113 hr = VFW_E_TIMEOUT;
114 end:
115 LeaveCriticalSection( &This->csMem );
116 TRACE("(%p) leave critical section\n",This);
118 return hr;
121 /* TRUE = all samples are released */
122 static BOOL
123 IMemAllocator_ReleaseUnusedBuffer(CMemoryAllocator* This)
125 LONG i;
126 BOOL bRet = TRUE;
128 TRACE("(%p) try to enter critical section\n",This);
129 EnterCriticalSection( &This->csMem );
130 TRACE("(%p) enter critical section\n",This);
132 if ( This->pData == NULL || This->ppSamples == NULL ||
133 This->prop.cBuffers <= 0 )
134 goto end;
136 for ( i = 0; i < This->prop.cBuffers; i++ )
138 if ( This->ppSamples[i]->ref == 0 )
140 QUARTZ_DestroyMemMediaSample( This->ppSamples[i] );
141 This->ppSamples[i] = NULL;
143 else
145 bRet = FALSE;
149 if ( bRet )
151 QUARTZ_FreeMem(This->ppSamples);
152 This->ppSamples = NULL;
153 QUARTZ_FreeMem(This->pData);
154 This->pData = NULL;
157 end:
158 LeaveCriticalSection( &This->csMem );
159 TRACE("(%p) leave critical section\n",This);
161 return bRet;
165 static HRESULT WINAPI
166 IMemAllocator_fnQueryInterface(IMemAllocator* iface,REFIID riid,void** ppobj)
168 CMemoryAllocator_THIS(iface,memalloc);
170 TRACE("(%p)->()\n",This);
172 return IUnknown_QueryInterface(This->unk.punkControl,riid,ppobj);
175 static ULONG WINAPI
176 IMemAllocator_fnAddRef(IMemAllocator* iface)
178 CMemoryAllocator_THIS(iface,memalloc);
180 TRACE("(%p)->()\n",This);
182 return IUnknown_AddRef(This->unk.punkControl);
185 static ULONG WINAPI
186 IMemAllocator_fnRelease(IMemAllocator* iface)
188 CMemoryAllocator_THIS(iface,memalloc);
190 TRACE("(%p)->()\n",This);
192 return IUnknown_Release(This->unk.punkControl);
195 static HRESULT WINAPI
196 IMemAllocator_fnSetProperties(IMemAllocator* iface,ALLOCATOR_PROPERTIES* pPropReq,ALLOCATOR_PROPERTIES* pPropActual)
198 CMemoryAllocator_THIS(iface,memalloc);
199 long padding;
200 HRESULT hr;
202 TRACE( "(%p)->(%p,%p)\n", This, pPropReq, pPropActual );
204 if ( pPropReq == NULL || pPropActual == NULL )
205 return E_POINTER;
206 if ( pPropReq->cBuffers < 0 ||
207 pPropReq->cbBuffer < 0 ||
208 pPropReq->cbAlign < 0 ||
209 pPropReq->cbPrefix < 0 )
211 TRACE("pPropReq is invalid\n");
212 return E_INVALIDARG;
215 if ( pPropReq->cbAlign == 0 ||
216 ( pPropReq->cbAlign & (pPropReq->cbAlign-1) ) != 0 )
218 WARN("cbAlign is invalid - %ld\n",pPropReq->cbAlign);
219 return VFW_E_BADALIGN;
222 hr = NOERROR;
224 EnterCriticalSection( &This->csMem );
226 if ( This->pData != NULL || This->ppSamples != NULL )
228 /* if commited, properties must not be changed. */
229 TRACE("already commited\n");
230 hr = E_UNEXPECTED;
231 goto end;
234 This->prop.cBuffers = pPropReq->cBuffers;
235 This->prop.cbBuffer = pPropReq->cbBuffer;
236 This->prop.cbAlign = pPropReq->cbAlign;
237 This->prop.cbPrefix = pPropReq->cbPrefix;
239 if ( This->prop.cbAlign == 0 )
240 This->prop.cbAlign = 1;
241 padding = This->prop.cbAlign -
242 ( (This->prop.cbBuffer+This->prop.cbPrefix) % This->prop.cbAlign );
244 This->prop.cbBuffer += padding;
246 memcpy( pPropActual, &This->prop, sizeof(ALLOCATOR_PROPERTIES) );
248 end:
249 LeaveCriticalSection( &This->csMem );
251 TRACE("returned successfully.\n");
253 return hr;
256 static HRESULT WINAPI
257 IMemAllocator_fnGetProperties(IMemAllocator* iface,ALLOCATOR_PROPERTIES* pProp)
259 CMemoryAllocator_THIS(iface,memalloc);
261 TRACE( "(%p)->(%p)\n", This, pProp );
263 if ( pProp == NULL )
264 return E_POINTER;
266 EnterCriticalSection( &This->csMem );
268 memcpy( pProp, &This->prop, sizeof(ALLOCATOR_PROPERTIES) );
270 LeaveCriticalSection( &This->csMem );
272 return NOERROR;
275 static HRESULT WINAPI
276 IMemAllocator_fnCommit(IMemAllocator* iface)
278 CMemoryAllocator_THIS(iface,memalloc);
279 HRESULT hr;
280 LONG lBufSize;
281 LONG i;
282 BYTE* pCur;
284 TRACE( "(%p)->()\n", This );
286 EnterCriticalSection( &This->csMem );
288 hr = NOERROR;
289 /* FIXME - handle in Decommitting */
290 if ( This->pData != NULL || This->ppSamples != NULL ||
291 This->prop.cBuffers <= 0 )
292 goto end;
294 lBufSize = This->prop.cBuffers *
295 (This->prop.cbBuffer + This->prop.cbPrefix) +
296 This->prop.cbAlign;
297 if ( lBufSize <= 0 )
298 lBufSize = 1;
300 This->pData = (BYTE*)QUARTZ_AllocMem( lBufSize );
301 if ( This->pData == NULL )
303 hr = E_OUTOFMEMORY;
304 goto end;
307 This->ppSamples = (CMemMediaSample**)QUARTZ_AllocMem(
308 sizeof(CMemMediaSample*) * This->prop.cBuffers );
309 if ( This->ppSamples == NULL )
311 hr = E_OUTOFMEMORY;
312 goto end;
315 for ( i = 0; i < This->prop.cBuffers; i++ )
316 This->ppSamples[i] = NULL;
318 pCur = This->pData + This->prop.cbAlign - ((This->pData-(BYTE*)NULL) & (This->prop.cbAlign-1));
320 for ( i = 0; i < This->prop.cBuffers; i++ )
322 hr = QUARTZ_CreateMemMediaSample(
323 pCur, (This->prop.cbBuffer + This->prop.cbPrefix),
324 iface, &This->ppSamples[i] );
325 if ( FAILED(hr) )
326 goto end;
327 pCur += (This->prop.cbBuffer + This->prop.cbPrefix);
330 hr = NOERROR;
331 end:
332 if ( FAILED(hr) )
333 IMemAllocator_Decommit(iface);
335 LeaveCriticalSection( &This->csMem );
337 return hr;
340 static HRESULT WINAPI
341 IMemAllocator_fnDecommit(IMemAllocator* iface)
343 CMemoryAllocator_THIS(iface,memalloc);
345 TRACE( "(%p)->()\n", This );
347 while ( 1 )
349 ResetEvent( This->hEventSample );
351 /* to avoid deadlock, don't hold critical section while blocking */
352 if ( IMemAllocator_ReleaseUnusedBuffer(This) )
353 break;
355 WaitForSingleObject( This->hEventSample, INFINITE );
358 return NOERROR;
361 static HRESULT WINAPI
362 IMemAllocator_fnGetBuffer(IMemAllocator* iface,IMediaSample** ppSample,REFERENCE_TIME* prtStart,REFERENCE_TIME* prtEnd,DWORD dwFlags)
364 CMemoryAllocator_THIS(iface,memalloc);
365 HRESULT hr;
367 TRACE( "(%p)->(%p,%p,%p,%lu)\n", This, ppSample, prtStart, prtEnd, dwFlags );
369 if ( ppSample == NULL )
370 return E_POINTER;
372 while ( 1 )
374 ResetEvent( This->hEventSample );
376 /* to avoid deadlock, don't hold critical section while blocking */
377 hr = IMemAllocator_LockUnusedBuffer(This,ppSample);
378 if ( ( hr != VFW_E_TIMEOUT ) || ( dwFlags & AM_GBF_NOWAIT ) )
379 goto end;
381 WaitForSingleObject( This->hEventSample, INFINITE );
384 end:
386 return hr;
389 static HRESULT WINAPI
390 IMemAllocator_fnReleaseBuffer(IMemAllocator* iface,IMediaSample* pSample)
392 CMemoryAllocator_THIS(iface,memalloc);
394 TRACE( "(%p)->(%p)\n", This, pSample );
395 SetEvent( This->hEventSample );
397 return NOERROR;
402 static ICOM_VTABLE(IMemAllocator) imemalloc =
404 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
405 /* IUnknown fields */
406 IMemAllocator_fnQueryInterface,
407 IMemAllocator_fnAddRef,
408 IMemAllocator_fnRelease,
409 /* IMemAllocator fields */
410 IMemAllocator_fnSetProperties,
411 IMemAllocator_fnGetProperties,
412 IMemAllocator_fnCommit,
413 IMemAllocator_fnDecommit,
414 IMemAllocator_fnGetBuffer,
415 IMemAllocator_fnReleaseBuffer,
419 HRESULT CMemoryAllocator_InitIMemAllocator( CMemoryAllocator* pma )
421 TRACE("(%p)\n",pma);
423 ICOM_VTBL(&pma->memalloc) = &imemalloc;
425 ZeroMemory( &pma->prop, sizeof(pma->prop) );
426 pma->hEventSample = (HANDLE)NULL;
427 pma->pData = NULL;
428 pma->ppSamples = NULL;
430 pma->hEventSample = CreateEventA( NULL, TRUE, FALSE, NULL );
431 if ( pma->hEventSample == (HANDLE)NULL )
432 return E_OUTOFMEMORY;
434 InitializeCriticalSection( &pma->csMem );
436 return NOERROR;
439 void CMemoryAllocator_UninitIMemAllocator( CMemoryAllocator* pma )
441 TRACE("(%p)\n",pma);
443 IMemAllocator_Decommit( (IMemAllocator*)(&pma->memalloc) );
445 DeleteCriticalSection( &pma->csMem );
447 if ( pma->hEventSample != (HANDLE)NULL )
448 CloseHandle( pma->hEventSample );