mfplat/sample: Optimize copying to 2d buffer.
[wine.git] / dlls / mfplat / sample.c
bloba50f81c93d4b374b724875ae56b431946cfb020a
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 IMF2DBuffer *buffer2d;
800 BOOL locked = FALSE;
801 HRESULT hr = E_FAIL;
802 size_t i;
804 TRACE("%p, %p.\n", iface, buffer);
806 EnterCriticalSection(&sample->attributes.cs);
808 total_length = sample_get_total_length(sample);
809 dst_current_length = 0;
811 if (sample->buffer_count == 1
812 && SUCCEEDED(IMFMediaBuffer_QueryInterface(buffer, &IID_IMF2DBuffer, (void **)&buffer2d)))
814 if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[0], &current_length))
815 && SUCCEEDED(IMF2DBuffer_GetContiguousLength(buffer2d, &dst_length))
816 && current_length == dst_length
817 && SUCCEEDED(IMFMediaBuffer_Lock(sample->buffers[0], &src_ptr, &src_max_length, &current_length)))
819 hr = IMF2DBuffer_ContiguousCopyFrom(buffer2d, src_ptr, current_length);
820 IMFMediaBuffer_Unlock(sample->buffers[0]);
822 IMF2DBuffer_Release(buffer2d);
823 if (SUCCEEDED(hr))
825 dst_current_length = current_length;
826 goto done;
830 dst_ptr = NULL;
831 dst_length = current_length = 0;
832 locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
833 if (!locked)
834 goto done;
836 if (dst_length < total_length)
838 hr = MF_E_BUFFERTOOSMALL;
839 goto done;
842 if (!dst_ptr)
843 goto done;
845 for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
847 src_ptr = NULL;
848 src_max_length = current_length = 0;
850 if (FAILED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
851 continue;
853 if (src_ptr)
855 if (current_length > dst_length)
856 hr = MF_E_BUFFERTOOSMALL;
857 else if (current_length)
859 memcpy(dst_ptr, src_ptr, current_length);
860 dst_length -= current_length;
861 dst_current_length += current_length;
862 dst_ptr += current_length;
865 IMFMediaBuffer_Unlock(sample->buffers[i]);
868 done:
869 IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
871 if (locked)
872 IMFMediaBuffer_Unlock(buffer);
874 LeaveCriticalSection(&sample->attributes.cs);
876 return hr;
879 static const IMFSampleVtbl samplevtbl =
881 sample_QueryInterface,
882 sample_AddRef,
883 sample_Release,
884 sample_GetItem,
885 sample_GetItemType,
886 sample_CompareItem,
887 sample_Compare,
888 sample_GetUINT32,
889 sample_GetUINT64,
890 sample_GetDouble,
891 sample_GetGUID,
892 sample_GetStringLength,
893 sample_GetString,
894 sample_GetAllocatedString,
895 sample_GetBlobSize,
896 sample_GetBlob,
897 sample_GetAllocatedBlob,
898 sample_GetUnknown,
899 sample_SetItem,
900 sample_DeleteItem,
901 sample_DeleteAllItems,
902 sample_SetUINT32,
903 sample_SetUINT64,
904 sample_SetDouble,
905 sample_SetGUID,
906 sample_SetString,
907 sample_SetBlob,
908 sample_SetUnknown,
909 sample_LockStore,
910 sample_UnlockStore,
911 sample_GetCount,
912 sample_GetItemByIndex,
913 sample_CopyAllItems,
914 sample_GetSampleFlags,
915 sample_SetSampleFlags,
916 sample_GetSampleTime,
917 sample_SetSampleTime,
918 sample_GetSampleDuration,
919 sample_SetSampleDuration,
920 sample_GetBufferCount,
921 sample_GetBufferByIndex,
922 sample_ConvertToContiguousBuffer,
923 sample_AddBuffer,
924 sample_RemoveBufferByIndex,
925 sample_RemoveAllBuffers,
926 sample_GetTotalLength,
927 sample_CopyToBuffer,
930 static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
932 struct sample *sample = impl_from_IMFTrackedSample(iface);
933 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
936 static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
938 struct sample *sample = impl_from_IMFTrackedSample(iface);
939 return IMFSample_AddRef(&sample->IMFSample_iface);
942 static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
944 struct sample *sample = impl_from_IMFTrackedSample(iface);
945 return IMFSample_Release(&sample->IMFSample_iface);
948 static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
949 IMFAsyncCallback *sample_allocator, IUnknown *state)
951 struct sample *sample = impl_from_IMFTrackedSample(iface);
952 HRESULT hr = S_OK;
954 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
956 EnterCriticalSection(&sample->attributes.cs);
958 if (sample->tracked_result)
959 hr = MF_E_NOTACCEPTING;
960 else
962 if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
963 state, &sample->tracked_result)))
965 /* Account for additional refcount brought by 'state' object. This threshold is used
966 on Release() to invoke tracker callback. */
967 sample->tracked_refcount = 1;
968 if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
969 state == (IUnknown *)&sample->IMFSample_iface)
971 ++sample->tracked_refcount;
976 LeaveCriticalSection(&sample->attributes.cs);
978 return hr;
981 static const IMFTrackedSampleVtbl tracked_sample_vtbl =
983 tracked_sample_QueryInterface,
984 tracked_sample_AddRef,
985 tracked_sample_Release,
986 tracked_sample_SetAllocator,
989 static const IMFSampleVtbl sample_tracked_vtbl =
991 sample_QueryInterface,
992 sample_AddRef,
993 sample_tracked_Release,
994 sample_GetItem,
995 sample_GetItemType,
996 sample_CompareItem,
997 sample_Compare,
998 sample_GetUINT32,
999 sample_GetUINT64,
1000 sample_GetDouble,
1001 sample_GetGUID,
1002 sample_GetStringLength,
1003 sample_GetString,
1004 sample_GetAllocatedString,
1005 sample_GetBlobSize,
1006 sample_GetBlob,
1007 sample_GetAllocatedBlob,
1008 sample_GetUnknown,
1009 sample_SetItem,
1010 sample_DeleteItem,
1011 sample_DeleteAllItems,
1012 sample_SetUINT32,
1013 sample_SetUINT64,
1014 sample_SetDouble,
1015 sample_SetGUID,
1016 sample_SetString,
1017 sample_SetBlob,
1018 sample_SetUnknown,
1019 sample_LockStore,
1020 sample_UnlockStore,
1021 sample_GetCount,
1022 sample_GetItemByIndex,
1023 sample_CopyAllItems,
1024 sample_GetSampleFlags,
1025 sample_SetSampleFlags,
1026 sample_GetSampleTime,
1027 sample_SetSampleTime,
1028 sample_GetSampleDuration,
1029 sample_SetSampleDuration,
1030 sample_GetBufferCount,
1031 sample_GetBufferByIndex,
1032 sample_ConvertToContiguousBuffer,
1033 sample_AddBuffer,
1034 sample_RemoveBufferByIndex,
1035 sample_RemoveAllBuffers,
1036 sample_GetTotalLength,
1037 sample_CopyToBuffer,
1040 /***********************************************************************
1041 * MFCreateSample (mfplat.@)
1043 HRESULT WINAPI MFCreateSample(IMFSample **sample)
1045 struct sample *object;
1046 HRESULT hr;
1048 TRACE("%p.\n", sample);
1050 if (!(object = calloc(1, sizeof(*object))))
1051 return E_OUTOFMEMORY;
1053 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1055 free(object);
1056 return hr;
1059 object->IMFSample_iface.lpVtbl = &samplevtbl;
1061 *sample = &object->IMFSample_iface;
1063 TRACE("Created sample %p.\n", *sample);
1065 return S_OK;
1068 /***********************************************************************
1069 * MFCreateTrackedSample (mfplat.@)
1071 HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
1073 struct sample *object;
1074 HRESULT hr;
1076 TRACE("%p.\n", sample);
1078 if (!(object = calloc(1, sizeof(*object))))
1079 return E_OUTOFMEMORY;
1081 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1083 free(object);
1084 return hr;
1087 object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
1088 object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
1090 *sample = &object->IMFTrackedSample_iface;
1092 return S_OK;
1095 static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocatorEx *iface, REFIID riid, void **obj)
1097 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1099 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1101 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorEx) ||
1102 IsEqualIID(riid, &IID_IMFVideoSampleAllocator) ||
1103 IsEqualIID(riid, &IID_IUnknown))
1105 *obj = &allocator->IMFVideoSampleAllocatorEx_iface;
1107 else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback))
1109 *obj = &allocator->IMFVideoSampleAllocatorCallback_iface;
1111 else
1113 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1114 *obj = NULL;
1115 return E_NOINTERFACE;
1118 IUnknown_AddRef((IUnknown *)*obj);
1119 return S_OK;
1122 static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocatorEx *iface)
1124 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1125 ULONG refcount = InterlockedIncrement(&allocator->refcount);
1127 TRACE("%p, refcount %lu.\n", iface, refcount);
1129 return refcount;
1132 static void sample_allocator_release_samples(struct sample_allocator *allocator)
1134 struct queued_sample *iter, *iter2;
1136 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry)
1138 list_remove(&iter->entry);
1139 IMFSample_Release(iter->sample);
1140 free(iter);
1143 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry)
1145 list_remove(&iter->entry);
1146 free(iter);
1149 allocator->free_sample_count = 0;
1150 allocator->cold_sample_count = 0;
1153 static void sample_allocator_set_media_type(struct sample_allocator *allocator, IMFMediaType *media_type)
1155 UINT64 frame_size;
1156 GUID subtype;
1158 if (!media_type)
1160 if (allocator->media_type)
1161 IMFMediaType_Release(allocator->media_type);
1162 allocator->media_type = NULL;
1163 return;
1166 /* Check if type is the same. */
1167 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size);
1168 IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1170 if (frame_size == ((UINT64) allocator->frame_desc.width << 32 | allocator->frame_desc.height) &&
1171 subtype.Data1 == allocator->frame_desc.d3d9_format)
1173 return;
1176 if (allocator->media_type)
1177 IMFMediaType_Release(allocator->media_type);
1178 allocator->media_type = media_type;
1179 if (allocator->media_type)
1180 IMFMediaType_AddRef(allocator->media_type);
1183 static void sample_allocator_set_attributes(struct sample_allocator *allocator, IMFAttributes *attributes)
1185 if (allocator->attributes)
1186 IMFAttributes_Release(allocator->attributes);
1187 allocator->attributes = attributes;
1188 if (allocator->attributes)
1189 IMFAttributes_AddRef(allocator->attributes);
1192 static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocatorEx *iface)
1194 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1195 ULONG refcount = InterlockedDecrement(&allocator->refcount);
1197 TRACE("%p, refcount %lu.\n", iface, refcount);
1199 if (!refcount)
1201 if (allocator->callback)
1202 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1203 if (allocator->d3d9_device_manager)
1204 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1205 if (allocator->dxgi_device_manager)
1206 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1207 sample_allocator_set_media_type(allocator, NULL);
1208 sample_allocator_set_attributes(allocator, NULL);
1209 sample_allocator_release_samples(allocator);
1210 DeleteCriticalSection(&allocator->cs);
1211 free(allocator);
1214 return refcount;
1217 static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocatorEx *iface,
1218 IUnknown *manager)
1220 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1221 IDirect3DDeviceManager9 *d3d9_device_manager = NULL;
1222 IMFDXGIDeviceManager *dxgi_device_manager = NULL;
1223 HRESULT hr;
1225 TRACE("%p, %p.\n", iface, manager);
1227 if (manager)
1229 if (FAILED(hr = IUnknown_QueryInterface(manager, &IID_IMFDXGIDeviceManager, (void **)&dxgi_device_manager)))
1231 hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9, (void **)&d3d9_device_manager);
1234 if (FAILED(hr))
1235 return hr;
1238 EnterCriticalSection(&allocator->cs);
1240 if (allocator->d3d9_device_manager)
1241 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1242 if (allocator->dxgi_device_manager)
1243 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1244 allocator->d3d9_device_manager = NULL;
1245 allocator->dxgi_device_manager = NULL;
1247 if (dxgi_device_manager)
1248 allocator->dxgi_device_manager = dxgi_device_manager;
1249 else if (d3d9_device_manager)
1250 allocator->d3d9_device_manager = d3d9_device_manager;
1252 LeaveCriticalSection(&allocator->cs);
1254 return S_OK;
1257 static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface)
1259 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1261 TRACE("%p.\n", iface);
1263 EnterCriticalSection(&allocator->cs);
1265 sample_allocator_release_samples(allocator);
1266 sample_allocator_set_media_type(allocator, NULL);
1267 sample_allocator_set_attributes(allocator, NULL);
1268 memset(&allocator->frame_desc, 0, sizeof(allocator->frame_desc));
1270 LeaveCriticalSection(&allocator->cs);
1272 return S_OK;
1275 struct surface_service
1277 IDirectXVideoProcessorService *dxva_service;
1278 ID3D11Device *d3d11_device;
1279 HANDLE hdevice;
1282 static HRESULT sample_allocator_get_surface_service(struct sample_allocator *allocator, struct surface_service *service)
1284 HRESULT hr = S_OK;
1286 memset(service, 0, sizeof(*service));
1288 if (allocator->d3d9_device_manager)
1290 if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->d3d9_device_manager, &service->hdevice)))
1292 if (FAILED(hr = IDirect3DDeviceManager9_GetVideoService(allocator->d3d9_device_manager, service->hdevice,
1293 &IID_IDirectXVideoProcessorService, (void **)&service->dxva_service)))
1295 WARN("Failed to get DXVA processor service, hr %#lx.\n", hr);
1296 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1300 else if (allocator->dxgi_device_manager)
1302 if (SUCCEEDED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(allocator->dxgi_device_manager, &service->hdevice)))
1304 if (FAILED(hr = IMFDXGIDeviceManager_GetVideoService(allocator->dxgi_device_manager, service->hdevice,
1305 &IID_ID3D11Device, (void **)&service->d3d11_device)))
1307 WARN("Failed to get D3D11 device, hr %#lx.\n", hr);
1308 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1313 if (FAILED(hr))
1314 memset(service, 0, sizeof(*service));
1316 return hr;
1319 static void sample_allocator_release_surface_service(struct sample_allocator *allocator,
1320 struct surface_service *service)
1322 if (service->dxva_service)
1323 IDirectXVideoProcessorService_Release(service->dxva_service);
1324 if (service->d3d11_device)
1325 ID3D11Device_Release(service->d3d11_device);
1327 if (allocator->d3d9_device_manager)
1328 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1329 else if (allocator->dxgi_device_manager)
1330 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1333 static HRESULT sample_allocator_allocate_sample(struct sample_allocator *allocator, const struct surface_service *service,
1334 struct queued_sample **queued_sample)
1336 IMFTrackedSample *tracked_sample;
1337 IMFMediaBuffer *buffer;
1338 IMFSample *sample;
1339 unsigned int i;
1340 HRESULT hr;
1342 if (FAILED(hr = MFCreateTrackedSample(&tracked_sample)))
1343 return hr;
1345 IMFTrackedSample_QueryInterface(tracked_sample, &IID_IMFSample, (void **)&sample);
1346 IMFTrackedSample_Release(tracked_sample);
1348 for (i = 0; i < allocator->frame_desc.buffer_count; ++i)
1350 if (service->dxva_service)
1352 IDirect3DSurface9 *surface;
1354 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service->dxva_service, allocator->frame_desc.width,
1355 allocator->frame_desc.height, 0, allocator->frame_desc.d3d9_format, D3DPOOL_DEFAULT, 0,
1356 DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
1358 hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer);
1359 IDirect3DSurface9_Release(surface);
1362 else if (service->d3d11_device)
1364 D3D11_TEXTURE2D_DESC desc = { 0 };
1365 ID3D11Texture2D *texture;
1367 desc.Width = allocator->frame_desc.width;
1368 desc.Height = allocator->frame_desc.height;
1369 desc.MipLevels = 1;
1370 desc.ArraySize = 1;
1371 desc.Format = allocator->frame_desc.dxgi_format;
1372 desc.SampleDesc.Count = 1;
1373 desc.SampleDesc.Quality = 0;
1374 desc.Usage = allocator->frame_desc.usage;
1375 desc.BindFlags = allocator->frame_desc.bindflags;
1376 if (desc.Usage == D3D11_USAGE_DYNAMIC)
1377 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1378 else if (desc.Usage == D3D11_USAGE_STAGING)
1379 desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE | D3D11_CPU_ACCESS_READ;
1380 desc.MiscFlags = allocator->frame_desc.miscflags;
1382 if (SUCCEEDED(hr = ID3D11Device_CreateTexture2D(service->d3d11_device, &desc, NULL, &texture)))
1384 hr = MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer);
1385 ID3D11Texture2D_Release(texture);
1388 else
1390 hr = MFCreate2DMediaBuffer(allocator->frame_desc.width, allocator->frame_desc.height,
1391 allocator->frame_desc.d3d9_format, FALSE, &buffer);
1394 if (SUCCEEDED(hr))
1396 hr = IMFSample_AddBuffer(sample, buffer);
1397 IMFMediaBuffer_Release(buffer);
1401 if (FAILED(hr))
1403 IMFSample_Release(sample);
1404 return hr;
1407 if (!(*queued_sample = malloc(sizeof(**queued_sample))))
1409 IMFSample_Release(sample);
1410 return E_OUTOFMEMORY;
1412 (*queued_sample)->sample = sample;
1414 return hr;
1417 static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, unsigned int sample_count,
1418 unsigned int max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1420 struct surface_service service;
1421 struct queued_sample *sample;
1422 DXGI_FORMAT dxgi_format;
1423 unsigned int i, value;
1424 GUID major, subtype;
1425 UINT64 frame_size;
1426 D3D11_USAGE usage;
1427 HRESULT hr;
1429 if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major)))
1430 return hr;
1432 if (!IsEqualGUID(&major, &MFMediaType_Video))
1433 return MF_E_INVALIDMEDIATYPE;
1435 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
1436 return hr;
1438 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
1439 return hr;
1441 if (sample_count > max_sample_count)
1442 return E_INVALIDARG;
1444 usage = D3D11_USAGE_DEFAULT;
1445 if (attributes)
1447 IMFAttributes_GetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, &allocator->frame_desc.buffer_count);
1448 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_USAGE, &usage);
1451 if (usage == D3D11_USAGE_IMMUTABLE || usage > D3D11_USAGE_STAGING)
1452 return E_INVALIDARG;
1454 dxgi_format = MFMapDX9FormatToDXGIFormat(subtype.Data1);
1456 allocator->frame_desc.bindflags = 0;
1457 allocator->frame_desc.miscflags = 0;
1458 allocator->frame_desc.usage = D3D11_USAGE_DEFAULT;
1460 if (dxgi_format == DXGI_FORMAT_B8G8R8A8_UNORM ||
1461 dxgi_format == DXGI_FORMAT_B8G8R8X8_UNORM)
1463 allocator->frame_desc.usage = usage;
1464 if (allocator->frame_desc.usage == D3D11_USAGE_DEFAULT)
1465 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
1466 else if (allocator->frame_desc.usage == D3D11_USAGE_DYNAMIC)
1467 allocator->frame_desc.bindflags = D3D11_BIND_SHADER_RESOURCE;
1470 if (attributes)
1472 IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_BINDFLAGS, &allocator->frame_desc.bindflags);
1473 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_SHARED, &value)) && value)
1474 allocator->frame_desc.miscflags |= D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX;
1475 if (SUCCEEDED(IMFAttributes_GetUINT32(attributes, &MF_SA_D3D11_SHARED_WITHOUT_MUTEX, &value)) && value)
1476 allocator->frame_desc.miscflags |= D3D11_RESOURCE_MISC_SHARED;
1479 sample_allocator_set_media_type(allocator, media_type);
1480 sample_allocator_set_attributes(allocator, attributes);
1482 sample_count = max(1, sample_count);
1483 max_sample_count = max(1, max_sample_count);
1485 allocator->frame_desc.d3d9_format = subtype.Data1;
1486 allocator->frame_desc.dxgi_format = dxgi_format;
1487 allocator->frame_desc.width = frame_size >> 32;
1488 allocator->frame_desc.height = frame_size;
1489 allocator->frame_desc.buffer_count = max(1, allocator->frame_desc.buffer_count);
1491 if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service)))
1492 return hr;
1494 sample_allocator_release_samples(allocator);
1496 for (i = 0; i < sample_count; ++i)
1498 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1500 list_add_tail(&allocator->free_samples, &sample->entry);
1501 allocator->free_sample_count++;
1504 allocator->cold_sample_count = max_sample_count - allocator->free_sample_count;
1506 sample_allocator_release_surface_service(allocator, &service);
1508 return hr;
1511 static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface,
1512 DWORD sample_count, IMFMediaType *media_type)
1514 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1515 HRESULT hr;
1517 TRACE("%p, %lu, %p.\n", iface, sample_count, media_type);
1519 if (!sample_count)
1520 return E_INVALIDARG;
1522 EnterCriticalSection(&allocator->cs);
1524 hr = sample_allocator_initialize(allocator, sample_count, sample_count, NULL, media_type);
1526 LeaveCriticalSection(&allocator->cs);
1528 return hr;
1531 static HRESULT sample_allocator_track_sample(struct sample_allocator *allocator, IMFSample *sample)
1533 IMFTrackedSample *tracked_sample;
1534 HRESULT hr;
1536 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
1538 hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
1539 IMFTrackedSample_Release(tracked_sample);
1542 return hr;
1545 static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx *iface, IMFSample **out)
1547 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1548 struct queued_sample *sample;
1549 HRESULT hr;
1551 TRACE("%p, %p.\n", iface, out);
1553 EnterCriticalSection(&allocator->cs);
1555 if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples))
1556 hr = MF_E_NOT_INITIALIZED;
1557 else if (list_empty(&allocator->free_samples) && !allocator->cold_sample_count)
1558 hr = MF_E_SAMPLEALLOCATOR_EMPTY;
1559 else if (!list_empty(&allocator->free_samples))
1561 struct list *head = list_head(&allocator->free_samples);
1563 sample = LIST_ENTRY(head, struct queued_sample, entry);
1565 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample->sample)))
1567 list_remove(head);
1568 list_add_tail(&allocator->used_samples, head);
1569 allocator->free_sample_count--;
1571 /* Reference counter is not increased when sample is returned, so next release could trigger
1572 tracking condition. This is balanced by incremented reference counter when sample is returned
1573 back to the free list. */
1574 *out = sample->sample;
1577 else /* allocator->cold_sample_count != 0 */
1579 struct surface_service service;
1581 if (SUCCEEDED(hr = sample_allocator_get_surface_service(allocator, &service)))
1583 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1585 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample->sample)))
1587 list_add_tail(&allocator->used_samples, &sample->entry);
1588 allocator->cold_sample_count--;
1590 *out = sample->sample;
1592 else
1594 IMFSample_Release(sample->sample);
1595 free(sample);
1599 sample_allocator_release_surface_service(allocator, &service);
1603 LeaveCriticalSection(&allocator->cs);
1605 return hr;
1608 static HRESULT WINAPI sample_allocator_InitializeSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface, DWORD initial_sample_count,
1609 DWORD max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1611 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1612 HRESULT hr;
1614 TRACE("%p, %lu, %lu, %p, %p.\n", iface, initial_sample_count, max_sample_count, attributes, media_type);
1616 EnterCriticalSection(&allocator->cs);
1618 hr = sample_allocator_initialize(allocator, initial_sample_count, max_sample_count, attributes, media_type);
1620 LeaveCriticalSection(&allocator->cs);
1622 return hr;
1625 static const IMFVideoSampleAllocatorExVtbl sample_allocator_vtbl =
1627 sample_allocator_QueryInterface,
1628 sample_allocator_AddRef,
1629 sample_allocator_Release,
1630 sample_allocator_SetDirectXManager,
1631 sample_allocator_UninitializeSampleAllocator,
1632 sample_allocator_InitializeSampleAllocator,
1633 sample_allocator_AllocateSample,
1634 sample_allocator_InitializeSampleAllocatorEx,
1637 static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface,
1638 REFIID riid, void **obj)
1640 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1641 return IMFVideoSampleAllocatorEx_QueryInterface(&allocator->IMFVideoSampleAllocatorEx_iface, riid, obj);
1644 static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface)
1646 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1647 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1650 static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface)
1652 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1653 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1656 static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface,
1657 IMFVideoSampleAllocatorNotify *callback)
1659 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1661 TRACE("%p, %p.\n", iface, callback);
1663 EnterCriticalSection(&allocator->cs);
1664 if (allocator->callback)
1665 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1666 allocator->callback = callback;
1667 if (allocator->callback)
1668 IMFVideoSampleAllocatorNotify_AddRef(allocator->callback);
1669 LeaveCriticalSection(&allocator->cs);
1671 return S_OK;
1674 static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface,
1675 LONG *count)
1677 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1679 TRACE("%p, %p.\n", iface, count);
1681 if (!count)
1682 return E_POINTER;
1684 EnterCriticalSection(&allocator->cs);
1685 *count = allocator->free_sample_count;
1686 LeaveCriticalSection(&allocator->cs);
1688 return S_OK;
1691 static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl =
1693 sample_allocator_callback_QueryInterface,
1694 sample_allocator_callback_AddRef,
1695 sample_allocator_callback_Release,
1696 sample_allocator_callback_SetCallback,
1697 sample_allocator_callback_GetFreeSampleCount,
1700 static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface,
1701 REFIID riid, void **obj)
1703 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1704 IsEqualIID(riid, &IID_IUnknown))
1706 *obj = iface;
1707 IMFAsyncCallback_AddRef(iface);
1708 return S_OK;
1711 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1712 *obj = NULL;
1713 return E_NOINTERFACE;
1716 static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface)
1718 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1719 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1722 static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
1724 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1725 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1728 static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface,
1729 DWORD *flags, DWORD *queue)
1731 return E_NOTIMPL;
1734 static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1736 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1737 struct queued_sample *iter;
1738 IUnknown *object = NULL;
1739 IMFSample *sample = NULL;
1740 HRESULT hr;
1742 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
1743 return E_UNEXPECTED;
1745 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
1746 IUnknown_Release(object);
1747 if (FAILED(hr))
1748 return E_UNEXPECTED;
1750 EnterCriticalSection(&allocator->cs);
1752 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
1754 if (sample == iter->sample)
1756 list_remove(&iter->entry);
1757 list_add_tail(&allocator->free_samples, &iter->entry);
1758 IMFSample_AddRef(iter->sample);
1759 allocator->free_sample_count++;
1760 break;
1764 IMFSample_Release(sample);
1766 if (allocator->callback)
1767 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
1769 LeaveCriticalSection(&allocator->cs);
1771 return S_OK;
1774 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
1776 sample_allocator_tracking_callback_QueryInterface,
1777 sample_allocator_tracking_callback_AddRef,
1778 sample_allocator_tracking_callback_Release,
1779 sample_allocator_tracking_callback_GetParameters,
1780 sample_allocator_tracking_callback_Invoke,
1783 /***********************************************************************
1784 * MFCreateVideoSampleAllocatorEx (mfplat.@)
1786 HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj)
1788 struct sample_allocator *object;
1789 HRESULT hr;
1791 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1793 if (!(object = calloc(1, sizeof(*object))))
1794 return E_OUTOFMEMORY;
1796 object->IMFVideoSampleAllocatorEx_iface.lpVtbl = &sample_allocator_vtbl;
1797 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
1798 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
1799 object->refcount = 1;
1800 list_init(&object->used_samples);
1801 list_init(&object->free_samples);
1802 InitializeCriticalSection(&object->cs);
1804 hr = IMFVideoSampleAllocatorEx_QueryInterface(&object->IMFVideoSampleAllocatorEx_iface, riid, obj);
1805 IMFVideoSampleAllocatorEx_Release(&object->IMFVideoSampleAllocatorEx_iface);
1807 return hr;