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