mf/samplegrabber: Handle paused state.
[wine.git] / dlls / mfplat / sample.c
blob09c65b5fcf183a232e3e0eed6f31c08ea90c794a
1 /*
2 * Copyright 2021 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "mfplat_private.h"
22 #include "rtworkq.h"
23 #include "d3d9.h"
24 #include "d3d11.h"
25 #include "initguid.h"
26 #include "dxva2api.h"
28 #include "wine/debug.h"
29 #include "wine/list.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
33 enum sample_prop_flags
35 SAMPLE_PROP_HAS_DURATION = 1 << 0,
36 SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
39 struct sample
41 struct attributes attributes;
42 IMFSample IMFSample_iface;
43 IMFTrackedSample IMFTrackedSample_iface;
45 IMFMediaBuffer **buffers;
46 size_t buffer_count;
47 size_t capacity;
48 DWORD flags;
49 DWORD prop_flags;
50 LONGLONG duration;
51 LONGLONG timestamp;
53 /* Tracked sample functionality. */
54 IRtwqAsyncResult *tracked_result;
55 LONG tracked_refcount;
58 struct sample_allocator
60 IMFVideoSampleAllocatorEx IMFVideoSampleAllocatorEx_iface;
61 IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface;
62 IMFAsyncCallback tracking_callback;
63 LONG refcount;
65 IMFVideoSampleAllocatorNotify *callback;
66 IDirect3DDeviceManager9 *d3d9_device_manager;
67 IMFDXGIDeviceManager *dxgi_device_manager;
69 struct
71 unsigned int width;
72 unsigned int height;
73 D3DFORMAT d3d9_format;
74 DXGI_FORMAT dxgi_format;
75 unsigned int usage;
76 unsigned int bindflags;
77 unsigned int buffer_count;
78 } frame_desc;
80 IMFAttributes *attributes;
81 IMFMediaType *media_type;
83 unsigned int free_sample_count;
84 unsigned int cold_sample_count;
85 struct list free_samples;
86 struct list used_samples;
87 CRITICAL_SECTION cs;
90 struct queued_sample
92 struct list entry;
93 IMFSample *sample;
96 static struct sample_allocator *impl_from_IMFVideoSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface)
98 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorEx_iface);
101 static struct sample_allocator *impl_from_IMFVideoSampleAllocatorCallback(IMFVideoSampleAllocatorCallback *iface)
103 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorCallback_iface);
106 static struct sample_allocator *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
108 return CONTAINING_RECORD(iface, struct sample_allocator, tracking_callback);
111 static struct sample *impl_from_IMFSample(IMFSample *iface)
113 return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
116 static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
118 return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface);
121 static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
123 struct sample *sample = impl_from_IMFSample(iface);
125 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
127 if (IsEqualIID(riid, &IID_IMFSample) ||
128 IsEqualIID(riid, &IID_IMFAttributes) ||
129 IsEqualIID(riid, &IID_IUnknown))
131 *out = &sample->IMFSample_iface;
133 else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample))
135 *out = &sample->IMFTrackedSample_iface;
137 else
139 WARN("Unsupported %s.\n", debugstr_guid(riid));
140 *out = NULL;
141 return E_NOINTERFACE;
144 IUnknown_AddRef((IUnknown *)*out);
145 return S_OK;
148 static ULONG WINAPI sample_AddRef(IMFSample *iface)
150 struct sample *sample = impl_from_IMFSample(iface);
151 ULONG refcount = InterlockedIncrement(&sample->attributes.ref);
153 TRACE("%p, refcount %u.\n", iface, refcount);
155 return refcount;
158 static void release_sample_object(struct sample *sample)
160 size_t i;
162 for (i = 0; i < sample->buffer_count; ++i)
163 IMFMediaBuffer_Release(sample->buffers[i]);
164 clear_attributes_object(&sample->attributes);
165 free(sample->buffers);
166 free(sample);
169 static ULONG WINAPI sample_Release(IMFSample *iface)
171 struct sample *sample = impl_from_IMFSample(iface);
172 ULONG refcount = InterlockedDecrement(&sample->attributes.ref);
174 TRACE("%p, refcount %u.\n", iface, refcount);
176 if (!refcount)
177 release_sample_object(sample);
179 return refcount;
182 static ULONG WINAPI sample_tracked_Release(IMFSample *iface)
184 struct sample *sample = impl_from_IMFSample(iface);
185 ULONG refcount;
186 HRESULT hr;
188 EnterCriticalSection(&sample->attributes.cs);
189 if (sample->tracked_result && sample->tracked_refcount == (sample->attributes.ref - 1))
191 IRtwqAsyncResult *tracked_result = sample->tracked_result;
192 sample->tracked_result = NULL;
193 sample->tracked_refcount = 0;
195 /* Call could fail if queue system is not initialized, it's not critical. */
196 if (FAILED(hr = RtwqInvokeCallback(tracked_result)))
197 WARN("Failed to invoke tracking callback, hr %#x.\n", hr);
198 IRtwqAsyncResult_Release(tracked_result);
200 LeaveCriticalSection(&sample->attributes.cs);
202 refcount = InterlockedDecrement(&sample->attributes.ref);
204 TRACE("%p, refcount %u.\n", iface, refcount);
206 if (!refcount)
207 release_sample_object(sample);
209 return refcount;
212 static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
214 struct sample *sample = impl_from_IMFSample(iface);
216 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
218 return attributes_GetItem(&sample->attributes, key, value);
221 static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
223 struct sample *sample = impl_from_IMFSample(iface);
225 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
227 return attributes_GetItemType(&sample->attributes, key, type);
230 static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
232 struct sample *sample = impl_from_IMFSample(iface);
234 TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result);
236 return attributes_CompareItem(&sample->attributes, key, value, result);
239 static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
240 BOOL *result)
242 struct sample *sample = impl_from_IMFSample(iface);
244 TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
246 return attributes_Compare(&sample->attributes, theirs, type, result);
249 static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
251 struct sample *sample = impl_from_IMFSample(iface);
253 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
255 return attributes_GetUINT32(&sample->attributes, key, value);
258 static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
260 struct sample *sample = impl_from_IMFSample(iface);
262 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
264 return attributes_GetUINT64(&sample->attributes, key, value);
267 static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
269 struct sample *sample = impl_from_IMFSample(iface);
271 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
273 return attributes_GetDouble(&sample->attributes, key, value);
276 static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
278 struct sample *sample = impl_from_IMFSample(iface);
280 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
282 return attributes_GetGUID(&sample->attributes, key, value);
285 static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
287 struct sample *sample = impl_from_IMFSample(iface);
289 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
291 return attributes_GetStringLength(&sample->attributes, key, length);
294 static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
296 struct sample *sample = impl_from_IMFSample(iface);
298 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
300 return attributes_GetString(&sample->attributes, key, value, size, length);
303 static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
305 struct sample *sample = impl_from_IMFSample(iface);
307 TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
309 return attributes_GetAllocatedString(&sample->attributes, key, value, length);
312 static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
314 struct sample *sample = impl_from_IMFSample(iface);
316 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
318 return attributes_GetBlobSize(&sample->attributes, key, size);
321 static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
323 struct sample *sample = impl_from_IMFSample(iface);
325 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
327 return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize);
330 static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
332 struct sample *sample = impl_from_IMFSample(iface);
334 TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
336 return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size);
339 static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
341 struct sample *sample = impl_from_IMFSample(iface);
343 TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
345 return attributes_GetUnknown(&sample->attributes, key, riid, out);
348 static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
350 struct sample *sample = impl_from_IMFSample(iface);
352 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value));
354 return attributes_SetItem(&sample->attributes, key, value);
357 static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key)
359 struct sample *sample = impl_from_IMFSample(iface);
361 TRACE("%p, %s.\n", iface, debugstr_attr(key));
363 return attributes_DeleteItem(&sample->attributes, key);
366 static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface)
368 struct sample *sample = impl_from_IMFSample(iface);
370 TRACE("%p.\n", iface);
372 return attributes_DeleteAllItems(&sample->attributes);
375 static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
377 struct sample *sample = impl_from_IMFSample(iface);
379 TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
381 return attributes_SetUINT32(&sample->attributes, key, value);
384 static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
386 struct sample *sample = impl_from_IMFSample(iface);
388 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
390 return attributes_SetUINT64(&sample->attributes, key, value);
393 static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value)
395 struct sample *sample = impl_from_IMFSample(iface);
397 TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
399 return attributes_SetDouble(&sample->attributes, key, value);
402 static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
404 struct sample *sample = impl_from_IMFSample(iface);
406 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
408 return attributes_SetGUID(&sample->attributes, key, value);
411 static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
413 struct sample *sample = impl_from_IMFSample(iface);
415 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
417 return attributes_SetString(&sample->attributes, key, value);
420 static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
422 struct sample *sample = impl_from_IMFSample(iface);
424 TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
426 return attributes_SetBlob(&sample->attributes, key, buf, size);
429 static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
431 struct sample *sample = impl_from_IMFSample(iface);
433 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
435 return attributes_SetUnknown(&sample->attributes, key, unknown);
438 static HRESULT WINAPI sample_LockStore(IMFSample *iface)
440 struct sample *sample = impl_from_IMFSample(iface);
442 TRACE("%p.\n", iface);
444 return attributes_LockStore(&sample->attributes);
447 static HRESULT WINAPI sample_UnlockStore(IMFSample *iface)
449 struct sample *sample = impl_from_IMFSample(iface);
451 TRACE("%p.\n", iface);
453 return attributes_UnlockStore(&sample->attributes);
456 static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count)
458 struct sample *sample = impl_from_IMFSample(iface);
460 TRACE("%p, %p.\n", iface, count);
462 return attributes_GetCount(&sample->attributes, count);
465 static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
467 struct sample *sample = impl_from_IMFSample(iface);
469 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
471 return attributes_GetItemByIndex(&sample->attributes, index, key, value);
474 static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
476 struct sample *sample = impl_from_IMFSample(iface);
478 TRACE("%p, %p.\n", iface, dest);
480 return attributes_CopyAllItems(&sample->attributes, dest);
483 static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
485 struct sample *sample = impl_from_IMFSample(iface);
487 TRACE("%p, %p.\n", iface, flags);
489 EnterCriticalSection(&sample->attributes.cs);
490 *flags = sample->flags;
491 LeaveCriticalSection(&sample->attributes.cs);
493 return S_OK;
496 static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags)
498 struct sample *sample = impl_from_IMFSample(iface);
500 TRACE("%p, %#x.\n", iface, flags);
502 EnterCriticalSection(&sample->attributes.cs);
503 sample->flags = flags;
504 LeaveCriticalSection(&sample->attributes.cs);
506 return S_OK;
509 static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
511 struct sample *sample = impl_from_IMFSample(iface);
512 HRESULT hr = S_OK;
514 TRACE("%p, %p.\n", iface, timestamp);
516 EnterCriticalSection(&sample->attributes.cs);
517 if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP)
518 *timestamp = sample->timestamp;
519 else
520 hr = MF_E_NO_SAMPLE_TIMESTAMP;
521 LeaveCriticalSection(&sample->attributes.cs);
523 return hr;
526 static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
528 struct sample *sample = impl_from_IMFSample(iface);
530 TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
532 EnterCriticalSection(&sample->attributes.cs);
533 sample->timestamp = timestamp;
534 sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP;
535 LeaveCriticalSection(&sample->attributes.cs);
537 return S_OK;
540 static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
542 struct sample *sample = impl_from_IMFSample(iface);
543 HRESULT hr = S_OK;
545 TRACE("%p, %p.\n", iface, duration);
547 EnterCriticalSection(&sample->attributes.cs);
548 if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION)
549 *duration = sample->duration;
550 else
551 hr = MF_E_NO_SAMPLE_DURATION;
552 LeaveCriticalSection(&sample->attributes.cs);
554 return hr;
557 static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
559 struct sample *sample = impl_from_IMFSample(iface);
561 TRACE("%p, %s.\n", iface, debugstr_time(duration));
563 EnterCriticalSection(&sample->attributes.cs);
564 sample->duration = duration;
565 sample->prop_flags |= SAMPLE_PROP_HAS_DURATION;
566 LeaveCriticalSection(&sample->attributes.cs);
568 return S_OK;
571 static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count)
573 struct sample *sample = impl_from_IMFSample(iface);
575 TRACE("%p, %p.\n", iface, count);
577 if (!count)
578 return E_INVALIDARG;
580 EnterCriticalSection(&sample->attributes.cs);
581 *count = sample->buffer_count;
582 LeaveCriticalSection(&sample->attributes.cs);
584 return S_OK;
587 static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
589 struct sample *sample = impl_from_IMFSample(iface);
590 HRESULT hr = S_OK;
592 TRACE("%p, %u, %p.\n", iface, index, buffer);
594 EnterCriticalSection(&sample->attributes.cs);
595 if (index < sample->buffer_count)
597 *buffer = sample->buffers[index];
598 IMFMediaBuffer_AddRef(*buffer);
600 else
601 hr = E_INVALIDARG;
602 LeaveCriticalSection(&sample->attributes.cs);
604 return hr;
607 static unsigned int sample_get_total_length(struct sample *sample)
609 DWORD total_length = 0, length;
610 size_t i;
612 for (i = 0; i < sample->buffer_count; ++i)
614 length = 0;
615 if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length)))
616 total_length += length;
619 return total_length;
622 static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer)
624 DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
625 BYTE *src_ptr, *dst_ptr;
626 BOOL locked;
627 HRESULT hr;
628 size_t i;
630 total_length = sample_get_total_length(sample);
631 dst_current_length = 0;
633 dst_ptr = NULL;
634 dst_length = current_length = 0;
635 locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
636 if (locked)
638 if (dst_length < total_length)
639 hr = MF_E_BUFFERTOOSMALL;
640 else if (dst_ptr)
642 for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
644 src_ptr = NULL;
645 src_max_length = current_length = 0;
646 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
648 if (src_ptr)
650 if (current_length > dst_length)
651 hr = MF_E_BUFFERTOOSMALL;
652 else if (current_length)
654 memcpy(dst_ptr, src_ptr, current_length);
655 dst_length -= current_length;
656 dst_current_length += current_length;
657 dst_ptr += current_length;
660 IMFMediaBuffer_Unlock(sample->buffers[i]);
666 if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length)))
667 WARN("Failed to set buffer length.\n");
669 if (locked)
670 IMFMediaBuffer_Unlock(buffer);
672 return hr;
675 static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
677 struct sample *sample = impl_from_IMFSample(iface);
678 unsigned int total_length, i;
679 IMFMediaBuffer *dest_buffer;
680 HRESULT hr = S_OK;
682 TRACE("%p, %p.\n", iface, buffer);
684 EnterCriticalSection(&sample->attributes.cs);
686 if (sample->buffer_count == 0)
687 hr = E_UNEXPECTED;
688 else if (sample->buffer_count > 1)
690 total_length = sample_get_total_length(sample);
691 if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer)))
693 if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer)))
695 for (i = 0; i < sample->buffer_count; ++i)
696 IMFMediaBuffer_Release(sample->buffers[i]);
698 sample->buffers[0] = dest_buffer;
699 IMFMediaBuffer_AddRef(sample->buffers[0]);
701 sample->buffer_count = 1;
703 IMFMediaBuffer_Release(dest_buffer);
707 if (SUCCEEDED(hr) && buffer)
709 *buffer = sample->buffers[0];
710 IMFMediaBuffer_AddRef(*buffer);
713 LeaveCriticalSection(&sample->attributes.cs);
715 return hr;
718 static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
720 struct sample *sample = impl_from_IMFSample(iface);
721 HRESULT hr = S_OK;
723 TRACE("%p, %p.\n", iface, buffer);
725 EnterCriticalSection(&sample->attributes.cs);
726 if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1,
727 sizeof(*sample->buffers)))
728 hr = E_OUTOFMEMORY;
729 else
731 sample->buffers[sample->buffer_count++] = buffer;
732 IMFMediaBuffer_AddRef(buffer);
734 LeaveCriticalSection(&sample->attributes.cs);
736 return hr;
739 static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
741 struct sample *sample = impl_from_IMFSample(iface);
742 HRESULT hr = S_OK;
744 TRACE("%p, %u.\n", iface, index);
746 EnterCriticalSection(&sample->attributes.cs);
747 if (index < sample->buffer_count)
749 IMFMediaBuffer_Release(sample->buffers[index]);
750 if (index < sample->buffer_count - 1)
752 memmove(&sample->buffers[index], &sample->buffers[index+1],
753 (sample->buffer_count - index - 1) * sizeof(*sample->buffers));
755 sample->buffer_count--;
757 else
758 hr = E_INVALIDARG;
759 LeaveCriticalSection(&sample->attributes.cs);
761 return hr;
764 static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface)
766 struct sample *sample = impl_from_IMFSample(iface);
767 size_t i;
769 TRACE("%p.\n", iface);
771 EnterCriticalSection(&sample->attributes.cs);
772 for (i = 0; i < sample->buffer_count; ++i)
773 IMFMediaBuffer_Release(sample->buffers[i]);
774 sample->buffer_count = 0;
775 LeaveCriticalSection(&sample->attributes.cs);
777 return S_OK;
780 static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
782 struct sample *sample = impl_from_IMFSample(iface);
784 TRACE("%p, %p.\n", iface, total_length);
786 EnterCriticalSection(&sample->attributes.cs);
787 *total_length = sample_get_total_length(sample);
788 LeaveCriticalSection(&sample->attributes.cs);
790 return S_OK;
793 static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
795 struct sample *sample = impl_from_IMFSample(iface);
796 DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
797 BYTE *src_ptr, *dst_ptr;
798 BOOL locked;
799 HRESULT hr;
800 size_t i;
802 TRACE("%p, %p.\n", iface, buffer);
804 EnterCriticalSection(&sample->attributes.cs);
806 total_length = sample_get_total_length(sample);
807 dst_current_length = 0;
809 dst_ptr = NULL;
810 dst_length = current_length = 0;
811 locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
812 if (locked)
814 if (dst_length < total_length)
815 hr = MF_E_BUFFERTOOSMALL;
816 else if (dst_ptr)
818 for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
820 src_ptr = NULL;
821 src_max_length = current_length = 0;
822 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
824 if (src_ptr)
826 if (current_length > dst_length)
827 hr = MF_E_BUFFERTOOSMALL;
828 else if (current_length)
830 memcpy(dst_ptr, src_ptr, current_length);
831 dst_length -= current_length;
832 dst_current_length += current_length;
833 dst_ptr += current_length;
836 IMFMediaBuffer_Unlock(sample->buffers[i]);
842 IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
844 if (locked)
845 IMFMediaBuffer_Unlock(buffer);
847 LeaveCriticalSection(&sample->attributes.cs);
849 return hr;
852 static const IMFSampleVtbl samplevtbl =
854 sample_QueryInterface,
855 sample_AddRef,
856 sample_Release,
857 sample_GetItem,
858 sample_GetItemType,
859 sample_CompareItem,
860 sample_Compare,
861 sample_GetUINT32,
862 sample_GetUINT64,
863 sample_GetDouble,
864 sample_GetGUID,
865 sample_GetStringLength,
866 sample_GetString,
867 sample_GetAllocatedString,
868 sample_GetBlobSize,
869 sample_GetBlob,
870 sample_GetAllocatedBlob,
871 sample_GetUnknown,
872 sample_SetItem,
873 sample_DeleteItem,
874 sample_DeleteAllItems,
875 sample_SetUINT32,
876 sample_SetUINT64,
877 sample_SetDouble,
878 sample_SetGUID,
879 sample_SetString,
880 sample_SetBlob,
881 sample_SetUnknown,
882 sample_LockStore,
883 sample_UnlockStore,
884 sample_GetCount,
885 sample_GetItemByIndex,
886 sample_CopyAllItems,
887 sample_GetSampleFlags,
888 sample_SetSampleFlags,
889 sample_GetSampleTime,
890 sample_SetSampleTime,
891 sample_GetSampleDuration,
892 sample_SetSampleDuration,
893 sample_GetBufferCount,
894 sample_GetBufferByIndex,
895 sample_ConvertToContiguousBuffer,
896 sample_AddBuffer,
897 sample_RemoveBufferByIndex,
898 sample_RemoveAllBuffers,
899 sample_GetTotalLength,
900 sample_CopyToBuffer,
903 static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
905 struct sample *sample = impl_from_IMFTrackedSample(iface);
906 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
909 static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
911 struct sample *sample = impl_from_IMFTrackedSample(iface);
912 return IMFSample_AddRef(&sample->IMFSample_iface);
915 static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
917 struct sample *sample = impl_from_IMFTrackedSample(iface);
918 return IMFSample_Release(&sample->IMFSample_iface);
921 static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
922 IMFAsyncCallback *sample_allocator, IUnknown *state)
924 struct sample *sample = impl_from_IMFTrackedSample(iface);
925 HRESULT hr = S_OK;
927 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
929 EnterCriticalSection(&sample->attributes.cs);
931 if (sample->tracked_result)
932 hr = MF_E_NOTACCEPTING;
933 else
935 if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
936 state, &sample->tracked_result)))
938 /* Account for additional refcount brought by 'state' object. This threshold is used
939 on Release() to invoke tracker callback. */
940 sample->tracked_refcount = 1;
941 if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
942 state == (IUnknown *)&sample->IMFSample_iface)
944 ++sample->tracked_refcount;
949 LeaveCriticalSection(&sample->attributes.cs);
951 return hr;
954 static const IMFTrackedSampleVtbl tracked_sample_vtbl =
956 tracked_sample_QueryInterface,
957 tracked_sample_AddRef,
958 tracked_sample_Release,
959 tracked_sample_SetAllocator,
962 static const IMFSampleVtbl sample_tracked_vtbl =
964 sample_QueryInterface,
965 sample_AddRef,
966 sample_tracked_Release,
967 sample_GetItem,
968 sample_GetItemType,
969 sample_CompareItem,
970 sample_Compare,
971 sample_GetUINT32,
972 sample_GetUINT64,
973 sample_GetDouble,
974 sample_GetGUID,
975 sample_GetStringLength,
976 sample_GetString,
977 sample_GetAllocatedString,
978 sample_GetBlobSize,
979 sample_GetBlob,
980 sample_GetAllocatedBlob,
981 sample_GetUnknown,
982 sample_SetItem,
983 sample_DeleteItem,
984 sample_DeleteAllItems,
985 sample_SetUINT32,
986 sample_SetUINT64,
987 sample_SetDouble,
988 sample_SetGUID,
989 sample_SetString,
990 sample_SetBlob,
991 sample_SetUnknown,
992 sample_LockStore,
993 sample_UnlockStore,
994 sample_GetCount,
995 sample_GetItemByIndex,
996 sample_CopyAllItems,
997 sample_GetSampleFlags,
998 sample_SetSampleFlags,
999 sample_GetSampleTime,
1000 sample_SetSampleTime,
1001 sample_GetSampleDuration,
1002 sample_SetSampleDuration,
1003 sample_GetBufferCount,
1004 sample_GetBufferByIndex,
1005 sample_ConvertToContiguousBuffer,
1006 sample_AddBuffer,
1007 sample_RemoveBufferByIndex,
1008 sample_RemoveAllBuffers,
1009 sample_GetTotalLength,
1010 sample_CopyToBuffer,
1013 /***********************************************************************
1014 * MFCreateSample (mfplat.@)
1016 HRESULT WINAPI MFCreateSample(IMFSample **sample)
1018 struct sample *object;
1019 HRESULT hr;
1021 TRACE("%p.\n", sample);
1023 if (!(object = calloc(1, sizeof(*object))))
1024 return E_OUTOFMEMORY;
1026 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1028 free(object);
1029 return hr;
1032 object->IMFSample_iface.lpVtbl = &samplevtbl;
1034 *sample = &object->IMFSample_iface;
1036 TRACE("Created sample %p.\n", *sample);
1038 return S_OK;
1041 /***********************************************************************
1042 * MFCreateTrackedSample (mfplat.@)
1044 HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
1046 struct sample *object;
1047 HRESULT hr;
1049 TRACE("%p.\n", sample);
1051 if (!(object = calloc(1, sizeof(*object))))
1052 return E_OUTOFMEMORY;
1054 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1056 free(object);
1057 return hr;
1060 object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
1061 object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
1063 *sample = &object->IMFTrackedSample_iface;
1065 return S_OK;
1068 static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocatorEx *iface, REFIID riid, void **obj)
1070 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1072 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1074 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorEx) ||
1075 IsEqualIID(riid, &IID_IMFVideoSampleAllocator) ||
1076 IsEqualIID(riid, &IID_IUnknown))
1078 *obj = &allocator->IMFVideoSampleAllocatorEx_iface;
1080 else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback))
1082 *obj = &allocator->IMFVideoSampleAllocatorCallback_iface;
1084 else
1086 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1087 *obj = NULL;
1088 return E_NOINTERFACE;
1091 IUnknown_AddRef((IUnknown *)*obj);
1092 return S_OK;
1095 static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocatorEx *iface)
1097 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1098 ULONG refcount = InterlockedIncrement(&allocator->refcount);
1100 TRACE("%p, refcount %u.\n", iface, refcount);
1102 return refcount;
1105 static void sample_allocator_release_samples(struct sample_allocator *allocator)
1107 struct queued_sample *iter, *iter2;
1109 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry)
1111 list_remove(&iter->entry);
1112 IMFSample_Release(iter->sample);
1113 free(iter);
1116 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry)
1118 list_remove(&iter->entry);
1119 free(iter);
1122 allocator->free_sample_count = 0;
1123 allocator->cold_sample_count = 0;
1126 static void sample_allocator_set_media_type(struct sample_allocator *allocator, IMFMediaType *media_type)
1128 UINT64 frame_size;
1129 GUID subtype;
1131 if (!media_type)
1133 if (allocator->media_type)
1134 IMFMediaType_Release(allocator->media_type);
1135 allocator->media_type = NULL;
1136 return;
1139 /* Check if type is the same. */
1140 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size);
1141 IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1143 if (frame_size == ((UINT64) allocator->frame_desc.width << 32 | allocator->frame_desc.height) &&
1144 subtype.Data1 == allocator->frame_desc.d3d9_format)
1146 return;
1149 if (allocator->media_type)
1150 IMFMediaType_Release(allocator->media_type);
1151 allocator->media_type = media_type;
1152 if (allocator->media_type)
1153 IMFMediaType_AddRef(allocator->media_type);
1156 static void sample_allocator_set_attributes(struct sample_allocator *allocator, IMFAttributes *attributes)
1158 if (allocator->attributes)
1159 IMFAttributes_Release(allocator->attributes);
1160 allocator->attributes = attributes;
1161 if (allocator->attributes)
1162 IMFAttributes_AddRef(allocator->attributes);
1165 static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocatorEx *iface)
1167 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1168 ULONG refcount = InterlockedDecrement(&allocator->refcount);
1170 TRACE("%p, refcount %u.\n", iface, refcount);
1172 if (!refcount)
1174 if (allocator->callback)
1175 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1176 if (allocator->d3d9_device_manager)
1177 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1178 if (allocator->dxgi_device_manager)
1179 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1180 sample_allocator_set_media_type(allocator, NULL);
1181 sample_allocator_set_attributes(allocator, NULL);
1182 sample_allocator_release_samples(allocator);
1183 DeleteCriticalSection(&allocator->cs);
1184 free(allocator);
1187 return refcount;
1190 static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocatorEx *iface,
1191 IUnknown *manager)
1193 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1194 IDirect3DDeviceManager9 *d3d9_device_manager = NULL;
1195 IMFDXGIDeviceManager *dxgi_device_manager = NULL;
1196 HRESULT hr;
1198 TRACE("%p, %p.\n", iface, manager);
1200 if (manager)
1202 if (FAILED(hr = IUnknown_QueryInterface(manager, &IID_IMFDXGIDeviceManager, (void **)&dxgi_device_manager)))
1204 hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9, (void **)&d3d9_device_manager);
1207 if (FAILED(hr))
1208 return hr;
1211 EnterCriticalSection(&allocator->cs);
1213 if (allocator->d3d9_device_manager)
1214 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1215 if (allocator->dxgi_device_manager)
1216 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1217 allocator->d3d9_device_manager = NULL;
1218 allocator->dxgi_device_manager = NULL;
1220 if (dxgi_device_manager)
1221 allocator->dxgi_device_manager = dxgi_device_manager;
1222 else if (d3d9_device_manager)
1223 allocator->d3d9_device_manager = d3d9_device_manager;
1225 LeaveCriticalSection(&allocator->cs);
1227 return S_OK;
1230 static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface)
1232 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1234 TRACE("%p.\n", iface);
1236 EnterCriticalSection(&allocator->cs);
1238 sample_allocator_release_samples(allocator);
1239 sample_allocator_set_media_type(allocator, NULL);
1240 sample_allocator_set_attributes(allocator, NULL);
1241 memset(&allocator->frame_desc, 0, sizeof(allocator->frame_desc));
1243 LeaveCriticalSection(&allocator->cs);
1245 return S_OK;
1248 struct surface_service
1250 IDirectXVideoProcessorService *dxva_service;
1251 ID3D11Device *d3d11_device;
1252 HANDLE hdevice;
1255 static HRESULT sample_allocator_get_surface_service(struct sample_allocator *allocator, struct surface_service *service)
1257 HRESULT hr = S_OK;
1259 memset(service, 0, sizeof(*service));
1261 if (allocator->d3d9_device_manager)
1263 if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->d3d9_device_manager, &service->hdevice)))
1265 if (FAILED(hr = IDirect3DDeviceManager9_GetVideoService(allocator->d3d9_device_manager, service->hdevice,
1266 &IID_IDirectXVideoProcessorService, (void **)&service->dxva_service)))
1268 WARN("Failed to get DXVA processor service, hr %#x.\n", hr);
1269 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1273 else if (allocator->dxgi_device_manager)
1275 if (SUCCEEDED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(allocator->dxgi_device_manager, &service->hdevice)))
1277 if (FAILED(hr = IMFDXGIDeviceManager_GetVideoService(allocator->dxgi_device_manager, service->hdevice,
1278 &IID_ID3D11Device, (void **)&service->d3d11_device)))
1280 WARN("Failed to get D3D11 device, hr %#x.\n", hr);
1281 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1286 if (FAILED(hr))
1287 memset(service, 0, sizeof(*service));
1289 return hr;
1292 static void sample_allocator_release_surface_service(struct sample_allocator *allocator,
1293 struct surface_service *service)
1295 if (service->dxva_service)
1296 IDirectXVideoProcessorService_Release(service->dxva_service);
1297 if (service->d3d11_device)
1298 ID3D11Device_Release(service->d3d11_device);
1300 if (allocator->d3d9_device_manager)
1301 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1302 else if (allocator->dxgi_device_manager)
1303 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1306 static HRESULT sample_allocator_allocate_sample(struct sample_allocator *allocator, const struct surface_service *service,
1307 IMFSample **sample)
1309 struct queued_sample *queued_sample = malloc(sizeof(*queued_sample));
1310 IMFTrackedSample *tracked_sample;
1311 IMFMediaBuffer *buffer;
1312 unsigned int i;
1313 HRESULT hr;
1315 if (FAILED(hr = MFCreateTrackedSample(&tracked_sample)))
1317 return hr;
1320 IMFTrackedSample_QueryInterface(tracked_sample, &IID_IMFSample, (void **)sample);
1321 IMFTrackedSample_Release(tracked_sample);
1323 for (i = 0; i < allocator->frame_desc.buffer_count; ++i)
1325 if (service->dxva_service)
1327 IDirect3DSurface9 *surface;
1329 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service->dxva_service, allocator->frame_desc.width,
1330 allocator->frame_desc.height, 0, allocator->frame_desc.d3d9_format, D3DPOOL_DEFAULT, 0,
1331 DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
1333 hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer);
1334 IDirect3DSurface9_Release(surface);
1337 else if (service->d3d11_device)
1339 D3D11_TEXTURE2D_DESC desc = { 0 };
1340 ID3D11Texture2D *texture;
1342 desc.Width = allocator->frame_desc.width;
1343 desc.Height = allocator->frame_desc.height;
1344 desc.MipLevels = 1;
1345 desc.ArraySize = 1;
1346 desc.Format = allocator->frame_desc.dxgi_format;
1347 desc.SampleDesc.Count = 1;
1348 desc.SampleDesc.Quality = 0;
1349 desc.Usage = allocator->frame_desc.usage;
1350 desc.BindFlags = allocator->frame_desc.bindflags;
1351 if (desc.Usage == D3D11_USAGE_DYNAMIC)
1352 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1353 else if (desc.Usage == D3D11_USAGE_STAGING)
1354 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
1356 if (SUCCEEDED(hr = ID3D11Device_CreateTexture2D(service->d3d11_device, &desc, NULL, &texture)))
1358 hr = MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer);
1359 ID3D11Texture2D_Release(texture);
1362 else
1364 hr = MFCreate2DMediaBuffer(allocator->frame_desc.width, allocator->frame_desc.height,
1365 allocator->frame_desc.d3d9_format, FALSE, &buffer);
1368 if (SUCCEEDED(hr))
1370 hr = IMFSample_AddBuffer(*sample, buffer);
1371 IMFMediaBuffer_Release(buffer);
1375 return hr;
1378 static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, unsigned int sample_count,
1379 unsigned int max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1381 struct surface_service service;
1382 DXGI_FORMAT dxgi_format;
1383 unsigned int i;
1384 GUID major, subtype;
1385 UINT64 frame_size;
1386 IMFSample *sample;
1387 D3D11_USAGE usage;
1388 HRESULT hr;
1390 if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major)))
1391 return hr;
1393 if (!IsEqualGUID(&major, &MFMediaType_Video))
1394 return MF_E_INVALIDMEDIATYPE;
1396 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
1397 return hr;
1399 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
1400 return hr;
1402 if (sample_count > max_sample_count)
1403 return E_INVALIDARG;
1405 usage = D3D11_USAGE_DEFAULT;
1406 if (attributes)
1408 IMFAttributes_GetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, &allocator->frame_desc.buffer_count);
1409 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_USAGE, &usage);
1412 if (usage == D3D11_USAGE_IMMUTABLE || usage > D3D11_USAGE_STAGING)
1413 return E_INVALIDARG;
1415 dxgi_format = MFMapDX9FormatToDXGIFormat(subtype.Data1);
1417 allocator->frame_desc.bindflags = 0;
1418 allocator->frame_desc.usage = D3D11_USAGE_DEFAULT;
1420 if (dxgi_format == DXGI_FORMAT_B8G8R8A8_UNORM ||
1421 dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM)
1423 allocator->frame_desc.usage = usage;
1424 if (allocator->frame_desc.usage == D3D11_USAGE_DEFAULT)
1425 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
1426 else if (allocator->frame_desc.usage == D3D11_USAGE_DYNAMIC)
1427 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE;
1430 if (attributes)
1431 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &allocator->frame_desc.bindflags);
1433 sample_allocator_set_media_type(allocator, media_type);
1434 sample_allocator_set_attributes(allocator, attributes);
1436 sample_count = max(1, sample_count);
1437 max_sample_count = max(1, max_sample_count);
1439 allocator->frame_desc.d3d9_format = subtype.Data1;
1440 allocator->frame_desc.dxgi_format = dxgi_format;
1441 allocator->frame_desc.width = frame_size >> 32;
1442 allocator->frame_desc.height = frame_size;
1443 allocator->frame_desc.buffer_count = max(1, allocator->frame_desc.buffer_count);
1445 if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service)))
1446 return hr;
1448 sample_allocator_release_samples(allocator);
1450 for (i = 0; i < sample_count; ++i)
1452 struct queued_sample *queued_sample;
1454 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1456 queued_sample = malloc(sizeof(*queued_sample));
1457 queued_sample->sample = sample;
1458 list_add_tail(&allocator->free_samples, &queued_sample->entry);
1459 allocator->free_sample_count++;
1462 allocator->cold_sample_count = max_sample_count - allocator->free_sample_count;
1464 sample_allocator_release_surface_service(allocator, &service);
1466 return hr;
1469 static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface,
1470 DWORD sample_count, IMFMediaType *media_type)
1472 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1473 HRESULT hr;
1475 TRACE("%p, %u, %p.\n", iface, sample_count, media_type);
1477 if (!sample_count)
1478 return E_INVALIDARG;
1480 EnterCriticalSection(&allocator->cs);
1482 hr = sample_allocator_initialize(allocator, sample_count, sample_count, NULL, media_type);
1484 LeaveCriticalSection(&allocator->cs);
1486 return hr;
1489 static HRESULT sample_allocator_track_sample(struct sample_allocator *allocator, IMFSample *sample)
1491 IMFTrackedSample *tracked_sample;
1492 HRESULT hr;
1494 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
1496 hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
1497 IMFTrackedSample_Release(tracked_sample);
1500 return hr;
1503 static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx *iface, IMFSample **out)
1505 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1506 IMFSample *sample;
1507 HRESULT hr;
1509 TRACE("%p, %p.\n", iface, out);
1511 EnterCriticalSection(&allocator->cs);
1513 if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples))
1514 hr = MF_E_NOT_INITIALIZED;
1515 else if (list_empty(&allocator->free_samples) && !allocator->cold_sample_count)
1516 hr = MF_E_SAMPLEALLOCATOR_EMPTY;
1517 else if (!list_empty(&allocator->free_samples))
1519 struct list *head = list_head(&allocator->free_samples);
1521 sample = LIST_ENTRY(head, struct queued_sample, entry)->sample;
1523 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample)))
1525 list_remove(head);
1526 list_add_tail(&allocator->used_samples, head);
1527 allocator->free_sample_count--;
1529 /* Reference counter is not increased when sample is returned, so next release could trigger
1530 tracking condition. This is balanced by incremented reference counter when sample is returned
1531 back to the free list. */
1532 *out = sample;
1535 else /* allocator->cold_sample_count != 0 */
1537 struct surface_service service;
1539 if (SUCCEEDED(hr = sample_allocator_get_surface_service(allocator, &service)))
1541 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1543 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample)))
1545 struct queued_sample *queued_sample = malloc(sizeof(*queued_sample));
1547 queued_sample->sample = sample;
1548 list_add_tail(&allocator->used_samples, &queued_sample->entry);
1549 allocator->cold_sample_count--;
1551 *out = queued_sample->sample;
1555 sample_allocator_release_surface_service(allocator, &service);
1559 LeaveCriticalSection(&allocator->cs);
1561 return hr;
1564 static HRESULT WINAPI sample_allocator_InitializeSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface, DWORD initial_sample_count,
1565 DWORD max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1567 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1568 HRESULT hr;
1570 TRACE("%p, %u, %u, %p, %p.\n", iface, initial_sample_count, max_sample_count, attributes, media_type);
1572 EnterCriticalSection(&allocator->cs);
1574 hr = sample_allocator_initialize(allocator, initial_sample_count, max_sample_count, attributes, media_type);
1576 LeaveCriticalSection(&allocator->cs);
1578 return hr;
1581 static const IMFVideoSampleAllocatorExVtbl sample_allocator_vtbl =
1583 sample_allocator_QueryInterface,
1584 sample_allocator_AddRef,
1585 sample_allocator_Release,
1586 sample_allocator_SetDirectXManager,
1587 sample_allocator_UninitializeSampleAllocator,
1588 sample_allocator_InitializeSampleAllocator,
1589 sample_allocator_AllocateSample,
1590 sample_allocator_InitializeSampleAllocatorEx,
1593 static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface,
1594 REFIID riid, void **obj)
1596 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1597 return IMFVideoSampleAllocatorEx_QueryInterface(&allocator->IMFVideoSampleAllocatorEx_iface, riid, obj);
1600 static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface)
1602 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1603 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1606 static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface)
1608 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1609 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1612 static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface,
1613 IMFVideoSampleAllocatorNotify *callback)
1615 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1617 TRACE("%p, %p.\n", iface, callback);
1619 EnterCriticalSection(&allocator->cs);
1620 if (allocator->callback)
1621 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1622 allocator->callback = callback;
1623 if (allocator->callback)
1624 IMFVideoSampleAllocatorNotify_AddRef(allocator->callback);
1625 LeaveCriticalSection(&allocator->cs);
1627 return S_OK;
1630 static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface,
1631 LONG *count)
1633 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1635 TRACE("%p, %p.\n", iface, count);
1637 if (!count)
1638 return E_POINTER;
1640 EnterCriticalSection(&allocator->cs);
1641 *count = allocator->free_sample_count;
1642 LeaveCriticalSection(&allocator->cs);
1644 return S_OK;
1647 static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl =
1649 sample_allocator_callback_QueryInterface,
1650 sample_allocator_callback_AddRef,
1651 sample_allocator_callback_Release,
1652 sample_allocator_callback_SetCallback,
1653 sample_allocator_callback_GetFreeSampleCount,
1656 static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface,
1657 REFIID riid, void **obj)
1659 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1660 IsEqualIID(riid, &IID_IUnknown))
1662 *obj = iface;
1663 IMFAsyncCallback_AddRef(iface);
1664 return S_OK;
1667 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1668 *obj = NULL;
1669 return E_NOINTERFACE;
1672 static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface)
1674 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1675 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1678 static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
1680 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1681 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1684 static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface,
1685 DWORD *flags, DWORD *queue)
1687 return E_NOTIMPL;
1690 static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1692 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1693 struct queued_sample *iter;
1694 IUnknown *object = NULL;
1695 IMFSample *sample = NULL;
1696 HRESULT hr;
1698 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
1699 return E_UNEXPECTED;
1701 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
1702 IUnknown_Release(object);
1703 if (FAILED(hr))
1704 return E_UNEXPECTED;
1706 EnterCriticalSection(&allocator->cs);
1708 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
1710 if (sample == iter->sample)
1712 list_remove(&iter->entry);
1713 list_add_tail(&allocator->free_samples, &iter->entry);
1714 IMFSample_AddRef(iter->sample);
1715 allocator->free_sample_count++;
1716 break;
1720 IMFSample_Release(sample);
1722 if (allocator->callback)
1723 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
1725 LeaveCriticalSection(&allocator->cs);
1727 return S_OK;
1730 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
1732 sample_allocator_tracking_callback_QueryInterface,
1733 sample_allocator_tracking_callback_AddRef,
1734 sample_allocator_tracking_callback_Release,
1735 sample_allocator_tracking_callback_GetParameters,
1736 sample_allocator_tracking_callback_Invoke,
1739 /***********************************************************************
1740 * MFCreateVideoSampleAllocatorEx (mfplat.@)
1742 HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj)
1744 struct sample_allocator *object;
1745 HRESULT hr;
1747 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1749 if (!(object = calloc(1, sizeof(*object))))
1750 return E_OUTOFMEMORY;
1752 object->IMFVideoSampleAllocatorEx_iface.lpVtbl = &sample_allocator_vtbl;
1753 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
1754 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
1755 object->refcount = 1;
1756 list_init(&object->used_samples);
1757 list_init(&object->free_samples);
1758 InitializeCriticalSection(&object->cs);
1760 hr = IMFVideoSampleAllocatorEx_QueryInterface(&object->IMFVideoSampleAllocatorEx_iface, riid, obj);
1761 IMFVideoSampleAllocatorEx_Release(&object->IMFVideoSampleAllocatorEx_iface);
1763 return hr;