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
21 #include "mfplat_private.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,
41 struct attributes attributes
;
42 IMFSample IMFSample_iface
;
43 IMFTrackedSample IMFTrackedSample_iface
;
45 IMFMediaBuffer
**buffers
;
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
;
65 IMFVideoSampleAllocatorNotify
*callback
;
66 IDirect3DDeviceManager9
*d3d9_device_manager
;
67 IMFDXGIDeviceManager
*dxgi_device_manager
;
73 D3DFORMAT d3d9_format
;
74 DXGI_FORMAT dxgi_format
;
76 unsigned int bindflags
;
77 unsigned int buffer_count
;
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
;
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
;
139 WARN("Unsupported %s.\n", debugstr_guid(riid
));
141 return E_NOINTERFACE
;
144 IUnknown_AddRef((IUnknown
*)*out
);
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
);
158 static void release_sample_object(struct sample
*sample
)
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
);
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
);
177 release_sample_object(sample
);
182 static ULONG WINAPI
sample_tracked_Release(IMFSample
*iface
)
184 struct sample
*sample
= impl_from_IMFSample(iface
);
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
);
207 release_sample_object(sample
);
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
,
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
);
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
);
509 static HRESULT WINAPI
sample_GetSampleTime(IMFSample
*iface
, LONGLONG
*timestamp
)
511 struct sample
*sample
= impl_from_IMFSample(iface
);
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
;
520 hr
= MF_E_NO_SAMPLE_TIMESTAMP
;
521 LeaveCriticalSection(&sample
->attributes
.cs
);
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
);
540 static HRESULT WINAPI
sample_GetSampleDuration(IMFSample
*iface
, LONGLONG
*duration
)
542 struct sample
*sample
= impl_from_IMFSample(iface
);
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
;
551 hr
= MF_E_NO_SAMPLE_DURATION
;
552 LeaveCriticalSection(&sample
->attributes
.cs
);
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
);
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
);
580 EnterCriticalSection(&sample
->attributes
.cs
);
581 *count
= sample
->buffer_count
;
582 LeaveCriticalSection(&sample
->attributes
.cs
);
587 static HRESULT WINAPI
sample_GetBufferByIndex(IMFSample
*iface
, DWORD index
, IMFMediaBuffer
**buffer
)
589 struct sample
*sample
= impl_from_IMFSample(iface
);
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
);
602 LeaveCriticalSection(&sample
->attributes
.cs
);
607 static unsigned int sample_get_total_length(struct sample
*sample
)
609 DWORD total_length
= 0, length
;
612 for (i
= 0; i
< sample
->buffer_count
; ++i
)
615 if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample
->buffers
[i
], &length
)))
616 total_length
+= 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
;
630 total_length
= sample_get_total_length(sample
);
631 dst_current_length
= 0;
634 dst_length
= current_length
= 0;
635 locked
= SUCCEEDED(hr
= IMFMediaBuffer_Lock(buffer
, &dst_ptr
, &dst_length
, ¤t_length
));
638 if (dst_length
< total_length
)
639 hr
= MF_E_BUFFERTOOSMALL
;
642 for (i
= 0; i
< sample
->buffer_count
&& SUCCEEDED(hr
); ++i
)
645 src_max_length
= current_length
= 0;
646 if (SUCCEEDED(hr
= IMFMediaBuffer_Lock(sample
->buffers
[i
], &src_ptr
, &src_max_length
, ¤t_length
)))
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");
670 IMFMediaBuffer_Unlock(buffer
);
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
;
682 TRACE("%p, %p.\n", iface
, buffer
);
684 EnterCriticalSection(&sample
->attributes
.cs
);
686 if (sample
->buffer_count
== 0)
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
);
718 static HRESULT WINAPI
sample_AddBuffer(IMFSample
*iface
, IMFMediaBuffer
*buffer
)
720 struct sample
*sample
= impl_from_IMFSample(iface
);
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
)))
731 sample
->buffers
[sample
->buffer_count
++] = buffer
;
732 IMFMediaBuffer_AddRef(buffer
);
734 LeaveCriticalSection(&sample
->attributes
.cs
);
739 static HRESULT WINAPI
sample_RemoveBufferByIndex(IMFSample
*iface
, DWORD index
)
741 struct sample
*sample
= impl_from_IMFSample(iface
);
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
--;
759 LeaveCriticalSection(&sample
->attributes
.cs
);
764 static HRESULT WINAPI
sample_RemoveAllBuffers(IMFSample
*iface
)
766 struct sample
*sample
= impl_from_IMFSample(iface
);
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
);
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
);
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
;
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;
810 dst_length
= current_length
= 0;
811 locked
= SUCCEEDED(hr
= IMFMediaBuffer_Lock(buffer
, &dst_ptr
, &dst_length
, ¤t_length
));
814 if (dst_length
< total_length
)
815 hr
= MF_E_BUFFERTOOSMALL
;
818 for (i
= 0; i
< sample
->buffer_count
&& SUCCEEDED(hr
); ++i
)
821 src_max_length
= current_length
= 0;
822 if (SUCCEEDED(hr
= IMFMediaBuffer_Lock(sample
->buffers
[i
], &src_ptr
, &src_max_length
, ¤t_length
)))
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
);
845 IMFMediaBuffer_Unlock(buffer
);
847 LeaveCriticalSection(&sample
->attributes
.cs
);
852 static const IMFSampleVtbl samplevtbl
=
854 sample_QueryInterface
,
865 sample_GetStringLength
,
867 sample_GetAllocatedString
,
870 sample_GetAllocatedBlob
,
874 sample_DeleteAllItems
,
885 sample_GetItemByIndex
,
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
,
897 sample_RemoveBufferByIndex
,
898 sample_RemoveAllBuffers
,
899 sample_GetTotalLength
,
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
);
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
;
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
);
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
,
966 sample_tracked_Release
,
975 sample_GetStringLength
,
977 sample_GetAllocatedString
,
980 sample_GetAllocatedBlob
,
984 sample_DeleteAllItems
,
995 sample_GetItemByIndex
,
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
,
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
;
1021 TRACE("%p.\n", sample
);
1023 object
= heap_alloc_zero(sizeof(*object
));
1025 return E_OUTOFMEMORY
;
1027 if (FAILED(hr
= init_attributes_object(&object
->attributes
, 0)))
1033 object
->IMFSample_iface
.lpVtbl
= &samplevtbl
;
1035 *sample
= &object
->IMFSample_iface
;
1037 TRACE("Created sample %p.\n", *sample
);
1042 /***********************************************************************
1043 * MFCreateTrackedSample (mfplat.@)
1045 HRESULT WINAPI
MFCreateTrackedSample(IMFTrackedSample
**sample
)
1047 struct sample
*object
;
1050 TRACE("%p.\n", sample
);
1052 object
= heap_alloc_zero(sizeof(*object
));
1054 return E_OUTOFMEMORY
;
1056 if (FAILED(hr
= init_attributes_object(&object
->attributes
, 0)))
1062 object
->IMFSample_iface
.lpVtbl
= &sample_tracked_vtbl
;
1063 object
->IMFTrackedSample_iface
.lpVtbl
= &tracked_sample_vtbl
;
1065 *sample
= &object
->IMFTrackedSample_iface
;
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
;
1088 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
1090 return E_NOINTERFACE
;
1093 IUnknown_AddRef((IUnknown
*)*obj
);
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
);
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
);
1118 LIST_FOR_EACH_ENTRY_SAFE(iter
, iter2
, &allocator
->used_samples
, struct queued_sample
, entry
)
1120 list_remove(&iter
->entry
);
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
)
1135 if (allocator
->media_type
)
1136 IMFMediaType_Release(allocator
->media_type
);
1137 allocator
->media_type
= NULL
;
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
)
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
);
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
);
1192 static HRESULT WINAPI
sample_allocator_SetDirectXManager(IMFVideoSampleAllocatorEx
*iface
,
1195 struct sample_allocator
*allocator
= impl_from_IMFVideoSampleAllocatorEx(iface
);
1196 IDirect3DDeviceManager9
*d3d9_device_manager
= NULL
;
1197 IMFDXGIDeviceManager
*dxgi_device_manager
= NULL
;
1200 TRACE("%p, %p.\n", iface
, 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
);
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
);
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
);
1250 struct surface_service
1252 IDirectXVideoProcessorService
*dxva_service
;
1253 ID3D11Device
*d3d11_device
;
1257 static HRESULT
sample_allocator_get_surface_service(struct sample_allocator
*allocator
, struct surface_service
*service
)
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
);
1289 memset(service
, 0, sizeof(*service
));
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
,
1311 struct queued_sample
*queued_sample
= heap_alloc(sizeof(*queued_sample
));
1312 IMFTrackedSample
*tracked_sample
;
1313 IMFMediaBuffer
*buffer
;
1317 if (FAILED(hr
= MFCreateTrackedSample(&tracked_sample
)))
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
;
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
);
1366 hr
= MFCreate2DMediaBuffer(allocator
->frame_desc
.width
, allocator
->frame_desc
.height
,
1367 allocator
->frame_desc
.d3d9_format
, FALSE
, &buffer
);
1372 hr
= IMFSample_AddBuffer(*sample
, buffer
);
1373 IMFMediaBuffer_Release(buffer
);
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
;
1385 GUID major
, subtype
;
1390 if (FAILED(hr
= IMFMediaType_GetMajorType(media_type
, &major
)))
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
)))
1399 if (FAILED(hr
= IMFMediaType_GetGUID(media_type
, &MF_MT_SUBTYPE
, &subtype
)))
1402 if (sample_count
> max_sample_count
)
1403 return E_INVALIDARG
;
1405 allocator
->frame_desc
.usage
= D3D11_USAGE_DEFAULT
;
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
;
1420 allocator
->frame_desc
.bindflags
= 0;
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
)))
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
);
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
);
1467 TRACE("%p, %u, %p.\n", iface
, sample_count
, media_type
);
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
);
1481 static HRESULT
sample_allocator_track_sample(struct sample_allocator
*allocator
, IMFSample
*sample
)
1483 IMFTrackedSample
*tracked_sample
;
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
);
1495 static HRESULT WINAPI
sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx
*iface
, IMFSample
**out
)
1497 struct sample_allocator
*allocator
= impl_from_IMFVideoSampleAllocatorEx(iface
);
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
)))
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. */
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
);
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
);
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
);
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
);
1622 static HRESULT WINAPI
sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback
*iface
,
1625 struct sample_allocator
*allocator
= impl_from_IMFVideoSampleAllocatorCallback(iface
);
1627 TRACE("%p, %p.\n", iface
, count
);
1632 EnterCriticalSection(&allocator
->cs
);
1633 *count
= allocator
->free_sample_count
;
1634 LeaveCriticalSection(&allocator
->cs
);
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
))
1655 IMFAsyncCallback_AddRef(iface
);
1659 WARN("Unsupported interface %s.\n", debugstr_guid(riid
));
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
)
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
;
1690 if (FAILED(IMFAsyncResult_GetObject(result
, &object
)))
1691 return E_UNEXPECTED
;
1693 hr
= IUnknown_QueryInterface(object
, &IID_IMFSample
, (void **)&sample
);
1694 IUnknown_Release(object
);
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
++;
1712 IMFSample_Release(sample
);
1714 if (allocator
->callback
)
1715 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator
->callback
);
1717 LeaveCriticalSection(&allocator
->cs
);
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
;
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
);