mfplat/sample: Optimize copying to 2d buffer.
[wine.git] / dlls / evr / sample.c
blobaa3f120b11565a1d6204173e747bd7c6b8298afc
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 BOOL lock_notify_release;
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 %lu.\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 free(iter);
470 LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry)
472 list_remove(&iter->entry);
473 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 %lu.\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 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, %#lx.\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 = malloc(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, %lu, %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 IMFVideoSampleAllocatorNotify *callback = NULL;
814 HRESULT hr;
816 if (FAILED(IMFAsyncResult_GetObject(result, &object)))
817 return E_UNEXPECTED;
819 hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample);
820 IUnknown_Release(object);
821 if (FAILED(hr))
822 return E_UNEXPECTED;
824 EnterCriticalSection(&allocator->cs);
826 LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry)
828 if (sample == iter->sample)
830 list_remove(&iter->entry);
831 list_add_tail(&allocator->free_samples, &iter->entry);
832 IMFSample_AddRef(iter->sample);
833 allocator->free_sample_count++;
834 break;
838 IMFSample_Release(sample);
840 if (allocator->callback)
842 if (allocator->lock_notify_release)
843 IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback);
844 else
846 callback = allocator->callback;
847 IMFVideoSampleAllocatorNotify_AddRef(callback);
851 LeaveCriticalSection(&allocator->cs);
853 if (callback)
855 IMFVideoSampleAllocatorNotify_NotifyRelease(callback);
856 IMFVideoSampleAllocatorNotify_Release(callback);
859 return S_OK;
862 static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl =
864 sample_allocator_tracking_callback_QueryInterface,
865 sample_allocator_tracking_callback_AddRef,
866 sample_allocator_tracking_callback_Release,
867 sample_allocator_tracking_callback_GetParameters,
868 sample_allocator_tracking_callback_Invoke,
871 HRESULT create_video_sample_allocator(BOOL lock_notify_release, REFIID riid, void **obj)
873 struct sample_allocator *object;
874 HRESULT hr;
876 if (!(object = calloc(1, sizeof(*object))))
877 return E_OUTOFMEMORY;
879 object->IMFVideoSampleAllocator_iface.lpVtbl = &sample_allocator_vtbl;
880 object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl;
881 object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl;
882 object->refcount = 1;
883 list_init(&object->used_samples);
884 list_init(&object->free_samples);
885 object->lock_notify_release = lock_notify_release;
886 InitializeCriticalSection(&object->cs);
888 hr = IMFVideoSampleAllocator_QueryInterface(&object->IMFVideoSampleAllocator_iface, riid, obj);
889 IMFVideoSampleAllocator_Release(&object->IMFVideoSampleAllocator_iface);
891 return hr;
894 HRESULT WINAPI MFCreateVideoSampleAllocator(REFIID riid, void **obj)
896 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
898 return create_video_sample_allocator(TRUE, riid, obj);
901 static HRESULT WINAPI video_sample_QueryInterface(IMFSample *iface, REFIID riid, void **out)
903 struct video_sample *sample = impl_from_IMFSample(iface);
905 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
907 if (IsEqualIID(riid, &IID_IMFSample) ||
908 IsEqualIID(riid, &IID_IMFAttributes) ||
909 IsEqualIID(riid, &IID_IUnknown))
911 *out = &sample->IMFSample_iface;
913 else if (IsEqualIID(riid, &IID_IMFTrackedSample))
915 *out = &sample->IMFTrackedSample_iface;
917 else if (IsEqualIID(riid, &IID_IMFDesiredSample))
919 *out = &sample->IMFDesiredSample_iface;
921 else
923 WARN("Unsupported %s.\n", debugstr_guid(riid));
924 *out = NULL;
925 return E_NOINTERFACE;
928 IUnknown_AddRef((IUnknown *)*out);
929 return S_OK;
932 static ULONG WINAPI video_sample_AddRef(IMFSample *iface)
934 struct video_sample *sample = impl_from_IMFSample(iface);
935 ULONG refcount = InterlockedIncrement(&sample->refcount);
937 TRACE("%p, refcount %lu.\n", iface, refcount);
939 return refcount;
942 static ULONG WINAPI video_sample_Release(IMFSample *iface)
944 struct video_sample *sample = impl_from_IMFSample(iface);
945 ULONG refcount = InterlockedDecrement(&sample->refcount);
946 IMFAsyncResult *tracked_result = NULL;
948 EnterCriticalSection(&sample->cs);
949 if (sample->tracked_result && sample->tracked_refcount == refcount)
951 tracked_result = sample->tracked_result;
952 video_sample_tracking_thread_invoke(tracked_result);
953 sample->tracked_result = NULL;
954 sample->tracked_refcount = 0;
956 LeaveCriticalSection(&sample->cs);
958 if (tracked_result)
959 IMFAsyncResult_Release(tracked_result);
961 TRACE("%p, refcount %lu.\n", iface, refcount);
963 if (!refcount)
965 video_sample_stop_tracking_thread();
966 if (sample->sample)
967 IMFSample_Release(sample->sample);
968 DeleteCriticalSection(&sample->cs);
969 free(sample);
972 return refcount;
975 static HRESULT WINAPI video_sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
977 struct video_sample *sample = impl_from_IMFSample(iface);
979 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
981 return IMFSample_GetItem(sample->sample, key, value);
984 static HRESULT WINAPI video_sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
986 struct video_sample *sample = impl_from_IMFSample(iface);
988 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
990 return IMFSample_GetItemType(sample->sample, key, type);
993 static HRESULT WINAPI video_sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
995 struct video_sample *sample = impl_from_IMFSample(iface);
997 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
999 return IMFSample_CompareItem(sample->sample, key, value, result);
1002 static HRESULT WINAPI video_sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
1003 BOOL *result)
1005 struct video_sample *sample = impl_from_IMFSample(iface);
1007 TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
1009 return IMFSample_Compare(sample->sample, theirs, type, result);
1012 static HRESULT WINAPI video_sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
1014 struct video_sample *sample = impl_from_IMFSample(iface);
1016 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1018 return IMFSample_GetUINT32(sample->sample, key, value);
1021 static HRESULT WINAPI video_sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
1023 struct video_sample *sample = impl_from_IMFSample(iface);
1025 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1027 return IMFSample_GetUINT64(sample->sample, key, value);
1030 static HRESULT WINAPI video_sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
1032 struct video_sample *sample = impl_from_IMFSample(iface);
1034 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1036 return IMFSample_GetDouble(sample->sample, key, value);
1039 static HRESULT WINAPI video_sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
1041 struct video_sample *sample = impl_from_IMFSample(iface);
1043 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1045 return IMFSample_GetGUID(sample->sample, key, value);
1048 static HRESULT WINAPI video_sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
1050 struct video_sample *sample = impl_from_IMFSample(iface);
1052 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
1054 return IMFSample_GetStringLength(sample->sample, key, length);
1057 static HRESULT WINAPI video_sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
1059 struct video_sample *sample = impl_from_IMFSample(iface);
1061 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), value, size, length);
1063 return IMFSample_GetString(sample->sample, key, value, size, length);
1066 static HRESULT WINAPI video_sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
1068 struct video_sample *sample = impl_from_IMFSample(iface);
1070 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
1072 return IMFSample_GetAllocatedString(sample->sample, key, value, length);
1075 static HRESULT WINAPI video_sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
1077 struct video_sample *sample = impl_from_IMFSample(iface);
1079 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
1081 return IMFSample_GetBlobSize(sample->sample, key, size);
1084 static HRESULT WINAPI video_sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
1086 struct video_sample *sample = impl_from_IMFSample(iface);
1088 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
1090 return IMFSample_GetBlob(sample->sample, key, buf, bufsize, blobsize);
1093 static HRESULT WINAPI video_sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
1095 struct video_sample *sample = impl_from_IMFSample(iface);
1097 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
1099 return IMFSample_GetAllocatedBlob(sample->sample, key, buf, size);
1102 static HRESULT WINAPI video_sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
1104 struct video_sample *sample = impl_from_IMFSample(iface);
1106 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
1108 return IMFSample_GetUnknown(sample->sample, key, riid, out);
1111 static HRESULT WINAPI video_sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
1113 struct video_sample *sample = impl_from_IMFSample(iface);
1115 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1117 return IMFSample_SetItem(sample->sample, key, value);
1120 static HRESULT WINAPI video_sample_DeleteItem(IMFSample *iface, REFGUID key)
1122 struct video_sample *sample = impl_from_IMFSample(iface);
1124 TRACE("%p, %s.\n", iface, debugstr_guid(key));
1126 return IMFSample_DeleteItem(sample->sample, key);
1129 static HRESULT WINAPI video_sample_DeleteAllItems(IMFSample *iface)
1131 struct video_sample *sample = impl_from_IMFSample(iface);
1133 TRACE("%p.\n", iface);
1135 return IMFSample_DeleteAllItems(sample->sample);
1138 static HRESULT WINAPI video_sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
1140 struct video_sample *sample = impl_from_IMFSample(iface);
1142 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
1144 return IMFSample_SetUINT32(sample->sample, key, value);
1147 static HRESULT WINAPI video_sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
1149 struct video_sample *sample = impl_from_IMFSample(iface);
1151 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
1153 return IMFSample_SetUINT64(sample->sample, key, value);
1156 static HRESULT WINAPI video_sample_SetDouble(IMFSample *iface, REFGUID key, double value)
1158 struct video_sample *sample = impl_from_IMFSample(iface);
1160 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
1162 return IMFSample_SetDouble(sample->sample, key, value);
1165 static HRESULT WINAPI video_sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
1167 struct video_sample *sample = impl_from_IMFSample(iface);
1169 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
1171 return IMFSample_SetGUID(sample->sample, key, value);
1174 static HRESULT WINAPI video_sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
1176 struct video_sample *sample = impl_from_IMFSample(iface);
1178 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
1180 return IMFSample_SetString(sample->sample, key, value);
1183 static HRESULT WINAPI video_sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
1185 struct video_sample *sample = impl_from_IMFSample(iface);
1187 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
1189 return IMFSample_SetBlob(sample->sample, key, buf, size);
1192 static HRESULT WINAPI video_sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
1194 struct video_sample *sample = impl_from_IMFSample(iface);
1196 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
1198 return IMFSample_SetUnknown(sample->sample, key, unknown);
1201 static HRESULT WINAPI video_sample_LockStore(IMFSample *iface)
1203 struct video_sample *sample = impl_from_IMFSample(iface);
1205 TRACE("%p.\n", iface);
1207 return IMFSample_LockStore(sample->sample);
1210 static HRESULT WINAPI video_sample_UnlockStore(IMFSample *iface)
1212 struct video_sample *sample = impl_from_IMFSample(iface);
1214 TRACE("%p.\n", iface);
1216 return IMFSample_UnlockStore(sample->sample);
1219 static HRESULT WINAPI video_sample_GetCount(IMFSample *iface, UINT32 *count)
1221 struct video_sample *sample = impl_from_IMFSample(iface);
1223 TRACE("%p, %p.\n", iface, count);
1225 return IMFSample_GetCount(sample->sample, count);
1228 static HRESULT WINAPI video_sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
1230 struct video_sample *sample = impl_from_IMFSample(iface);
1232 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
1234 return IMFSample_GetItemByIndex(sample->sample, index, key, value);
1237 static HRESULT WINAPI video_sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
1239 struct video_sample *sample = impl_from_IMFSample(iface);
1241 TRACE("%p, %p.\n", iface, dest);
1243 return IMFSample_CopyAllItems(sample->sample, dest);
1246 static HRESULT WINAPI video_sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
1248 struct video_sample *sample = impl_from_IMFSample(iface);
1250 TRACE("%p, %p.\n", iface, flags);
1252 return IMFSample_GetSampleFlags(sample->sample, flags);
1255 static HRESULT WINAPI video_sample_SetSampleFlags(IMFSample *iface, DWORD flags)
1257 struct video_sample *sample = impl_from_IMFSample(iface);
1259 TRACE("%p, %#lx.\n", iface, flags);
1261 return IMFSample_SetSampleFlags(sample->sample, flags);
1264 static HRESULT WINAPI video_sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
1266 struct video_sample *sample = impl_from_IMFSample(iface);
1267 HRESULT hr = S_OK;
1269 TRACE("%p, %p.\n", iface, timestamp);
1271 EnterCriticalSection(&sample->cs);
1272 if (sample->flags & SAMPLE_PROP_HAS_TIMESTAMP)
1273 *timestamp = sample->timestamp;
1274 else
1275 hr = MF_E_NO_SAMPLE_TIMESTAMP;
1276 LeaveCriticalSection(&sample->cs);
1278 return hr;
1281 static HRESULT WINAPI video_sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
1283 struct video_sample *sample = impl_from_IMFSample(iface);
1285 TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
1287 EnterCriticalSection(&sample->cs);
1288 sample->timestamp = timestamp;
1289 sample->flags |= SAMPLE_PROP_HAS_TIMESTAMP;
1290 LeaveCriticalSection(&sample->cs);
1292 return S_OK;
1295 static HRESULT WINAPI video_sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
1297 struct video_sample *sample = impl_from_IMFSample(iface);
1298 HRESULT hr = S_OK;
1300 TRACE("%p, %p.\n", iface, duration);
1302 EnterCriticalSection(&sample->cs);
1303 if (sample->flags & SAMPLE_PROP_HAS_DURATION)
1304 *duration = sample->duration;
1305 else
1306 hr = MF_E_NO_SAMPLE_DURATION;
1307 LeaveCriticalSection(&sample->cs);
1309 return hr;
1312 static HRESULT WINAPI video_sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
1314 struct video_sample *sample = impl_from_IMFSample(iface);
1316 TRACE("%p, %s.\n", iface, debugstr_time(duration));
1318 EnterCriticalSection(&sample->cs);
1319 sample->duration = duration;
1320 sample->flags |= SAMPLE_PROP_HAS_DURATION;
1321 LeaveCriticalSection(&sample->cs);
1323 return S_OK;
1326 static HRESULT WINAPI video_sample_GetBufferCount(IMFSample *iface, DWORD *count)
1328 struct video_sample *sample = impl_from_IMFSample(iface);
1330 TRACE("%p, %p.\n", iface, count);
1332 return IMFSample_GetBufferCount(sample->sample, count);
1335 static HRESULT WINAPI video_sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
1337 struct video_sample *sample = impl_from_IMFSample(iface);
1339 TRACE("%p, %lu, %p.\n", iface, index, buffer);
1341 return IMFSample_GetBufferByIndex(sample->sample, index, buffer);
1344 static HRESULT WINAPI video_sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
1346 TRACE("%p, %p.\n", iface, buffer);
1348 return E_NOTIMPL;
1351 static HRESULT WINAPI video_sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1353 struct video_sample *sample = impl_from_IMFSample(iface);
1355 TRACE("%p, %p.\n", iface, buffer);
1357 return IMFSample_AddBuffer(sample->sample, buffer);
1360 static HRESULT WINAPI video_sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
1362 struct video_sample *sample = impl_from_IMFSample(iface);
1364 TRACE("%p, %lu.\n", iface, index);
1366 return IMFSample_RemoveBufferByIndex(sample->sample, index);
1369 static HRESULT WINAPI video_sample_RemoveAllBuffers(IMFSample *iface)
1371 struct video_sample *sample = impl_from_IMFSample(iface);
1373 TRACE("%p.\n", iface);
1375 return IMFSample_RemoveAllBuffers(sample->sample);
1378 static HRESULT WINAPI video_sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
1380 TRACE("%p, %p.\n", iface, total_length);
1382 *total_length = 0;
1384 return S_OK;
1387 static HRESULT WINAPI video_sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1389 TRACE("%p, %p.\n", iface, buffer);
1391 return E_NOTIMPL;
1394 static const IMFSampleVtbl video_sample_vtbl =
1396 video_sample_QueryInterface,
1397 video_sample_AddRef,
1398 video_sample_Release,
1399 video_sample_GetItem,
1400 video_sample_GetItemType,
1401 video_sample_CompareItem,
1402 video_sample_Compare,
1403 video_sample_GetUINT32,
1404 video_sample_GetUINT64,
1405 video_sample_GetDouble,
1406 video_sample_GetGUID,
1407 video_sample_GetStringLength,
1408 video_sample_GetString,
1409 video_sample_GetAllocatedString,
1410 video_sample_GetBlobSize,
1411 video_sample_GetBlob,
1412 video_sample_GetAllocatedBlob,
1413 video_sample_GetUnknown,
1414 video_sample_SetItem,
1415 video_sample_DeleteItem,
1416 video_sample_DeleteAllItems,
1417 video_sample_SetUINT32,
1418 video_sample_SetUINT64,
1419 video_sample_SetDouble,
1420 video_sample_SetGUID,
1421 video_sample_SetString,
1422 video_sample_SetBlob,
1423 video_sample_SetUnknown,
1424 video_sample_LockStore,
1425 video_sample_UnlockStore,
1426 video_sample_GetCount,
1427 video_sample_GetItemByIndex,
1428 video_sample_CopyAllItems,
1429 video_sample_GetSampleFlags,
1430 video_sample_SetSampleFlags,
1431 video_sample_GetSampleTime,
1432 video_sample_SetSampleTime,
1433 video_sample_GetSampleDuration,
1434 video_sample_SetSampleDuration,
1435 video_sample_GetBufferCount,
1436 video_sample_GetBufferByIndex,
1437 video_sample_ConvertToContiguousBuffer,
1438 video_sample_AddBuffer,
1439 video_sample_RemoveBufferByIndex,
1440 video_sample_RemoveAllBuffers,
1441 video_sample_GetTotalLength,
1442 video_sample_CopyToBuffer,
1445 static HRESULT WINAPI tracked_video_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
1447 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1448 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
1451 static ULONG WINAPI tracked_video_sample_AddRef(IMFTrackedSample *iface)
1453 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1454 return IMFSample_AddRef(&sample->IMFSample_iface);
1457 static ULONG WINAPI tracked_video_sample_Release(IMFTrackedSample *iface)
1459 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1460 return IMFSample_Release(&sample->IMFSample_iface);
1463 static HRESULT WINAPI tracked_video_sample_SetAllocator(IMFTrackedSample *iface,
1464 IMFAsyncCallback *sample_allocator, IUnknown *state)
1466 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1467 HRESULT hr = S_OK;
1469 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
1471 EnterCriticalSection(&sample->cs);
1472 if (sample->tracked_result)
1473 hr = MF_E_NOTACCEPTING;
1474 else
1476 if (SUCCEEDED(hr = create_async_result((IUnknown *)iface, sample_allocator, state, &sample->tracked_result)))
1478 /* Account for additional refcount brought by 'state' object. This threshold is used
1479 on Release() to invoke tracker callback. */
1480 sample->tracked_refcount = 1;
1481 if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
1482 state == (IUnknown *)&sample->IMFSample_iface)
1484 ++sample->tracked_refcount;
1488 LeaveCriticalSection(&sample->cs);
1490 return hr;
1493 static const IMFTrackedSampleVtbl tracked_video_sample_vtbl =
1495 tracked_video_sample_QueryInterface,
1496 tracked_video_sample_AddRef,
1497 tracked_video_sample_Release,
1498 tracked_video_sample_SetAllocator,
1501 static HRESULT WINAPI desired_video_sample_QueryInterface(IMFDesiredSample *iface, REFIID riid, void **obj)
1503 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1504 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
1507 static ULONG WINAPI desired_video_sample_AddRef(IMFDesiredSample *iface)
1509 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1510 return IMFSample_AddRef(&sample->IMFSample_iface);
1513 static ULONG WINAPI desired_video_sample_Release(IMFDesiredSample *iface)
1515 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1516 return IMFSample_Release(&sample->IMFSample_iface);
1519 static HRESULT WINAPI desired_video_sample_GetDesiredSampleTimeAndDuration(IMFDesiredSample *iface,
1520 LONGLONG *sample_time, LONGLONG *sample_duration)
1522 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1523 HRESULT hr = S_OK;
1525 TRACE("%p, %p, %p.\n", iface, sample_time, sample_duration);
1527 if (!sample_time || !sample_duration)
1528 return E_POINTER;
1530 EnterCriticalSection(&sample->cs);
1531 if (sample->flags & SAMPLE_PROP_HAS_DESIRED_PROPS)
1533 *sample_time = sample->desired_timestamp;
1534 *sample_duration = sample->desired_duration;
1536 else
1537 hr = MF_E_NOT_AVAILABLE;
1538 LeaveCriticalSection(&sample->cs);
1540 return hr;
1543 static void WINAPI desired_video_sample_SetDesiredSampleTimeAndDuration(IMFDesiredSample *iface,
1544 LONGLONG sample_time, LONGLONG sample_duration)
1546 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1548 TRACE("%p, %s, %s.\n", iface, debugstr_time(sample_time), debugstr_time(sample_duration));
1550 EnterCriticalSection(&sample->cs);
1551 sample->flags |= SAMPLE_PROP_HAS_DESIRED_PROPS;
1552 sample->desired_timestamp = sample_time;
1553 sample->desired_duration = sample_duration;
1554 LeaveCriticalSection(&sample->cs);
1557 static void WINAPI desired_video_sample_Clear(IMFDesiredSample *iface)
1559 struct video_sample *sample = impl_from_IMFDesiredSample(iface);
1561 TRACE("%p.\n", iface);
1563 EnterCriticalSection(&sample->cs);
1564 sample->flags = 0;
1565 IMFSample_SetSampleFlags(sample->sample, 0);
1566 IMFSample_DeleteAllItems(sample->sample);
1567 LeaveCriticalSection(&sample->cs);
1570 static const IMFDesiredSampleVtbl desired_video_sample_vtbl =
1572 desired_video_sample_QueryInterface,
1573 desired_video_sample_AddRef,
1574 desired_video_sample_Release,
1575 desired_video_sample_GetDesiredSampleTimeAndDuration,
1576 desired_video_sample_SetDesiredSampleTimeAndDuration,
1577 desired_video_sample_Clear,
1580 static HRESULT WINAPI surface_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **obj)
1582 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1584 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1586 if (IsEqualIID(riid, &IID_IMFMediaBuffer) || IsEqualIID(riid, &IID_IUnknown))
1588 *obj = &buffer->IMFMediaBuffer_iface;
1590 else if (IsEqualIID(riid, &IID_IMFGetService))
1592 *obj = &buffer->IMFGetService_iface;
1594 else
1596 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
1597 *obj = NULL;
1598 return E_NOINTERFACE;
1601 IUnknown_AddRef((IUnknown *)*obj);
1602 return S_OK;
1605 static ULONG WINAPI surface_buffer_AddRef(IMFMediaBuffer *iface)
1607 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1608 ULONG refcount = InterlockedIncrement(&buffer->refcount);
1610 TRACE("%p, refcount %lu.\n", iface, refcount);
1612 return refcount;
1615 static ULONG WINAPI surface_buffer_Release(IMFMediaBuffer *iface)
1617 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1618 ULONG refcount = InterlockedDecrement(&buffer->refcount);
1620 TRACE("%p, refcount %lu.\n", iface, refcount);
1622 if (!refcount)
1624 IUnknown_Release(buffer->surface);
1625 free(buffer);
1628 return refcount;
1631 static HRESULT WINAPI surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *maxlength, DWORD *length)
1633 TRACE("%p, %p, %p, %p.\n", iface, data, maxlength, length);
1635 return E_NOTIMPL;
1638 static HRESULT WINAPI surface_buffer_Unlock(IMFMediaBuffer *iface)
1640 TRACE("%p.\n", iface);
1642 return E_NOTIMPL;
1645 static HRESULT WINAPI surface_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *length)
1647 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1649 TRACE("%p.\n", iface);
1651 *length = buffer->length;
1653 return S_OK;
1656 static HRESULT WINAPI surface_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD length)
1658 struct surface_buffer *buffer = impl_from_IMFMediaBuffer(iface);
1660 TRACE("%p.\n", iface);
1662 buffer->length = length;
1664 return S_OK;
1667 static HRESULT WINAPI surface_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *length)
1669 TRACE("%p.\n", iface);
1671 return E_NOTIMPL;
1674 static const IMFMediaBufferVtbl surface_buffer_vtbl =
1676 surface_buffer_QueryInterface,
1677 surface_buffer_AddRef,
1678 surface_buffer_Release,
1679 surface_buffer_Lock,
1680 surface_buffer_Unlock,
1681 surface_buffer_GetCurrentLength,
1682 surface_buffer_SetCurrentLength,
1683 surface_buffer_GetMaxLength,
1686 static HRESULT WINAPI surface_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
1688 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1689 return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
1692 static ULONG WINAPI surface_buffer_gs_AddRef(IMFGetService *iface)
1694 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1695 return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
1698 static ULONG WINAPI surface_buffer_gs_Release(IMFGetService *iface)
1700 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1701 return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
1704 static HRESULT WINAPI surface_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
1706 struct surface_buffer *buffer = impl_from_IMFGetService(iface);
1708 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
1710 if (IsEqualGUID(service, &MR_BUFFER_SERVICE))
1711 return IUnknown_QueryInterface(buffer->surface, riid, obj);
1713 return E_NOINTERFACE;
1716 static const IMFGetServiceVtbl surface_buffer_gs_vtbl =
1718 surface_buffer_gs_QueryInterface,
1719 surface_buffer_gs_AddRef,
1720 surface_buffer_gs_Release,
1721 surface_buffer_gs_GetService,
1724 static HRESULT create_surface_buffer(IUnknown *surface, IMFMediaBuffer **buffer)
1726 struct surface_buffer *object;
1728 if (!(object = calloc(1, sizeof(*object))))
1729 return E_OUTOFMEMORY;
1731 object->IMFMediaBuffer_iface.lpVtbl = &surface_buffer_vtbl;
1732 object->IMFGetService_iface.lpVtbl = &surface_buffer_gs_vtbl;
1733 object->refcount = 1;
1734 object->surface = surface;
1735 IUnknown_AddRef(object->surface);
1737 *buffer = &object->IMFMediaBuffer_iface;
1739 return S_OK;
1742 HRESULT WINAPI MFCreateVideoSampleFromSurface(IUnknown *surface, IMFSample **sample)
1744 struct video_sample *object;
1745 IMFMediaBuffer *buffer = NULL;
1746 HRESULT hr;
1748 TRACE("%p, %p.\n", surface, sample);
1750 if (!(object = calloc(1, sizeof(*object))))
1751 return E_OUTOFMEMORY;
1753 object->IMFSample_iface.lpVtbl = &video_sample_vtbl;
1754 object->IMFTrackedSample_iface.lpVtbl = &tracked_video_sample_vtbl;
1755 object->IMFDesiredSample_iface.lpVtbl = &desired_video_sample_vtbl;
1756 object->refcount = 1;
1757 InitializeCriticalSection(&object->cs);
1759 if (FAILED(hr = MFCreateSample(&object->sample)))
1761 free(object);
1762 return hr;
1765 if (surface && FAILED(hr = create_surface_buffer(surface, &buffer)))
1767 IMFSample_Release(&object->IMFSample_iface);
1768 return hr;
1771 if (buffer)
1773 IMFSample_AddBuffer(object->sample, buffer);
1774 IMFMediaBuffer_Release(buffer);
1777 video_sample_create_tracking_thread();
1779 *sample = &object->IMFSample_iface;
1781 return S_OK;