mfplat: Handle tracked sample release condition separately from refcount update.
[wine.git] / dlls / mfplat / sample.c
blob82e7c8680ddbcd7016ccca0dce2f57527a5c96aa
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 buffer_count;
76 } frame_desc;
78 IMFAttributes *attributes;
79 IMFMediaType *media_type;
81 unsigned int free_sample_count;
82 unsigned int cold_sample_count;
83 struct list free_samples;
84 struct list used_samples;
85 CRITICAL_SECTION cs;
88 struct queued_sample
90 struct list entry;
91 IMFSample *sample;
94 static struct sample_allocator *impl_from_IMFVideoSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface)
96 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorEx_iface);
99 static struct sample_allocator *impl_from_IMFVideoSampleAllocatorCallback(IMFVideoSampleAllocatorCallback *iface)
101 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorCallback_iface);
104 static struct sample_allocator *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
106 return CONTAINING_RECORD(iface, struct sample_allocator, tracking_callback);
109 static struct sample *impl_from_IMFSample(IMFSample *iface)
111 return CONTAINING_RECORD(iface, struct sample, IMFSample_iface);
114 static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
116 return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface);
119 static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
121 struct sample *sample = impl_from_IMFSample(iface);
123 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
125 if (IsEqualIID(riid, &IID_IMFSample) ||
126 IsEqualIID(riid, &IID_IMFAttributes) ||
127 IsEqualIID(riid, &IID_IUnknown))
129 *out = &sample->IMFSample_iface;
131 else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample))
133 *out = &sample->IMFTrackedSample_iface;
135 else
137 WARN("Unsupported %s.\n", debugstr_guid(riid));
138 *out = NULL;
139 return E_NOINTERFACE;
142 IUnknown_AddRef((IUnknown *)*out);
143 return S_OK;
146 static ULONG WINAPI sample_AddRef(IMFSample *iface)
148 struct sample *sample = impl_from_IMFSample(iface);
149 ULONG refcount = InterlockedIncrement(&sample->attributes.ref);
151 TRACE("%p, refcount %u.\n", iface, refcount);
153 return refcount;
156 static void release_sample_object(struct sample *sample)
158 size_t i;
160 for (i = 0; i < sample->buffer_count; ++i)
161 IMFMediaBuffer_Release(sample->buffers[i]);
162 clear_attributes_object(&sample->attributes);
163 heap_free(sample->buffers);
164 heap_free(sample);
167 static ULONG WINAPI sample_Release(IMFSample *iface)
169 struct sample *sample = impl_from_IMFSample(iface);
170 ULONG refcount = InterlockedDecrement(&sample->attributes.ref);
172 TRACE("%p, refcount %u.\n", iface, refcount);
174 if (!refcount)
175 release_sample_object(sample);
177 return refcount;
180 static ULONG WINAPI sample_tracked_Release(IMFSample *iface)
182 struct sample *sample = impl_from_IMFSample(iface);
183 ULONG refcount;
184 HRESULT hr;
186 EnterCriticalSection(&sample->attributes.cs);
187 if (sample->tracked_result && sample->tracked_refcount == (sample->attributes.ref - 1))
189 IRtwqAsyncResult *tracked_result = sample->tracked_result;
190 sample->tracked_result = NULL;
191 sample->tracked_refcount = 0;
193 /* Call could fail if queue system is not initialized, it's not critical. */
194 if (FAILED(hr = RtwqInvokeCallback(tracked_result)))
195 WARN("Failed to invoke tracking callback, hr %#x.\n", hr);
196 IRtwqAsyncResult_Release(tracked_result);
198 LeaveCriticalSection(&sample->attributes.cs);
200 refcount = InterlockedDecrement(&sample->attributes.ref);
202 TRACE("%p, refcount %u.\n", iface, refcount);
204 if (!refcount)
205 release_sample_object(sample);
207 return refcount;
210 static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
212 struct sample *sample = impl_from_IMFSample(iface);
214 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
216 return attributes_GetItem(&sample->attributes, key, value);
219 static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
221 struct sample *sample = impl_from_IMFSample(iface);
223 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type);
225 return attributes_GetItemType(&sample->attributes, key, type);
228 static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
230 struct sample *sample = impl_from_IMFSample(iface);
232 TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result);
234 return attributes_CompareItem(&sample->attributes, key, value, result);
237 static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
238 BOOL *result)
240 struct sample *sample = impl_from_IMFSample(iface);
242 TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
244 return attributes_Compare(&sample->attributes, theirs, type, result);
247 static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
249 struct sample *sample = impl_from_IMFSample(iface);
251 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
253 return attributes_GetUINT32(&sample->attributes, key, value);
256 static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
258 struct sample *sample = impl_from_IMFSample(iface);
260 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
262 return attributes_GetUINT64(&sample->attributes, key, value);
265 static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
267 struct sample *sample = impl_from_IMFSample(iface);
269 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
271 return attributes_GetDouble(&sample->attributes, key, value);
274 static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
276 struct sample *sample = impl_from_IMFSample(iface);
278 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value);
280 return attributes_GetGUID(&sample->attributes, key, value);
283 static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
285 struct sample *sample = impl_from_IMFSample(iface);
287 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length);
289 return attributes_GetStringLength(&sample->attributes, key, length);
292 static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
294 struct sample *sample = impl_from_IMFSample(iface);
296 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length);
298 return attributes_GetString(&sample->attributes, key, value, size, length);
301 static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
303 struct sample *sample = impl_from_IMFSample(iface);
305 TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length);
307 return attributes_GetAllocatedString(&sample->attributes, key, value, length);
310 static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
312 struct sample *sample = impl_from_IMFSample(iface);
314 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size);
316 return attributes_GetBlobSize(&sample->attributes, key, size);
319 static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
321 struct sample *sample = impl_from_IMFSample(iface);
323 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize);
325 return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize);
328 static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
330 struct sample *sample = impl_from_IMFSample(iface);
332 TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size);
334 return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size);
337 static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
339 struct sample *sample = impl_from_IMFSample(iface);
341 TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out);
343 return attributes_GetUnknown(&sample->attributes, key, riid, out);
346 static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
348 struct sample *sample = impl_from_IMFSample(iface);
350 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value));
352 return attributes_SetItem(&sample->attributes, key, value);
355 static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key)
357 struct sample *sample = impl_from_IMFSample(iface);
359 TRACE("%p, %s.\n", iface, debugstr_attr(key));
361 return attributes_DeleteItem(&sample->attributes, key);
364 static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface)
366 struct sample *sample = impl_from_IMFSample(iface);
368 TRACE("%p.\n", iface);
370 return attributes_DeleteAllItems(&sample->attributes);
373 static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
375 struct sample *sample = impl_from_IMFSample(iface);
377 TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value);
379 return attributes_SetUINT32(&sample->attributes, key, value);
382 static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
384 struct sample *sample = impl_from_IMFSample(iface);
386 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value));
388 return attributes_SetUINT64(&sample->attributes, key, value);
391 static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value)
393 struct sample *sample = impl_from_IMFSample(iface);
395 TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value);
397 return attributes_SetDouble(&sample->attributes, key, value);
400 static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
402 struct sample *sample = impl_from_IMFSample(iface);
404 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value));
406 return attributes_SetGUID(&sample->attributes, key, value);
409 static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
411 struct sample *sample = impl_from_IMFSample(iface);
413 TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value));
415 return attributes_SetString(&sample->attributes, key, value);
418 static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
420 struct sample *sample = impl_from_IMFSample(iface);
422 TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size);
424 return attributes_SetBlob(&sample->attributes, key, buf, size);
427 static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
429 struct sample *sample = impl_from_IMFSample(iface);
431 TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown);
433 return attributes_SetUnknown(&sample->attributes, key, unknown);
436 static HRESULT WINAPI sample_LockStore(IMFSample *iface)
438 struct sample *sample = impl_from_IMFSample(iface);
440 TRACE("%p.\n", iface);
442 return attributes_LockStore(&sample->attributes);
445 static HRESULT WINAPI sample_UnlockStore(IMFSample *iface)
447 struct sample *sample = impl_from_IMFSample(iface);
449 TRACE("%p.\n", iface);
451 return attributes_UnlockStore(&sample->attributes);
454 static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count)
456 struct sample *sample = impl_from_IMFSample(iface);
458 TRACE("%p, %p.\n", iface, count);
460 return attributes_GetCount(&sample->attributes, count);
463 static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
465 struct sample *sample = impl_from_IMFSample(iface);
467 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
469 return attributes_GetItemByIndex(&sample->attributes, index, key, value);
472 static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
474 struct sample *sample = impl_from_IMFSample(iface);
476 TRACE("%p, %p.\n", iface, dest);
478 return attributes_CopyAllItems(&sample->attributes, dest);
481 static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
483 struct sample *sample = impl_from_IMFSample(iface);
485 TRACE("%p, %p.\n", iface, flags);
487 EnterCriticalSection(&sample->attributes.cs);
488 *flags = sample->flags;
489 LeaveCriticalSection(&sample->attributes.cs);
491 return S_OK;
494 static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags)
496 struct sample *sample = impl_from_IMFSample(iface);
498 TRACE("%p, %#x.\n", iface, flags);
500 EnterCriticalSection(&sample->attributes.cs);
501 sample->flags = flags;
502 LeaveCriticalSection(&sample->attributes.cs);
504 return S_OK;
507 static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
509 struct sample *sample = impl_from_IMFSample(iface);
510 HRESULT hr = S_OK;
512 TRACE("%p, %p.\n", iface, timestamp);
514 EnterCriticalSection(&sample->attributes.cs);
515 if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP)
516 *timestamp = sample->timestamp;
517 else
518 hr = MF_E_NO_SAMPLE_TIMESTAMP;
519 LeaveCriticalSection(&sample->attributes.cs);
521 return hr;
524 static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
526 struct sample *sample = impl_from_IMFSample(iface);
528 TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
530 EnterCriticalSection(&sample->attributes.cs);
531 sample->timestamp = timestamp;
532 sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP;
533 LeaveCriticalSection(&sample->attributes.cs);
535 return S_OK;
538 static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
540 struct sample *sample = impl_from_IMFSample(iface);
541 HRESULT hr = S_OK;
543 TRACE("%p, %p.\n", iface, duration);
545 EnterCriticalSection(&sample->attributes.cs);
546 if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION)
547 *duration = sample->duration;
548 else
549 hr = MF_E_NO_SAMPLE_DURATION;
550 LeaveCriticalSection(&sample->attributes.cs);
552 return hr;
555 static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
557 struct sample *sample = impl_from_IMFSample(iface);
559 TRACE("%p, %s.\n", iface, debugstr_time(duration));
561 EnterCriticalSection(&sample->attributes.cs);
562 sample->duration = duration;
563 sample->prop_flags |= SAMPLE_PROP_HAS_DURATION;
564 LeaveCriticalSection(&sample->attributes.cs);
566 return S_OK;
569 static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count)
571 struct sample *sample = impl_from_IMFSample(iface);
573 TRACE("%p, %p.\n", iface, count);
575 if (!count)
576 return E_INVALIDARG;
578 EnterCriticalSection(&sample->attributes.cs);
579 *count = sample->buffer_count;
580 LeaveCriticalSection(&sample->attributes.cs);
582 return S_OK;
585 static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
587 struct sample *sample = impl_from_IMFSample(iface);
588 HRESULT hr = S_OK;
590 TRACE("%p, %u, %p.\n", iface, index, buffer);
592 EnterCriticalSection(&sample->attributes.cs);
593 if (index < sample->buffer_count)
595 *buffer = sample->buffers[index];
596 IMFMediaBuffer_AddRef(*buffer);
598 else
599 hr = E_INVALIDARG;
600 LeaveCriticalSection(&sample->attributes.cs);
602 return hr;
605 static unsigned int sample_get_total_length(struct sample *sample)
607 DWORD total_length = 0, length;
608 size_t i;
610 for (i = 0; i < sample->buffer_count; ++i)
612 length = 0;
613 if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length)))
614 total_length += length;
617 return total_length;
620 static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer)
622 DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
623 BYTE *src_ptr, *dst_ptr;
624 BOOL locked;
625 HRESULT hr;
626 size_t i;
628 total_length = sample_get_total_length(sample);
629 dst_current_length = 0;
631 dst_ptr = NULL;
632 dst_length = current_length = 0;
633 locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
634 if (locked)
636 if (dst_length < total_length)
637 hr = MF_E_BUFFERTOOSMALL;
638 else if (dst_ptr)
640 for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
642 src_ptr = NULL;
643 src_max_length = current_length = 0;
644 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
646 if (src_ptr)
648 if (current_length > dst_length)
649 hr = MF_E_BUFFERTOOSMALL;
650 else if (current_length)
652 memcpy(dst_ptr, src_ptr, current_length);
653 dst_length -= current_length;
654 dst_current_length += current_length;
655 dst_ptr += current_length;
658 IMFMediaBuffer_Unlock(sample->buffers[i]);
664 if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length)))
665 WARN("Failed to set buffer length.\n");
667 if (locked)
668 IMFMediaBuffer_Unlock(buffer);
670 return hr;
673 static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
675 struct sample *sample = impl_from_IMFSample(iface);
676 unsigned int total_length, i;
677 IMFMediaBuffer *dest_buffer;
678 HRESULT hr = S_OK;
680 TRACE("%p, %p.\n", iface, buffer);
682 EnterCriticalSection(&sample->attributes.cs);
684 if (sample->buffer_count == 0)
685 hr = E_UNEXPECTED;
686 else if (sample->buffer_count > 1)
688 total_length = sample_get_total_length(sample);
689 if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer)))
691 if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer)))
693 for (i = 0; i < sample->buffer_count; ++i)
694 IMFMediaBuffer_Release(sample->buffers[i]);
696 sample->buffers[0] = dest_buffer;
697 IMFMediaBuffer_AddRef(sample->buffers[0]);
699 sample->buffer_count = 1;
701 IMFMediaBuffer_Release(dest_buffer);
705 if (SUCCEEDED(hr) && buffer)
707 *buffer = sample->buffers[0];
708 IMFMediaBuffer_AddRef(*buffer);
711 LeaveCriticalSection(&sample->attributes.cs);
713 return hr;
716 static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
718 struct sample *sample = impl_from_IMFSample(iface);
719 HRESULT hr = S_OK;
721 TRACE("%p, %p.\n", iface, buffer);
723 EnterCriticalSection(&sample->attributes.cs);
724 if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1,
725 sizeof(*sample->buffers)))
726 hr = E_OUTOFMEMORY;
727 else
729 sample->buffers[sample->buffer_count++] = buffer;
730 IMFMediaBuffer_AddRef(buffer);
732 LeaveCriticalSection(&sample->attributes.cs);
734 return hr;
737 static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
739 struct sample *sample = impl_from_IMFSample(iface);
740 HRESULT hr = S_OK;
742 TRACE("%p, %u.\n", iface, index);
744 EnterCriticalSection(&sample->attributes.cs);
745 if (index < sample->buffer_count)
747 IMFMediaBuffer_Release(sample->buffers[index]);
748 if (index < sample->buffer_count - 1)
750 memmove(&sample->buffers[index], &sample->buffers[index+1],
751 (sample->buffer_count - index - 1) * sizeof(*sample->buffers));
753 sample->buffer_count--;
755 else
756 hr = E_INVALIDARG;
757 LeaveCriticalSection(&sample->attributes.cs);
759 return hr;
762 static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface)
764 struct sample *sample = impl_from_IMFSample(iface);
765 size_t i;
767 TRACE("%p.\n", iface);
769 EnterCriticalSection(&sample->attributes.cs);
770 for (i = 0; i < sample->buffer_count; ++i)
771 IMFMediaBuffer_Release(sample->buffers[i]);
772 sample->buffer_count = 0;
773 LeaveCriticalSection(&sample->attributes.cs);
775 return S_OK;
778 static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
780 struct sample *sample = impl_from_IMFSample(iface);
782 TRACE("%p, %p.\n", iface, total_length);
784 EnterCriticalSection(&sample->attributes.cs);
785 *total_length = sample_get_total_length(sample);
786 LeaveCriticalSection(&sample->attributes.cs);
788 return S_OK;
791 static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
793 struct sample *sample = impl_from_IMFSample(iface);
794 DWORD total_length, dst_length, dst_current_length, src_max_length, current_length;
795 BYTE *src_ptr, *dst_ptr;
796 BOOL locked;
797 HRESULT hr;
798 size_t i;
800 TRACE("%p, %p.\n", iface, buffer);
802 EnterCriticalSection(&sample->attributes.cs);
804 total_length = sample_get_total_length(sample);
805 dst_current_length = 0;
807 dst_ptr = NULL;
808 dst_length = current_length = 0;
809 locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, &current_length));
810 if (locked)
812 if (dst_length < total_length)
813 hr = MF_E_BUFFERTOOSMALL;
814 else if (dst_ptr)
816 for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i)
818 src_ptr = NULL;
819 src_max_length = current_length = 0;
820 if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, &current_length)))
822 if (src_ptr)
824 if (current_length > dst_length)
825 hr = MF_E_BUFFERTOOSMALL;
826 else if (current_length)
828 memcpy(dst_ptr, src_ptr, current_length);
829 dst_length -= current_length;
830 dst_current_length += current_length;
831 dst_ptr += current_length;
834 IMFMediaBuffer_Unlock(sample->buffers[i]);
840 IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length);
842 if (locked)
843 IMFMediaBuffer_Unlock(buffer);
845 LeaveCriticalSection(&sample->attributes.cs);
847 return hr;
850 static const IMFSampleVtbl samplevtbl =
852 sample_QueryInterface,
853 sample_AddRef,
854 sample_Release,
855 sample_GetItem,
856 sample_GetItemType,
857 sample_CompareItem,
858 sample_Compare,
859 sample_GetUINT32,
860 sample_GetUINT64,
861 sample_GetDouble,
862 sample_GetGUID,
863 sample_GetStringLength,
864 sample_GetString,
865 sample_GetAllocatedString,
866 sample_GetBlobSize,
867 sample_GetBlob,
868 sample_GetAllocatedBlob,
869 sample_GetUnknown,
870 sample_SetItem,
871 sample_DeleteItem,
872 sample_DeleteAllItems,
873 sample_SetUINT32,
874 sample_SetUINT64,
875 sample_SetDouble,
876 sample_SetGUID,
877 sample_SetString,
878 sample_SetBlob,
879 sample_SetUnknown,
880 sample_LockStore,
881 sample_UnlockStore,
882 sample_GetCount,
883 sample_GetItemByIndex,
884 sample_CopyAllItems,
885 sample_GetSampleFlags,
886 sample_SetSampleFlags,
887 sample_GetSampleTime,
888 sample_SetSampleTime,
889 sample_GetSampleDuration,
890 sample_SetSampleDuration,
891 sample_GetBufferCount,
892 sample_GetBufferByIndex,
893 sample_ConvertToContiguousBuffer,
894 sample_AddBuffer,
895 sample_RemoveBufferByIndex,
896 sample_RemoveAllBuffers,
897 sample_GetTotalLength,
898 sample_CopyToBuffer,
901 static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
903 struct sample *sample = impl_from_IMFTrackedSample(iface);
904 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
907 static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface)
909 struct sample *sample = impl_from_IMFTrackedSample(iface);
910 return IMFSample_AddRef(&sample->IMFSample_iface);
913 static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface)
915 struct sample *sample = impl_from_IMFTrackedSample(iface);
916 return IMFSample_Release(&sample->IMFSample_iface);
919 static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface,
920 IMFAsyncCallback *sample_allocator, IUnknown *state)
922 struct sample *sample = impl_from_IMFTrackedSample(iface);
923 HRESULT hr = S_OK;
925 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
927 EnterCriticalSection(&sample->attributes.cs);
929 if (sample->tracked_result)
930 hr = MF_E_NOTACCEPTING;
931 else
933 if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator,
934 state, &sample->tracked_result)))
936 /* Account for additional refcount brought by 'state' object. This threshold is used
937 on Release() to invoke tracker callback. */
938 sample->tracked_refcount = 1;
939 if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
940 state == (IUnknown *)&sample->IMFSample_iface)
942 ++sample->tracked_refcount;
947 LeaveCriticalSection(&sample->attributes.cs);
949 return hr;
952 static const IMFTrackedSampleVtbl tracked_sample_vtbl =
954 tracked_sample_QueryInterface,
955 tracked_sample_AddRef,
956 tracked_sample_Release,
957 tracked_sample_SetAllocator,
960 static const IMFSampleVtbl sample_tracked_vtbl =
962 sample_QueryInterface,
963 sample_AddRef,
964 sample_tracked_Release,
965 sample_GetItem,
966 sample_GetItemType,
967 sample_CompareItem,
968 sample_Compare,
969 sample_GetUINT32,
970 sample_GetUINT64,
971 sample_GetDouble,
972 sample_GetGUID,
973 sample_GetStringLength,
974 sample_GetString,
975 sample_GetAllocatedString,
976 sample_GetBlobSize,
977 sample_GetBlob,
978 sample_GetAllocatedBlob,
979 sample_GetUnknown,
980 sample_SetItem,
981 sample_DeleteItem,
982 sample_DeleteAllItems,
983 sample_SetUINT32,
984 sample_SetUINT64,
985 sample_SetDouble,
986 sample_SetGUID,
987 sample_SetString,
988 sample_SetBlob,
989 sample_SetUnknown,
990 sample_LockStore,
991 sample_UnlockStore,
992 sample_GetCount,
993 sample_GetItemByIndex,
994 sample_CopyAllItems,
995 sample_GetSampleFlags,
996 sample_SetSampleFlags,
997 sample_GetSampleTime,
998 sample_SetSampleTime,
999 sample_GetSampleDuration,
1000 sample_SetSampleDuration,
1001 sample_GetBufferCount,
1002 sample_GetBufferByIndex,
1003 sample_ConvertToContiguousBuffer,
1004 sample_AddBuffer,
1005 sample_RemoveBufferByIndex,
1006 sample_RemoveAllBuffers,
1007 sample_GetTotalLength,
1008 sample_CopyToBuffer,
1011 /***********************************************************************
1012 * MFCreateSample (mfplat.@)
1014 HRESULT WINAPI MFCreateSample(IMFSample **sample)
1016 struct sample *object;
1017 HRESULT hr;
1019 TRACE("%p.\n", sample);
1021 object = heap_alloc_zero(sizeof(*object));
1022 if (!object)
1023 return E_OUTOFMEMORY;
1025 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1027 heap_free(object);
1028 return hr;
1031 object->IMFSample_iface.lpVtbl = &samplevtbl;
1033 *sample = &object->IMFSample_iface;
1035 TRACE("Created sample %p.\n", *sample);
1037 return S_OK;
1040 /***********************************************************************
1041 * MFCreateTrackedSample (mfplat.@)
1043 HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
1045 struct sample *object;
1046 HRESULT hr;
1048 TRACE("%p.\n", sample);
1050 object = heap_alloc_zero(sizeof(*object));
1051 if (!object)
1052 return E_OUTOFMEMORY;
1054 if (FAILED(hr = init_attributes_object(&object->attributes, 0)))
1056 heap_free(object);
1057 return hr;
1060 object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl;
1061 object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl;
1063 *sample = &object->IMFTrackedSample_iface;
1065 return S_OK;
1068 static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocatorEx *iface, REFIID riid, void **obj)
1070 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1072 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1074 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorEx) ||
1075 IsEqualIID(riid, &IID_IMFVideoSampleAllocator) ||
1076 IsEqualIID(riid, &IID_IUnknown))
1078 *obj = &allocator->IMFVideoSampleAllocatorEx_iface;
1080 else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback))
1082 *obj = &allocator->IMFVideoSampleAllocatorCallback_iface;
1084 else
1086 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1087 *obj = NULL;
1088 return E_NOINTERFACE;
1091 IUnknown_AddRef((IUnknown *)*obj);
1092 return S_OK;
1095 static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocatorEx *iface)
1097 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1098 ULONG refcount = InterlockedIncrement(&allocator->refcount);
1100 TRACE("%p, refcount %u.\n", iface, refcount);
1102 return refcount;
1105 static void sample_allocator_release_samples(struct sample_allocator *allocator)
1107 struct queued_sample *iter, *iter2;
1109 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry)
1111 list_remove(&iter->entry);
1112 IMFSample_Release(iter->sample);
1113 heap_free(iter);
1116 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry)
1118 list_remove(&iter->entry);
1119 heap_free(iter);
1122 allocator->free_sample_count = 0;
1123 allocator->cold_sample_count = 0;
1126 static void sample_allocator_set_media_type(struct sample_allocator *allocator, IMFMediaType *media_type)
1128 UINT64 frame_size;
1129 GUID subtype;
1131 if (!media_type)
1133 if (allocator->media_type)
1134 IMFMediaType_Release(allocator->media_type);
1135 allocator->media_type = NULL;
1136 return;
1139 /* Check if type is the same. */
1140 IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size);
1141 IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype);
1143 if (frame_size == ((UINT64) allocator->frame_desc.width << 32 | allocator->frame_desc.height) &&
1144 subtype.Data1 == allocator->frame_desc.d3d9_format)
1146 return;
1149 if (allocator->media_type)
1150 IMFMediaType_Release(allocator->media_type);
1151 allocator->media_type = media_type;
1152 if (allocator->media_type)
1153 IMFMediaType_AddRef(allocator->media_type);
1156 static void sample_allocator_set_attributes(struct sample_allocator *allocator, IMFAttributes *attributes)
1158 if (allocator->attributes)
1159 IMFAttributes_Release(allocator->attributes);
1160 allocator->attributes = attributes;
1161 if (allocator->attributes)
1162 IMFAttributes_AddRef(allocator->attributes);
1165 static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocatorEx *iface)
1167 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1168 ULONG refcount = InterlockedDecrement(&allocator->refcount);
1170 TRACE("%p, refcount %u.\n", iface, refcount);
1172 if (!refcount)
1174 if (allocator->callback)
1175 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1176 if (allocator->d3d9_device_manager)
1177 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1178 if (allocator->dxgi_device_manager)
1179 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1180 sample_allocator_set_media_type(allocator, NULL);
1181 sample_allocator_set_attributes(allocator, NULL);
1182 sample_allocator_release_samples(allocator);
1183 DeleteCriticalSection(&allocator->cs);
1184 heap_free(allocator);
1187 return refcount;
1190 static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocatorEx *iface,
1191 IUnknown *manager)
1193 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1194 IDirect3DDeviceManager9 *d3d9_device_manager = NULL;
1195 IMFDXGIDeviceManager *dxgi_device_manager = NULL;
1196 HRESULT hr;
1198 TRACE("%p, %p.\n", iface, manager);
1200 if (manager)
1202 if (FAILED(hr = IUnknown_QueryInterface(manager, &IID_IMFDXGIDeviceManager, (void **)&dxgi_device_manager)))
1204 hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9, (void **)&d3d9_device_manager);
1207 if (FAILED(hr))
1208 return hr;
1211 EnterCriticalSection(&allocator->cs);
1213 if (allocator->d3d9_device_manager)
1214 IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager);
1215 if (allocator->dxgi_device_manager)
1216 IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager);
1217 allocator->d3d9_device_manager = NULL;
1218 allocator->dxgi_device_manager = NULL;
1220 if (dxgi_device_manager)
1221 allocator->dxgi_device_manager = dxgi_device_manager;
1222 else if (d3d9_device_manager)
1223 allocator->d3d9_device_manager = d3d9_device_manager;
1225 LeaveCriticalSection(&allocator->cs);
1227 return S_OK;
1230 static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface)
1232 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1234 TRACE("%p.\n", iface);
1236 EnterCriticalSection(&allocator->cs);
1238 sample_allocator_release_samples(allocator);
1239 sample_allocator_set_media_type(allocator, NULL);
1240 sample_allocator_set_attributes(allocator, NULL);
1241 memset(&allocator->frame_desc, 0, sizeof(allocator->frame_desc));
1243 LeaveCriticalSection(&allocator->cs);
1245 return S_OK;
1248 struct surface_service
1250 IDirectXVideoProcessorService *dxva_service;
1251 ID3D11Device *d3d11_device;
1252 HANDLE hdevice;
1255 static HRESULT sample_allocator_get_surface_service(struct sample_allocator *allocator, struct surface_service *service)
1257 HRESULT hr = S_OK;
1259 memset(service, 0, sizeof(*service));
1261 if (allocator->d3d9_device_manager)
1263 if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->d3d9_device_manager, &service->hdevice)))
1265 if (FAILED(hr = IDirect3DDeviceManager9_GetVideoService(allocator->d3d9_device_manager, service->hdevice,
1266 &IID_IDirectXVideoProcessorService, (void **)&service->dxva_service)))
1268 WARN("Failed to get DXVA processor service, hr %#x.\n", hr);
1269 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1273 else if (allocator->dxgi_device_manager)
1275 if (SUCCEEDED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(allocator->dxgi_device_manager, &service->hdevice)))
1277 if (FAILED(hr = IMFDXGIDeviceManager_GetVideoService(allocator->dxgi_device_manager, service->hdevice,
1278 &IID_ID3D11Device, (void **)&service->d3d11_device)))
1280 WARN("Failed to get D3D11 device, hr %#x.\n", hr);
1281 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1286 if (FAILED(hr))
1287 memset(service, 0, sizeof(*service));
1289 return hr;
1292 static void sample_allocator_release_surface_service(struct sample_allocator *allocator,
1293 struct surface_service *service)
1295 if (service->dxva_service)
1296 IDirectXVideoProcessorService_Release(service->dxva_service);
1297 if (service->d3d11_device)
1298 ID3D11Device_Release(service->d3d11_device);
1300 if (allocator->d3d9_device_manager)
1301 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice);
1302 else if (allocator->dxgi_device_manager)
1303 IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice);
1306 static HRESULT sample_allocator_allocate_sample(struct sample_allocator *allocator, const struct surface_service *service,
1307 IMFSample **sample)
1309 struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample));
1310 IMFTrackedSample *tracked_sample;
1311 IMFMediaBuffer *buffer;
1312 unsigned int i;
1313 HRESULT hr;
1315 if (FAILED(hr = MFCreateTrackedSample(&tracked_sample)))
1317 return hr;
1320 IMFTrackedSample_QueryInterface(tracked_sample, &IID_IMFSample, (void **)sample);
1321 IMFTrackedSample_Release(tracked_sample);
1323 for (i = 0; i < allocator->frame_desc.buffer_count; ++i)
1325 if (service->dxva_service)
1327 IDirect3DSurface9 *surface;
1329 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service->dxva_service, allocator->frame_desc.width,
1330 allocator->frame_desc.height, 0, allocator->frame_desc.d3d9_format, D3DPOOL_DEFAULT, 0,
1331 DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
1333 hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer);
1334 IDirect3DSurface9_Release(surface);
1337 else if (service->d3d11_device)
1339 D3D11_TEXTURE2D_DESC desc = { 0 };
1340 ID3D11Texture2D *texture;
1342 desc.Width = allocator->frame_desc.width;
1343 desc.Height = allocator->frame_desc.height;
1344 desc.MipLevels = 1;
1345 desc.ArraySize = 1;
1346 desc.Format = allocator->frame_desc.dxgi_format;
1347 desc.SampleDesc.Count = 1;
1348 desc.SampleDesc.Quality = 0;
1349 desc.Usage = 0;
1350 desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
1352 if (SUCCEEDED(hr = ID3D11Device_CreateTexture2D(service->d3d11_device, &desc, NULL, &texture)))
1354 hr = MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer);
1355 ID3D11Texture2D_Release(texture);
1358 else
1360 hr = MFCreate2DMediaBuffer(allocator->frame_desc.width, allocator->frame_desc.height,
1361 allocator->frame_desc.d3d9_format, FALSE, &buffer);
1364 if (SUCCEEDED(hr))
1366 hr = IMFSample_AddBuffer(*sample, buffer);
1367 IMFMediaBuffer_Release(buffer);
1371 return hr;
1374 static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, unsigned int sample_count,
1375 unsigned int max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1377 struct surface_service service;
1378 unsigned int i;
1379 GUID major, subtype;
1380 UINT64 frame_size;
1381 IMFSample *sample;
1382 HRESULT hr;
1384 if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major)))
1385 return hr;
1387 if (!IsEqualGUID(&major, &MFMediaType_Video))
1388 return MF_E_INVALIDMEDIATYPE;
1390 if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
1391 return hr;
1393 if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
1394 return hr;
1396 if (sample_count > max_sample_count)
1397 return E_INVALIDARG;
1399 sample_allocator_set_media_type(allocator, media_type);
1400 sample_allocator_set_attributes(allocator, attributes);
1402 sample_count = max(1, sample_count);
1403 max_sample_count = max(1, max_sample_count);
1405 if (attributes)
1406 IMFAttributes_GetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, &allocator->frame_desc.buffer_count);
1408 allocator->frame_desc.d3d9_format = subtype.Data1;
1409 allocator->frame_desc.dxgi_format = MFMapDX9FormatToDXGIFormat(allocator->frame_desc.d3d9_format);
1410 allocator->frame_desc.width = frame_size >> 32;
1411 allocator->frame_desc.height = frame_size;
1412 allocator->frame_desc.buffer_count = max(1, allocator->frame_desc.buffer_count);
1414 if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service)))
1415 return hr;
1417 sample_allocator_release_samples(allocator);
1419 for (i = 0; i < sample_count; ++i)
1421 struct queued_sample *queued_sample;
1423 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1425 queued_sample = heap_alloc(sizeof(*queued_sample));
1426 queued_sample->sample = sample;
1427 list_add_tail(&allocator->free_samples, &queued_sample->entry);
1428 allocator->free_sample_count++;
1431 allocator->cold_sample_count = max_sample_count - allocator->free_sample_count;
1433 sample_allocator_release_surface_service(allocator, &service);
1435 return hr;
1438 static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface,
1439 DWORD sample_count, IMFMediaType *media_type)
1441 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1442 HRESULT hr;
1444 TRACE("%p, %u, %p.\n", iface, sample_count, media_type);
1446 if (!sample_count)
1447 return E_INVALIDARG;
1449 EnterCriticalSection(&allocator->cs);
1451 hr = sample_allocator_initialize(allocator, sample_count, sample_count, NULL, media_type);
1453 LeaveCriticalSection(&allocator->cs);
1455 return hr;
1458 static HRESULT sample_allocator_track_sample(struct sample_allocator *allocator, IMFSample *sample)
1460 IMFTrackedSample *tracked_sample;
1461 HRESULT hr;
1463 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
1465 hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
1466 IMFTrackedSample_Release(tracked_sample);
1469 return hr;
1472 static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx *iface, IMFSample **out)
1474 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1475 IMFSample *sample;
1476 HRESULT hr;
1478 TRACE("%p, %p.\n", iface, out);
1480 EnterCriticalSection(&allocator->cs);
1482 if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples))
1483 hr = MF_E_NOT_INITIALIZED;
1484 else if (list_empty(&allocator->free_samples) && !allocator->cold_sample_count)
1485 hr = MF_E_SAMPLEALLOCATOR_EMPTY;
1486 else if (!list_empty(&allocator->free_samples))
1488 struct list *head = list_head(&allocator->free_samples);
1490 sample = LIST_ENTRY(head, struct queued_sample, entry)->sample;
1492 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample)))
1494 list_remove(head);
1495 list_add_tail(&allocator->used_samples, head);
1496 allocator->free_sample_count--;
1498 /* Reference counter is not increased when sample is returned, so next release could trigger
1499 tracking condition. This is balanced by incremented reference counter when sample is returned
1500 back to the free list. */
1501 *out = sample;
1504 else /* allocator->cold_sample_count != 0 */
1506 struct surface_service service;
1508 if (SUCCEEDED(hr = sample_allocator_get_surface_service(allocator, &service)))
1510 if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample)))
1512 if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample)))
1514 struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample));
1516 queued_sample->sample = sample;
1517 list_add_tail(&allocator->used_samples, &queued_sample->entry);
1518 allocator->cold_sample_count--;
1520 *out = queued_sample->sample;
1524 sample_allocator_release_surface_service(allocator, &service);
1528 LeaveCriticalSection(&allocator->cs);
1530 return hr;
1533 static HRESULT WINAPI sample_allocator_InitializeSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface, DWORD initial_sample_count,
1534 DWORD max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type)
1536 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface);
1537 HRESULT hr;
1539 TRACE("%p, %u, %u, %p, %p.\n", iface, initial_sample_count, max_sample_count, attributes, media_type);
1541 EnterCriticalSection(&allocator->cs);
1543 hr = sample_allocator_initialize(allocator, initial_sample_count, max_sample_count, attributes, media_type);
1545 LeaveCriticalSection(&allocator->cs);
1547 return hr;
1550 static const IMFVideoSampleAllocatorExVtbl sample_allocator_vtbl =
1552 sample_allocator_QueryInterface,
1553 sample_allocator_AddRef,
1554 sample_allocator_Release,
1555 sample_allocator_SetDirectXManager,
1556 sample_allocator_UninitializeSampleAllocator,
1557 sample_allocator_InitializeSampleAllocator,
1558 sample_allocator_AllocateSample,
1559 sample_allocator_InitializeSampleAllocatorEx,
1562 static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface,
1563 REFIID riid, void **obj)
1565 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1566 return IMFVideoSampleAllocatorEx_QueryInterface(&allocator->IMFVideoSampleAllocatorEx_iface, riid, obj);
1569 static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface)
1571 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1572 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1575 static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface)
1577 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1578 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1581 static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface,
1582 IMFVideoSampleAllocatorNotify *callback)
1584 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1586 TRACE("%p, %p.\n", iface, callback);
1588 EnterCriticalSection(&allocator->cs);
1589 if (allocator->callback)
1590 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
1591 allocator->callback = callback;
1592 if (allocator->callback)
1593 IMFVideoSampleAllocatorNotify_AddRef(allocator->callback);
1594 LeaveCriticalSection(&allocator->cs);
1596 return S_OK;
1599 static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface,
1600 LONG *count)
1602 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
1604 TRACE("%p, %p.\n", iface, count);
1606 if (!count)
1607 return E_POINTER;
1609 EnterCriticalSection(&allocator->cs);
1610 *count = allocator->free_sample_count;
1611 LeaveCriticalSection(&allocator->cs);
1613 return S_OK;
1616 static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl =
1618 sample_allocator_callback_QueryInterface,
1619 sample_allocator_callback_AddRef,
1620 sample_allocator_callback_Release,
1621 sample_allocator_callback_SetCallback,
1622 sample_allocator_callback_GetFreeSampleCount,
1625 static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface,
1626 REFIID riid, void **obj)
1628 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
1629 IsEqualIID(riid, &IID_IUnknown))
1631 *obj = iface;
1632 IMFAsyncCallback_AddRef(iface);
1633 return S_OK;
1636 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1637 *obj = NULL;
1638 return E_NOINTERFACE;
1641 static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface)
1643 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1644 return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface);
1647 static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
1649 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1650 return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface);
1653 static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface,
1654 DWORD *flags, DWORD *queue)
1656 return E_NOTIMPL;
1659 static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
1661 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
1662 struct queued_sample *iter;
1663 IUnknown *object = NULL;
1664 IMFSample *sample = NULL;
1665 HRESULT hr;
1667 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
1668 return E_UNEXPECTED;
1670 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
1671 IUnknown_Release(object);
1672 if (FAILED(hr))
1673 return E_UNEXPECTED;
1675 EnterCriticalSection(&allocator->cs);
1677 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
1679 if (sample == iter->sample)
1681 list_remove(&iter->entry);
1682 list_add_tail(&allocator->free_samples, &iter->entry);
1683 IMFSample_AddRef(iter->sample);
1684 allocator->free_sample_count++;
1685 break;
1689 IMFSample_Release(sample);
1691 if (allocator->callback)
1692 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
1694 LeaveCriticalSection(&allocator->cs);
1696 return S_OK;
1699 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
1701 sample_allocator_tracking_callback_QueryInterface,
1702 sample_allocator_tracking_callback_AddRef,
1703 sample_allocator_tracking_callback_Release,
1704 sample_allocator_tracking_callback_GetParameters,
1705 sample_allocator_tracking_callback_Invoke,
1708 /***********************************************************************
1709 * MFCreateVideoSampleAllocatorEx (mfplat.@)
1711 HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj)
1713 struct sample_allocator *object;
1714 HRESULT hr;
1716 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
1718 if (!(object = heap_alloc_zero(sizeof(*object))))
1719 return E_OUTOFMEMORY;
1721 object->IMFVideoSampleAllocatorEx_iface.lpVtbl = &sample_allocator_vtbl;
1722 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
1723 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
1724 object->refcount = 1;
1725 list_init(&object->used_samples);
1726 list_init(&object->free_samples);
1727 InitializeCriticalSection(&object->cs);
1729 hr = IMFVideoSampleAllocatorEx_QueryInterface(&object->IMFVideoSampleAllocatorEx_iface, riid, obj);
1730 IMFVideoSampleAllocatorEx_Release(&object->IMFVideoSampleAllocatorEx_iface);
1732 return hr;