ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

memallocator.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.