kernel32/tests/pipe: Enable compilation with long types.
[wine.git] / dlls / mfplat / sample.c
blob8ef80eb5f246a52c0d11f8633e1eb837daf56a99
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/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
32 enum sample_prop_flags
34 SAMPLE_PROP_HAS_DURATION = 1 << 0,
35 SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
38 struct sample
40 struct attributes attributes;
41 IMFSample IMFSample_iface;
42 IMFTrackedSample IMFTrackedSample_iface;
44 IMFMediaBuffer **buffers;
45 size_t buffer_count;
46 size_t capacity;
47 DWORD flags;
48 DWORD prop_flags;
49 LONGLONG duration;
50 LONGLONG timestamp;
52 /* Tracked sample functionality. */
53 IRtwqAsyncResult *tracked_result;
54 LONG tracked_refcount;
57 struct sample_allocator
59 IMFVideoSampleAllocatorEx IMFVideoSampleAllocatorEx_iface;
60 IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface;
61 IMFAsyncCallback tracking_callback;
62 LONG refcount;
64 IMFVideoSampleAllocatorNotify *callback;
65 IDirect3DDeviceManager9 *d3d9_device_manager;
66 IMFDXGIDeviceManager *dxgi_device_manager;
68 struct
70 unsigned int width;
71 unsigned int height;
72 D3DFORMAT d3d9_format;
73 DXGI_FORMAT dxgi_format;
74 unsigned int usage;
75 unsigned int bindflags;
76 unsigned int miscflags;
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 %lu.\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 %lu.\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 %#lx.\n", hr);
198 IRtwqAsyncResult_Release(tracked_result);
200 LeaveCriticalSection(&sample->attributes.cs);
202 refcount = InterlockedDecrement(&sample->attributes.ref);
204 TRACE("%p, refcount %lu.\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, %#lx.\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, %lu, %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, %lu.\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 %lu.\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 %lu.\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 %#lx.\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 %#lx.\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 struct queued_sample **queued_sample)
1309 IMFTrackedSample *tracked_sample;
1310 IMFMediaBuffer *buffer;
1311 IMFSample *sample;
1312 unsigned int i;
1313 HRESULT hr;
1315 if (FAILED(hr = MFCreateTrackedSample(&tracked_sample)))
1316 return hr;
1318 IMFTrackedSample_QueryInterface(tracked_sample, &IID_IMFSample, (void **)&sample);
1319 IMFTrackedSample_Release(tracked_sample);
1321 for (i = 0; i < allocator->frame_desc.buffer_count; ++i)
1323 if (service->dxva_service)
1325 IDirect3DSurface9 *surface;
1327 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service->dxva_service, allocator->frame_desc.width,
1328 allocator->frame_desc.height, 0, allocator->frame_desc.d3d9_format, D3DPOOL_DEFAULT, 0,
1329 DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
1331 hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer);
1332 IDirect3DSurface9_Release(surface);
1335 else if (service->d3d11_device)
1337 D3D11_TEXTURE2D_DESC desc = { 0 };
1338 ID3D11Texture2D *texture;
1340 desc.Width = allocator->frame_desc.width;
1341 desc.Height = allocator->frame_desc.height;
1342 desc.MipLevels = 1;
1343 desc.ArraySize = 1;
1344 desc.Format = allocator->frame_desc.dxgi_format;
1345 desc.SampleDesc.Count = 1;
1346 desc.SampleDesc.Quality = 0;
1347 desc.Usage = allocator->frame_desc.usage;
1348 desc.BindFlags = allocator->frame_desc.bindflags;
1349 if (desc.Usage == D3D11_USAGE_DYNAMIC)
1350 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1351 else if (desc.Usage == D3D11_USAGE_STAGING)
1352 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
1353 desc.MiscFlags = allocator->frame_desc.miscflags;
1355 if (SUCCEEDED(hr = ID3D11Device_CreateTexture2D(service->d3d11_device, &desc, NULL, &texture)))
1357 hr = MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer);
1358 ID3D11Texture2D_Release(texture);
1361 else
1363 hr = MFCreate2DMediaBuffer(allocator->frame_desc.width, allocator->frame_desc.height,
1364 allocator->frame_desc.d3d9_format, FALSE, &buffer);
1367 if (SUCCEEDED(hr))
1369 hr = IMFSample_AddBuffer(sample, buffer);
1370 IMFMediaBuffer_Release(buffer);
1374 if (FAILED(hr))
1376 IMFSample_Release(sample);
1377 return hr;
1380 if (!(*queued_sample = malloc(sizeof(**queued_sample))))
1382 IMFSample_Release(sample);
1383 return E_OUTOFMEMORY;
1385 (*queued_sample)->sample = sample;
1387 return hr;
1390 static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, unsigned int sample_count,
1391 unsigned int max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1393 struct surface_service service;
1394 struct queued_sample *sample;
1395 DXGI_FORMAT dxgi_format;
1396 unsigned int i, value;
1397 GUID major, subtype;
1398 UINT64 frame_size;
1399 D3D11_USAGE usage;
1400 HRESULT hr;
1402 if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major)))
1403 return hr;
1405 if (!IsEqualGUID(&major, &MFMediaType_Video))
1406 return MF_E_INVALIDMEDIATYPE;
1408 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
1409 return hr;
1411 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
1412 return hr;
1414 if (sample_count > max_sample_count)
1415 return E_INVALIDARG;
1417 usage = D3D11_USAGE_DEFAULT;
1418 if (attributes)
1420 IMFAttributes_GetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, &allocator->frame_desc.buffer_count);
1421 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_USAGE, &usage);
1424 if (usage == D3D11_USAGE_IMMUTABLE || usage > D3D11_USAGE_STAGING)
1425 return E_INVALIDARG;
1427 dxgi_format = MFMapDX9FormatToDXGIFormat(subtype.Data1);
1429 allocator->frame_desc.bindflags = 0;
1430 allocator->frame_desc.miscflags = 0;
1431 allocator->frame_desc.usage = D3D11_USAGE_DEFAULT;
1433 if (dxgi_format == DXGI_FORMAT_B8G8R8A8_UNORM ||
1434 dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM)
1436 allocator->frame_desc.usage = usage;
1437 if (allocator->frame_desc.usage == D3D11_USAGE_DEFAULT)
1438 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
1439 else if (allocator->frame_desc.usage == D3D11_USAGE_DYNAMIC)
1440 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE;
1443 if (attributes)
1445 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &allocator->frame_desc.bindflags);
1446 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_SHARED, &value)) && value)
1447 allocator->frame_desc.miscflags |= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
1448 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &value)) && value)
1449 allocator->frame_desc.miscflags |= D3D11_RESOURCE_MISC_SHARED;
1452 sample_allocator_set_media_type(allocator, media_type);
1453 sample_allocator_set_attributes(allocator, attributes);
1455 sample_count = max(1, sample_count);
1456 max_sample_count = max(1, max_sample_count);
1458 allocator->frame_desc.d3d9_format = subtype.Data1;
1459 allocator->frame_desc.dxgi_format = dxgi_format;
1460 allocator->frame_desc.width = frame_size >> 32;
1461 allocator->frame_desc.height = frame_size;
1462 allocator->frame_desc.buffer_count = max(1, allocator->frame_desc.buffer_count);
1464 if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service)))
1465 return hr;
1467 sample_allocator_release_samples(allocator);
1469 for (i = 0; i < sample_count; ++i)
1471 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1473 list_add_tail(&allocator->free_samples, &sample->entry);
1474 allocator->free_sample_count++;
1477 allocator->cold_sample_count = max_sample_count - allocator->free_sample_count;
1479 sample_allocator_release_surface_service(allocator, &service);
1481 return hr;
1484 static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface,
1485 DWORD sample_count, IMFMediaType *media_type)
1487 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1488 HRESULT hr;
1490 TRACE("%p, %lu, %p.\n", iface, sample_count, media_type);
1492 if (!sample_count)
1493 return E_INVALIDARG;
1495 EnterCriticalSection(&allocator->cs);
1497 hr = sample_allocator_initialize(allocator, sample_count, sample_count, NULL, media_type);
1499 LeaveCriticalSection(&allocator->cs);
1501 return hr;
1504 static HRESULT sample_allocator_track_sample(struct sample_allocator *allocator, IMFSample *sample)
1506 IMFTrackedSample *tracked_sample;
1507 HRESULT hr;
1509 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
1511 hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
1512 IMFTrackedSample_Release(tracked_sample);
1515 return hr;
1518 static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx *iface, IMFSample **out)
1520 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1521 struct queued_sample *sample;
1522 HRESULT hr;
1524 TRACE("%p, %p.\n", iface, out);
1526 EnterCriticalSection(&allocator->cs);
1528 if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples))
1529 hr = MF_E_NOT_INITIALIZED;
1530 else if (list_empty(&allocator->free_samples) && !allocator->cold_sample_count)
1531 hr = MF_E_SAMPLEALLOCATOR_EMPTY;
1532 else if (!list_empty(&allocator->free_samples))
1534 struct list *head = list_head(&allocator->free_samples);
1536 sample = LIST_ENTRY(head, struct queued_sample, entry);
1538 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample->sample)))
1540 list_remove(head);
1541 list_add_tail(&allocator->used_samples, head);
1542 allocator->free_sample_count--;
1544 /* Reference counter is not increased when sample is returned, so next release could trigger
1545 tracking condition. This is balanced by incremented reference counter when sample is returned
1546 back to the free list. */
1547 *out = sample->sample;
1550 else /* allocator->cold_sample_count != 0 */
1552 struct surface_service service;
1554 if (SUCCEEDED(hr = sample_allocator_get_surface_service(allocator, &service)))
1556 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1558 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample->sample)))
1560 list_add_tail(&allocator->used_samples, &sample->entry);
1561 allocator->cold_sample_count--;
1563 *out = sample->sample;
1565 else
1567 IMFSample_Release(sample->sample);
1568 free(sample);
1572 sample_allocator_release_surface_service(allocator, &service);
1576 LeaveCriticalSection(&allocator->cs);
1578 return hr;
1581 static HRESULT WINAPI sample_allocator_InitializeSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface, DWORD initial_sample_count,
1582 DWORD max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1584 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1585 HRESULT hr;
1587 TRACE("%p, %lu, %lu, %p, %p.\n", iface, initial_sample_count, max_sample_count, attributes, media_type);
1589 EnterCriticalSection(&allocator->cs);
1591 hr = sample_allocator_initialize(allocator, initial_sample_count, max_sample_count, attributes, media_type);
1593 LeaveCriticalSection(&allocator->cs);
1595 return hr;
1598 static const IMFVideoSampleAllocatorExVtbl sample_allocator_vtbl =
1600 sample_allocator_QueryInterface,
1601 sample_allocator_AddRef,
1602 sample_allocator_Release,
1603 sample_allocator_SetDirectXManager,
1604 sample_allocator_UninitializeSampleAllocator,
1605 sample_allocator_InitializeSampleAllocator,
1606 sample_allocator_AllocateSample,
1607 sample_allocator_InitializeSampleAllocatorEx,
1610 static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface,
1611 REFIID riid, void **obj)
1613 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1614 return IMFVideoSampleAllocatorEx_QueryInterface(&allocator->IMFVideoSampleAllocatorEx_iface, riid, obj);
1617 static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface)
1619 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1620 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1623 static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface)
1625 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1626 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1629 static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface,
1630 IMFVideoSampleAllocatorNotify *callback)
1632 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1634 TRACE("%p, %p.\n", iface, callback);
1636 EnterCriticalSection(&allocator->cs);
1637 if (allocator->callback)
1638 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1639 allocator->callback = callback;
1640 if (allocator->callback)
1641 IMFVideoSampleAllocatorNotify_AddRef(allocator->callback);
1642 LeaveCriticalSection(&allocator->cs);
1644 return S_OK;
1647 static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface,
1648 LONG *count)
1650 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1652 TRACE("%p, %p.\n", iface, count);
1654 if (!count)
1655 return E_POINTER;
1657 EnterCriticalSection(&allocator->cs);
1658 *count = allocator->free_sample_count;
1659 LeaveCriticalSection(&allocator->cs);
1661 return S_OK;
1664 static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl =
1666 sample_allocator_callback_QueryInterface,
1667 sample_allocator_callback_AddRef,
1668 sample_allocator_callback_Release,
1669 sample_allocator_callback_SetCallback,
1670 sample_allocator_callback_GetFreeSampleCount,
1673 static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface,
1674 REFIID riid, void **obj)
1676 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1677 IsEqualIID(riid, &IID_IUnknown))
1679 *obj = iface;
1680 IMFAsyncCallback_AddRef(iface);
1681 return S_OK;
1684 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1685 *obj = NULL;
1686 return E_NOINTERFACE;
1689 static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface)
1691 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1692 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1695 static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
1697 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1698 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1701 static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface,
1702 DWORD *flags, DWORD *queue)
1704 return E_NOTIMPL;
1707 static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1709 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1710 struct queued_sample *iter;
1711 IUnknown *object = NULL;
1712 IMFSample *sample = NULL;
1713 HRESULT hr;
1715 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
1716 return E_UNEXPECTED;
1718 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
1719 IUnknown_Release(object);
1720 if (FAILED(hr))
1721 return E_UNEXPECTED;
1723 EnterCriticalSection(&allocator->cs);
1725 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
1727 if (sample == iter->sample)
1729 list_remove(&iter->entry);
1730 list_add_tail(&allocator->free_samples, &iter->entry);
1731 IMFSample_AddRef(iter->sample);
1732 allocator->free_sample_count++;
1733 break;
1737 IMFSample_Release(sample);
1739 if (allocator->callback)
1740 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
1742 LeaveCriticalSection(&allocator->cs);
1744 return S_OK;
1747 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
1749 sample_allocator_tracking_callback_QueryInterface,
1750 sample_allocator_tracking_callback_AddRef,
1751 sample_allocator_tracking_callback_Release,
1752 sample_allocator_tracking_callback_GetParameters,
1753 sample_allocator_tracking_callback_Invoke,
1756 /***********************************************************************
1757 * MFCreateVideoSampleAllocatorEx (mfplat.@)
1759 HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj)
1761 struct sample_allocator *object;
1762 HRESULT hr;
1764 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1766 if (!(object = calloc(1, sizeof(*object))))
1767 return E_OUTOFMEMORY;
1769 object->IMFVideoSampleAllocatorEx_iface.lpVtbl = &sample_allocator_vtbl;
1770 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
1771 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
1772 object->refcount = 1;
1773 list_init(&object->used_samples);
1774 list_init(&object->free_samples);
1775 InitializeCriticalSection(&object->cs);
1777 hr = IMFVideoSampleAllocatorEx_QueryInterface(&object->IMFVideoSampleAllocatorEx_iface, riid, obj);
1778 IMFVideoSampleAllocatorEx_Release(&object->IMFVideoSampleAllocatorEx_iface);
1780 return hr;