blob: 4019adb315f7e2bb15ec6375811fb8162fbca654 [file] [log] [blame]
Robert Shearman8e538a32003-09-11 21:18:36 +00001/*
2 * Memory Allocator and Media Sample Implementation
3 *
4 * Copyright 2003 Robert Shearman
5 *
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.
10 *
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.
15 *
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
19 */
20
21#include <assert.h>
22#include <limits.h>
23#include <stdarg.h>
24
25#include "windef.h"
26#include "winbase.h"
27#include "vfwmsgs.h"
28
29#include "quartz_private.h"
30#include "wine/list.h"
31#include "wine/debug.h"
32
33WINE_DEFAULT_DEBUG_CHANNEL(quartz);
34
35void dump_AM_SAMPLE2_PROPERTIES(AM_SAMPLE2_PROPERTIES * pProps)
36{
37 if (!pProps)
38 {
39 TRACE("AM_SAMPLE2_PROPERTIES: (null)\n");
40 return;
41 }
42 TRACE("\tcbData: %ld\n", pProps->cbData);
43 TRACE("\tdwTypeSpecificFlags: 0x%8lx\n", pProps->dwTypeSpecificFlags);
44 TRACE("\tdwSampleFlags: 0x%8lx\n", pProps->dwSampleFlags);
45 TRACE("\tlActual: %ld\n", pProps->lActual);
46 TRACE("\ttStart: %lx%08lx%s\n", (LONG)(pProps->tStart >> 32), (LONG)pProps->tStart, pProps->dwSampleFlags & AM_SAMPLE_TIMEVALID ? "" : " (not valid)");
47 TRACE("\ttStop: %lx%08lx%s\n", (LONG)(pProps->tStop >> 32), (LONG)pProps->tStop, pProps->dwSampleFlags & AM_SAMPLE_STOPVALID ? "" : " (not valid)");
48 TRACE("\tdwStreamId: 0x%lx\n", pProps->dwStreamId);
49 TRACE("\tpMediaType: %p\n", pProps->pMediaType);
50 TRACE("\tpbBuffer: %p\n", pProps->pbBuffer);
51 TRACE("\tcbBuffer: %ld\n", pProps->cbBuffer);
52}
53
54typedef struct BaseMemAllocator
55{
56 const IMemAllocatorVtbl * lpVtbl;
57
Mike McCormack0791d062005-07-12 19:21:36 +000058 LONG ref;
Robert Shearman8e538a32003-09-11 21:18:36 +000059 ALLOCATOR_PROPERTIES * pProps;
60 CRITICAL_SECTION csState;
61 HRESULT (* fnAlloc) (IMemAllocator *);
62 HRESULT (* fnFree)(IMemAllocator *);
63 HANDLE hSemWaiting;
64 BOOL bDecommitQueued;
65 BOOL bCommitted;
66 LONG lWaiting;
67 struct list free_list;
68 struct list used_list;
69} BaseMemAllocator;
70
71typedef struct StdMediaSample2
72{
73 const IMediaSample2Vtbl * lpvtbl;
74
Mike McCormack0791d062005-07-12 19:21:36 +000075 LONG ref;
Robert Shearman8e538a32003-09-11 21:18:36 +000076 AM_SAMPLE2_PROPERTIES props;
77 IMemAllocator * pParent;
78 struct list listentry;
79 LONGLONG tMediaStart;
80 LONGLONG tMediaEnd;
81} StdMediaSample2;
82
Dmitry Timoshkoveba47f12005-06-06 19:50:35 +000083static const IMemAllocatorVtbl BaseMemAllocator_VTable;
84static const IMediaSample2Vtbl StdMediaSample2_VTable;
Robert Shearman8e538a32003-09-11 21:18:36 +000085
86#define AM_SAMPLE2_PROP_SIZE_WRITABLE (unsigned int)(&((AM_SAMPLE2_PROPERTIES *)0)->pbBuffer)
87
Alexandre Julliard305b2212005-09-14 10:30:36 +000088#define INVALID_MEDIA_TIME (((ULONGLONG)0x7fffffff << 32) | 0xffffffff)
Robert Shearman8e538a32003-09-11 21:18:36 +000089
90static HRESULT BaseMemAllocator_Init(HRESULT (* fnAlloc)(IMemAllocator *), HRESULT (* fnFree)(IMemAllocator *), BaseMemAllocator * pMemAlloc)
91{
92 assert(fnAlloc && fnFree);
93
94 pMemAlloc->lpVtbl = &BaseMemAllocator_VTable;
95
Christian Costa8b0ec722004-08-13 19:49:16 +000096 pMemAlloc->ref = 1;
Robert Shearman8e538a32003-09-11 21:18:36 +000097 pMemAlloc->pProps = NULL;
98 list_init(&pMemAlloc->free_list);
99 list_init(&pMemAlloc->used_list);
100 pMemAlloc->fnAlloc = fnAlloc;
101 pMemAlloc->fnFree = fnFree;
102 pMemAlloc->bDecommitQueued = FALSE;
103 pMemAlloc->bCommitted = FALSE;
104 pMemAlloc->hSemWaiting = NULL;
105 pMemAlloc->lWaiting = 0;
106
107 InitializeCriticalSection(&pMemAlloc->csState);
108
109 return S_OK;
110}
111
112static HRESULT WINAPI BaseMemAllocator_QueryInterface(IMemAllocator * iface, REFIID riid, LPVOID * ppv)
113{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000114 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Christian Costa8f3cc762005-08-22 09:27:41 +0000115 TRACE("(%p)->(%s, %p)\n", This, qzdebugstr_guid(riid), ppv);
Robert Shearman8e538a32003-09-11 21:18:36 +0000116
117 *ppv = NULL;
118
119 if (IsEqualIID(riid, &IID_IUnknown))
120 *ppv = (LPVOID)This;
121 else if (IsEqualIID(riid, &IID_IMemAllocator))
122 *ppv = (LPVOID)This;
123
124 if (*ppv)
125 {
126 IUnknown_AddRef((IUnknown *)(*ppv));
127 return S_OK;
128 }
129
130 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
131
132 return E_NOINTERFACE;
133}
134
135static ULONG WINAPI BaseMemAllocator_AddRef(IMemAllocator * iface)
136{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000137 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Paul Vriensc6559a12005-01-06 19:36:47 +0000138 ULONG ref = InterlockedIncrement(&This->ref);
Robert Shearman8e538a32003-09-11 21:18:36 +0000139
Paul Vriensc6559a12005-01-06 19:36:47 +0000140 TRACE("(%p)->() AddRef from %ld\n", iface, ref - 1);
Robert Shearman8e538a32003-09-11 21:18:36 +0000141
Paul Vriensc6559a12005-01-06 19:36:47 +0000142 return ref;
Robert Shearman8e538a32003-09-11 21:18:36 +0000143}
144
145static ULONG WINAPI BaseMemAllocator_Release(IMemAllocator * iface)
146{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000147 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Paul Vriensc6559a12005-01-06 19:36:47 +0000148 ULONG ref = InterlockedDecrement(&This->ref);
Robert Shearman8e538a32003-09-11 21:18:36 +0000149
Paul Vriensc6559a12005-01-06 19:36:47 +0000150 TRACE("(%p)->() Release from %ld\n", iface, ref + 1);
Robert Shearman8e538a32003-09-11 21:18:36 +0000151
Paul Vriensc6559a12005-01-06 19:36:47 +0000152 if (!ref)
Robert Shearman8e538a32003-09-11 21:18:36 +0000153 {
154 CloseHandle(This->hSemWaiting);
155 if (This->bCommitted)
156 This->fnFree(iface);
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +0000157 HeapFree(GetProcessHeap(), 0, This->pProps);
Robert Shearman8e538a32003-09-11 21:18:36 +0000158 CoTaskMemFree(This);
159 return 0;
160 }
Paul Vriensc6559a12005-01-06 19:36:47 +0000161 return ref;
Robert Shearman8e538a32003-09-11 21:18:36 +0000162}
163
164static HRESULT WINAPI BaseMemAllocator_SetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual)
165{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000166 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000167 HRESULT hr;
168
Christian Costa8f3cc762005-08-22 09:27:41 +0000169 TRACE("(%p)->(%p, %p)\n", This, pRequest, pActual);
Robert Shearman8e538a32003-09-11 21:18:36 +0000170
171 EnterCriticalSection(&This->csState);
172 {
173 if (!list_empty(&This->used_list))
174 hr = VFW_E_BUFFERS_OUTSTANDING;
175 else if (This->bCommitted)
176 hr = VFW_E_ALREADY_COMMITTED;
Robert Shearman51ae41e2005-04-11 18:50:58 +0000177 else if (pRequest->cbAlign == 0)
178 hr = VFW_E_BADALIGN;
Robert Shearman8e538a32003-09-11 21:18:36 +0000179 else
180 {
181 if (!This->pProps)
182 This->pProps = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->pProps));
183
184 if (!This->pProps)
185 hr = E_OUTOFMEMORY;
186 else
187 {
188 memcpy(This->pProps, pRequest, sizeof(*This->pProps));
189
190 memcpy(pActual, pRequest, sizeof(*pActual));
191
192 hr = S_OK;
193 }
194 }
195 }
196 LeaveCriticalSection(&This->csState);
197
198 return hr;
199}
200
201static HRESULT WINAPI BaseMemAllocator_GetProperties(IMemAllocator * iface, ALLOCATOR_PROPERTIES *pProps)
202{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000203 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000204 HRESULT hr = S_OK;
205
Christian Costa8f3cc762005-08-22 09:27:41 +0000206 TRACE("(%p)->(%p)\n", This, pProps);
Robert Shearman8e538a32003-09-11 21:18:36 +0000207
208 EnterCriticalSection(&This->csState);
209 {
210 /* NOTE: this is different from the native version.
211 * It would silently succeed if the properties had
212 * not been set, but would fail further on down the
213 * line with some obscure error like having an
214 * invalid alignment. Whether or not our version
215 * will cause any problems remains to be seen */
216 if (!This->pProps)
217 hr = VFW_E_SIZENOTSET;
218 else
219 memcpy(pProps, This->pProps, sizeof(*pProps));
220 }
221 LeaveCriticalSection(&This->csState);
222
223 return hr;
224}
225
226static HRESULT WINAPI BaseMemAllocator_Commit(IMemAllocator * iface)
227{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000228 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000229 HRESULT hr;
230
Christian Costa8f3cc762005-08-22 09:27:41 +0000231 TRACE("(%p)->()\n", This);
Robert Shearman8e538a32003-09-11 21:18:36 +0000232
233 EnterCriticalSection(&This->csState);
234 {
235 if (!This->pProps)
236 hr = VFW_E_SIZENOTSET;
237 else if (This->bCommitted)
Christian Costa8f3cc762005-08-22 09:27:41 +0000238 hr = S_OK;
Robert Shearman8e538a32003-09-11 21:18:36 +0000239 else if (This->bDecommitQueued)
240 {
241 This->bDecommitQueued = FALSE;
242 hr = S_OK;
243 }
244 else
245 {
246 if (!(This->hSemWaiting = CreateSemaphoreW(NULL, This->pProps->cBuffers, This->pProps->cBuffers, NULL)))
247 {
248 ERR("Couldn't create semaphore (error was %ld)\n", GetLastError());
249 hr = HRESULT_FROM_WIN32(GetLastError());
250 }
251 else
252 {
253 hr = This->fnAlloc(iface);
254 if (SUCCEEDED(hr))
255 This->bCommitted = TRUE;
256 else
257 ERR("fnAlloc failed with error 0x%lx\n", hr);
258 }
259 }
260 }
261 LeaveCriticalSection(&This->csState);
262
263 return hr;
264}
265
266static HRESULT WINAPI BaseMemAllocator_Decommit(IMemAllocator * iface)
267{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000268 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000269 HRESULT hr;
270
Christian Costa8f3cc762005-08-22 09:27:41 +0000271 TRACE("(%p)->()\n", This);
Robert Shearman8e538a32003-09-11 21:18:36 +0000272
273 EnterCriticalSection(&This->csState);
274 {
275 if (!This->bCommitted)
Christian Costa8f3cc762005-08-22 09:27:41 +0000276 hr = S_OK;
Robert Shearman8e538a32003-09-11 21:18:36 +0000277 else
278 {
279 if (!list_empty(&This->used_list))
280 {
281 This->bDecommitQueued = TRUE;
282 /* notify ALL waiting threads that they cannot be allocated a buffer any more */
283 ReleaseSemaphore(This->hSemWaiting, This->lWaiting, NULL);
284
285 hr = S_OK;
286 }
287 else
288 {
289 assert(This->lWaiting == 0);
290
291 This->bCommitted = FALSE;
292 CloseHandle(This->hSemWaiting);
293 This->hSemWaiting = NULL;
294
295 hr = This->fnFree(iface);
296 if (FAILED(hr))
297 ERR("fnFree failed with error 0x%lx\n", hr);
298 }
299 }
300 }
301 LeaveCriticalSection(&This->csState);
302
303 return hr;
304}
305
306static HRESULT WINAPI BaseMemAllocator_GetBuffer(IMemAllocator * iface, IMediaSample ** pSample, REFERENCE_TIME *pStartTime, REFERENCE_TIME *pEndTime, DWORD dwFlags)
307{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000308 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000309 HRESULT hr = S_OK;
310
311 /* NOTE: The pStartTime and pEndTime parameters are not applied to the sample.
312 * The allocator might use these values to determine which buffer it retrieves */
313
Christian Costa8f3cc762005-08-22 09:27:41 +0000314 TRACE("(%p)->(%p, %p, %p, %lx)\n", This, pSample, pStartTime, pEndTime, dwFlags);
Robert Shearman8e538a32003-09-11 21:18:36 +0000315
316 *pSample = NULL;
317
318 if (!This->bCommitted)
319 return VFW_E_NOT_COMMITTED;
320
321 This->lWaiting++;
322 if (WaitForSingleObject(This->hSemWaiting, (dwFlags & AM_GBF_NOWAIT) ? 0 : INFINITE) != WAIT_OBJECT_0)
323 {
324 This->lWaiting--;
325 return VFW_E_TIMEOUT;
326 }
327 This->lWaiting--;
328
329 EnterCriticalSection(&This->csState);
330 {
331 if (!This->bCommitted)
332 hr = VFW_E_NOT_COMMITTED;
333 else if (This->bDecommitQueued)
334 hr = VFW_E_TIMEOUT;
335 else
336 {
337 struct list * free = list_head(&This->free_list);
338 list_remove(free);
339 list_add_head(&This->used_list, free);
340
341 *pSample = (IMediaSample *)LIST_ENTRY(free, StdMediaSample2, listentry);
342
343 assert(((StdMediaSample2 *)*pSample)->ref == 0);
344
345 IMediaSample_AddRef(*pSample);
346 }
347 }
348 LeaveCriticalSection(&This->csState);
349
350 return hr;
351}
352
353static HRESULT WINAPI BaseMemAllocator_ReleaseBuffer(IMemAllocator * iface, IMediaSample * pSample)
354{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000355 BaseMemAllocator *This = (BaseMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000356 StdMediaSample2 * pStdSample = (StdMediaSample2 *)pSample;
357 HRESULT hr = S_OK;
358
Christian Costa8f3cc762005-08-22 09:27:41 +0000359 TRACE("(%p)->(%p)\n", This, pSample);
Robert Shearman8e538a32003-09-11 21:18:36 +0000360
361 /* FIXME: make sure that sample is currently on the used list */
362
363 /* FIXME: we should probably check the ref count on the sample before freeing
364 * it to make sure that it is not still in use */
365 EnterCriticalSection(&This->csState);
366 {
367 if (!This->bCommitted)
368 ERR("Releasing a buffer when the allocator is not committed?!?\n");
369
370 /* remove from used_list */
371 list_remove(&pStdSample->listentry);
372
373 list_add_head(&This->free_list, &pStdSample->listentry);
374
375 if (list_empty(&This->used_list) && This->bDecommitQueued && This->bCommitted)
376 {
377 HRESULT hrfree;
378
379 assert(This->lWaiting == 0);
380
381 This->bCommitted = FALSE;
382 This->bDecommitQueued = FALSE;
383
384 CloseHandle(This->hSemWaiting);
385 This->hSemWaiting = NULL;
386
387 if (FAILED(hrfree = This->fnFree(iface)))
388 ERR("fnFree failed with error 0x%lx\n", hrfree);
389 }
390 }
391 LeaveCriticalSection(&This->csState);
392
393 /* notify a waiting thread that there is now a free buffer */
394 if (!ReleaseSemaphore(This->hSemWaiting, 1, NULL))
395 {
396 ERR("ReleaseSemaphore failed with error %ld\n", GetLastError());
397 hr = HRESULT_FROM_WIN32(GetLastError());
398 }
399
400 return hr;
401}
402
403static const IMemAllocatorVtbl BaseMemAllocator_VTable =
404{
Robert Shearman8e538a32003-09-11 21:18:36 +0000405 BaseMemAllocator_QueryInterface,
406 BaseMemAllocator_AddRef,
407 BaseMemAllocator_Release,
408 BaseMemAllocator_SetProperties,
409 BaseMemAllocator_GetProperties,
410 BaseMemAllocator_Commit,
411 BaseMemAllocator_Decommit,
412 BaseMemAllocator_GetBuffer,
413 BaseMemAllocator_ReleaseBuffer
414};
415
416static HRESULT StdMediaSample2_Construct(BYTE * pbBuffer, LONG cbBuffer, IMemAllocator * pParent, StdMediaSample2 ** ppSample)
417{
418 assert(pbBuffer && pParent && (cbBuffer > 0));
419
420 if (!(*ppSample = CoTaskMemAlloc(sizeof(StdMediaSample2))))
421 return E_OUTOFMEMORY;
422
423 (*ppSample)->lpvtbl = &StdMediaSample2_VTable;
424 (*ppSample)->ref = 0;
425 ZeroMemory(&(*ppSample)->props, sizeof((*ppSample)->props));
426
427 /* NOTE: no need to AddRef as the parent is guaranteed to be around
428 * at least as long as us and we don't want to create circular
429 * dependencies on the ref count */
430 (*ppSample)->pParent = pParent;
431 (*ppSample)->props.cbData = sizeof(AM_SAMPLE2_PROPERTIES);
432 (*ppSample)->props.cbBuffer = (*ppSample)->props.lActual = cbBuffer;
433 (*ppSample)->props.pbBuffer = pbBuffer;
434 (*ppSample)->tMediaStart = INVALID_MEDIA_TIME;
435 (*ppSample)->tMediaEnd = 0;
436
437 return S_OK;
438}
439
440static void StdMediaSample2_Delete(StdMediaSample2 * This)
441{
442 /* NOTE: does not remove itself from the list it belongs to */
443 CoTaskMemFree(This);
444}
445
446static HRESULT WINAPI StdMediaSample2_QueryInterface(IMediaSample2 * iface, REFIID riid, LPVOID * ppv)
447{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000448 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000449 TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv);
450
451 *ppv = NULL;
452
453 if (IsEqualIID(riid, &IID_IUnknown))
454 *ppv = (LPVOID)This;
455 else if (IsEqualIID(riid, &IID_IMediaSample))
456 *ppv = (LPVOID)This;
457 else if (IsEqualIID(riid, &IID_IMediaSample2))
458 *ppv = (LPVOID)This;
459
460 if (*ppv)
461 {
462 IUnknown_AddRef((IUnknown *)(*ppv));
463 return S_OK;
464 }
465
466 FIXME("No interface for %s!\n", qzdebugstr_guid(riid));
467
468 return E_NOINTERFACE;
469}
470
471static ULONG WINAPI StdMediaSample2_AddRef(IMediaSample2 * iface)
472{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000473 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Paul Vriensc6559a12005-01-06 19:36:47 +0000474 ULONG ref = InterlockedIncrement(&This->ref);
Robert Shearman8e538a32003-09-11 21:18:36 +0000475
Paul Vriensc6559a12005-01-06 19:36:47 +0000476 TRACE("(%p)->() AddRef from %ld\n", iface, ref - 1);
Robert Shearman8e538a32003-09-11 21:18:36 +0000477
Paul Vriensc6559a12005-01-06 19:36:47 +0000478 return ref;
Robert Shearman8e538a32003-09-11 21:18:36 +0000479}
480
481static ULONG WINAPI StdMediaSample2_Release(IMediaSample2 * iface)
482{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000483 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Paul Vriensc6559a12005-01-06 19:36:47 +0000484 ULONG ref = InterlockedDecrement(&This->ref);
Robert Shearman8e538a32003-09-11 21:18:36 +0000485
Paul Vriensc6559a12005-01-06 19:36:47 +0000486 TRACE("(%p)->() Release from %ld\n", iface, ref + 1);
Robert Shearman8e538a32003-09-11 21:18:36 +0000487
Paul Vriensc6559a12005-01-06 19:36:47 +0000488 if (!ref)
Robert Shearman8e538a32003-09-11 21:18:36 +0000489 {
490 IMemAllocator_ReleaseBuffer(This->pParent, (IMediaSample *)iface);
491 return 0;
492 }
Paul Vriensc6559a12005-01-06 19:36:47 +0000493 return ref;
Robert Shearman8e538a32003-09-11 21:18:36 +0000494}
495
496static HRESULT WINAPI StdMediaSample2_GetPointer(IMediaSample2 * iface, BYTE ** ppBuffer)
497{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000498 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000499
500 TRACE("(%p)\n", ppBuffer);
501
502 *ppBuffer = This->props.pbBuffer;
503
504 return S_OK;
505}
506
507static long WINAPI StdMediaSample2_GetSize(IMediaSample2 * iface)
508{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000509 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000510
511 TRACE("StdMediaSample2_GetSize()\n");
512
513 return This->props.cbBuffer;
514}
515
516static HRESULT WINAPI StdMediaSample2_GetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
517{
518 HRESULT hr;
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000519 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000520
521 TRACE("(%p, %p)\n", pStart, pEnd);
522
523 if (!(This->props.dwSampleFlags & AM_SAMPLE_TIMEVALID))
524 hr = VFW_E_SAMPLE_TIME_NOT_SET;
525 else if (!(This->props.dwSampleFlags & AM_SAMPLE_STOPVALID))
526 {
527 *pStart = This->props.tStart;
528 *pEnd = This->props.tStart + 1;
529
530 hr = VFW_S_NO_STOP_TIME;
531 }
532 else
533 {
534 *pStart = This->props.tStart;
535 *pEnd = This->props.tStop;
536
537 hr = S_OK;
538 }
539
540 return S_OK;
541}
542
543static HRESULT WINAPI StdMediaSample2_SetTime(IMediaSample2 * iface, REFERENCE_TIME * pStart, REFERENCE_TIME * pEnd)
544{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000545 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000546
547 TRACE("(%p, %p)\n", pStart, pEnd);
548
549 if (pStart)
550 {
551 This->props.tStart = *pStart;
552 This->props.dwSampleFlags |= AM_SAMPLE_TIMEVALID;
553 }
554 else
555 This->props.dwSampleFlags &= ~AM_SAMPLE_TIMEVALID;
556
557 if (pEnd)
558 {
559 This->props.tStop = *pEnd;
560 This->props.dwSampleFlags |= AM_SAMPLE_STOPVALID;
561 }
562 else
563 This->props.dwSampleFlags &= ~AM_SAMPLE_STOPVALID;
564
565 return S_OK;
566}
567
568static HRESULT WINAPI StdMediaSample2_IsSyncPoint(IMediaSample2 * iface)
569{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000570 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000571
572 TRACE("()\n");
573
574 return (This->props.dwSampleFlags & AM_SAMPLE_SPLICEPOINT) ? S_OK : S_FALSE;
575}
576
577static HRESULT WINAPI StdMediaSample2_SetSyncPoint(IMediaSample2 * iface, BOOL bIsSyncPoint)
578{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000579 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000580
581 TRACE("(%s)\n", bIsSyncPoint ? "TRUE" : "FALSE");
582
583 This->props.dwSampleFlags = (This->props.dwSampleFlags & ~AM_SAMPLE_SPLICEPOINT) | bIsSyncPoint ? AM_SAMPLE_SPLICEPOINT : 0;
584
585 return S_OK;
586}
587
588static HRESULT WINAPI StdMediaSample2_IsPreroll(IMediaSample2 * iface)
589{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000590 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000591
592 TRACE("()\n");
593
594 return (This->props.dwSampleFlags & AM_SAMPLE_PREROLL) ? S_OK : S_FALSE;
595}
596
597static HRESULT WINAPI StdMediaSample2_SetPreroll(IMediaSample2 * iface, BOOL bIsPreroll)
598{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000599 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000600
601 TRACE("(%s)\n", bIsPreroll ? "TRUE" : "FALSE");
602
603 This->props.dwSampleFlags = (This->props.dwSampleFlags & ~AM_SAMPLE_PREROLL) | bIsPreroll ? AM_SAMPLE_PREROLL : 0;
604
605 return S_OK;
606}
607
608static LONG WINAPI StdMediaSample2_GetActualDataLength(IMediaSample2 * iface)
609{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000610 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000611
612 TRACE("()\n");
613
614 return This->props.lActual;
615}
616
617static HRESULT WINAPI StdMediaSample2_SetActualDataLength(IMediaSample2 * iface, LONG len)
618{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000619 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000620
621 TRACE("(%ld)\n", len);
622
623 if ((len > This->props.cbBuffer) || (len < 0))
624 return VFW_E_BUFFER_OVERFLOW;
625 else
626 {
627 This->props.lActual = len;
628 return S_OK;
629 }
630}
631
632static HRESULT WINAPI StdMediaSample2_GetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE ** ppMediaType)
633{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000634 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000635
636 TRACE("(%p)\n", ppMediaType);
637
Christian Costa5182f702004-12-20 17:07:17 +0000638 if (!This->props.pMediaType) {
639 /* Make sure we return a NULL pointer (required by native Quartz dll) */
640 if (ppMediaType)
641 *ppMediaType = NULL;
Robert Shearman8e538a32003-09-11 21:18:36 +0000642 return S_FALSE;
Christian Costa5182f702004-12-20 17:07:17 +0000643 }
Robert Shearman8e538a32003-09-11 21:18:36 +0000644
645 if (!(*ppMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
646 return E_OUTOFMEMORY;
647
648 return CopyMediaType(*ppMediaType, This->props.pMediaType);
649}
650
651static HRESULT WINAPI StdMediaSample2_SetMediaType(IMediaSample2 * iface, AM_MEDIA_TYPE * pMediaType)
652{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000653 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000654
655 TRACE("(%p)\n", pMediaType);
656
657 if (This->props.pMediaType)
Maarten Lankhorst0caae472005-05-18 13:25:20 +0000658 FreeMediaType(This->props.pMediaType);
Robert Shearman8e538a32003-09-11 21:18:36 +0000659 else if (!(This->props.pMediaType = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE))))
660 return E_OUTOFMEMORY;
661
662 return CopyMediaType(This->props.pMediaType, pMediaType);
663}
664
665static HRESULT WINAPI StdMediaSample2_IsDiscontinuity(IMediaSample2 * iface)
666{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000667 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000668
669 TRACE("()\n");
670
671 return (This->props.dwSampleFlags & AM_SAMPLE_DATADISCONTINUITY) ? S_OK : S_FALSE;
672}
673
674static HRESULT WINAPI StdMediaSample2_SetDiscontinuity(IMediaSample2 * iface, BOOL bIsDiscontinuity)
675{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000676 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000677
678 TRACE("(%s)\n", bIsDiscontinuity ? "TRUE" : "FALSE");
679
680 This->props.dwSampleFlags = (This->props.dwSampleFlags & ~AM_SAMPLE_DATADISCONTINUITY) | bIsDiscontinuity ? AM_SAMPLE_DATADISCONTINUITY : 0;
681
682 return S_OK;
683}
684
685static HRESULT WINAPI StdMediaSample2_GetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
686{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000687 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000688
689 TRACE("(%p, %p)\n", pStart, pEnd);
690
691 if (This->tMediaStart == INVALID_MEDIA_TIME)
692 return VFW_E_MEDIA_TIME_NOT_SET;
693
694 *pStart = This->tMediaStart;
695 *pEnd = This->tMediaEnd;
696
697 return E_NOTIMPL;
698}
699
700static HRESULT WINAPI StdMediaSample2_SetMediaTime(IMediaSample2 * iface, LONGLONG * pStart, LONGLONG * pEnd)
701{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000702 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000703
704 TRACE("(%p, %p)\n", pStart, pEnd);
705
706 if (pStart)
707 This->tMediaStart = *pStart;
708 else
709 This->tMediaStart = INVALID_MEDIA_TIME;
710
711 if (pEnd)
712 This->tMediaEnd = *pEnd;
713 else
714 This->tMediaEnd = 0;
715
716 return S_OK;
717}
718
719static HRESULT WINAPI StdMediaSample2_GetProperties(IMediaSample2 * iface, DWORD cbProperties, BYTE * pbProperties)
720{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000721 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000722
723 TRACE("(%ld, %p)\n", cbProperties, pbProperties);
724
725 memcpy(pbProperties, &This->props, min(cbProperties, sizeof(This->props)));
726
727 return S_OK;
728}
729
730static HRESULT WINAPI StdMediaSample2_SetProperties(IMediaSample2 * iface, DWORD cbProperties, const BYTE * pbProperties)
731{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000732 StdMediaSample2 *This = (StdMediaSample2 *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000733
734 TRACE("(%ld, %p)\n", cbProperties, pbProperties);
735
736 /* NOTE: pbBuffer and cbBuffer are read-only */
737 memcpy(&This->props, pbProperties, min(cbProperties, AM_SAMPLE2_PROP_SIZE_WRITABLE));
738
739 return S_OK;
740}
741
742static const IMediaSample2Vtbl StdMediaSample2_VTable =
743{
Robert Shearman8e538a32003-09-11 21:18:36 +0000744 StdMediaSample2_QueryInterface,
745 StdMediaSample2_AddRef,
746 StdMediaSample2_Release,
747 StdMediaSample2_GetPointer,
748 StdMediaSample2_GetSize,
749 StdMediaSample2_GetTime,
750 StdMediaSample2_SetTime,
751 StdMediaSample2_IsSyncPoint,
752 StdMediaSample2_SetSyncPoint,
753 StdMediaSample2_IsPreroll,
754 StdMediaSample2_SetPreroll,
755 StdMediaSample2_GetActualDataLength,
756 StdMediaSample2_SetActualDataLength,
757 StdMediaSample2_GetMediaType,
758 StdMediaSample2_SetMediaType,
759 StdMediaSample2_IsDiscontinuity,
760 StdMediaSample2_SetDiscontinuity,
761 StdMediaSample2_GetMediaTime,
762 StdMediaSample2_SetMediaTime,
763 StdMediaSample2_GetProperties,
764 StdMediaSample2_SetProperties
765};
766
767typedef struct StdMemAllocator
768{
769 BaseMemAllocator base;
770 LPVOID pMemory;
771} StdMemAllocator;
772
773static HRESULT StdMemAllocator_Alloc(IMemAllocator * iface)
774{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000775 StdMemAllocator *This = (StdMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000776 StdMediaSample2 * pSample = NULL;
777 SYSTEM_INFO si;
778 long i;
779
780 assert(list_empty(&This->base.free_list));
781
782 /* check alignment */
783 GetSystemInfo(&si);
784
785 /* we do not allow a courser alignment than the OS page size */
786 if ((si.dwPageSize % This->base.pProps->cbAlign) != 0)
787 return VFW_E_BADALIGN;
788
789 /* FIXME: each sample has to have its buffer start on the right alignment.
790 * We don't do this at the moment */
791
792 /* allocate memory */
793 This->pMemory = VirtualAlloc(NULL, (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) * This->base.pProps->cBuffers, MEM_COMMIT, PAGE_READWRITE);
794
795 for (i = This->base.pProps->cBuffers - 1; i >= 0; i--)
796 {
797 /* pbBuffer does not start at the base address, it starts at base + cbPrefix */
798 BYTE * pbBuffer = (BYTE *)This->pMemory + i * (This->base.pProps->cbBuffer + This->base.pProps->cbPrefix) + This->base.pProps->cbPrefix;
799
800 StdMediaSample2_Construct(pbBuffer, This->base.pProps->cbBuffer, iface, &pSample);
801
802 list_add_head(&This->base.free_list, &pSample->listentry);
803 }
804
805 return S_OK;
806}
807
808static HRESULT StdMemAllocator_Free(IMemAllocator * iface)
809{
Alexandre Julliardf5f7a182004-09-08 01:50:37 +0000810 StdMemAllocator *This = (StdMemAllocator *)iface;
Robert Shearman8e538a32003-09-11 21:18:36 +0000811 struct list * cursor;
812
813 assert(list_empty(&This->base.used_list));
814
815 while ((cursor = list_head(&This->base.free_list)) != NULL)
816 {
817 list_remove(cursor);
818 StdMediaSample2_Delete(LIST_ENTRY(cursor, StdMediaSample2, listentry));
819 }
820
821 /* free memory */
822 if (!VirtualFree(This->pMemory, 0, MEM_RELEASE))
823 {
824 ERR("Couldn't free memory. Error: %ld\n", GetLastError());
825 return HRESULT_FROM_WIN32(GetLastError());
826 }
827
828 return S_OK;
829}
830
831HRESULT StdMemAllocator_create(LPUNKNOWN lpUnkOuter, LPVOID * ppv)
832{
833 StdMemAllocator * pMemAlloc;
834 HRESULT hr;
835
836 *ppv = NULL;
837
838 if (lpUnkOuter)
839 return CLASS_E_NOAGGREGATION;
840
841 if (!(pMemAlloc = CoTaskMemAlloc(sizeof(*pMemAlloc))))
842 return E_OUTOFMEMORY;
843
844 pMemAlloc->pMemory = NULL;
845
846 if (SUCCEEDED(hr = BaseMemAllocator_Init(StdMemAllocator_Alloc, StdMemAllocator_Free, &pMemAlloc->base)))
847 *ppv = (LPVOID)pMemAlloc;
848 else
849 CoTaskMemFree(pMemAlloc);
850
851 return hr;
852}