comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / mfplat / sample.c
blob687ada1a4775ac108ad59449552b1ac1864f1b01
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 = InterlockedDecrement(&sample->attributes.ref);
186 IRtwqAsyncResult *tracked_result = NULL;
187 HRESULT hr;
189 EnterCriticalSection(&sample->attributes.cs);
190 if (sample->tracked_result && sample->tracked_refcount == refcount)
192 tracked_result = sample->tracked_result;
193 sample->tracked_result = NULL;
194 sample->tracked_refcount = 0;
196 /* Call could fail if queue system is not initialized, it's not critical. */
197 if (FAILED(hr = RtwqInvokeCallback(tracked_result)))
198 WARN("Failed to invoke tracking callback, hr %#lx.\n", hr);
200 LeaveCriticalSection(&sample->attributes.cs);
202 if (tracked_result)
203 IRtwqAsyncResult_Release(tracked_result);
205 TRACE("%p, refcount %lu.\n", iface, refcount);
207 if (!refcount)
208 release_sample_object(sample);
210 return refcount;
213 static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
215 struct sample *sample = impl_from_IMFSample(iface);
217 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
219 return attributes_GetItem(&sample->attributes, key, value);
222 static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
224 struct sample *sample = impl_from_IMFSample(iface);
226 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
228 return attributes_GetItemType(&sample->attributes, key, type);
231 static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
233 struct sample *sample = impl_from_IMFSample(iface);
235 TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result);
237 return attributes_CompareItem(&sample->attributes, key, value, result);
240 static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
241 BOOL *result)
243 struct sample *sample = impl_from_IMFSample(iface);
245 TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
247 return attributes_Compare(&sample->attributes, theirs, type, result);
250 static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
252 struct sample *sample = impl_from_IMFSample(iface);
254 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
256 return attributes_GetUINT32(&sample->attributes, key, value);
259 static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
261 struct sample *sample = impl_from_IMFSample(iface);
263 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
265 return attributes_GetUINT64(&sample->attributes, key, value);
268 static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
270 struct sample *sample = impl_from_IMFSample(iface);
272 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
274 return attributes_GetDouble(&sample->attributes, key, value);
277 static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
279 struct sample *sample = impl_from_IMFSample(iface);
281 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
283 return attributes_GetGUID(&sample->attributes, key, value);
286 static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
288 struct sample *sample = impl_from_IMFSample(iface);
290 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
292 return attributes_GetStringLength(&sample->attributes, key, length);
295 static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
297 struct sample *sample = impl_from_IMFSample(iface);
299 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
301 return attributes_GetString(&sample->attributes, key, value, size, length);
304 static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
306 struct sample *sample = impl_from_IMFSample(iface);
308 TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
310 return attributes_GetAllocatedString(&sample->attributes, key, value, length);
313 static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
315 struct sample *sample = impl_from_IMFSample(iface);
317 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
319 return attributes_GetBlobSize(&sample->attributes, key, size);
322 static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
324 struct sample *sample = impl_from_IMFSample(iface);
326 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
328 return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize);
331 static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
333 struct sample *sample = impl_from_IMFSample(iface);
335 TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
337 return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size);
340 static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
342 struct sample *sample = impl_from_IMFSample(iface);
344 TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
346 return attributes_GetUnknown(&sample->attributes, key, riid, out);
349 static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
351 struct sample *sample = impl_from_IMFSample(iface);
353 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value));
355 return attributes_SetItem(&sample->attributes, key, value);
358 static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key)
360 struct sample *sample = impl_from_IMFSample(iface);
362 TRACE("%p, %s.\n", iface, debugstr_attr(key));
364 return attributes_DeleteItem(&sample->attributes, key);
367 static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface)
369 struct sample *sample = impl_from_IMFSample(iface);
371 TRACE("%p.\n", iface);
373 return attributes_DeleteAllItems(&sample->attributes);
376 static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
378 struct sample *sample = impl_from_IMFSample(iface);
380 TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
382 return attributes_SetUINT32(&sample->attributes, key, value);
385 static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
387 struct sample *sample = impl_from_IMFSample(iface);
389 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
391 return attributes_SetUINT64(&sample->attributes, key, value);
394 static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value)
396 struct sample *sample = impl_from_IMFSample(iface);
398 TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
400 return attributes_SetDouble(&sample->attributes, key, value);
403 static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
405 struct sample *sample = impl_from_IMFSample(iface);
407 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
409 return attributes_SetGUID(&sample->attributes, key, value);
412 static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
414 struct sample *sample = impl_from_IMFSample(iface);
416 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
418 return attributes_SetString(&sample->attributes, key, value);
421 static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
423 struct sample *sample = impl_from_IMFSample(iface);
425 TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
427 return attributes_SetBlob(&sample->attributes, key, buf, size);
430 static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
432 struct sample *sample = impl_from_IMFSample(iface);
434 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
436 return attributes_SetUnknown(&sample->attributes, key, unknown);
439 static HRESULT WINAPI sample_LockStore(IMFSample *iface)
441 struct sample *sample = impl_from_IMFSample(iface);
443 TRACE("%p.\n", iface);
445 return attributes_LockStore(&sample->attributes);
448 static HRESULT WINAPI sample_UnlockStore(IMFSample *iface)
450 struct sample *sample = impl_from_IMFSample(iface);
452 TRACE("%p.\n", iface);
454 return attributes_UnlockStore(&sample->attributes);
457 static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count)
459 struct sample *sample = impl_from_IMFSample(iface);
461 TRACE("%p, %p.\n", iface, count);
463 return attributes_GetCount(&sample->attributes, count);
466 static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
468 struct sample *sample = impl_from_IMFSample(iface);
470 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
472 return attributes_GetItemByIndex(&sample->attributes, index, key, value);
475 static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
477 struct sample *sample = impl_from_IMFSample(iface);
479 TRACE("%p, %p.\n", iface, dest);
481 return attributes_CopyAllItems(&sample->attributes, dest);
484 static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
486 struct sample *sample = impl_from_IMFSample(iface);
488 TRACE("%p, %p.\n", iface, flags);
490 EnterCriticalSection(&sample->attributes.cs);
491 *flags = sample->flags;
492 LeaveCriticalSection(&sample->attributes.cs);
494 return S_OK;
497 static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags)
499 struct sample *sample = impl_from_IMFSample(iface);
501 TRACE("%p, %#lx.\n", iface, flags);
503 EnterCriticalSection(&sample->attributes.cs);
504 sample->flags = flags;
505 LeaveCriticalSection(&sample->attributes.cs);
507 return S_OK;
510 static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
512 struct sample *sample = impl_from_IMFSample(iface);
513 HRESULT hr = S_OK;
515 TRACE("%p, %p.\n", iface, timestamp);
517 EnterCriticalSection(&sample->attributes.cs);
518 if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP)
519 *timestamp = sample->timestamp;
520 else
521 hr = MF_E_NO_SAMPLE_TIMESTAMP;
522 LeaveCriticalSection(&sample->attributes.cs);
524 return hr;
527 static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
529 struct sample *sample = impl_from_IMFSample(iface);
531 TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
533 EnterCriticalSection(&sample->attributes.cs);
534 sample->timestamp = timestamp;
535 sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP;
536 LeaveCriticalSection(&sample->attributes.cs);
538 return S_OK;
541 static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
543 struct sample *sample = impl_from_IMFSample(iface);
544 HRESULT hr = S_OK;
546 TRACE("%p, %p.\n", iface, duration);
548 EnterCriticalSection(&sample->attributes.cs);
549 if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION)
550 *duration = sample->duration;
551 else
552 hr = MF_E_NO_SAMPLE_DURATION;
553 LeaveCriticalSection(&sample->attributes.cs);
555 return hr;
558 static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
560 struct sample *sample = impl_from_IMFSample(iface);
562 TRACE("%p, %s.\n", iface, debugstr_time(duration));
564 EnterCriticalSection(&sample->attributes.cs);
565 sample->duration = duration;
566 sample->prop_flags |= SAMPLE_PROP_HAS_DURATION;
567 LeaveCriticalSection(&sample->attributes.cs);
569 return S_OK;
572 static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count)
574 struct sample *sample = impl_from_IMFSample(iface);
576 TRACE("%p, %p.\n", iface, count);
578 if (!count)
579 return E_INVALIDARG;
581 EnterCriticalSection(&sample->attributes.cs);
582 *count = sample->buffer_count;
583 LeaveCriticalSection(&sample->attributes.cs);
585 return S_OK;
588 static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
590 struct sample *sample = impl_from_IMFSample(iface);
591 HRESULT hr = S_OK;
593 TRACE("%p, %lu, %p.\n", iface, index, buffer);
595 EnterCriticalSection(&sample->attributes.cs);
596 if (index < sample->buffer_count)
598 *buffer = sample->buffers[index];
599 IMFMediaBuffer_AddRef(*buffer);
601 else
602 hr = E_INVALIDARG;
603 LeaveCriticalSection(&sample->attributes.cs);
605 return hr;
608 static unsigned int sample_get_total_length(struct sample *sample)
610 DWORD total_length = 0, length;
611 size_t i;
613 for (i = 0; i < sample->buffer_count; ++i)
615 length = 0;
616 if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length)))
617 total_length += length;
620 return total_length;
623 static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer)
625 DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
626 BYTE *src_ptr, *dst_ptr;
627 BOOL locked;
628 HRESULT hr;
629 size_t i;
631 total_length = sample_get_total_length(sample);
632 dst_current_length = 0;
634 dst_ptr = NULL;
635 dst_length = current_length = 0;
636 locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
637 if (locked)
639 if (dst_length < total_length)
640 hr = MF_E_BUFFERTOOSMALL;
641 else if (dst_ptr)
643 for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
645 src_ptr = NULL;
646 src_max_length = current_length = 0;
647 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
649 if (src_ptr)
651 if (current_length > dst_length)
652 hr = MF_E_BUFFERTOOSMALL;
653 else if (current_length)
655 memcpy(dst_ptr, src_ptr, current_length);
656 dst_length -= current_length;
657 dst_current_length += current_length;
658 dst_ptr += current_length;
661 IMFMediaBuffer_Unlock(sample->buffers[i]);
667 if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length)))
668 WARN("Failed to set buffer length.\n");
670 if (locked)
671 IMFMediaBuffer_Unlock(buffer);
673 return hr;
676 static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
678 struct sample *sample = impl_from_IMFSample(iface);
679 unsigned int total_length, i;
680 IMFMediaBuffer *dest_buffer;
681 HRESULT hr = S_OK;
683 TRACE("%p, %p.\n", iface, buffer);
685 EnterCriticalSection(&sample->attributes.cs);
687 if (sample->buffer_count == 0)
688 hr = E_UNEXPECTED;
689 else if (sample->buffer_count > 1)
691 total_length = sample_get_total_length(sample);
692 if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer)))
694 if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer)))
696 for (i = 0; i < sample->buffer_count; ++i)
697 IMFMediaBuffer_Release(sample->buffers[i]);
699 sample->buffers[0] = dest_buffer;
700 IMFMediaBuffer_AddRef(sample->buffers[0]);
702 sample->buffer_count = 1;
704 IMFMediaBuffer_Release(dest_buffer);
708 if (SUCCEEDED(hr) && buffer)
710 *buffer = sample->buffers[0];
711 IMFMediaBuffer_AddRef(*buffer);
714 LeaveCriticalSection(&sample->attributes.cs);
716 return hr;
719 static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
721 struct sample *sample = impl_from_IMFSample(iface);
722 HRESULT hr = S_OK;
724 TRACE("%p, %p.\n", iface, buffer);
726 EnterCriticalSection(&sample->attributes.cs);
727 if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1,
728 sizeof(*sample->buffers)))
729 hr = E_OUTOFMEMORY;
730 else
732 sample->buffers[sample->buffer_count++] = buffer;
733 IMFMediaBuffer_AddRef(buffer);
735 LeaveCriticalSection(&sample->attributes.cs);
737 return hr;
740 static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
742 struct sample *sample = impl_from_IMFSample(iface);
743 HRESULT hr = S_OK;
745 TRACE("%p, %lu.\n", iface, index);
747 EnterCriticalSection(&sample->attributes.cs);
748 if (index < sample->buffer_count)
750 IMFMediaBuffer_Release(sample->buffers[index]);
751 if (index < sample->buffer_count - 1)
753 memmove(&sample->buffers[index], &sample->buffers[index+1],
754 (sample->buffer_count - index - 1) * sizeof(*sample->buffers));
756 sample->buffer_count--;
758 else
759 hr = E_INVALIDARG;
760 LeaveCriticalSection(&sample->attributes.cs);
762 return hr;
765 static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface)
767 struct sample *sample = impl_from_IMFSample(iface);
768 size_t i;
770 TRACE("%p.\n", iface);
772 EnterCriticalSection(&sample->attributes.cs);
773 for (i = 0; i < sample->buffer_count; ++i)
774 IMFMediaBuffer_Release(sample->buffers[i]);
775 sample->buffer_count = 0;
776 LeaveCriticalSection(&sample->attributes.cs);
778 return S_OK;
781 static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
783 struct sample *sample = impl_from_IMFSample(iface);
785 TRACE("%p, %p.\n", iface, total_length);
787 EnterCriticalSection(&sample->attributes.cs);
788 *total_length = sample_get_total_length(sample);
789 LeaveCriticalSection(&sample->attributes.cs);
791 return S_OK;
794 static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
796 struct sample *sample = impl_from_IMFSample(iface);
797 DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
798 BYTE *src_ptr, *dst_ptr;
799 BOOL locked;
800 HRESULT hr;
801 size_t i;
803 TRACE("%p, %p.\n", iface, buffer);
805 EnterCriticalSection(&sample->attributes.cs);
807 total_length = sample_get_total_length(sample);
808 dst_current_length = 0;
810 dst_ptr = NULL;
811 dst_length = current_length = 0;
812 locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
813 if (locked)
815 if (dst_length < total_length)
816 hr = MF_E_BUFFERTOOSMALL;
817 else if (dst_ptr)
819 for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
821 src_ptr = NULL;
822 src_max_length = current_length = 0;
823 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
825 if (src_ptr)
827 if (current_length > dst_length)
828 hr = MF_E_BUFFERTOOSMALL;
829 else if (current_length)
831 memcpy(dst_ptr, src_ptr, current_length);
832 dst_length -= current_length;
833 dst_current_length += current_length;
834 dst_ptr += current_length;
837 IMFMediaBuffer_Unlock(sample->buffers[i]);
843 IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
845 if (locked)
846 IMFMediaBuffer_Unlock(buffer);
848 LeaveCriticalSection(&sample->attributes.cs);
850 return hr;
853 static const IMFSampleVtbl samplevtbl =
855 sample_QueryInterface,
856 sample_AddRef,
857 sample_Release,
858 sample_GetItem,
859 sample_GetItemType,
860 sample_CompareItem,
861 sample_Compare,
862 sample_GetUINT32,
863 sample_GetUINT64,
864 sample_GetDouble,
865 sample_GetGUID,
866 sample_GetStringLength,
867 sample_GetString,
868 sample_GetAllocatedString,
869 sample_GetBlobSize,
870 sample_GetBlob,
871 sample_GetAllocatedBlob,
872 sample_GetUnknown,
873 sample_SetItem,
874 sample_DeleteItem,
875 sample_DeleteAllItems,
876 sample_SetUINT32,
877 sample_SetUINT64,
878 sample_SetDouble,
879 sample_SetGUID,
880 sample_SetString,
881 sample_SetBlob,
882 sample_SetUnknown,
883 sample_LockStore,
884 sample_UnlockStore,
885 sample_GetCount,
886 sample_GetItemByIndex,
887 sample_CopyAllItems,
888 sample_GetSampleFlags,
889 sample_SetSampleFlags,
890 sample_GetSampleTime,
891 sample_SetSampleTime,
892 sample_GetSampleDuration,
893 sample_SetSampleDuration,
894 sample_GetBufferCount,
895 sample_GetBufferByIndex,
896 sample_ConvertToContiguousBuffer,
897 sample_AddBuffer,
898 sample_RemoveBufferByIndex,
899 sample_RemoveAllBuffers,
900 sample_GetTotalLength,
901 sample_CopyToBuffer,
904 static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
906 struct sample *sample = impl_from_IMFTrackedSample(iface);
907 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
910 static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
912 struct sample *sample = impl_from_IMFTrackedSample(iface);
913 return IMFSample_AddRef(&sample->IMFSample_iface);
916 static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
918 struct sample *sample = impl_from_IMFTrackedSample(iface);
919 return IMFSample_Release(&sample->IMFSample_iface);
922 static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
923 IMFAsyncCallback *sample_allocator, IUnknown *state)
925 struct sample *sample = impl_from_IMFTrackedSample(iface);
926 HRESULT hr = S_OK;
928 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
930 EnterCriticalSection(&sample->attributes.cs);
932 if (sample->tracked_result)
933 hr = MF_E_NOTACCEPTING;
934 else
936 if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
937 state, &sample->tracked_result)))
939 /* Account for additional refcount brought by 'state' object. This threshold is used
940 on Release() to invoke tracker callback. */
941 sample->tracked_refcount = 1;
942 if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
943 state == (IUnknown *)&sample->IMFSample_iface)
945 ++sample->tracked_refcount;
950 LeaveCriticalSection(&sample->attributes.cs);
952 return hr;
955 static const IMFTrackedSampleVtbl tracked_sample_vtbl =
957 tracked_sample_QueryInterface,
958 tracked_sample_AddRef,
959 tracked_sample_Release,
960 tracked_sample_SetAllocator,
963 static const IMFSampleVtbl sample_tracked_vtbl =
965 sample_QueryInterface,
966 sample_AddRef,
967 sample_tracked_Release,
968 sample_GetItem,
969 sample_GetItemType,
970 sample_CompareItem,
971 sample_Compare,
972 sample_GetUINT32,
973 sample_GetUINT64,
974 sample_GetDouble,
975 sample_GetGUID,
976 sample_GetStringLength,
977 sample_GetString,
978 sample_GetAllocatedString,
979 sample_GetBlobSize,
980 sample_GetBlob,
981 sample_GetAllocatedBlob,
982 sample_GetUnknown,
983 sample_SetItem,
984 sample_DeleteItem,
985 sample_DeleteAllItems,
986 sample_SetUINT32,
987 sample_SetUINT64,
988 sample_SetDouble,
989 sample_SetGUID,
990 sample_SetString,
991 sample_SetBlob,
992 sample_SetUnknown,
993 sample_LockStore,
994 sample_UnlockStore,
995 sample_GetCount,
996 sample_GetItemByIndex,
997 sample_CopyAllItems,
998 sample_GetSampleFlags,
999 sample_SetSampleFlags,
1000 sample_GetSampleTime,
1001 sample_SetSampleTime,
1002 sample_GetSampleDuration,
1003 sample_SetSampleDuration,
1004 sample_GetBufferCount,
1005 sample_GetBufferByIndex,
1006 sample_ConvertToContiguousBuffer,
1007 sample_AddBuffer,
1008 sample_RemoveBufferByIndex,
1009 sample_RemoveAllBuffers,
1010 sample_GetTotalLength,
1011 sample_CopyToBuffer,
1014 /***********************************************************************
1015 * MFCreateSample (mfplat.@)
1017 HRESULT WINAPI MFCreateSample(IMFSample **sample)
1019 struct sample *object;
1020 HRESULT hr;
1022 TRACE("%p.\n", sample);
1024 if (!(object = calloc(1, sizeof(*object))))
1025 return E_OUTOFMEMORY;
1027 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1029 free(object);
1030 return hr;
1033 object->IMFSample_iface.lpVtbl = &samplevtbl;
1035 *sample = &object->IMFSample_iface;
1037 TRACE("Created sample %p.\n", *sample);
1039 return S_OK;
1042 /***********************************************************************
1043 * MFCreateTrackedSample (mfplat.@)
1045 HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
1047 struct sample *object;
1048 HRESULT hr;
1050 TRACE("%p.\n", sample);
1052 if (!(object = calloc(1, sizeof(*object))))
1053 return E_OUTOFMEMORY;
1055 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1057 free(object);
1058 return hr;
1061 object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
1062 object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
1064 *sample = &object->IMFTrackedSample_iface;
1066 return S_OK;
1069 static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocatorEx *iface, REFIID riid, void **obj)
1071 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1073 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1075 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorEx) ||
1076 IsEqualIID(riid, &IID_IMFVideoSampleAllocator) ||
1077 IsEqualIID(riid, &IID_IUnknown))
1079 *obj = &allocator->IMFVideoSampleAllocatorEx_iface;
1081 else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback))
1083 *obj = &allocator->IMFVideoSampleAllocatorCallback_iface;
1085 else
1087 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1088 *obj = NULL;
1089 return E_NOINTERFACE;
1092 IUnknown_AddRef((IUnknown *)*obj);
1093 return S_OK;
1096 static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocatorEx *iface)
1098 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1099 ULONG refcount = InterlockedIncrement(&allocator->refcount);
1101 TRACE("%p, refcount %lu.\n", iface, refcount);
1103 return refcount;
1106 static void sample_allocator_release_samples(struct sample_allocator *allocator)
1108 struct queued_sample *iter, *iter2;
1110 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry)
1112 list_remove(&iter->entry);
1113 IMFSample_Release(iter->sample);
1114 free(iter);
1117 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry)
1119 list_remove(&iter->entry);
1120 free(iter);
1123 allocator->free_sample_count = 0;
1124 allocator->cold_sample_count = 0;
1127 static void sample_allocator_set_media_type(struct sample_allocator *allocator, IMFMediaType *media_type)
1129 UINT64 frame_size;
1130 GUID subtype;
1132 if (!media_type)
1134 if (allocator->media_type)
1135 IMFMediaType_Release(allocator->media_type);
1136 allocator->media_type = NULL;
1137 return;
1140 /* Check if type is the same. */
1141 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size);
1142 IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1144 if (frame_size == ((UINT64) allocator->frame_desc.width << 32 | allocator->frame_desc.height) &&
1145 subtype.Data1 == allocator->frame_desc.d3d9_format)
1147 return;
1150 if (allocator->media_type)
1151 IMFMediaType_Release(allocator->media_type);
1152 allocator->media_type = media_type;
1153 if (allocator->media_type)
1154 IMFMediaType_AddRef(allocator->media_type);
1157 static void sample_allocator_set_attributes(struct sample_allocator *allocator, IMFAttributes *attributes)
1159 if (allocator->attributes)
1160 IMFAttributes_Release(allocator->attributes);
1161 allocator->attributes = attributes;
1162 if (allocator->attributes)
1163 IMFAttributes_AddRef(allocator->attributes);
1166 static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocatorEx *iface)
1168 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1169 ULONG refcount = InterlockedDecrement(&allocator->refcount);
1171 TRACE("%p, refcount %lu.\n", iface, refcount);
1173 if (!refcount)
1175 if (allocator->callback)
1176 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1177 if (allocator->d3d9_device_manager)
1178 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1179 if (allocator->dxgi_device_manager)
1180 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1181 sample_allocator_set_media_type(allocator, NULL);
1182 sample_allocator_set_attributes(allocator, NULL);
1183 sample_allocator_release_samples(allocator);
1184 DeleteCriticalSection(&allocator->cs);
1185 free(allocator);
1188 return refcount;
1191 static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocatorEx *iface,
1192 IUnknown *manager)
1194 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1195 IDirect3DDeviceManager9 *d3d9_device_manager = NULL;
1196 IMFDXGIDeviceManager *dxgi_device_manager = NULL;
1197 HRESULT hr;
1199 TRACE("%p, %p.\n", iface, manager);
1201 if (manager)
1203 if (FAILED(hr = IUnknown_QueryInterface(manager, &IID_IMFDXGIDeviceManager, (void **)&dxgi_device_manager)))
1205 hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9, (void **)&d3d9_device_manager);
1208 if (FAILED(hr))
1209 return hr;
1212 EnterCriticalSection(&allocator->cs);
1214 if (allocator->d3d9_device_manager)
1215 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1216 if (allocator->dxgi_device_manager)
1217 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1218 allocator->d3d9_device_manager = NULL;
1219 allocator->dxgi_device_manager = NULL;
1221 if (dxgi_device_manager)
1222 allocator->dxgi_device_manager = dxgi_device_manager;
1223 else if (d3d9_device_manager)
1224 allocator->d3d9_device_manager = d3d9_device_manager;
1226 LeaveCriticalSection(&allocator->cs);
1228 return S_OK;
1231 static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface)
1233 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1235 TRACE("%p.\n", iface);
1237 EnterCriticalSection(&allocator->cs);
1239 sample_allocator_release_samples(allocator);
1240 sample_allocator_set_media_type(allocator, NULL);
1241 sample_allocator_set_attributes(allocator, NULL);
1242 memset(&allocator->frame_desc, 0, sizeof(allocator->frame_desc));
1244 LeaveCriticalSection(&allocator->cs);
1246 return S_OK;
1249 struct surface_service
1251 IDirectXVideoProcessorService *dxva_service;
1252 ID3D11Device *d3d11_device;
1253 HANDLE hdevice;
1256 static HRESULT sample_allocator_get_surface_service(struct sample_allocator *allocator, struct surface_service *service)
1258 HRESULT hr = S_OK;
1260 memset(service, 0, sizeof(*service));
1262 if (allocator->d3d9_device_manager)
1264 if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->d3d9_device_manager, &service->hdevice)))
1266 if (FAILED(hr = IDirect3DDeviceManager9_GetVideoService(allocator->d3d9_device_manager, service->hdevice,
1267 &IID_IDirectXVideoProcessorService, (void **)&service->dxva_service)))
1269 WARN("Failed to get DXVA processor service, hr %#lx.\n", hr);
1270 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1274 else if (allocator->dxgi_device_manager)
1276 if (SUCCEEDED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(allocator->dxgi_device_manager, &service->hdevice)))
1278 if (FAILED(hr = IMFDXGIDeviceManager_GetVideoService(allocator->dxgi_device_manager, service->hdevice,
1279 &IID_ID3D11Device, (void **)&service->d3d11_device)))
1281 WARN("Failed to get D3D11 device, hr %#lx.\n", hr);
1282 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1287 if (FAILED(hr))
1288 memset(service, 0, sizeof(*service));
1290 return hr;
1293 static void sample_allocator_release_surface_service(struct sample_allocator *allocator,
1294 struct surface_service *service)
1296 if (service->dxva_service)
1297 IDirectXVideoProcessorService_Release(service->dxva_service);
1298 if (service->d3d11_device)
1299 ID3D11Device_Release(service->d3d11_device);
1301 if (allocator->d3d9_device_manager)
1302 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1303 else if (allocator->dxgi_device_manager)
1304 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1307 static HRESULT sample_allocator_allocate_sample(struct sample_allocator *allocator, const struct surface_service *service,
1308 struct queued_sample **queued_sample)
1310 IMFTrackedSample *tracked_sample;
1311 IMFMediaBuffer *buffer;
1312 IMFSample *sample;
1313 unsigned int i;
1314 HRESULT hr;
1316 if (FAILED(hr = MFCreateTrackedSample(&tracked_sample)))
1317 return hr;
1319 IMFTrackedSample_QueryInterface(tracked_sample, &IID_IMFSample, (void **)&sample);
1320 IMFTrackedSample_Release(tracked_sample);
1322 for (i = 0; i < allocator->frame_desc.buffer_count; ++i)
1324 if (service->dxva_service)
1326 IDirect3DSurface9 *surface;
1328 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service->dxva_service, allocator->frame_desc.width,
1329 allocator->frame_desc.height, 0, allocator->frame_desc.d3d9_format, D3DPOOL_DEFAULT, 0,
1330 DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
1332 hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer);
1333 IDirect3DSurface9_Release(surface);
1336 else if (service->d3d11_device)
1338 D3D11_TEXTURE2D_DESC desc = { 0 };
1339 ID3D11Texture2D *texture;
1341 desc.Width = allocator->frame_desc.width;
1342 desc.Height = allocator->frame_desc.height;
1343 desc.MipLevels = 1;
1344 desc.ArraySize = 1;
1345 desc.Format = allocator->frame_desc.dxgi_format;
1346 desc.SampleDesc.Count = 1;
1347 desc.SampleDesc.Quality = 0;
1348 desc.Usage = allocator->frame_desc.usage;
1349 desc.BindFlags = allocator->frame_desc.bindflags;
1350 if (desc.Usage == D3D11_USAGE_DYNAMIC)
1351 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1352 else if (desc.Usage == D3D11_USAGE_STAGING)
1353 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
1354 desc.MiscFlags = allocator->frame_desc.miscflags;
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 if (FAILED(hr))
1377 IMFSample_Release(sample);
1378 return hr;
1381 if (!(*queued_sample = malloc(sizeof(**queued_sample))))
1383 IMFSample_Release(sample);
1384 return E_OUTOFMEMORY;
1386 (*queued_sample)->sample = sample;
1388 return hr;
1391 static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, unsigned int sample_count,
1392 unsigned int max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1394 struct surface_service service;
1395 struct queued_sample *sample;
1396 DXGI_FORMAT dxgi_format;
1397 unsigned int i, value;
1398 GUID major, subtype;
1399 UINT64 frame_size;
1400 D3D11_USAGE usage;
1401 HRESULT hr;
1403 if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major)))
1404 return hr;
1406 if (!IsEqualGUID(&major, &MFMediaType_Video))
1407 return MF_E_INVALIDMEDIATYPE;
1409 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
1410 return hr;
1412 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
1413 return hr;
1415 if (sample_count > max_sample_count)
1416 return E_INVALIDARG;
1418 usage = D3D11_USAGE_DEFAULT;
1419 if (attributes)
1421 IMFAttributes_GetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, &allocator->frame_desc.buffer_count);
1422 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_USAGE, &usage);
1425 if (usage == D3D11_USAGE_IMMUTABLE || usage > D3D11_USAGE_STAGING)
1426 return E_INVALIDARG;
1428 dxgi_format = MFMapDX9FormatToDXGIFormat(subtype.Data1);
1430 allocator->frame_desc.bindflags = 0;
1431 allocator->frame_desc.miscflags = 0;
1432 allocator->frame_desc.usage = D3D11_USAGE_DEFAULT;
1434 if (dxgi_format == DXGI_FORMAT_B8G8R8A8_UNORM ||
1435 dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM)
1437 allocator->frame_desc.usage = usage;
1438 if (allocator->frame_desc.usage == D3D11_USAGE_DEFAULT)
1439 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
1440 else if (allocator->frame_desc.usage == D3D11_USAGE_DYNAMIC)
1441 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE;
1444 if (attributes)
1446 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &allocator->frame_desc.bindflags);
1447 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_SHARED, &value)) && value)
1448 allocator->frame_desc.miscflags |= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
1449 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &value)) && value)
1450 allocator->frame_desc.miscflags |= D3D11_RESOURCE_MISC_SHARED;
1453 sample_allocator_set_media_type(allocator, media_type);
1454 sample_allocator_set_attributes(allocator, attributes);
1456 sample_count = max(1, sample_count);
1457 max_sample_count = max(1, max_sample_count);
1459 allocator->frame_desc.d3d9_format = subtype.Data1;
1460 allocator->frame_desc.dxgi_format = dxgi_format;
1461 allocator->frame_desc.width = frame_size >> 32;
1462 allocator->frame_desc.height = frame_size;
1463 allocator->frame_desc.buffer_count = max(1, allocator->frame_desc.buffer_count);
1465 if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service)))
1466 return hr;
1468 sample_allocator_release_samples(allocator);
1470 for (i = 0; i < sample_count; ++i)
1472 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1474 list_add_tail(&allocator->free_samples, &sample->entry);
1475 allocator->free_sample_count++;
1478 allocator->cold_sample_count = max_sample_count - allocator->free_sample_count;
1480 sample_allocator_release_surface_service(allocator, &service);
1482 return hr;
1485 static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface,
1486 DWORD sample_count, IMFMediaType *media_type)
1488 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1489 HRESULT hr;
1491 TRACE("%p, %lu, %p.\n", iface, sample_count, media_type);
1493 if (!sample_count)
1494 return E_INVALIDARG;
1496 EnterCriticalSection(&allocator->cs);
1498 hr = sample_allocator_initialize(allocator, sample_count, sample_count, NULL, media_type);
1500 LeaveCriticalSection(&allocator->cs);
1502 return hr;
1505 static HRESULT sample_allocator_track_sample(struct sample_allocator *allocator, IMFSample *sample)
1507 IMFTrackedSample *tracked_sample;
1508 HRESULT hr;
1510 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
1512 hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
1513 IMFTrackedSample_Release(tracked_sample);
1516 return hr;
1519 static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx *iface, IMFSample **out)
1521 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1522 struct queued_sample *sample;
1523 HRESULT hr;
1525 TRACE("%p, %p.\n", iface, out);
1527 EnterCriticalSection(&allocator->cs);
1529 if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples))
1530 hr = MF_E_NOT_INITIALIZED;
1531 else if (list_empty(&allocator->free_samples) && !allocator->cold_sample_count)
1532 hr = MF_E_SAMPLEALLOCATOR_EMPTY;
1533 else if (!list_empty(&allocator->free_samples))
1535 struct list *head = list_head(&allocator->free_samples);
1537 sample = LIST_ENTRY(head, struct queued_sample, entry);
1539 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample->sample)))
1541 list_remove(head);
1542 list_add_tail(&allocator->used_samples, head);
1543 allocator->free_sample_count--;
1545 /* Reference counter is not increased when sample is returned, so next release could trigger
1546 tracking condition. This is balanced by incremented reference counter when sample is returned
1547 back to the free list. */
1548 *out = sample->sample;
1551 else /* allocator->cold_sample_count != 0 */
1553 struct surface_service service;
1555 if (SUCCEEDED(hr = sample_allocator_get_surface_service(allocator, &service)))
1557 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1559 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample->sample)))
1561 list_add_tail(&allocator->used_samples, &sample->entry);
1562 allocator->cold_sample_count--;
1564 *out = sample->sample;
1566 else
1568 IMFSample_Release(sample->sample);
1569 free(sample);
1573 sample_allocator_release_surface_service(allocator, &service);
1577 LeaveCriticalSection(&allocator->cs);
1579 return hr;
1582 static HRESULT WINAPI sample_allocator_InitializeSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface, DWORD initial_sample_count,
1583 DWORD max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1585 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1586 HRESULT hr;
1588 TRACE("%p, %lu, %lu, %p, %p.\n", iface, initial_sample_count, max_sample_count, attributes, media_type);
1590 EnterCriticalSection(&allocator->cs);
1592 hr = sample_allocator_initialize(allocator, initial_sample_count, max_sample_count, attributes, media_type);
1594 LeaveCriticalSection(&allocator->cs);
1596 return hr;
1599 static const IMFVideoSampleAllocatorExVtbl sample_allocator_vtbl =
1601 sample_allocator_QueryInterface,
1602 sample_allocator_AddRef,
1603 sample_allocator_Release,
1604 sample_allocator_SetDirectXManager,
1605 sample_allocator_UninitializeSampleAllocator,
1606 sample_allocator_InitializeSampleAllocator,
1607 sample_allocator_AllocateSample,
1608 sample_allocator_InitializeSampleAllocatorEx,
1611 static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface,
1612 REFIID riid, void **obj)
1614 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1615 return IMFVideoSampleAllocatorEx_QueryInterface(&allocator->IMFVideoSampleAllocatorEx_iface, riid, obj);
1618 static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface)
1620 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1621 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1624 static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface)
1626 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1627 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1630 static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface,
1631 IMFVideoSampleAllocatorNotify *callback)
1633 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1635 TRACE("%p, %p.\n", iface, callback);
1637 EnterCriticalSection(&allocator->cs);
1638 if (allocator->callback)
1639 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1640 allocator->callback = callback;
1641 if (allocator->callback)
1642 IMFVideoSampleAllocatorNotify_AddRef(allocator->callback);
1643 LeaveCriticalSection(&allocator->cs);
1645 return S_OK;
1648 static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface,
1649 LONG *count)
1651 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1653 TRACE("%p, %p.\n", iface, count);
1655 if (!count)
1656 return E_POINTER;
1658 EnterCriticalSection(&allocator->cs);
1659 *count = allocator->free_sample_count;
1660 LeaveCriticalSection(&allocator->cs);
1662 return S_OK;
1665 static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl =
1667 sample_allocator_callback_QueryInterface,
1668 sample_allocator_callback_AddRef,
1669 sample_allocator_callback_Release,
1670 sample_allocator_callback_SetCallback,
1671 sample_allocator_callback_GetFreeSampleCount,
1674 static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface,
1675 REFIID riid, void **obj)
1677 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1678 IsEqualIID(riid, &IID_IUnknown))
1680 *obj = iface;
1681 IMFAsyncCallback_AddRef(iface);
1682 return S_OK;
1685 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1686 *obj = NULL;
1687 return E_NOINTERFACE;
1690 static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface)
1692 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1693 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1696 static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
1698 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1699 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1702 static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface,
1703 DWORD *flags, DWORD *queue)
1705 return E_NOTIMPL;
1708 static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1710 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1711 struct queued_sample *iter;
1712 IUnknown *object = NULL;
1713 IMFSample *sample = NULL;
1714 HRESULT hr;
1716 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
1717 return E_UNEXPECTED;
1719 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
1720 IUnknown_Release(object);
1721 if (FAILED(hr))
1722 return E_UNEXPECTED;
1724 EnterCriticalSection(&allocator->cs);
1726 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
1728 if (sample == iter->sample)
1730 list_remove(&iter->entry);
1731 list_add_tail(&allocator->free_samples, &iter->entry);
1732 IMFSample_AddRef(iter->sample);
1733 allocator->free_sample_count++;
1734 break;
1738 IMFSample_Release(sample);
1740 if (allocator->callback)
1741 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
1743 LeaveCriticalSection(&allocator->cs);
1745 return S_OK;
1748 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
1750 sample_allocator_tracking_callback_QueryInterface,
1751 sample_allocator_tracking_callback_AddRef,
1752 sample_allocator_tracking_callback_Release,
1753 sample_allocator_tracking_callback_GetParameters,
1754 sample_allocator_tracking_callback_Invoke,
1757 /***********************************************************************
1758 * MFCreateVideoSampleAllocatorEx (mfplat.@)
1760 HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj)
1762 struct sample_allocator *object;
1763 HRESULT hr;
1765 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1767 if (!(object = calloc(1, sizeof(*object))))
1768 return E_OUTOFMEMORY;
1770 object->IMFVideoSampleAllocatorEx_iface.lpVtbl = &sample_allocator_vtbl;
1771 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
1772 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
1773 object->refcount = 1;
1774 list_init(&object->used_samples);
1775 list_init(&object->free_samples);
1776 InitializeCriticalSection(&object->cs);
1778 hr = IMFVideoSampleAllocatorEx_QueryInterface(&object->IMFVideoSampleAllocatorEx_iface, riid, obj);
1779 IMFVideoSampleAllocatorEx_Release(&object->IMFVideoSampleAllocatorEx_iface);
1781 return hr;