widl: Always check the runtimeclass interfaces presence.
[wine/zf.git] / dlls / evr / sample.c
blob9c76011f1535a07ad5e0bb8be682613c20b77d0b
1 /*
2 * Copyright 2020 Nikolay Sivov
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "evr.h"
22 #include "mfapi.h"
23 #include "mferror.h"
24 #include "d3d9.h"
25 #include "dxva2api.h"
27 #include "wine/debug.h"
28 #include "wine/heap.h"
29 #include "wine/list.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(evr);
33 static const char *debugstr_time(LONGLONG time)
35 ULONGLONG abstime = time >= 0 ? time : -time;
36 unsigned int i = 0, j = 0;
37 char buffer[23], rev[23];
39 while (abstime || i <= 8)
41 buffer[i++] = '0' + (abstime % 10);
42 abstime /= 10;
43 if (i == 7) buffer[i++] = '.';
45 if (time < 0) buffer[i++] = '-';
47 while (i--) rev[j++] = buffer[i];
48 while (rev[j-1] == '0' && rev[j-2] != '.') --j;
49 rev[j] = 0;
51 return wine_dbg_sprintf("%s", rev);
54 struct surface_buffer
56 IMFMediaBuffer IMFMediaBuffer_iface;
57 IMFGetService IMFGetService_iface;
58 LONG refcount;
60 IUnknown *surface;
61 ULONG length;
64 enum sample_prop_flags
66 SAMPLE_PROP_HAS_DURATION = 1 << 0,
67 SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
68 SAMPLE_PROP_HAS_DESIRED_PROPS = 1 << 2,
71 struct video_sample
73 IMFSample IMFSample_iface;
74 IMFTrackedSample IMFTrackedSample_iface;
75 IMFDesiredSample IMFDesiredSample_iface;
76 LONG refcount;
78 IMFSample *sample;
80 IMFAsyncResult *tracked_result;
81 LONG tracked_refcount;
83 LONGLONG timestamp;
84 LONGLONG duration;
85 LONGLONG desired_timestamp;
86 LONGLONG desired_duration;
87 unsigned int flags;
88 CRITICAL_SECTION cs;
91 static struct video_sample *impl_from_IMFSample(IMFSample *iface)
93 return CONTAINING_RECORD(iface, struct video_sample, IMFSample_iface);
96 static struct video_sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
98 return CONTAINING_RECORD(iface, struct video_sample, IMFTrackedSample_iface);
101 static struct video_sample *impl_from_IMFDesiredSample(IMFDesiredSample *iface)
103 return CONTAINING_RECORD(iface, struct video_sample, IMFDesiredSample_iface);
106 static struct surface_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface)
108 return CONTAINING_RECORD(iface, struct surface_buffer, IMFMediaBuffer_iface);
111 static struct surface_buffer *impl_from_IMFGetService(IMFGetService *iface)
113 return CONTAINING_RECORD(iface, struct surface_buffer, IMFGetService_iface);
116 struct tracked_async_result
118 MFASYNCRESULT result;
119 LONG refcount;
120 IUnknown *object;
121 IUnknown *state;
124 static struct tracked_async_result *impl_from_IMFAsyncResult(IMFAsyncResult *iface)
126 return CONTAINING_RECORD(iface, struct tracked_async_result, result.AsyncResult);
129 static HRESULT WINAPI tracked_async_result_QueryInterface(IMFAsyncResult *iface, REFIID riid, void **obj)
131 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
133 if (IsEqualIID(riid, &IID_IMFAsyncResult) ||
134 IsEqualIID(riid, &IID_IUnknown))
136 *obj = iface;
137 IMFAsyncResult_AddRef(iface);
138 return S_OK;
141 *obj = NULL;
142 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
143 return E_NOINTERFACE;
146 static ULONG WINAPI tracked_async_result_AddRef(IMFAsyncResult *iface)
148 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
149 ULONG refcount = InterlockedIncrement(&result->refcount);
151 TRACE("%p, %u.\n", iface, refcount);
153 return refcount;
156 static ULONG WINAPI tracked_async_result_Release(IMFAsyncResult *iface)
158 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
159 ULONG refcount = InterlockedDecrement(&result->refcount);
161 TRACE("%p, %u.\n", iface, refcount);
163 if (!refcount)
165 if (result->result.pCallback)
166 IMFAsyncCallback_Release(result->result.pCallback);
167 if (result->object)
168 IUnknown_Release(result->object);
169 if (result->state)
170 IUnknown_Release(result->state);
171 heap_free(result);
174 return refcount;
177 static HRESULT WINAPI tracked_async_result_GetState(IMFAsyncResult *iface, IUnknown **state)
179 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
181 TRACE("%p, %p.\n", iface, state);
183 if (!result->state)
184 return E_POINTER;
186 *state = result->state;
187 IUnknown_AddRef(*state);
189 return S_OK;
192 static HRESULT WINAPI tracked_async_result_GetStatus(IMFAsyncResult *iface)
194 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
196 TRACE("%p.\n", iface);
198 return result->result.hrStatusResult;
201 static HRESULT WINAPI tracked_async_result_SetStatus(IMFAsyncResult *iface, HRESULT status)
203 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
205 TRACE("%p, %#x.\n", iface, status);
207 result->result.hrStatusResult = status;
209 return S_OK;
212 static HRESULT WINAPI tracked_async_result_GetObject(IMFAsyncResult *iface, IUnknown **object)
214 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
216 TRACE("%p, %p.\n", iface, object);
218 if (!result->object)
219 return E_POINTER;
221 *object = result->object;
222 IUnknown_AddRef(*object);
224 return S_OK;
227 static IUnknown * WINAPI tracked_async_result_GetStateNoAddRef(IMFAsyncResult *iface)
229 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
231 TRACE("%p.\n", iface);
233 return result->state;
236 static const IMFAsyncResultVtbl tracked_async_result_vtbl =
238 tracked_async_result_QueryInterface,
239 tracked_async_result_AddRef,
240 tracked_async_result_Release,
241 tracked_async_result_GetState,
242 tracked_async_result_GetStatus,
243 tracked_async_result_SetStatus,
244 tracked_async_result_GetObject,
245 tracked_async_result_GetStateNoAddRef,
248 static HRESULT create_async_result(IUnknown *object, IMFAsyncCallback *callback,
249 IUnknown *state, IMFAsyncResult **out)
251 struct tracked_async_result *result;
253 result = heap_alloc_zero(sizeof(*result));
254 if (!result)
255 return E_OUTOFMEMORY;
257 result->result.AsyncResult.lpVtbl = &tracked_async_result_vtbl;
258 result->refcount = 1;
259 result->object = object;
260 if (result->object)
261 IUnknown_AddRef(result->object);
262 result->result.pCallback = callback;
263 if (result->result.pCallback)
264 IMFAsyncCallback_AddRef(result->result.pCallback);
265 result->state = state;
266 if (result->state)
267 IUnknown_AddRef(result->state);
269 *out = &result->result.AsyncResult;
271 return S_OK;
274 struct tracking_thread
276 HANDLE hthread;
277 DWORD tid;
278 LONG refcount;
280 static struct tracking_thread tracking_thread;
282 static CRITICAL_SECTION tracking_thread_cs = { NULL, -1, 0, 0, 0, 0 };
284 enum tracking_thread_message
286 TRACKM_STOP = WM_USER,
287 TRACKM_INVOKE = WM_USER + 1,
290 static DWORD CALLBACK tracking_thread_proc(void *arg)
292 HANDLE ready_event = arg;
293 BOOL stop_thread = FALSE;
294 IMFAsyncResult *result;
295 MFASYNCRESULT *data;
296 MSG msg;
298 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
300 SetEvent(ready_event);
302 while (!stop_thread)
304 MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_POSTMESSAGE);
306 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
308 switch (msg.message)
310 case TRACKM_INVOKE:
311 result = (IMFAsyncResult *)msg.lParam;
312 data = (MFASYNCRESULT *)result;
313 if (data->pCallback)
314 IMFAsyncCallback_Invoke(data->pCallback, result);
315 IMFAsyncResult_Release(result);
316 break;
318 case TRACKM_STOP:
319 stop_thread = TRUE;
320 break;
322 default:
328 TRACE("Tracking thread exiting.\n");
330 return 0;
333 static void video_sample_create_tracking_thread(void)
335 EnterCriticalSection(&tracking_thread_cs);
337 if (++tracking_thread.refcount == 1)
339 HANDLE ready_event;
341 ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
343 if (!(tracking_thread.hthread = CreateThread(NULL, 0, tracking_thread_proc,
344 ready_event, 0, &tracking_thread.tid)))
346 WARN("Failed to create sample tracking thread.\n");
347 CloseHandle(ready_event);
348 LeaveCriticalSection(&tracking_thread_cs);
349 return;
352 WaitForSingleObject(ready_event, INFINITE);
353 CloseHandle(ready_event);
355 TRACE("Create tracking thread %#x.\n", tracking_thread.tid);
358 LeaveCriticalSection(&tracking_thread_cs);
361 static void video_sample_stop_tracking_thread(void)
363 EnterCriticalSection(&tracking_thread_cs);
365 if (!--tracking_thread.refcount)
367 PostThreadMessageW(tracking_thread.tid, TRACKM_STOP, 0, 0);
368 CloseHandle(tracking_thread.hthread);
369 memset(&tracking_thread, 0, sizeof(tracking_thread));
372 LeaveCriticalSection(&tracking_thread_cs);
375 static void video_sample_tracking_thread_invoke(IMFAsyncResult *result)
377 if (!tracking_thread.tid)
379 WARN("Sample tracking thread is not initialized.\n");
380 return;
383 IMFAsyncResult_AddRef(result);
384 PostThreadMessageW(tracking_thread.tid, TRACKM_INVOKE, 0, (LPARAM)result);
387 struct sample_allocator
389 IMFVideoSampleAllocator IMFVideoSampleAllocator_iface;
390 IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface;
391 IMFAsyncCallback tracking_callback;
392 LONG refcount;
394 IMFVideoSampleAllocatorNotify *callback;
395 IDirect3DDeviceManager9 *device_manager;
396 unsigned int free_sample_count;
397 struct list free_samples;
398 struct list used_samples;
399 CRITICAL_SECTION cs;
402 struct queued_sample
404 struct list entry;
405 IMFSample *sample;
408 static struct sample_allocator *impl_from_IMFVideoSampleAllocator(IMFVideoSampleAllocator *iface)
410 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocator_iface);
413 static struct sample_allocator *impl_from_IMFVideoSampleAllocatorCallback(IMFVideoSampleAllocatorCallback *iface)
415 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorCallback_iface);
418 static struct sample_allocator *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
420 return CONTAINING_RECORD(iface, struct sample_allocator, tracking_callback);
423 static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocator *iface, REFIID riid, void **obj)
425 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
427 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
429 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocator) ||
430 IsEqualIID(riid, &IID_IUnknown))
432 *obj = &allocator->IMFVideoSampleAllocator_iface;
434 else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback))
436 *obj = &allocator->IMFVideoSampleAllocatorCallback_iface;
438 else
440 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
441 *obj = NULL;
442 return E_NOINTERFACE;
445 IUnknown_AddRef((IUnknown *)*obj);
446 return S_OK;
449 static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocator *iface)
451 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
452 ULONG refcount = InterlockedIncrement(&allocator->refcount);
454 TRACE("%p, refcount %u.\n", iface, refcount);
456 return refcount;
459 static void sample_allocator_release_samples(struct sample_allocator *allocator)
461 struct queued_sample *iter, *iter2;
463 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry)
465 list_remove(&iter->entry);
466 IMFSample_Release(iter->sample);
467 heap_free(iter);
470 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry)
472 list_remove(&iter->entry);
473 heap_free(iter);
477 static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocator *iface)
479 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
480 ULONG refcount = InterlockedDecrement(&allocator->refcount);
482 TRACE("%p, refcount %u.\n", iface, refcount);
484 if (!refcount)
486 if (allocator->callback)
487 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
488 if (allocator->device_manager)
489 IDirect3DDeviceManager9_Release(allocator->device_manager);
490 sample_allocator_release_samples(allocator);
491 DeleteCriticalSection(&allocator->cs);
492 heap_free(allocator);
495 return refcount;
498 static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocator *iface,
499 IUnknown *manager)
501 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
502 IDirect3DDeviceManager9 *device_manager = NULL;
503 HRESULT hr;
505 TRACE("%p, %p.\n", iface, manager);
507 if (manager && FAILED(hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9,
508 (void **)&device_manager)))
510 return hr;
513 EnterCriticalSection(&allocator->cs);
515 if (allocator->device_manager)
516 IDirect3DDeviceManager9_Release(allocator->device_manager);
517 allocator->device_manager = device_manager;
519 LeaveCriticalSection(&allocator->cs);
521 return S_OK;
524 static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocator *iface)
526 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
528 TRACE("%p.\n", iface);
530 EnterCriticalSection(&allocator->cs);
532 sample_allocator_release_samples(allocator);
533 allocator->free_sample_count = 0;
535 LeaveCriticalSection(&allocator->cs);
537 return S_OK;
540 static HRESULT sample_allocator_create_samples(struct sample_allocator *allocator, unsigned int sample_count,
541 IMFMediaType *media_type)
543 IDirectXVideoProcessorService *service = NULL;
544 unsigned int i, width, height;
545 IDirect3DSurface9 *surface;
546 HANDLE hdevice = NULL;
547 GUID major, subtype;
548 UINT64 frame_size;
549 IMFSample *sample;
550 D3DFORMAT format;
551 HRESULT hr;
553 if (FAILED(IMFMediaType_GetMajorType(media_type, &major)))
554 return MF_E_INVALIDMEDIATYPE;
556 if (!IsEqualGUID(&major, &MFMediaType_Video))
557 return MF_E_INVALIDMEDIATYPE;
559 if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
560 return MF_E_INVALIDMEDIATYPE;
562 if (FAILED(IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
563 return MF_E_INVALIDMEDIATYPE;
565 format = subtype.Data1;
566 height = frame_size;
567 width = frame_size >> 32;
569 if (allocator->device_manager)
571 if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->device_manager, &hdevice)))
573 hr = IDirect3DDeviceManager9_GetVideoService(allocator->device_manager, hdevice,
574 &IID_IDirectXVideoProcessorService, (void **)&service);
577 if (FAILED(hr))
579 WARN("Failed to get processor service, %#x.\n", hr);
580 return hr;
584 sample_allocator_release_samples(allocator);
586 for (i = 0; i < sample_count; ++i)
588 struct queued_sample *queued_sample;
589 IMFMediaBuffer *buffer;
591 if (SUCCEEDED(hr = MFCreateVideoSampleFromSurface(NULL, &sample)))
593 if (service)
595 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service, width, height,
596 0, format, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
598 hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer);
599 IDirect3DSurface9_Release(surface);
602 else
604 hr = MFCreate2DMediaBuffer(width, height, format, FALSE, &buffer);
607 if (SUCCEEDED(hr))
609 hr = IMFSample_AddBuffer(sample, buffer);
610 IMFMediaBuffer_Release(buffer);
614 if (FAILED(hr))
616 WARN("Unable to allocate %u samples.\n", sample_count);
617 sample_allocator_release_samples(allocator);
618 break;
621 queued_sample = heap_alloc(sizeof(*queued_sample));
622 queued_sample->sample = sample;
623 list_add_tail(&allocator->free_samples, &queued_sample->entry);
624 allocator->free_sample_count++;
627 if (service)
628 IDirectXVideoProcessorService_Release(service);
630 if (allocator->device_manager)
631 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->device_manager, hdevice);
633 return hr;
636 static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocator *iface,
637 DWORD sample_count, IMFMediaType *media_type)
639 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
640 HRESULT hr;
642 TRACE("%p, %u, %p.\n", iface, sample_count, media_type);
644 if (!sample_count)
645 sample_count = 1;
647 EnterCriticalSection(&allocator->cs);
649 hr = sample_allocator_create_samples(allocator, sample_count, media_type);
651 LeaveCriticalSection(&allocator->cs);
653 return hr;
656 static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocator *iface, IMFSample **out)
658 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
659 IMFTrackedSample *tracked_sample;
660 IMFSample *sample;
661 HRESULT hr;
663 TRACE("%p, %p.\n", iface, out);
665 EnterCriticalSection(&allocator->cs);
667 if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples))
668 hr = MF_E_NOT_INITIALIZED;
669 else if (list_empty(&allocator->free_samples))
670 hr = MF_E_SAMPLEALLOCATOR_EMPTY;
671 else
673 struct list *head = list_head(&allocator->free_samples);
675 sample = LIST_ENTRY(head, struct queued_sample, entry)->sample;
677 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
679 hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
680 IMFTrackedSample_Release(tracked_sample);
683 if (SUCCEEDED(hr))
685 list_remove(head);
686 list_add_tail(&allocator->used_samples, head);
687 allocator->free_sample_count--;
689 /* Reference counter is not increased when sample is returned, so next release could trigger
690 tracking condition. This is balanced by incremented reference counter when sample is returned
691 back to the free list. */
692 *out = sample;
696 LeaveCriticalSection(&allocator->cs);
698 return hr;
701 static const IMFVideoSampleAllocatorVtbl sample_allocator_vtbl =
703 sample_allocator_QueryInterface,
704 sample_allocator_AddRef,
705 sample_allocator_Release,
706 sample_allocator_SetDirectXManager,
707 sample_allocator_UninitializeSampleAllocator,
708 sample_allocator_InitializeSampleAllocator,
709 sample_allocator_AllocateSample,
712 static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface,
713 REFIID riid, void **obj)
715 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
716 return IMFVideoSampleAllocator_QueryInterface(&allocator->IMFVideoSampleAllocator_iface, riid, obj);
719 static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface)
721 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
722 return IMFVideoSampleAllocator_AddRef(&allocator->IMFVideoSampleAllocator_iface);
725 static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface)
727 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
728 return IMFVideoSampleAllocator_Release(&allocator->IMFVideoSampleAllocator_iface);
731 static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface,
732 IMFVideoSampleAllocatorNotify *callback)
734 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
736 TRACE("%p, %p.\n", iface, callback);
738 EnterCriticalSection(&allocator->cs);
739 if (allocator->callback)
740 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
741 allocator->callback = callback;
742 if (allocator->callback)
743 IMFVideoSampleAllocatorNotify_AddRef(allocator->callback);
744 LeaveCriticalSection(&allocator->cs);
746 return S_OK;
749 static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface,
750 LONG *count)
752 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
754 TRACE("%p, %p.\n", iface, count);
756 EnterCriticalSection(&allocator->cs);
757 if (count)
758 *count = allocator->free_sample_count;
759 LeaveCriticalSection(&allocator->cs);
761 return S_OK;
764 static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl =
766 sample_allocator_callback_QueryInterface,
767 sample_allocator_callback_AddRef,
768 sample_allocator_callback_Release,
769 sample_allocator_callback_SetCallback,
770 sample_allocator_callback_GetFreeSampleCount,
773 static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface,
774 REFIID riid, void **obj)
776 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
777 IsEqualIID(riid, &IID_IUnknown))
779 *obj = iface;
780 IMFAsyncCallback_AddRef(iface);
781 return S_OK;
784 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
785 *obj = NULL;
786 return E_NOINTERFACE;
789 static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface)
791 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
792 return IMFVideoSampleAllocator_AddRef(&allocator->IMFVideoSampleAllocator_iface);
795 static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
797 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
798 return IMFVideoSampleAllocator_Release(&allocator->IMFVideoSampleAllocator_iface);
801 static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface,
802 DWORD *flags, DWORD *queue)
804 return E_NOTIMPL;
807 static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
809 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
810 struct queued_sample *iter;
811 IUnknown *object = NULL;
812 IMFSample *sample = NULL;
813 HRESULT hr;
815 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
816 return E_UNEXPECTED;
818 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
819 IUnknown_Release(object);
820 if (FAILED(hr))
821 return E_UNEXPECTED;
823 EnterCriticalSection(&allocator->cs);
825 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
827 if (sample == iter->sample)
829 list_remove(&iter->entry);
830 list_add_tail(&allocator->free_samples, &iter->entry);
831 IMFSample_AddRef(iter->sample);
832 allocator->free_sample_count++;
833 break;
837 IMFSample_Release(sample);
839 if (allocator->callback)
840 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
842 LeaveCriticalSection(&allocator->cs);
844 return S_OK;
847 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
849 sample_allocator_tracking_callback_QueryInterface,
850 sample_allocator_tracking_callback_AddRef,
851 sample_allocator_tracking_callback_Release,
852 sample_allocator_tracking_callback_GetParameters,
853 sample_allocator_tracking_callback_Invoke,
856 HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj)
858 struct sample_allocator *object;
859 HRESULT hr;
861 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
863 if (!(object = heap_alloc_zero(sizeof(*object))))
864 return E_OUTOFMEMORY;
866 object->IMFVideoSampleAllocator_iface.lpVtbl = &sample_allocator_vtbl;
867 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
868 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
869 object->refcount = 1;
870 list_init(&object->used_samples);
871 list_init(&object->free_samples);
872 InitializeCriticalSection(&object->cs);
874 hr = IMFVideoSampleAllocator_QueryInterface(&object->IMFVideoSampleAllocator_iface, riid, obj);
875 IMFVideoSampleAllocator_Release(&object->IMFVideoSampleAllocator_iface);
877 return hr;
880 static HRESULT WINAPI video_sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
882 struct video_sample *sample = impl_from_IMFSample(iface);
884 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
886 if (IsEqualIID(riid, &IID_IMFSample) ||
887 IsEqualIID(riid, &IID_IMFAttributes) ||
888 IsEqualIID(riid, &IID_IUnknown))
890 *out = &sample->IMFSample_iface;
892 else if (IsEqualIID(riid, &IID_IMFTrackedSample))
894 *out = &sample->IMFTrackedSample_iface;
896 else if (IsEqualIID(riid, &IID_IMFDesiredSample))
898 *out = &sample->IMFDesiredSample_iface;
900 else
902 WARN("Unsupported %s.\n", debugstr_guid(riid));
903 *out = NULL;
904 return E_NOINTERFACE;
907 IUnknown_AddRef((IUnknown *)*out);
908 return S_OK;
911 static ULONG WINAPI video_sample_AddRef(IMFSample *iface)
913 struct video_sample *sample = impl_from_IMFSample(iface);
914 ULONG refcount = InterlockedIncrement(&sample->refcount);
916 TRACE("%p, refcount %u.\n", iface, refcount);
918 return refcount;
921 static ULONG WINAPI video_sample_Release(IMFSample *iface)
923 struct video_sample *sample = impl_from_IMFSample(iface);
924 ULONG refcount;
926 IMFSample_LockStore(sample->sample);
927 if (sample->tracked_result && sample->tracked_refcount == (sample->refcount - 1))
929 video_sample_tracking_thread_invoke(sample->tracked_result);
930 IMFAsyncResult_Release(sample->tracked_result);
931 sample->tracked_result = NULL;
932 sample->tracked_refcount = 0;
934 IMFSample_UnlockStore(sample->sample);
936 refcount = InterlockedDecrement(&sample->refcount);
938 TRACE("%p, refcount %u.\n", iface, refcount);
940 if (!refcount)
942 video_sample_stop_tracking_thread();
943 if (sample->sample)
944 IMFSample_Release(sample->sample);
945 DeleteCriticalSection(&sample->cs);
946 heap_free(sample);
949 return refcount;
952 static HRESULT WINAPI video_sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
954 struct video_sample *sample = impl_from_IMFSample(iface);
956 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
958 return IMFSample_GetItem(sample->sample, key, value);
961 static HRESULT WINAPI video_sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
963 struct video_sample *sample = impl_from_IMFSample(iface);
965 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
967 return IMFSample_GetItemType(sample->sample, key, type);
970 static HRESULT WINAPI video_sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
972 struct video_sample *sample = impl_from_IMFSample(iface);
974 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
976 return IMFSample_CompareItem(sample->sample, key, value, result);
979 static HRESULT WINAPI video_sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
980 BOOL *result)
982 struct video_sample *sample = impl_from_IMFSample(iface);
984 TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
986 return IMFSample_Compare(sample->sample, theirs, type, result);
989 static HRESULT WINAPI video_sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
991 struct video_sample *sample = impl_from_IMFSample(iface);
993 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
995 return IMFSample_GetUINT32(sample->sample, key, value);
998 static HRESULT WINAPI video_sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
1000 struct video_sample *sample = impl_from_IMFSample(iface);
1002 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1004 return IMFSample_GetUINT64(sample->sample, key, value);
1007 static HRESULT WINAPI video_sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
1009 struct video_sample *sample = impl_from_IMFSample(iface);
1011 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1013 return IMFSample_GetDouble(sample->sample, key, value);
1016 static HRESULT WINAPI video_sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
1018 struct video_sample *sample = impl_from_IMFSample(iface);
1020 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1022 return IMFSample_GetGUID(sample->sample, key, value);
1025 static HRESULT WINAPI video_sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
1027 struct video_sample *sample = impl_from_IMFSample(iface);
1029 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
1031 return IMFSample_GetStringLength(sample->sample, key, length);
1034 static HRESULT WINAPI video_sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
1036 struct video_sample *sample = impl_from_IMFSample(iface);
1038 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), value, size, length);
1040 return IMFSample_GetString(sample->sample, key, value, size, length);
1043 static HRESULT WINAPI video_sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
1045 struct video_sample *sample = impl_from_IMFSample(iface);
1047 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
1049 return IMFSample_GetAllocatedString(sample->sample, key, value, length);
1052 static HRESULT WINAPI video_sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
1054 struct video_sample *sample = impl_from_IMFSample(iface);
1056 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
1058 return IMFSample_GetBlobSize(sample->sample, key, size);
1061 static HRESULT WINAPI video_sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
1063 struct video_sample *sample = impl_from_IMFSample(iface);
1065 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
1067 return IMFSample_GetBlob(sample->sample, key, buf, bufsize, blobsize);
1070 static HRESULT WINAPI video_sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
1072 struct video_sample *sample = impl_from_IMFSample(iface);
1074 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
1076 return IMFSample_GetAllocatedBlob(sample->sample, key, buf, size);
1079 static HRESULT WINAPI video_sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
1081 struct video_sample *sample = impl_from_IMFSample(iface);
1083 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
1085 return IMFSample_GetUnknown(sample->sample, key, riid, out);
1088 static HRESULT WINAPI video_sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
1090 struct video_sample *sample = impl_from_IMFSample(iface);
1092 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1094 return IMFSample_SetItem(sample->sample, key, value);
1097 static HRESULT WINAPI video_sample_DeleteItem(IMFSample *iface, REFGUID key)
1099 struct video_sample *sample = impl_from_IMFSample(iface);
1101 TRACE("%p, %s.\n", iface, debugstr_guid(key));
1103 return IMFSample_DeleteItem(sample->sample, key);
1106 static HRESULT WINAPI video_sample_DeleteAllItems(IMFSample *iface)
1108 struct video_sample *sample = impl_from_IMFSample(iface);
1110 TRACE("%p.\n", iface);
1112 return IMFSample_DeleteAllItems(sample->sample);
1115 static HRESULT WINAPI video_sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
1117 struct video_sample *sample = impl_from_IMFSample(iface);
1119 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
1121 return IMFSample_SetUINT32(sample->sample, key, value);
1124 static HRESULT WINAPI video_sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
1126 struct video_sample *sample = impl_from_IMFSample(iface);
1128 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
1130 return IMFSample_SetUINT64(sample->sample, key, value);
1133 static HRESULT WINAPI video_sample_SetDouble(IMFSample *iface, REFGUID key, double value)
1135 struct video_sample *sample = impl_from_IMFSample(iface);
1137 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
1139 return IMFSample_SetDouble(sample->sample, key, value);
1142 static HRESULT WINAPI video_sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
1144 struct video_sample *sample = impl_from_IMFSample(iface);
1146 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
1148 return IMFSample_SetGUID(sample->sample, key, value);
1151 static HRESULT WINAPI video_sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
1153 struct video_sample *sample = impl_from_IMFSample(iface);
1155 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
1157 return IMFSample_SetString(sample->sample, key, value);
1160 static HRESULT WINAPI video_sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
1162 struct video_sample *sample = impl_from_IMFSample(iface);
1164 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
1166 return IMFSample_SetBlob(sample->sample, key, buf, size);
1169 static HRESULT WINAPI video_sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
1171 struct video_sample *sample = impl_from_IMFSample(iface);
1173 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
1175 return IMFSample_SetUnknown(sample->sample, key, unknown);
1178 static HRESULT WINAPI video_sample_LockStore(IMFSample *iface)
1180 struct video_sample *sample = impl_from_IMFSample(iface);
1182 TRACE("%p.\n", iface);
1184 return IMFSample_LockStore(sample->sample);
1187 static HRESULT WINAPI video_sample_UnlockStore(IMFSample *iface)
1189 struct video_sample *sample = impl_from_IMFSample(iface);
1191 TRACE("%p.\n", iface);
1193 return IMFSample_UnlockStore(sample->sample);
1196 static HRESULT WINAPI video_sample_GetCount(IMFSample *iface, UINT32 *count)
1198 struct video_sample *sample = impl_from_IMFSample(iface);
1200 TRACE("%p, %p.\n", iface, count);
1202 return IMFSample_GetCount(sample->sample, count);
1205 static HRESULT WINAPI video_sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
1207 struct video_sample *sample = impl_from_IMFSample(iface);
1209 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
1211 return IMFSample_GetItemByIndex(sample->sample, index, key, value);
1214 static HRESULT WINAPI video_sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
1216 struct video_sample *sample = impl_from_IMFSample(iface);
1218 TRACE("%p, %p.\n", iface, dest);
1220 return IMFSample_CopyAllItems(sample->sample, dest);
1223 static HRESULT WINAPI video_sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
1225 struct video_sample *sample = impl_from_IMFSample(iface);
1227 TRACE("%p, %p.\n", iface, flags);
1229 return IMFSample_GetSampleFlags(sample->sample, flags);
1232 static HRESULT WINAPI video_sample_SetSampleFlags(IMFSample *iface, DWORD flags)
1234 struct video_sample *sample = impl_from_IMFSample(iface);
1236 TRACE("%p, %#x.\n", iface, flags);
1238 return IMFSample_SetSampleFlags(sample->sample, flags);
1241 static HRESULT WINAPI video_sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
1243 struct video_sample *sample = impl_from_IMFSample(iface);
1244 HRESULT hr = S_OK;
1246 TRACE("%p, %p.\n", iface, timestamp);
1248 EnterCriticalSection(&sample->cs);
1249 if (sample->flags & SAMPLE_PROP_HAS_TIMESTAMP)
1250 *timestamp = sample->timestamp;
1251 else
1252 hr = MF_E_NO_SAMPLE_TIMESTAMP;
1253 LeaveCriticalSection(&sample->cs);
1255 return hr;
1258 static HRESULT WINAPI video_sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
1260 struct video_sample *sample = impl_from_IMFSample(iface);
1262 TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
1264 EnterCriticalSection(&sample->cs);
1265 sample->timestamp = timestamp;
1266 sample->flags |= SAMPLE_PROP_HAS_TIMESTAMP;
1267 LeaveCriticalSection(&sample->cs);
1269 return S_OK;
1272 static HRESULT WINAPI video_sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
1274 struct video_sample *sample = impl_from_IMFSample(iface);
1275 HRESULT hr = S_OK;
1277 TRACE("%p, %p.\n", iface, duration);
1279 EnterCriticalSection(&sample->cs);
1280 if (sample->flags & SAMPLE_PROP_HAS_DURATION)
1281 *duration = sample->duration;
1282 else
1283 hr = MF_E_NO_SAMPLE_DURATION;
1284 LeaveCriticalSection(&sample->cs);
1286 return hr;
1289 static HRESULT WINAPI video_sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
1291 struct video_sample *sample = impl_from_IMFSample(iface);
1293 TRACE("%p, %s.\n", iface, debugstr_time(duration));
1295 EnterCriticalSection(&sample->cs);
1296 sample->duration = duration;
1297 sample->flags |= SAMPLE_PROP_HAS_DURATION;
1298 LeaveCriticalSection(&sample->cs);
1300 return S_OK;
1303 static HRESULT WINAPI video_sample_GetBufferCount(IMFSample *iface, DWORD *count)
1305 struct video_sample *sample = impl_from_IMFSample(iface);
1307 TRACE("%p, %p.\n", iface, count);
1309 return IMFSample_GetBufferCount(sample->sample, count);
1312 static HRESULT WINAPI video_sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
1314 struct video_sample *sample = impl_from_IMFSample(iface);
1316 TRACE("%p, %u, %p.\n", iface, index, buffer);
1318 return IMFSample_GetBufferByIndex(sample->sample, index, buffer);
1321 static HRESULT WINAPI video_sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
1323 TRACE("%p, %p.\n", iface, buffer);
1325 return E_NOTIMPL;
1328 static HRESULT WINAPI video_sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1330 struct video_sample *sample = impl_from_IMFSample(iface);
1332 TRACE("%p, %p.\n", iface, buffer);
1334 return IMFSample_AddBuffer(sample->sample, buffer);
1337 static HRESULT WINAPI video_sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
1339 struct video_sample *sample = impl_from_IMFSample(iface);
1341 TRACE("%p, %u.\n", iface, index);
1343 return IMFSample_RemoveBufferByIndex(sample->sample, index);
1346 static HRESULT WINAPI video_sample_RemoveAllBuffers(IMFSample *iface)
1348 struct video_sample *sample = impl_from_IMFSample(iface);
1350 TRACE("%p.\n", iface);
1352 return IMFSample_RemoveAllBuffers(sample->sample);
1355 static HRESULT WINAPI video_sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
1357 TRACE("%p, %p.\n", iface, total_length);
1359 *total_length = 0;
1361 return S_OK;
1364 static HRESULT WINAPI video_sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1366 TRACE("%p, %p.\n", iface, buffer);
1368 return E_NOTIMPL;
1371 static const IMFSampleVtbl video_sample_vtbl =
1373 video_sample_QueryInterface,
1374 video_sample_AddRef,
1375 video_sample_Release,
1376 video_sample_GetItem,
1377 video_sample_GetItemType,
1378 video_sample_CompareItem,
1379 video_sample_Compare,
1380 video_sample_GetUINT32,
1381 video_sample_GetUINT64,
1382 video_sample_GetDouble,
1383 video_sample_GetGUID,
1384 video_sample_GetStringLength,
1385 video_sample_GetString,
1386 video_sample_GetAllocatedString,
1387 video_sample_GetBlobSize,
1388 video_sample_GetBlob,
1389 video_sample_GetAllocatedBlob,
1390 video_sample_GetUnknown,
1391 video_sample_SetItem,
1392 video_sample_DeleteItem,
1393 video_sample_DeleteAllItems,
1394 video_sample_SetUINT32,
1395 video_sample_SetUINT64,
1396 video_sample_SetDouble,
1397 video_sample_SetGUID,
1398 video_sample_SetString,
1399 video_sample_SetBlob,
1400 video_sample_SetUnknown,
1401 video_sample_LockStore,
1402 video_sample_UnlockStore,
1403 video_sample_GetCount,
1404 video_sample_GetItemByIndex,
1405 video_sample_CopyAllItems,
1406 video_sample_GetSampleFlags,
1407 video_sample_SetSampleFlags,
1408 video_sample_GetSampleTime,
1409 video_sample_SetSampleTime,
1410 video_sample_GetSampleDuration,
1411 video_sample_SetSampleDuration,
1412 video_sample_GetBufferCount,
1413 video_sample_GetBufferByIndex,
1414 video_sample_ConvertToContiguousBuffer,
1415 video_sample_AddBuffer,
1416 video_sample_RemoveBufferByIndex,
1417 video_sample_RemoveAllBuffers,
1418 video_sample_GetTotalLength,
1419 video_sample_CopyToBuffer,
1422 static HRESULT WINAPI tracked_video_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
1424 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1425 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
1428 static ULONG WINAPI tracked_video_sample_AddRef(IMFTrackedSample *iface)
1430 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1431 return IMFSample_AddRef(&sample->IMFSample_iface);
1434 static ULONG WINAPI tracked_video_sample_Release(IMFTrackedSample *iface)
1436 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1437 return IMFSample_Release(&sample->IMFSample_iface);
1440 static HRESULT WINAPI tracked_video_sample_SetAllocator(IMFTrackedSample *iface,
1441 IMFAsyncCallback *sample_allocator, IUnknown *state)
1443 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1444 HRESULT hr = S_OK;
1446 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
1448 IMFSample_LockStore(sample->sample);
1450 if (sample->tracked_result)
1451 hr = MF_E_NOTACCEPTING;
1452 else
1454 if (SUCCEEDED(hr = create_async_result((IUnknown *)iface, sample_allocator, state, &sample->tracked_result)))
1456 /* Account for additional refcount brought by 'state' object. This threshold is used
1457 on Release() to invoke tracker callback. */
1458 sample->tracked_refcount = 1;
1459 if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
1460 state == (IUnknown *)&sample->IMFSample_iface)
1462 ++sample->tracked_refcount;
1467 IMFSample_UnlockStore(sample->sample);
1469 return hr;
1472 static const IMFTrackedSampleVtbl tracked_video_sample_vtbl =
1474 tracked_video_sample_QueryInterface,
1475 tracked_video_sample_AddRef,
1476 tracked_video_sample_Release,
1477 tracked_video_sample_SetAllocator,
1480 static HRESULT WINAPI desired_video_sample_QueryInterface(IMFDesiredSample *iface, REFIID riid, void **obj)
1482 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1483 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
1486 static ULONG WINAPI desired_video_sample_AddRef(IMFDesiredSample *iface)
1488 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1489 return IMFSample_AddRef(&sample->IMFSample_iface);
1492 static ULONG WINAPI desired_video_sample_Release(IMFDesiredSample *iface)
1494 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1495 return IMFSample_Release(&sample->IMFSample_iface);
1498 static HRESULT WINAPI desired_video_sample_GetDesiredSampleTimeAndDuration(IMFDesiredSample *iface,
1499 LONGLONG *sample_time, LONGLONG *sample_duration)
1501 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1502 HRESULT hr = S_OK;
1504 TRACE("%p, %p, %p.\n", iface, sample_time, sample_duration);
1506 if (!sample_time || !sample_duration)
1507 return E_POINTER;
1509 EnterCriticalSection(&sample->cs);
1510 if (sample->flags & SAMPLE_PROP_HAS_DESIRED_PROPS)
1512 *sample_time = sample->desired_timestamp;
1513 *sample_duration = sample->desired_duration;
1515 else
1516 hr = MF_E_NOT_AVAILABLE;
1517 LeaveCriticalSection(&sample->cs);
1519 return hr;
1522 static void WINAPI desired_video_sample_SetDesiredSampleTimeAndDuration(IMFDesiredSample *iface,
1523 LONGLONG sample_time, LONGLONG sample_duration)
1525 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1527 TRACE("%p, %s, %s.\n", iface, debugstr_time(sample_time), debugstr_time(sample_duration));
1529 EnterCriticalSection(&sample->cs);
1530 sample->flags |= SAMPLE_PROP_HAS_DESIRED_PROPS;
1531 sample->desired_timestamp = sample_time;
1532 sample->desired_duration = sample_duration;
1533 LeaveCriticalSection(&sample->cs);
1536 static void WINAPI desired_video_sample_Clear(IMFDesiredSample *iface)
1538 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1540 TRACE("%p.\n", iface);
1542 EnterCriticalSection(&sample->cs);
1543 sample->flags = 0;
1544 IMFSample_SetSampleFlags(sample->sample, 0);
1545 IMFSample_DeleteAllItems(sample->sample);
1546 LeaveCriticalSection(&sample->cs);
1549 static const IMFDesiredSampleVtbl desired_video_sample_vtbl =
1551 desired_video_sample_QueryInterface,
1552 desired_video_sample_AddRef,
1553 desired_video_sample_Release,
1554 desired_video_sample_GetDesiredSampleTimeAndDuration,
1555 desired_video_sample_SetDesiredSampleTimeAndDuration,
1556 desired_video_sample_Clear,
1559 static HRESULT WINAPI surface_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **obj)
1561 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1563 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1565 if (IsEqualIID(riid, &IID_IMFMediaBuffer) || IsEqualIID(riid, &IID_IUnknown))
1567 *obj = &buffer->IMFMediaBuffer_iface;
1569 else if (IsEqualIID(riid, &IID_IMFGetService))
1571 *obj = &buffer->IMFGetService_iface;
1573 else
1575 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1576 *obj = NULL;
1577 return E_NOINTERFACE;
1580 IUnknown_AddRef((IUnknown *)*obj);
1581 return S_OK;
1584 static ULONG WINAPI surface_buffer_AddRef(IMFMediaBuffer *iface)
1586 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1587 ULONG refcount = InterlockedIncrement(&buffer->refcount);
1589 TRACE("%p, refcount %u.\n", iface, refcount);
1591 return refcount;
1594 static ULONG WINAPI surface_buffer_Release(IMFMediaBuffer *iface)
1596 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1597 ULONG refcount = InterlockedDecrement(&buffer->refcount);
1599 TRACE("%p, refcount %u.\n", iface, refcount);
1601 if (!refcount)
1603 IUnknown_Release(buffer->surface);
1604 heap_free(buffer);
1607 return refcount;
1610 static HRESULT WINAPI surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *maxlength, DWORD *length)
1612 TRACE("%p, %p, %p, %p.\n", iface, data, maxlength, length);
1614 return E_NOTIMPL;
1617 static HRESULT WINAPI surface_buffer_Unlock(IMFMediaBuffer *iface)
1619 TRACE("%p.\n", iface);
1621 return E_NOTIMPL;
1624 static HRESULT WINAPI surface_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *length)
1626 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1628 TRACE("%p.\n", iface);
1630 *length = buffer->length;
1632 return S_OK;
1635 static HRESULT WINAPI surface_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD length)
1637 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1639 TRACE("%p.\n", iface);
1641 buffer->length = length;
1643 return S_OK;
1646 static HRESULT WINAPI surface_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *length)
1648 TRACE("%p.\n", iface);
1650 return E_NOTIMPL;
1653 static const IMFMediaBufferVtbl surface_buffer_vtbl =
1655 surface_buffer_QueryInterface,
1656 surface_buffer_AddRef,
1657 surface_buffer_Release,
1658 surface_buffer_Lock,
1659 surface_buffer_Unlock,
1660 surface_buffer_GetCurrentLength,
1661 surface_buffer_SetCurrentLength,
1662 surface_buffer_GetMaxLength,
1665 static HRESULT WINAPI surface_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1667 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1668 return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
1671 static ULONG WINAPI surface_buffer_gs_AddRef(IMFGetService *iface)
1673 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1674 return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
1677 static ULONG WINAPI surface_buffer_gs_Release(IMFGetService *iface)
1679 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1680 return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
1683 static HRESULT WINAPI surface_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1685 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1687 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1689 if (IsEqualGUID(service, &MR_BUFFER_SERVICE))
1690 return IUnknown_QueryInterface(buffer->surface, riid, obj);
1692 return E_NOINTERFACE;
1695 static const IMFGetServiceVtbl surface_buffer_gs_vtbl =
1697 surface_buffer_gs_QueryInterface,
1698 surface_buffer_gs_AddRef,
1699 surface_buffer_gs_Release,
1700 surface_buffer_gs_GetService,
1703 static HRESULT create_surface_buffer(IUnknown *surface, IMFMediaBuffer **buffer)
1705 struct surface_buffer *object;
1707 if (!(object = heap_alloc_zero(sizeof(*object))))
1708 return E_OUTOFMEMORY;
1710 object->IMFMediaBuffer_iface.lpVtbl = &surface_buffer_vtbl;
1711 object->IMFGetService_iface.lpVtbl = &surface_buffer_gs_vtbl;
1712 object->refcount = 1;
1713 object->surface = surface;
1714 IUnknown_AddRef(object->surface);
1716 *buffer = &object->IMFMediaBuffer_iface;
1718 return S_OK;
1721 HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *surface, IMFSample **sample)
1723 struct video_sample *object;
1724 IMFMediaBuffer *buffer = NULL;
1725 HRESULT hr;
1727 TRACE("%p, %p.\n", surface, sample);
1729 if (!(object = heap_alloc_zero(sizeof(*object))))
1730 return E_OUTOFMEMORY;
1732 object->IMFSample_iface.lpVtbl = &video_sample_vtbl;
1733 object->IMFTrackedSample_iface.lpVtbl = &tracked_video_sample_vtbl;
1734 object->IMFDesiredSample_iface.lpVtbl = &desired_video_sample_vtbl;
1735 object->refcount = 1;
1736 InitializeCriticalSection(&object->cs);
1738 if (FAILED(hr = MFCreateSample(&object->sample)))
1740 heap_free(object);
1741 return hr;
1744 if (surface && FAILED(hr = create_surface_buffer(surface, &buffer)))
1746 IMFSample_Release(&object->IMFSample_iface);
1747 return hr;
1750 if (buffer)
1751 IMFSample_AddBuffer(object->sample, buffer);
1753 video_sample_create_tracking_thread();
1755 *sample = &object->IMFSample_iface;
1757 return S_OK;