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