mshtml: Implement MediaQueryList's addListener method.
[wine.git] / dlls / evr / sample.c
blob6a1bbf564f565eb4d25e8828b7a766d5b96a3ab8
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/list.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(evr);
32 static const char *debugstr_time(LONGLONG time)
34 ULONGLONG abstime = time >= 0 ? time : -time;
35 unsigned int i = 0, j = 0;
36 char buffer[23], rev[23];
38 while (abstime || i <= 8)
40 buffer[i++] = '0' + (abstime % 10);
41 abstime /= 10;
42 if (i == 7) buffer[i++] = '.';
44 if (time < 0) buffer[i++] = '-';
46 while (i--) rev[j++] = buffer[i];
47 while (rev[j-1] == '0' && rev[j-2] != '.') --j;
48 rev[j] = 0;
50 return wine_dbg_sprintf("%s", rev);
53 struct surface_buffer
55 IMFMediaBuffer IMFMediaBuffer_iface;
56 IMFGetService IMFGetService_iface;
57 LONG refcount;
59 IUnknown *surface;
60 ULONG length;
63 enum sample_prop_flags
65 SAMPLE_PROP_HAS_DURATION = 1 << 0,
66 SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1,
67 SAMPLE_PROP_HAS_DESIRED_PROPS = 1 << 2,
70 struct video_sample
72 IMFSample IMFSample_iface;
73 IMFTrackedSample IMFTrackedSample_iface;
74 IMFDesiredSample IMFDesiredSample_iface;
75 LONG refcount;
77 IMFSample *sample;
79 IMFAsyncResult *tracked_result;
80 LONG tracked_refcount;
82 LONGLONG timestamp;
83 LONGLONG duration;
84 LONGLONG desired_timestamp;
85 LONGLONG desired_duration;
86 unsigned int flags;
87 CRITICAL_SECTION cs;
90 static struct video_sample *impl_from_IMFSample(IMFSample *iface)
92 return CONTAINING_RECORD(iface, struct video_sample, IMFSample_iface);
95 static struct video_sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface)
97 return CONTAINING_RECORD(iface, struct video_sample, IMFTrackedSample_iface);
100 static struct video_sample *impl_from_IMFDesiredSample(IMFDesiredSample *iface)
102 return CONTAINING_RECORD(iface, struct video_sample, IMFDesiredSample_iface);
105 static struct surface_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface)
107 return CONTAINING_RECORD(iface, struct surface_buffer, IMFMediaBuffer_iface);
110 static struct surface_buffer *impl_from_IMFGetService(IMFGetService *iface)
112 return CONTAINING_RECORD(iface, struct surface_buffer, IMFGetService_iface);
115 struct tracked_async_result
117 MFASYNCRESULT result;
118 LONG refcount;
119 IUnknown *object;
120 IUnknown *state;
123 static struct tracked_async_result *impl_from_IMFAsyncResult(IMFAsyncResult *iface)
125 return CONTAINING_RECORD(iface, struct tracked_async_result, result.AsyncResult);
128 static HRESULT WINAPI tracked_async_result_QueryInterface(IMFAsyncResult *iface, REFIID riid, void **obj)
130 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
132 if (IsEqualIID(riid, &IID_IMFAsyncResult) ||
133 IsEqualIID(riid, &IID_IUnknown))
135 *obj = iface;
136 IMFAsyncResult_AddRef(iface);
137 return S_OK;
140 *obj = NULL;
141 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
142 return E_NOINTERFACE;
145 static ULONG WINAPI tracked_async_result_AddRef(IMFAsyncResult *iface)
147 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
148 ULONG refcount = InterlockedIncrement(&result->refcount);
150 TRACE("%p, refcount %lu.\n", iface, refcount);
152 return refcount;
155 static ULONG WINAPI tracked_async_result_Release(IMFAsyncResult *iface)
157 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
158 ULONG refcount = InterlockedDecrement(&result->refcount);
160 TRACE("%p, refcount %lu.\n", iface, refcount);
162 if (!refcount)
164 if (result->result.pCallback)
165 IMFAsyncCallback_Release(result->result.pCallback);
166 if (result->object)
167 IUnknown_Release(result->object);
168 if (result->state)
169 IUnknown_Release(result->state);
170 free(result);
173 return refcount;
176 static HRESULT WINAPI tracked_async_result_GetState(IMFAsyncResult *iface, IUnknown **state)
178 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
180 TRACE("%p, %p.\n", iface, state);
182 if (!result->state)
183 return E_POINTER;
185 *state = result->state;
186 IUnknown_AddRef(*state);
188 return S_OK;
191 static HRESULT WINAPI tracked_async_result_GetStatus(IMFAsyncResult *iface)
193 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
195 TRACE("%p.\n", iface);
197 return result->result.hrStatusResult;
200 static HRESULT WINAPI tracked_async_result_SetStatus(IMFAsyncResult *iface, HRESULT status)
202 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
204 TRACE("%p, %#lx.\n", iface, status);
206 result->result.hrStatusResult = status;
208 return S_OK;
211 static HRESULT WINAPI tracked_async_result_GetObject(IMFAsyncResult *iface, IUnknown **object)
213 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
215 TRACE("%p, %p.\n", iface, object);
217 if (!result->object)
218 return E_POINTER;
220 *object = result->object;
221 IUnknown_AddRef(*object);
223 return S_OK;
226 static IUnknown * WINAPI tracked_async_result_GetStateNoAddRef(IMFAsyncResult *iface)
228 struct tracked_async_result *result = impl_from_IMFAsyncResult(iface);
230 TRACE("%p.\n", iface);
232 return result->state;
235 static const IMFAsyncResultVtbl tracked_async_result_vtbl =
237 tracked_async_result_QueryInterface,
238 tracked_async_result_AddRef,
239 tracked_async_result_Release,
240 tracked_async_result_GetState,
241 tracked_async_result_GetStatus,
242 tracked_async_result_SetStatus,
243 tracked_async_result_GetObject,
244 tracked_async_result_GetStateNoAddRef,
247 static HRESULT create_async_result(IUnknown *object, IMFAsyncCallback *callback,
248 IUnknown *state, IMFAsyncResult **out)
250 struct tracked_async_result *result;
252 result = calloc(1, sizeof(*result));
253 if (!result)
254 return E_OUTOFMEMORY;
256 result->result.AsyncResult.lpVtbl = &tracked_async_result_vtbl;
257 result->refcount = 1;
258 result->object = object;
259 if (result->object)
260 IUnknown_AddRef(result->object);
261 result->result.pCallback = callback;
262 if (result->result.pCallback)
263 IMFAsyncCallback_AddRef(result->result.pCallback);
264 result->state = state;
265 if (result->state)
266 IUnknown_AddRef(result->state);
268 *out = &result->result.AsyncResult;
270 return S_OK;
273 struct tracking_thread
275 HANDLE hthread;
276 DWORD tid;
277 LONG refcount;
279 static struct tracking_thread tracking_thread;
281 static CRITICAL_SECTION tracking_thread_cs = { NULL, -1, 0, 0, 0, 0 };
283 enum tracking_thread_message
285 TRACKM_STOP = WM_USER,
286 TRACKM_INVOKE = WM_USER + 1,
289 static DWORD CALLBACK tracking_thread_proc(void *arg)
291 HANDLE ready_event = arg;
292 BOOL stop_thread = FALSE;
293 IMFAsyncResult *result;
294 MFASYNCRESULT *data;
295 MSG msg;
297 PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
299 SetEvent(ready_event);
301 while (!stop_thread)
303 MsgWaitForMultipleObjects(0, NULL, FALSE, INFINITE, QS_POSTMESSAGE);
305 while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
307 switch (msg.message)
309 case TRACKM_INVOKE:
310 result = (IMFAsyncResult *)msg.lParam;
311 data = (MFASYNCRESULT *)result;
312 if (data->pCallback)
313 IMFAsyncCallback_Invoke(data->pCallback, result);
314 IMFAsyncResult_Release(result);
315 break;
317 case TRACKM_STOP:
318 stop_thread = TRUE;
319 break;
321 default:
327 TRACE("Tracking thread exiting.\n");
329 return 0;
332 static void video_sample_create_tracking_thread(void)
334 EnterCriticalSection(&tracking_thread_cs);
336 if (++tracking_thread.refcount == 1)
338 HANDLE ready_event;
340 ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
342 if (!(tracking_thread.hthread = CreateThread(NULL, 0, tracking_thread_proc,
343 ready_event, 0, &tracking_thread.tid)))
345 WARN("Failed to create sample tracking thread.\n");
346 CloseHandle(ready_event);
347 LeaveCriticalSection(&tracking_thread_cs);
348 return;
351 WaitForSingleObject(ready_event, INFINITE);
352 CloseHandle(ready_event);
354 TRACE("Create tracking thread %#lx.\n", tracking_thread.tid);
357 LeaveCriticalSection(&tracking_thread_cs);
360 static void video_sample_stop_tracking_thread(void)
362 EnterCriticalSection(&tracking_thread_cs);
364 if (!--tracking_thread.refcount)
366 PostThreadMessageW(tracking_thread.tid, TRACKM_STOP, 0, 0);
367 CloseHandle(tracking_thread.hthread);
368 memset(&tracking_thread, 0, sizeof(tracking_thread));
371 LeaveCriticalSection(&tracking_thread_cs);
374 static void video_sample_tracking_thread_invoke(IMFAsyncResult *result)
376 if (!tracking_thread.tid)
378 WARN("Sample tracking thread is not initialized.\n");
379 return;
382 IMFAsyncResult_AddRef(result);
383 PostThreadMessageW(tracking_thread.tid, TRACKM_INVOKE, 0, (LPARAM)result);
386 struct sample_allocator
388 IMFVideoSampleAllocator IMFVideoSampleAllocator_iface;
389 IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface;
390 IMFAsyncCallback tracking_callback;
391 LONG refcount;
393 IMFVideoSampleAllocatorNotify *callback;
394 IDirect3DDeviceManager9 *device_manager;
395 unsigned int free_sample_count;
396 struct list free_samples;
397 struct list used_samples;
398 CRITICAL_SECTION cs;
401 struct queued_sample
403 struct list entry;
404 IMFSample *sample;
407 static struct sample_allocator *impl_from_IMFVideoSampleAllocator(IMFVideoSampleAllocator *iface)
409 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocator_iface);
412 static struct sample_allocator *impl_from_IMFVideoSampleAllocatorCallback(IMFVideoSampleAllocatorCallback *iface)
414 return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorCallback_iface);
417 static struct sample_allocator *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface)
419 return CONTAINING_RECORD(iface, struct sample_allocator, tracking_callback);
422 static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocator *iface, REFIID riid, void **obj)
424 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
426 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
428 if (IsEqualIID(riid, &IID_IMFVideoSampleAllocator) ||
429 IsEqualIID(riid, &IID_IUnknown))
431 *obj = &allocator->IMFVideoSampleAllocator_iface;
433 else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback))
435 *obj = &allocator->IMFVideoSampleAllocatorCallback_iface;
437 else
439 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
440 *obj = NULL;
441 return E_NOINTERFACE;
444 IUnknown_AddRef((IUnknown *)*obj);
445 return S_OK;
448 static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocator *iface)
450 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
451 ULONG refcount = InterlockedIncrement(&allocator->refcount);
453 TRACE("%p, refcount %lu.\n", iface, refcount);
455 return refcount;
458 static void sample_allocator_release_samples(struct sample_allocator *allocator)
460 struct queued_sample *iter, *iter2;
462 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry)
464 list_remove(&iter->entry);
465 IMFSample_Release(iter->sample);
466 free(iter);
469 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry)
471 list_remove(&iter->entry);
472 free(iter);
476 static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocator *iface)
478 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
479 ULONG refcount = InterlockedDecrement(&allocator->refcount);
481 TRACE("%p, refcount %lu.\n", iface, refcount);
483 if (!refcount)
485 if (allocator->callback)
486 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
487 if (allocator->device_manager)
488 IDirect3DDeviceManager9_Release(allocator->device_manager);
489 sample_allocator_release_samples(allocator);
490 DeleteCriticalSection(&allocator->cs);
491 free(allocator);
494 return refcount;
497 static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocator *iface,
498 IUnknown *manager)
500 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
501 IDirect3DDeviceManager9 *device_manager = NULL;
502 HRESULT hr;
504 TRACE("%p, %p.\n", iface, manager);
506 if (manager && FAILED(hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9,
507 (void **)&device_manager)))
509 return hr;
512 EnterCriticalSection(&allocator->cs);
514 if (allocator->device_manager)
515 IDirect3DDeviceManager9_Release(allocator->device_manager);
516 allocator->device_manager = device_manager;
518 LeaveCriticalSection(&allocator->cs);
520 return S_OK;
523 static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocator *iface)
525 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
527 TRACE("%p.\n", iface);
529 EnterCriticalSection(&allocator->cs);
531 sample_allocator_release_samples(allocator);
532 allocator->free_sample_count = 0;
534 LeaveCriticalSection(&allocator->cs);
536 return S_OK;
539 static HRESULT sample_allocator_create_samples(struct sample_allocator *allocator, unsigned int sample_count,
540 IMFMediaType *media_type)
542 IDirectXVideoProcessorService *service = NULL;
543 unsigned int i, width, height;
544 IDirect3DSurface9 *surface;
545 HANDLE hdevice = NULL;
546 GUID major, subtype;
547 UINT64 frame_size;
548 IMFSample *sample;
549 D3DFORMAT format;
550 HRESULT hr;
552 if (FAILED(IMFMediaType_GetMajorType(media_type, &major)))
553 return MF_E_INVALIDMEDIATYPE;
555 if (!IsEqualGUID(&major, &MFMediaType_Video))
556 return MF_E_INVALIDMEDIATYPE;
558 if (FAILED(IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size)))
559 return MF_E_INVALIDMEDIATYPE;
561 if (FAILED(IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype)))
562 return MF_E_INVALIDMEDIATYPE;
564 format = subtype.Data1;
565 height = frame_size;
566 width = frame_size >> 32;
568 if (allocator->device_manager)
570 if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->device_manager, &hdevice)))
572 hr = IDirect3DDeviceManager9_GetVideoService(allocator->device_manager, hdevice,
573 &IID_IDirectXVideoProcessorService, (void **)&service);
576 if (FAILED(hr))
578 WARN("Failed to get processor service, %#lx.\n", hr);
579 return hr;
583 sample_allocator_release_samples(allocator);
585 for (i = 0; i < sample_count; ++i)
587 struct queued_sample *queued_sample;
588 IMFMediaBuffer *buffer;
590 if (SUCCEEDED(hr = MFCreateVideoSampleFromSurface(NULL, &sample)))
592 if (service)
594 if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service, width, height,
595 0, format, D3DPOOL_DEFAULT, 0, DXVA2_VideoProcessorRenderTarget, &surface, NULL)))
597 hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer);
598 IDirect3DSurface9_Release(surface);
601 else
603 hr = MFCreate2DMediaBuffer(width, height, format, FALSE, &buffer);
606 if (SUCCEEDED(hr))
608 hr = IMFSample_AddBuffer(sample, buffer);
609 IMFMediaBuffer_Release(buffer);
613 if (FAILED(hr))
615 WARN("Unable to allocate %u samples.\n", sample_count);
616 sample_allocator_release_samples(allocator);
617 break;
620 queued_sample = malloc(sizeof(*queued_sample));
621 queued_sample->sample = sample;
622 list_add_tail(&allocator->free_samples, &queued_sample->entry);
623 allocator->free_sample_count++;
626 if (service)
627 IDirectXVideoProcessorService_Release(service);
629 if (allocator->device_manager)
630 IDirect3DDeviceManager9_CloseDeviceHandle(allocator->device_manager, hdevice);
632 return hr;
635 static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocator *iface,
636 DWORD sample_count, IMFMediaType *media_type)
638 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
639 HRESULT hr;
641 TRACE("%p, %lu, %p.\n", iface, sample_count, media_type);
643 if (!sample_count)
644 sample_count = 1;
646 EnterCriticalSection(&allocator->cs);
648 hr = sample_allocator_create_samples(allocator, sample_count, media_type);
650 LeaveCriticalSection(&allocator->cs);
652 return hr;
655 static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocator *iface, IMFSample **out)
657 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocator(iface);
658 IMFTrackedSample *tracked_sample;
659 IMFSample *sample;
660 HRESULT hr;
662 TRACE("%p, %p.\n", iface, out);
664 EnterCriticalSection(&allocator->cs);
666 if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples))
667 hr = MF_E_NOT_INITIALIZED;
668 else if (list_empty(&allocator->free_samples))
669 hr = MF_E_SAMPLEALLOCATOR_EMPTY;
670 else
672 struct list *head = list_head(&allocator->free_samples);
674 sample = LIST_ENTRY(head, struct queued_sample, entry)->sample;
676 if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample)))
678 hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL);
679 IMFTrackedSample_Release(tracked_sample);
682 if (SUCCEEDED(hr))
684 list_remove(head);
685 list_add_tail(&allocator->used_samples, head);
686 allocator->free_sample_count--;
688 /* Reference counter is not increased when sample is returned, so next release could trigger
689 tracking condition. This is balanced by incremented reference counter when sample is returned
690 back to the free list. */
691 *out = sample;
695 LeaveCriticalSection(&allocator->cs);
697 return hr;
700 static const IMFVideoSampleAllocatorVtbl sample_allocator_vtbl =
702 sample_allocator_QueryInterface,
703 sample_allocator_AddRef,
704 sample_allocator_Release,
705 sample_allocator_SetDirectXManager,
706 sample_allocator_UninitializeSampleAllocator,
707 sample_allocator_InitializeSampleAllocator,
708 sample_allocator_AllocateSample,
711 static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface,
712 REFIID riid, void **obj)
714 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
715 return IMFVideoSampleAllocator_QueryInterface(&allocator->IMFVideoSampleAllocator_iface, riid, obj);
718 static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface)
720 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
721 return IMFVideoSampleAllocator_AddRef(&allocator->IMFVideoSampleAllocator_iface);
724 static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface)
726 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
727 return IMFVideoSampleAllocator_Release(&allocator->IMFVideoSampleAllocator_iface);
730 static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface,
731 IMFVideoSampleAllocatorNotify *callback)
733 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
735 TRACE("%p, %p.\n", iface, callback);
737 EnterCriticalSection(&allocator->cs);
738 if (allocator->callback)
739 IMFVideoSampleAllocatorNotify_Release(allocator->callback);
740 allocator->callback = callback;
741 if (allocator->callback)
742 IMFVideoSampleAllocatorNotify_AddRef(allocator->callback);
743 LeaveCriticalSection(&allocator->cs);
745 return S_OK;
748 static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface,
749 LONG *count)
751 struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface);
753 TRACE("%p, %p.\n", iface, count);
755 EnterCriticalSection(&allocator->cs);
756 if (count)
757 *count = allocator->free_sample_count;
758 LeaveCriticalSection(&allocator->cs);
760 return S_OK;
763 static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl =
765 sample_allocator_callback_QueryInterface,
766 sample_allocator_callback_AddRef,
767 sample_allocator_callback_Release,
768 sample_allocator_callback_SetCallback,
769 sample_allocator_callback_GetFreeSampleCount,
772 static HRESULT WINAPI sample_allocator_tracking_callback_QueryInterface(IMFAsyncCallback *iface,
773 REFIID riid, void **obj)
775 if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
776 IsEqualIID(riid, &IID_IUnknown))
778 *obj = iface;
779 IMFAsyncCallback_AddRef(iface);
780 return S_OK;
783 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
784 *obj = NULL;
785 return E_NOINTERFACE;
788 static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface)
790 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
791 return IMFVideoSampleAllocator_AddRef(&allocator->IMFVideoSampleAllocator_iface);
794 static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface)
796 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
797 return IMFVideoSampleAllocator_Release(&allocator->IMFVideoSampleAllocator_iface);
800 static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface,
801 DWORD *flags, DWORD *queue)
803 return E_NOTIMPL;
806 static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
808 struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface);
809 struct queued_sample *iter;
810 IUnknown *object = NULL;
811 IMFSample *sample = NULL;
812 HRESULT hr;
814 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
815 return E_UNEXPECTED;
817 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
818 IUnknown_Release(object);
819 if (FAILED(hr))
820 return E_UNEXPECTED;
822 EnterCriticalSection(&allocator->cs);
824 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
826 if (sample == iter->sample)
828 list_remove(&iter->entry);
829 list_add_tail(&allocator->free_samples, &iter->entry);
830 IMFSample_AddRef(iter->sample);
831 allocator->free_sample_count++;
832 break;
836 IMFSample_Release(sample);
838 if (allocator->callback)
839 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
841 LeaveCriticalSection(&allocator->cs);
843 return S_OK;
846 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
848 sample_allocator_tracking_callback_QueryInterface,
849 sample_allocator_tracking_callback_AddRef,
850 sample_allocator_tracking_callback_Release,
851 sample_allocator_tracking_callback_GetParameters,
852 sample_allocator_tracking_callback_Invoke,
855 HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj)
857 struct sample_allocator *object;
858 HRESULT hr;
860 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
862 if (!(object = calloc(1, sizeof(*object))))
863 return E_OUTOFMEMORY;
865 object->IMFVideoSampleAllocator_iface.lpVtbl = &sample_allocator_vtbl;
866 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
867 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
868 object->refcount = 1;
869 list_init(&object->used_samples);
870 list_init(&object->free_samples);
871 InitializeCriticalSection(&object->cs);
873 hr = IMFVideoSampleAllocator_QueryInterface(&object->IMFVideoSampleAllocator_iface, riid, obj);
874 IMFVideoSampleAllocator_Release(&object->IMFVideoSampleAllocator_iface);
876 return hr;
879 static HRESULT WINAPI video_sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
881 struct video_sample *sample = impl_from_IMFSample(iface);
883 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
885 if (IsEqualIID(riid, &IID_IMFSample) ||
886 IsEqualIID(riid, &IID_IMFAttributes) ||
887 IsEqualIID(riid, &IID_IUnknown))
889 *out = &sample->IMFSample_iface;
891 else if (IsEqualIID(riid, &IID_IMFTrackedSample))
893 *out = &sample->IMFTrackedSample_iface;
895 else if (IsEqualIID(riid, &IID_IMFDesiredSample))
897 *out = &sample->IMFDesiredSample_iface;
899 else
901 WARN("Unsupported %s.\n", debugstr_guid(riid));
902 *out = NULL;
903 return E_NOINTERFACE;
906 IUnknown_AddRef((IUnknown *)*out);
907 return S_OK;
910 static ULONG WINAPI video_sample_AddRef(IMFSample *iface)
912 struct video_sample *sample = impl_from_IMFSample(iface);
913 ULONG refcount = InterlockedIncrement(&sample->refcount);
915 TRACE("%p, refcount %lu.\n", iface, refcount);
917 return refcount;
920 static ULONG WINAPI video_sample_Release(IMFSample *iface)
922 struct video_sample *sample = impl_from_IMFSample(iface);
923 ULONG refcount = InterlockedDecrement(&sample->refcount);
924 IMFAsyncResult *tracked_result = NULL;
926 EnterCriticalSection(&sample->cs);
927 if (sample->tracked_result && sample->tracked_refcount == refcount)
929 tracked_result = sample->tracked_result;
930 video_sample_tracking_thread_invoke(tracked_result);
931 sample->tracked_result = NULL;
932 sample->tracked_refcount = 0;
934 LeaveCriticalSection(&sample->cs);
936 if (tracked_result)
937 IMFAsyncResult_Release(tracked_result);
939 TRACE("%p, refcount %lu.\n", iface, refcount);
941 if (!refcount)
943 video_sample_stop_tracking_thread();
944 if (sample->sample)
945 IMFSample_Release(sample->sample);
946 DeleteCriticalSection(&sample->cs);
947 free(sample);
950 return refcount;
953 static HRESULT WINAPI video_sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
955 struct video_sample *sample = impl_from_IMFSample(iface);
957 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
959 return IMFSample_GetItem(sample->sample, key, value);
962 static HRESULT WINAPI video_sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
964 struct video_sample *sample = impl_from_IMFSample(iface);
966 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
968 return IMFSample_GetItemType(sample->sample, key, type);
971 static HRESULT WINAPI video_sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
973 struct video_sample *sample = impl_from_IMFSample(iface);
975 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
977 return IMFSample_CompareItem(sample->sample, key, value, result);
980 static HRESULT WINAPI video_sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
981 BOOL *result)
983 struct video_sample *sample = impl_from_IMFSample(iface);
985 TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
987 return IMFSample_Compare(sample->sample, theirs, type, result);
990 static HRESULT WINAPI video_sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
992 struct video_sample *sample = impl_from_IMFSample(iface);
994 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
996 return IMFSample_GetUINT32(sample->sample, key, value);
999 static HRESULT WINAPI video_sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
1001 struct video_sample *sample = impl_from_IMFSample(iface);
1003 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1005 return IMFSample_GetUINT64(sample->sample, key, value);
1008 static HRESULT WINAPI video_sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
1010 struct video_sample *sample = impl_from_IMFSample(iface);
1012 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1014 return IMFSample_GetDouble(sample->sample, key, value);
1017 static HRESULT WINAPI video_sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
1019 struct video_sample *sample = impl_from_IMFSample(iface);
1021 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1023 return IMFSample_GetGUID(sample->sample, key, value);
1026 static HRESULT WINAPI video_sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
1028 struct video_sample *sample = impl_from_IMFSample(iface);
1030 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
1032 return IMFSample_GetStringLength(sample->sample, key, length);
1035 static HRESULT WINAPI video_sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
1037 struct video_sample *sample = impl_from_IMFSample(iface);
1039 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), value, size, length);
1041 return IMFSample_GetString(sample->sample, key, value, size, length);
1044 static HRESULT WINAPI video_sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
1046 struct video_sample *sample = impl_from_IMFSample(iface);
1048 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
1050 return IMFSample_GetAllocatedString(sample->sample, key, value, length);
1053 static HRESULT WINAPI video_sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
1055 struct video_sample *sample = impl_from_IMFSample(iface);
1057 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
1059 return IMFSample_GetBlobSize(sample->sample, key, size);
1062 static HRESULT WINAPI video_sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
1064 struct video_sample *sample = impl_from_IMFSample(iface);
1066 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
1068 return IMFSample_GetBlob(sample->sample, key, buf, bufsize, blobsize);
1071 static HRESULT WINAPI video_sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
1073 struct video_sample *sample = impl_from_IMFSample(iface);
1075 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
1077 return IMFSample_GetAllocatedBlob(sample->sample, key, buf, size);
1080 static HRESULT WINAPI video_sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
1082 struct video_sample *sample = impl_from_IMFSample(iface);
1084 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
1086 return IMFSample_GetUnknown(sample->sample, key, riid, out);
1089 static HRESULT WINAPI video_sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
1091 struct video_sample *sample = impl_from_IMFSample(iface);
1093 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1095 return IMFSample_SetItem(sample->sample, key, value);
1098 static HRESULT WINAPI video_sample_DeleteItem(IMFSample *iface, REFGUID key)
1100 struct video_sample *sample = impl_from_IMFSample(iface);
1102 TRACE("%p, %s.\n", iface, debugstr_guid(key));
1104 return IMFSample_DeleteItem(sample->sample, key);
1107 static HRESULT WINAPI video_sample_DeleteAllItems(IMFSample *iface)
1109 struct video_sample *sample = impl_from_IMFSample(iface);
1111 TRACE("%p.\n", iface);
1113 return IMFSample_DeleteAllItems(sample->sample);
1116 static HRESULT WINAPI video_sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
1118 struct video_sample *sample = impl_from_IMFSample(iface);
1120 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
1122 return IMFSample_SetUINT32(sample->sample, key, value);
1125 static HRESULT WINAPI video_sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
1127 struct video_sample *sample = impl_from_IMFSample(iface);
1129 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
1131 return IMFSample_SetUINT64(sample->sample, key, value);
1134 static HRESULT WINAPI video_sample_SetDouble(IMFSample *iface, REFGUID key, double value)
1136 struct video_sample *sample = impl_from_IMFSample(iface);
1138 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
1140 return IMFSample_SetDouble(sample->sample, key, value);
1143 static HRESULT WINAPI video_sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
1145 struct video_sample *sample = impl_from_IMFSample(iface);
1147 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
1149 return IMFSample_SetGUID(sample->sample, key, value);
1152 static HRESULT WINAPI video_sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
1154 struct video_sample *sample = impl_from_IMFSample(iface);
1156 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
1158 return IMFSample_SetString(sample->sample, key, value);
1161 static HRESULT WINAPI video_sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
1163 struct video_sample *sample = impl_from_IMFSample(iface);
1165 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
1167 return IMFSample_SetBlob(sample->sample, key, buf, size);
1170 static HRESULT WINAPI video_sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
1172 struct video_sample *sample = impl_from_IMFSample(iface);
1174 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
1176 return IMFSample_SetUnknown(sample->sample, key, unknown);
1179 static HRESULT WINAPI video_sample_LockStore(IMFSample *iface)
1181 struct video_sample *sample = impl_from_IMFSample(iface);
1183 TRACE("%p.\n", iface);
1185 return IMFSample_LockStore(sample->sample);
1188 static HRESULT WINAPI video_sample_UnlockStore(IMFSample *iface)
1190 struct video_sample *sample = impl_from_IMFSample(iface);
1192 TRACE("%p.\n", iface);
1194 return IMFSample_UnlockStore(sample->sample);
1197 static HRESULT WINAPI video_sample_GetCount(IMFSample *iface, UINT32 *count)
1199 struct video_sample *sample = impl_from_IMFSample(iface);
1201 TRACE("%p, %p.\n", iface, count);
1203 return IMFSample_GetCount(sample->sample, count);
1206 static HRESULT WINAPI video_sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
1208 struct video_sample *sample = impl_from_IMFSample(iface);
1210 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
1212 return IMFSample_GetItemByIndex(sample->sample, index, key, value);
1215 static HRESULT WINAPI video_sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
1217 struct video_sample *sample = impl_from_IMFSample(iface);
1219 TRACE("%p, %p.\n", iface, dest);
1221 return IMFSample_CopyAllItems(sample->sample, dest);
1224 static HRESULT WINAPI video_sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
1226 struct video_sample *sample = impl_from_IMFSample(iface);
1228 TRACE("%p, %p.\n", iface, flags);
1230 return IMFSample_GetSampleFlags(sample->sample, flags);
1233 static HRESULT WINAPI video_sample_SetSampleFlags(IMFSample *iface, DWORD flags)
1235 struct video_sample *sample = impl_from_IMFSample(iface);
1237 TRACE("%p, %#lx.\n", iface, flags);
1239 return IMFSample_SetSampleFlags(sample->sample, flags);
1242 static HRESULT WINAPI video_sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
1244 struct video_sample *sample = impl_from_IMFSample(iface);
1245 HRESULT hr = S_OK;
1247 TRACE("%p, %p.\n", iface, timestamp);
1249 EnterCriticalSection(&sample->cs);
1250 if (sample->flags & SAMPLE_PROP_HAS_TIMESTAMP)
1251 *timestamp = sample->timestamp;
1252 else
1253 hr = MF_E_NO_SAMPLE_TIMESTAMP;
1254 LeaveCriticalSection(&sample->cs);
1256 return hr;
1259 static HRESULT WINAPI video_sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
1261 struct video_sample *sample = impl_from_IMFSample(iface);
1263 TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
1265 EnterCriticalSection(&sample->cs);
1266 sample->timestamp = timestamp;
1267 sample->flags |= SAMPLE_PROP_HAS_TIMESTAMP;
1268 LeaveCriticalSection(&sample->cs);
1270 return S_OK;
1273 static HRESULT WINAPI video_sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
1275 struct video_sample *sample = impl_from_IMFSample(iface);
1276 HRESULT hr = S_OK;
1278 TRACE("%p, %p.\n", iface, duration);
1280 EnterCriticalSection(&sample->cs);
1281 if (sample->flags & SAMPLE_PROP_HAS_DURATION)
1282 *duration = sample->duration;
1283 else
1284 hr = MF_E_NO_SAMPLE_DURATION;
1285 LeaveCriticalSection(&sample->cs);
1287 return hr;
1290 static HRESULT WINAPI video_sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
1292 struct video_sample *sample = impl_from_IMFSample(iface);
1294 TRACE("%p, %s.\n", iface, debugstr_time(duration));
1296 EnterCriticalSection(&sample->cs);
1297 sample->duration = duration;
1298 sample->flags |= SAMPLE_PROP_HAS_DURATION;
1299 LeaveCriticalSection(&sample->cs);
1301 return S_OK;
1304 static HRESULT WINAPI video_sample_GetBufferCount(IMFSample *iface, DWORD *count)
1306 struct video_sample *sample = impl_from_IMFSample(iface);
1308 TRACE("%p, %p.\n", iface, count);
1310 return IMFSample_GetBufferCount(sample->sample, count);
1313 static HRESULT WINAPI video_sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
1315 struct video_sample *sample = impl_from_IMFSample(iface);
1317 TRACE("%p, %lu, %p.\n", iface, index, buffer);
1319 return IMFSample_GetBufferByIndex(sample->sample, index, buffer);
1322 static HRESULT WINAPI video_sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
1324 TRACE("%p, %p.\n", iface, buffer);
1326 return E_NOTIMPL;
1329 static HRESULT WINAPI video_sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1331 struct video_sample *sample = impl_from_IMFSample(iface);
1333 TRACE("%p, %p.\n", iface, buffer);
1335 return IMFSample_AddBuffer(sample->sample, buffer);
1338 static HRESULT WINAPI video_sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
1340 struct video_sample *sample = impl_from_IMFSample(iface);
1342 TRACE("%p, %lu.\n", iface, index);
1344 return IMFSample_RemoveBufferByIndex(sample->sample, index);
1347 static HRESULT WINAPI video_sample_RemoveAllBuffers(IMFSample *iface)
1349 struct video_sample *sample = impl_from_IMFSample(iface);
1351 TRACE("%p.\n", iface);
1353 return IMFSample_RemoveAllBuffers(sample->sample);
1356 static HRESULT WINAPI video_sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
1358 TRACE("%p, %p.\n", iface, total_length);
1360 *total_length = 0;
1362 return S_OK;
1365 static HRESULT WINAPI video_sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1367 TRACE("%p, %p.\n", iface, buffer);
1369 return E_NOTIMPL;
1372 static const IMFSampleVtbl video_sample_vtbl =
1374 video_sample_QueryInterface,
1375 video_sample_AddRef,
1376 video_sample_Release,
1377 video_sample_GetItem,
1378 video_sample_GetItemType,
1379 video_sample_CompareItem,
1380 video_sample_Compare,
1381 video_sample_GetUINT32,
1382 video_sample_GetUINT64,
1383 video_sample_GetDouble,
1384 video_sample_GetGUID,
1385 video_sample_GetStringLength,
1386 video_sample_GetString,
1387 video_sample_GetAllocatedString,
1388 video_sample_GetBlobSize,
1389 video_sample_GetBlob,
1390 video_sample_GetAllocatedBlob,
1391 video_sample_GetUnknown,
1392 video_sample_SetItem,
1393 video_sample_DeleteItem,
1394 video_sample_DeleteAllItems,
1395 video_sample_SetUINT32,
1396 video_sample_SetUINT64,
1397 video_sample_SetDouble,
1398 video_sample_SetGUID,
1399 video_sample_SetString,
1400 video_sample_SetBlob,
1401 video_sample_SetUnknown,
1402 video_sample_LockStore,
1403 video_sample_UnlockStore,
1404 video_sample_GetCount,
1405 video_sample_GetItemByIndex,
1406 video_sample_CopyAllItems,
1407 video_sample_GetSampleFlags,
1408 video_sample_SetSampleFlags,
1409 video_sample_GetSampleTime,
1410 video_sample_SetSampleTime,
1411 video_sample_GetSampleDuration,
1412 video_sample_SetSampleDuration,
1413 video_sample_GetBufferCount,
1414 video_sample_GetBufferByIndex,
1415 video_sample_ConvertToContiguousBuffer,
1416 video_sample_AddBuffer,
1417 video_sample_RemoveBufferByIndex,
1418 video_sample_RemoveAllBuffers,
1419 video_sample_GetTotalLength,
1420 video_sample_CopyToBuffer,
1423 static HRESULT WINAPI tracked_video_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
1425 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1426 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
1429 static ULONG WINAPI tracked_video_sample_AddRef(IMFTrackedSample *iface)
1431 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1432 return IMFSample_AddRef(&sample->IMFSample_iface);
1435 static ULONG WINAPI tracked_video_sample_Release(IMFTrackedSample *iface)
1437 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1438 return IMFSample_Release(&sample->IMFSample_iface);
1441 static HRESULT WINAPI tracked_video_sample_SetAllocator(IMFTrackedSample *iface,
1442 IMFAsyncCallback *sample_allocator, IUnknown *state)
1444 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1445 HRESULT hr = S_OK;
1447 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
1449 EnterCriticalSection(&sample->cs);
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;
1466 LeaveCriticalSection(&sample->cs);
1468 return hr;
1471 static const IMFTrackedSampleVtbl tracked_video_sample_vtbl =
1473 tracked_video_sample_QueryInterface,
1474 tracked_video_sample_AddRef,
1475 tracked_video_sample_Release,
1476 tracked_video_sample_SetAllocator,
1479 static HRESULT WINAPI desired_video_sample_QueryInterface(IMFDesiredSample *iface, REFIID riid, void **obj)
1481 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1482 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
1485 static ULONG WINAPI desired_video_sample_AddRef(IMFDesiredSample *iface)
1487 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1488 return IMFSample_AddRef(&sample->IMFSample_iface);
1491 static ULONG WINAPI desired_video_sample_Release(IMFDesiredSample *iface)
1493 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1494 return IMFSample_Release(&sample->IMFSample_iface);
1497 static HRESULT WINAPI desired_video_sample_GetDesiredSampleTimeAndDuration(IMFDesiredSample *iface,
1498 LONGLONG *sample_time, LONGLONG *sample_duration)
1500 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1501 HRESULT hr = S_OK;
1503 TRACE("%p, %p, %p.\n", iface, sample_time, sample_duration);
1505 if (!sample_time || !sample_duration)
1506 return E_POINTER;
1508 EnterCriticalSection(&sample->cs);
1509 if (sample->flags & SAMPLE_PROP_HAS_DESIRED_PROPS)
1511 *sample_time = sample->desired_timestamp;
1512 *sample_duration = sample->desired_duration;
1514 else
1515 hr = MF_E_NOT_AVAILABLE;
1516 LeaveCriticalSection(&sample->cs);
1518 return hr;
1521 static void WINAPI desired_video_sample_SetDesiredSampleTimeAndDuration(IMFDesiredSample *iface,
1522 LONGLONG sample_time, LONGLONG sample_duration)
1524 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1526 TRACE("%p, %s, %s.\n", iface, debugstr_time(sample_time), debugstr_time(sample_duration));
1528 EnterCriticalSection(&sample->cs);
1529 sample->flags |= SAMPLE_PROP_HAS_DESIRED_PROPS;
1530 sample->desired_timestamp = sample_time;
1531 sample->desired_duration = sample_duration;
1532 LeaveCriticalSection(&sample->cs);
1535 static void WINAPI desired_video_sample_Clear(IMFDesiredSample *iface)
1537 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1539 TRACE("%p.\n", iface);
1541 EnterCriticalSection(&sample->cs);
1542 sample->flags = 0;
1543 IMFSample_SetSampleFlags(sample->sample, 0);
1544 IMFSample_DeleteAllItems(sample->sample);
1545 LeaveCriticalSection(&sample->cs);
1548 static const IMFDesiredSampleVtbl desired_video_sample_vtbl =
1550 desired_video_sample_QueryInterface,
1551 desired_video_sample_AddRef,
1552 desired_video_sample_Release,
1553 desired_video_sample_GetDesiredSampleTimeAndDuration,
1554 desired_video_sample_SetDesiredSampleTimeAndDuration,
1555 desired_video_sample_Clear,
1558 static HRESULT WINAPI surface_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **obj)
1560 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1562 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1564 if (IsEqualIID(riid, &IID_IMFMediaBuffer) || IsEqualIID(riid, &IID_IUnknown))
1566 *obj = &buffer->IMFMediaBuffer_iface;
1568 else if (IsEqualIID(riid, &IID_IMFGetService))
1570 *obj = &buffer->IMFGetService_iface;
1572 else
1574 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1575 *obj = NULL;
1576 return E_NOINTERFACE;
1579 IUnknown_AddRef((IUnknown *)*obj);
1580 return S_OK;
1583 static ULONG WINAPI surface_buffer_AddRef(IMFMediaBuffer *iface)
1585 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1586 ULONG refcount = InterlockedIncrement(&buffer->refcount);
1588 TRACE("%p, refcount %lu.\n", iface, refcount);
1590 return refcount;
1593 static ULONG WINAPI surface_buffer_Release(IMFMediaBuffer *iface)
1595 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1596 ULONG refcount = InterlockedDecrement(&buffer->refcount);
1598 TRACE("%p, refcount %lu.\n", iface, refcount);
1600 if (!refcount)
1602 IUnknown_Release(buffer->surface);
1603 free(buffer);
1606 return refcount;
1609 static HRESULT WINAPI surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *maxlength, DWORD *length)
1611 TRACE("%p, %p, %p, %p.\n", iface, data, maxlength, length);
1613 return E_NOTIMPL;
1616 static HRESULT WINAPI surface_buffer_Unlock(IMFMediaBuffer *iface)
1618 TRACE("%p.\n", iface);
1620 return E_NOTIMPL;
1623 static HRESULT WINAPI surface_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *length)
1625 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1627 TRACE("%p.\n", iface);
1629 *length = buffer->length;
1631 return S_OK;
1634 static HRESULT WINAPI surface_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD length)
1636 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1638 TRACE("%p.\n", iface);
1640 buffer->length = length;
1642 return S_OK;
1645 static HRESULT WINAPI surface_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *length)
1647 TRACE("%p.\n", iface);
1649 return E_NOTIMPL;
1652 static const IMFMediaBufferVtbl surface_buffer_vtbl =
1654 surface_buffer_QueryInterface,
1655 surface_buffer_AddRef,
1656 surface_buffer_Release,
1657 surface_buffer_Lock,
1658 surface_buffer_Unlock,
1659 surface_buffer_GetCurrentLength,
1660 surface_buffer_SetCurrentLength,
1661 surface_buffer_GetMaxLength,
1664 static HRESULT WINAPI surface_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1666 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1667 return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
1670 static ULONG WINAPI surface_buffer_gs_AddRef(IMFGetService *iface)
1672 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1673 return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
1676 static ULONG WINAPI surface_buffer_gs_Release(IMFGetService *iface)
1678 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1679 return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
1682 static HRESULT WINAPI surface_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1684 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1686 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1688 if (IsEqualGUID(service, &MR_BUFFER_SERVICE))
1689 return IUnknown_QueryInterface(buffer->surface, riid, obj);
1691 return E_NOINTERFACE;
1694 static const IMFGetServiceVtbl surface_buffer_gs_vtbl =
1696 surface_buffer_gs_QueryInterface,
1697 surface_buffer_gs_AddRef,
1698 surface_buffer_gs_Release,
1699 surface_buffer_gs_GetService,
1702 static HRESULT create_surface_buffer(IUnknown *surface, IMFMediaBuffer **buffer)
1704 struct surface_buffer *object;
1706 if (!(object = calloc(1, sizeof(*object))))
1707 return E_OUTOFMEMORY;
1709 object->IMFMediaBuffer_iface.lpVtbl = &surface_buffer_vtbl;
1710 object->IMFGetService_iface.lpVtbl = &surface_buffer_gs_vtbl;
1711 object->refcount = 1;
1712 object->surface = surface;
1713 IUnknown_AddRef(object->surface);
1715 *buffer = &object->IMFMediaBuffer_iface;
1717 return S_OK;
1720 HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *surface, IMFSample **sample)
1722 struct video_sample *object;
1723 IMFMediaBuffer *buffer = NULL;
1724 HRESULT hr;
1726 TRACE("%p, %p.\n", surface, sample);
1728 if (!(object = calloc(1, sizeof(*object))))
1729 return E_OUTOFMEMORY;
1731 object->IMFSample_iface.lpVtbl = &video_sample_vtbl;
1732 object->IMFTrackedSample_iface.lpVtbl = &tracked_video_sample_vtbl;
1733 object->IMFDesiredSample_iface.lpVtbl = &desired_video_sample_vtbl;
1734 object->refcount = 1;
1735 InitializeCriticalSection(&object->cs);
1737 if (FAILED(hr = MFCreateSample(&object->sample)))
1739 free(object);
1740 return hr;
1743 if (surface && FAILED(hr = create_surface_buffer(surface, &buffer)))
1745 IMFSample_Release(&object->IMFSample_iface);
1746 return hr;
1749 if (buffer)
1751 IMFSample_AddBuffer(object->sample, buffer);
1752 IMFMediaBuffer_Release(buffer);
1755 video_sample_create_tracking_thread();
1757 *sample = &object->IMFSample_iface;
1759 return S_OK;