Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenmemallocator.c
Go to the documentation of this file.
00001 /* 00002 * Memory Allocator and Media Sample Implementation 00003 * 00004 * Copyright 2003 Robert Shearman 00005 * 00006 * This library is free software; you can redistribute it and/or 00007 * modify it under the terms of the GNU Lesser General Public 00008 * License as published by the Free Software Foundation; either 00009 * version 2.1 of the License, or (at your option) any later version. 00010 * 00011 * This library is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00014 * Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public 00017 * License along with this library; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 00019 */ 00020 00021 #include <assert.h> 00022 #include <limits.h> 00023 #include <stdarg.h> 00024 00025 #include "windef.h" 00026 #include "winbase.h" 00027 #include "vfwmsgs.h" 00028 00029 #include "quartz_private.h" 00030 #include "wine/debug.h" 00031 00032 WINE_DEFAULT_DEBUG_CHANNEL(quartz); 00033 00034 typedef struct BaseMemAllocator 00035 { 00036 const IMemAllocatorVtbl * lpVtbl; 00037 00038 LONG ref; 00039 ALLOCATOR_PROPERTIES props; 00040 HRESULT (* fnAlloc) (IMemAllocator *); 00041 HRESULT (* fnFree)(IMemAllocator *); 00042 HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *); 00043 HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD flags); 00044 HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *); 00045 void (* fnDestroyed)(IMemAllocator *); 00046 HANDLE hSemWaiting; 00047 BOOL bDecommitQueued; 00048 BOOL bCommitted; 00049 LONG lWaiting; 00050 struct list free_list; 00051 struct list used_list; 00052 CRITICAL_SECTION *pCritSect; 00053 } BaseMemAllocator; 00054 00055 static const IMemAllocatorVtbl BaseMemAllocator_VTable; 00056 static const IMediaSample2Vtbl StdMediaSample2_VTable; 00057 00058 #define AM_SAMPLE2_PROP_SIZE_WRITABLE FIELD_OFFSET(AM_SAMPLE2_PROPERTIES, pbBuffer) 00059 00060 #define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff) 00061 00062 static HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), 00063 HRESULT (* fnFree)(IMemAllocator *), 00064 HRESULT (* fnVerify)(IMemAllocator *, ALLOCATOR_PROPERTIES *), 00065 HRESULT (* fnBufferPrepare)(IMemAllocator *, StdMediaSample2 *, DWORD), 00066 HRESULT (* fnBufferReleased)(IMemAllocator *, StdMediaSample2 *), 00067 void (* fnDestroyed)(IMemAllocator *), 00068 CRITICAL_SECTION *pCritSect, 00069 BaseMemAllocator * pMemAlloc) 00070 { 00071 assert(fnAlloc && fnFree && fnDestroyed); 00072 00073 pMemAlloc->lpVtbl = &BaseMemAllocator_VTable; 00074 00075 pMemAlloc->ref = 1; 00076 ZeroMemory(&pMemAlloc->props, sizeof(pMemAlloc->props)); 00077 list_init(&pMemAlloc->free_list); 00078 list_init(&pMemAlloc->used_list); 00079 pMemAlloc->fnAlloc = fnAlloc; 00080 pMemAlloc->fnFree = fnFree; 00081 pMemAlloc->fnVerify = fnVerify; 00082 pMemAlloc->fnBufferPrepare = fnBufferPrepare; 00083 pMemAlloc->fnBufferReleased = fnBufferReleased; 00084 pMemAlloc->fnDestroyed = fnDestroyed; 00085 pMemAlloc->bDecommitQueued = FALSE; 00086 pMemAlloc->bCommitted = FALSE; 00087 pMemAlloc->hSemWaiting = NULL; 00088 pMemAlloc->lWaiting = 0; 00089 pMemAlloc->pCritSect = pCritSect; 00090 00091 return S_OK; 00092 } 00093 00094 static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv) 00095 { 00096 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00097 TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv); 00098 00099 *ppv = NULL; 00100 00101 if (IsEqualIID(riid, &IID_IUnknown)) 00102 *ppv = This; 00103 else if (IsEqualIID(riid, &IID_IMemAllocator)) 00104 *ppv = This; 00105 00106 if (*ppv) 00107 { 00108 IUnknown_AddRef((IUnknown *)(*ppv)); 00109 return S_OK; 00110 } 00111 00112 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 00113 00114 return E_NOINTERFACE; 00115 } 00116 00117 static ULONG WINAPI BaseMemAllocator_AddRef(IMemAllocator * iface) 00118 { 00119 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00120 ULONG ref = InterlockedIncrement(&This->ref); 00121 00122 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1); 00123 00124 return ref; 00125 } 00126 00127 static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface) 00128 { 00129 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00130 ULONG ref = InterlockedDecrement(&This->ref); 00131 00132 TRACE("(%p)->() Release from %d\n", iface, ref + 1); 00133 00134 if (!ref) 00135 { 00136 CloseHandle(This->hSemWaiting); 00137 if (This->bCommitted) 00138 This->fnFree(iface); 00139 00140 This->fnDestroyed(iface); 00141 return 0; 00142 } 00143 return ref; 00144 } 00145 00146 static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual) 00147 { 00148 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00149 HRESULT hr; 00150 00151 TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual); 00152 00153 EnterCriticalSection(This->pCritSect); 00154 { 00155 if (!list_empty(&This->used_list)) 00156 hr = VFW_E_BUFFERS_OUTSTANDING; 00157 else if (This->bCommitted) 00158 hr = VFW_E_ALREADY_COMMITTED; 00159 else if (pRequest->cbAlign == 0) 00160 hr = VFW_E_BADALIGN; 00161 else 00162 { 00163 if (This->fnVerify) 00164 hr = This->fnVerify(iface, pRequest); 00165 else 00166 hr = S_OK; 00167 00168 if (SUCCEEDED(hr)) 00169 This->props = *pRequest; 00170 00171 *pActual = This->props; 00172 } 00173 } 00174 LeaveCriticalSection(This->pCritSect); 00175 00176 return hr; 00177 } 00178 00179 static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps) 00180 { 00181 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00182 HRESULT hr = S_OK; 00183 00184 TRACE("(%p)->(%p)\n", This, pProps); 00185 00186 EnterCriticalSection(This->pCritSect); 00187 { 00188 memcpy(pProps, &This->props, sizeof(*pProps)); 00189 } 00190 LeaveCriticalSection(This->pCritSect); 00191 00192 return hr; 00193 } 00194 00195 static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface) 00196 { 00197 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00198 HRESULT hr; 00199 00200 TRACE("(%p)->()\n", This); 00201 00202 EnterCriticalSection(This->pCritSect); 00203 { 00204 if (!This->props.cbAlign) 00205 hr = VFW_E_BADALIGN; 00206 else if (!This->props.cbBuffer) 00207 hr = VFW_E_SIZENOTSET; 00208 else if (!This->props.cBuffers) 00209 hr = VFW_E_BUFFER_NOTSET; 00210 else if (This->bDecommitQueued && This->bCommitted) 00211 { 00212 This->bDecommitQueued = FALSE; 00213 hr = S_OK; 00214 } 00215 else if (This->bCommitted) 00216 hr = S_OK; 00217 else 00218 { 00219 if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->props.cBuffers, This->props.cBuffers, NULL))) 00220 { 00221 ERR("Couldn't create semaphore (error was %u)\n", GetLastError()); 00222 hr = HRESULT_FROM_WIN32(GetLastError()); 00223 } 00224 else 00225 { 00226 hr = This->fnAlloc(iface); 00227 if (SUCCEEDED(hr)) 00228 This->bCommitted = TRUE; 00229 else 00230 ERR("fnAlloc failed with error 0x%x\n", hr); 00231 } 00232 } 00233 } 00234 LeaveCriticalSection(This->pCritSect); 00235 00236 return hr; 00237 } 00238 00239 static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface) 00240 { 00241 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00242 HRESULT hr; 00243 00244 TRACE("(%p)->()\n", This); 00245 00246 EnterCriticalSection(This->pCritSect); 00247 { 00248 if (!This->bCommitted) 00249 hr = S_OK; 00250 else 00251 { 00252 if (!list_empty(&This->used_list)) 00253 { 00254 This->bDecommitQueued = TRUE; 00255 /* notify ALL waiting threads that they cannot be allocated a buffer any more */ 00256 ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL); 00257 00258 hr = S_OK; 00259 } 00260 else 00261 { 00262 if (This->lWaiting != 0) 00263 ERR("Waiting: %d\n", This->lWaiting); 00264 00265 This->bCommitted = FALSE; 00266 CloseHandle(This->hSemWaiting); 00267 This->hSemWaiting = NULL; 00268 00269 hr = This->fnFree(iface); 00270 if (FAILED(hr)) 00271 ERR("fnFree failed with error 0x%x\n", hr); 00272 } 00273 } 00274 } 00275 LeaveCriticalSection(This->pCritSect); 00276 00277 return hr; 00278 } 00279 00280 static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags) 00281 { 00282 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00283 HRESULT hr = S_OK; 00284 00285 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample. 00286 * The allocator might use these values to determine which buffer it retrieves */ 00287 00288 TRACE("(%p)->(%p, %p, %p, %x)\n", This, pSample, pStartTime, pEndTime, dwFlags); 00289 00290 *pSample = NULL; 00291 00292 EnterCriticalSection(This->pCritSect); 00293 if (!This->bCommitted || This->bDecommitQueued) 00294 { 00295 WARN("Not committed\n"); 00296 hr = VFW_E_NOT_COMMITTED; 00297 } 00298 else 00299 ++This->lWaiting; 00300 LeaveCriticalSection(This->pCritSect); 00301 if (FAILED(hr)) 00302 return hr; 00303 00304 if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0) 00305 { 00306 EnterCriticalSection(This->pCritSect); 00307 --This->lWaiting; 00308 LeaveCriticalSection(This->pCritSect); 00309 WARN("Timed out\n"); 00310 return VFW_E_TIMEOUT; 00311 } 00312 00313 EnterCriticalSection(This->pCritSect); 00314 { 00315 --This->lWaiting; 00316 if (!This->bCommitted) 00317 hr = VFW_E_NOT_COMMITTED; 00318 else if (This->bDecommitQueued) 00319 hr = VFW_E_TIMEOUT; 00320 else 00321 { 00322 struct list * free = list_head(&This->free_list); 00323 list_remove(free); 00324 list_add_head(&This->used_list, free); 00325 00326 *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry); 00327 00328 assert(((StdMediaSample2 *)*pSample)->ref == 0); 00329 00330 IMediaSample_AddRef(*pSample); 00331 } 00332 } 00333 LeaveCriticalSection(This->pCritSect); 00334 00335 if (hr != S_OK) 00336 WARN("%08x\n", hr); 00337 return hr; 00338 } 00339 00340 static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample) 00341 { 00342 BaseMemAllocator *This = (BaseMemAllocator *)iface; 00343 StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample; 00344 HRESULT hr = S_OK; 00345 00346 TRACE("(%p)->(%p)\n", This, pSample); 00347 00348 /* FIXME: make sure that sample is currently on the used list */ 00349 00350 /* FIXME: we should probably check the ref count on the sample before freeing 00351 * it to make sure that it is not still in use */ 00352 EnterCriticalSection(This->pCritSect); 00353 { 00354 if (!This->bCommitted) 00355 ERR("Releasing a buffer when the allocator is not committed?!?\n"); 00356 00357 /* remove from used_list */ 00358 list_remove(&pStdSample->listentry); 00359 00360 list_add_head(&This->free_list, &pStdSample->listentry); 00361 00362 if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted) 00363 { 00364 HRESULT hrfree; 00365 00366 if (This->lWaiting != 0) 00367 ERR("Waiting: %d\n", This->lWaiting); 00368 00369 This->bCommitted = FALSE; 00370 This->bDecommitQueued = FALSE; 00371 00372 CloseHandle(This->hSemWaiting); 00373 This->hSemWaiting = NULL; 00374 00375 if (FAILED(hrfree = This->fnFree(iface))) 00376 ERR("fnFree failed with error 0x%x\n", hrfree); 00377 } 00378 } 00379 LeaveCriticalSection(This->pCritSect); 00380 00381 /* notify a waiting thread that there is now a free buffer */ 00382 if (This->hSemWaiting && !ReleaseSemaphore(This->hSemWaiting, 1, NULL)) 00383 { 00384 ERR("ReleaseSemaphore failed with error %u\n", GetLastError()); 00385 hr = HRESULT_FROM_WIN32(GetLastError()); 00386 } 00387 00388 return hr; 00389 } 00390 00391 static const IMemAllocatorVtbl BaseMemAllocator_VTable = 00392 { 00393 BaseMemAllocator_QueryInterface, 00394 BaseMemAllocator_AddRef, 00395 BaseMemAllocator_Release, 00396 BaseMemAllocator_SetProperties, 00397 BaseMemAllocator_GetProperties, 00398 BaseMemAllocator_Commit, 00399 BaseMemAllocator_Decommit, 00400 BaseMemAllocator_GetBuffer, 00401 BaseMemAllocator_ReleaseBuffer 00402 }; 00403 00404 static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample) 00405 { 00406 assert(pbBuffer && pParent && (cbBuffer > 0)); 00407 00408 if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2)))) 00409 return E_OUTOFMEMORY; 00410 00411 (*ppSample)->lpvtbl = &StdMediaSample2_VTable; 00412 (*ppSample)->ref = 0; 00413 ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props)); 00414 00415 /* NOTE: no need to AddRef as the parent is guaranteed to be around 00416 * at least as long as us and we don't want to create circular 00417 * dependencies on the ref count */ 00418 (*ppSample)->pParent = pParent; 00419 (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES); 00420 (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer; 00421 (*ppSample)->props.pbBuffer = pbBuffer; 00422 (*ppSample)->tMediaStart = INVALID_MEDIA_TIME; 00423 (*ppSample)->tMediaEnd = 0; 00424 00425 return S_OK; 00426 } 00427 00428 static void StdMediaSample2_Delete(StdMediaSample2 * This) 00429 { 00430 /* NOTE: does not remove itself from the list it belongs to */ 00431 CoTaskMemFree(This); 00432 } 00433 00434 static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv) 00435 { 00436 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00437 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); 00438 00439 *ppv = NULL; 00440 00441 if (IsEqualIID(riid, &IID_IUnknown)) 00442 *ppv = This; 00443 else if (IsEqualIID(riid, &IID_IMediaSample)) 00444 *ppv = This; 00445 else if (IsEqualIID(riid, &IID_IMediaSample2)) 00446 *ppv = This; 00447 00448 if (*ppv) 00449 { 00450 IUnknown_AddRef((IUnknown *)(*ppv)); 00451 return S_OK; 00452 } 00453 00454 FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); 00455 00456 return E_NOINTERFACE; 00457 } 00458 00459 static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface) 00460 { 00461 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00462 ULONG ref = InterlockedIncrement(&This->ref); 00463 00464 TRACE("(%p)->() AddRef from %d\n", iface, ref - 1); 00465 00466 return ref; 00467 } 00468 00469 static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface) 00470 { 00471 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00472 ULONG ref = InterlockedDecrement(&This->ref); 00473 00474 TRACE("(%p)->() Release from %d\n", iface, ref + 1); 00475 00476 if (!ref) 00477 { 00478 if (This->pParent) 00479 IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface); 00480 else 00481 StdMediaSample2_Delete(This); 00482 return 0; 00483 } 00484 return ref; 00485 } 00486 00487 static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer) 00488 { 00489 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00490 00491 TRACE("(%p)->(%p)\n", iface, ppBuffer); 00492 00493 *ppBuffer = This->props.pbBuffer; 00494 00495 if (!*ppBuffer) 00496 { 00497 ERR("Requested an unlocked surface and trying to lock regardless\n"); 00498 return E_FAIL; 00499 } 00500 00501 return S_OK; 00502 } 00503 00504 static LONG WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface) 00505 { 00506 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00507 00508 TRACE("StdMediaSample2_GetSize()\n"); 00509 00510 return This->props.cbBuffer; 00511 } 00512 00513 static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd) 00514 { 00515 HRESULT hr; 00516 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00517 00518 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd); 00519 00520 if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID)) 00521 hr = VFW_E_SAMPLE_TIME_NOT_SET; 00522 else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID)) 00523 { 00524 *pStart = This->props.tStart; 00525 *pEnd = This->props.tStart + 1; 00526 00527 hr = VFW_S_NO_STOP_TIME; 00528 } 00529 else 00530 { 00531 *pStart = This->props.tStart; 00532 *pEnd = This->props.tStop; 00533 00534 hr = S_OK; 00535 } 00536 00537 return hr; 00538 } 00539 00540 static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd) 00541 { 00542 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00543 00544 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd); 00545 00546 if (pStart) 00547 { 00548 This->props.tStart = *pStart; 00549 This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID; 00550 } 00551 else 00552 This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID; 00553 00554 if (pEnd) 00555 { 00556 This->props.tStop = *pEnd; 00557 This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID; 00558 } 00559 else 00560 This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID; 00561 00562 return S_OK; 00563 } 00564 00565 static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface) 00566 { 00567 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00568 00569 TRACE("(%p)->()\n", iface); 00570 00571 return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE; 00572 } 00573 00574 static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint) 00575 { 00576 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00577 00578 TRACE("(%p)->(%s)\n", iface, bIsSyncPoint ? "TRUE" : "FALSE"); 00579 00580 if (bIsSyncPoint) 00581 This->props.dwSampleFlags |= AM_SAMPLE_SPLICEPOINT; 00582 else 00583 This->props.dwSampleFlags &= ~AM_SAMPLE_SPLICEPOINT; 00584 00585 return S_OK; 00586 } 00587 00588 static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface) 00589 { 00590 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00591 00592 TRACE("(%p)->()\n", iface); 00593 00594 return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE; 00595 } 00596 00597 static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll) 00598 { 00599 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00600 00601 TRACE("(%p)->(%s)\n", iface, bIsPreroll ? "TRUE" : "FALSE"); 00602 00603 if (bIsPreroll) 00604 This->props.dwSampleFlags |= AM_SAMPLE_PREROLL; 00605 else 00606 This->props.dwSampleFlags &= ~AM_SAMPLE_PREROLL; 00607 00608 return S_OK; 00609 } 00610 00611 static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface) 00612 { 00613 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00614 00615 TRACE("(%p)->()\n", iface); 00616 00617 return This->props.lActual; 00618 } 00619 00620 static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len) 00621 { 00622 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00623 00624 TRACE("(%p)->(%d)\n", iface, len); 00625 00626 if ((len > This->props.cbBuffer) || (len < 0)) 00627 { 00628 WARN("Tried to set length to %d, while max is %d\n", len, This->props.cbBuffer); 00629 return VFW_E_BUFFER_OVERFLOW; 00630 } 00631 else 00632 { 00633 This->props.lActual = len; 00634 return S_OK; 00635 } 00636 } 00637 00638 static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType) 00639 { 00640 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00641 00642 TRACE("(%p)->(%p)\n", iface, ppMediaType); 00643 00644 if (!This->props.pMediaType) { 00645 /* Make sure we return a NULL pointer (required by native Quartz dll) */ 00646 if (ppMediaType) 00647 *ppMediaType = NULL; 00648 return S_FALSE; 00649 } 00650 00651 if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)))) 00652 return E_OUTOFMEMORY; 00653 00654 return CopyMediaType(*ppMediaType, This->props.pMediaType); 00655 } 00656 00657 static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType) 00658 { 00659 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00660 00661 TRACE("(%p)->(%p)\n", iface, pMediaType); 00662 00663 if (This->props.pMediaType) 00664 FreeMediaType(This->props.pMediaType); 00665 else if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)))) 00666 return E_OUTOFMEMORY; 00667 00668 return CopyMediaType(This->props.pMediaType, pMediaType); 00669 } 00670 00671 static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface) 00672 { 00673 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00674 00675 TRACE("(%p)->()\n", iface); 00676 00677 return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE; 00678 } 00679 00680 static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity) 00681 { 00682 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00683 00684 TRACE("(%p)->(%s)\n", iface, bIsDiscontinuity ? "TRUE" : "FALSE"); 00685 00686 if (bIsDiscontinuity) 00687 This->props.dwSampleFlags |= AM_SAMPLE_DATADISCONTINUITY; 00688 else 00689 This->props.dwSampleFlags &= ~AM_SAMPLE_DATADISCONTINUITY; 00690 00691 return S_OK; 00692 } 00693 00694 static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd) 00695 { 00696 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00697 00698 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd); 00699 00700 if (This->tMediaStart == INVALID_MEDIA_TIME) 00701 return VFW_E_MEDIA_TIME_NOT_SET; 00702 00703 *pStart = This->tMediaStart; 00704 *pEnd = This->tMediaEnd; 00705 00706 return E_NOTIMPL; 00707 } 00708 00709 static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd) 00710 { 00711 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00712 00713 TRACE("(%p)->(%p, %p)\n", iface, pStart, pEnd); 00714 00715 if (pStart) 00716 This->tMediaStart = *pStart; 00717 else 00718 This->tMediaStart = INVALID_MEDIA_TIME; 00719 00720 if (pEnd) 00721 This->tMediaEnd = *pEnd; 00722 else 00723 This->tMediaEnd = 0; 00724 00725 return S_OK; 00726 } 00727 00728 static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties) 00729 { 00730 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00731 00732 TRACE("(%p)->(%d, %p)\n", iface, cbProperties, pbProperties); 00733 00734 memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props))); 00735 00736 return S_OK; 00737 } 00738 00739 static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties) 00740 { 00741 StdMediaSample2 *This = (StdMediaSample2 *)iface; 00742 00743 TRACE("(%p)->(%d, %p)\n", iface, cbProperties, pbProperties); 00744 00745 /* NOTE: pbBuffer and cbBuffer are read-only */ 00746 memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE)); 00747 00748 return S_OK; 00749 } 00750 00751 static const IMediaSample2Vtbl StdMediaSample2_VTable = 00752 { 00753 StdMediaSample2_QueryInterface, 00754 StdMediaSample2_AddRef, 00755 StdMediaSample2_Release, 00756 StdMediaSample2_GetPointer, 00757 StdMediaSample2_GetSize, 00758 StdMediaSample2_GetTime, 00759 StdMediaSample2_SetTime, 00760 StdMediaSample2_IsSyncPoint, 00761 StdMediaSample2_SetSyncPoint, 00762 StdMediaSample2_IsPreroll, 00763 StdMediaSample2_SetPreroll, 00764 StdMediaSample2_GetActualDataLength, 00765 StdMediaSample2_SetActualDataLength, 00766 StdMediaSample2_GetMediaType, 00767 StdMediaSample2_SetMediaType, 00768 StdMediaSample2_IsDiscontinuity, 00769 StdMediaSample2_SetDiscontinuity, 00770 StdMediaSample2_GetMediaTime, 00771 StdMediaSample2_SetMediaTime, 00772 StdMediaSample2_GetProperties, 00773 StdMediaSample2_SetProperties 00774 }; 00775 00776 typedef struct StdMemAllocator 00777 { 00778 BaseMemAllocator base; 00779 CRITICAL_SECTION csState; 00780 LPVOID pMemory; 00781 } StdMemAllocator; 00782 00783 static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface) 00784 { 00785 StdMemAllocator *This = (StdMemAllocator *)iface; 00786 StdMediaSample2 * pSample = NULL; 00787 SYSTEM_INFO si; 00788 LONG i; 00789 00790 assert(list_empty(&This->base.free_list)); 00791 00792 /* check alignment */ 00793 GetSystemInfo(&si); 00794 00795 /* we do not allow a courser alignment than the OS page size */ 00796 if ((si.dwPageSize % This->base.props.cbAlign) != 0) 00797 return VFW_E_BADALIGN; 00798 00799 /* FIXME: each sample has to have its buffer start on the right alignment. 00800 * We don't do this at the moment */ 00801 00802 /* allocate memory */ 00803 This->pMemory = VirtualAlloc(NULL, (This->base.props.cbBuffer + This->base.props.cbPrefix) * This->base.props.cBuffers, MEM_COMMIT, PAGE_READWRITE); 00804 00805 for (i = This->base.props.cBuffers - 1; i >= 0; i--) 00806 { 00807 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */ 00808 BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.props.cbBuffer + This->base.props.cbPrefix) + This->base.props.cbPrefix; 00809 00810 StdMediaSample2_Construct(pbBuffer, This->base.props.cbBuffer, iface, &pSample); 00811 00812 list_add_head(&This->base.free_list, &pSample->listentry); 00813 } 00814 00815 return S_OK; 00816 } 00817 00818 static HRESULT StdMemAllocator_Free(IMemAllocator * iface) 00819 { 00820 StdMemAllocator *This = (StdMemAllocator *)iface; 00821 struct list * cursor; 00822 00823 if (!list_empty(&This->base.used_list)) 00824 { 00825 WARN("Freeing allocator with outstanding samples!\n"); 00826 while ((cursor = list_head(&This->base.used_list)) != NULL) 00827 { 00828 StdMediaSample2 *pSample; 00829 list_remove(cursor); 00830 pSample = LIST_ENTRY(cursor, StdMediaSample2, listentry); 00831 pSample->pParent = NULL; 00832 } 00833 } 00834 00835 while ((cursor = list_head(&This->base.free_list)) != NULL) 00836 { 00837 list_remove(cursor); 00838 StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry)); 00839 } 00840 00841 /* free memory */ 00842 if (!VirtualFree(This->pMemory, 0, MEM_RELEASE)) 00843 { 00844 ERR("Couldn't free memory. Error: %u\n", GetLastError()); 00845 return HRESULT_FROM_WIN32(GetLastError()); 00846 } 00847 00848 return S_OK; 00849 } 00850 00851 static void StdMemAllocator_Destroy(IMemAllocator *iface) 00852 { 00853 StdMemAllocator *This = (StdMemAllocator *)iface; 00854 00855 This->csState.DebugInfo->Spare[0] = 0; 00856 DeleteCriticalSection(&This->csState); 00857 00858 CoTaskMemFree(This); 00859 } 00860 00861 HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv) 00862 { 00863 StdMemAllocator * pMemAlloc; 00864 HRESULT hr; 00865 00866 *ppv = NULL; 00867 00868 if (lpUnkOuter) 00869 return CLASS_E_NOAGGREGATION; 00870 00871 if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc)))) 00872 return E_OUTOFMEMORY; 00873 00874 InitializeCriticalSection(&pMemAlloc->csState); 00875 pMemAlloc->csState.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": StdMemAllocator.csState"); 00876 00877 pMemAlloc->pMemory = NULL; 00878 00879 if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, NULL, NULL, NULL, StdMemAllocator_Destroy, &pMemAlloc->csState, &pMemAlloc->base))) 00880 *ppv = pMemAlloc; 00881 else 00882 CoTaskMemFree(pMemAlloc); 00883 00884 return hr; 00885 } Generated on Sun May 27 2012 04:21:57 for ReactOS by
1.7.6.1
|