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