wined3d: Use context->ops->prepare_upload_bo() in wined3d_device_context_map() if...
[wine.git] / dlls / evr / sample.c
blobcbba384e18178149f5275a128560bb76fd8e8296
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, %u.\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, %u.\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, %#x.\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 %#x.\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 %u.\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 %u.\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, %#x.\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, %u, %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 %u.\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;
925 IMFSample_LockStore(sample->sample);
926 if (sample->tracked_result && sample->tracked_refcount == (sample->refcount - 1))
928 video_sample_tracking_thread_invoke(sample->tracked_result);
929 IMFAsyncResult_Release(sample->tracked_result);
930 sample->tracked_result = NULL;
931 sample->tracked_refcount = 0;
933 IMFSample_UnlockStore(sample->sample);
935 refcount = InterlockedDecrement(&sample->refcount);
937 TRACE("%p, refcount %u.\n", iface, refcount);
939 if (!refcount)
941 video_sample_stop_tracking_thread();
942 if (sample->sample)
943 IMFSample_Release(sample->sample);
944 DeleteCriticalSection(&sample->cs);
945 free(sample);
948 return refcount;
951 static HRESULT WINAPI video_sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value)
953 struct video_sample *sample = impl_from_IMFSample(iface);
955 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
957 return IMFSample_GetItem(sample->sample, key, value);
960 static HRESULT WINAPI video_sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type)
962 struct video_sample *sample = impl_from_IMFSample(iface);
964 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), type);
966 return IMFSample_GetItemType(sample->sample, key, type);
969 static HRESULT WINAPI video_sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result)
971 struct video_sample *sample = impl_from_IMFSample(iface);
973 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, result);
975 return IMFSample_CompareItem(sample->sample, key, value, result);
978 static HRESULT WINAPI video_sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type,
979 BOOL *result)
981 struct video_sample *sample = impl_from_IMFSample(iface);
983 TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result);
985 return IMFSample_Compare(sample->sample, theirs, type, result);
988 static HRESULT WINAPI video_sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value)
990 struct video_sample *sample = impl_from_IMFSample(iface);
992 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
994 return IMFSample_GetUINT32(sample->sample, key, value);
997 static HRESULT WINAPI video_sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value)
999 struct video_sample *sample = impl_from_IMFSample(iface);
1001 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1003 return IMFSample_GetUINT64(sample->sample, key, value);
1006 static HRESULT WINAPI video_sample_GetDouble(IMFSample *iface, REFGUID key, double *value)
1008 struct video_sample *sample = impl_from_IMFSample(iface);
1010 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1012 return IMFSample_GetDouble(sample->sample, key, value);
1015 static HRESULT WINAPI video_sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value)
1017 struct video_sample *sample = impl_from_IMFSample(iface);
1019 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1021 return IMFSample_GetGUID(sample->sample, key, value);
1024 static HRESULT WINAPI video_sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length)
1026 struct video_sample *sample = impl_from_IMFSample(iface);
1028 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), length);
1030 return IMFSample_GetStringLength(sample->sample, key, length);
1033 static HRESULT WINAPI video_sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length)
1035 struct video_sample *sample = impl_from_IMFSample(iface);
1037 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), value, size, length);
1039 return IMFSample_GetString(sample->sample, key, value, size, length);
1042 static HRESULT WINAPI video_sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length)
1044 struct video_sample *sample = impl_from_IMFSample(iface);
1046 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), value, length);
1048 return IMFSample_GetAllocatedString(sample->sample, key, value, length);
1051 static HRESULT WINAPI video_sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size)
1053 struct video_sample *sample = impl_from_IMFSample(iface);
1055 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), size);
1057 return IMFSample_GetBlobSize(sample->sample, key, size);
1060 static HRESULT WINAPI video_sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize)
1062 struct video_sample *sample = impl_from_IMFSample(iface);
1064 TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_guid(key), buf, bufsize, blobsize);
1066 return IMFSample_GetBlob(sample->sample, key, buf, bufsize, blobsize);
1069 static HRESULT WINAPI video_sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size)
1071 struct video_sample *sample = impl_from_IMFSample(iface);
1073 TRACE("%p, %s, %p, %p.\n", iface, debugstr_guid(key), buf, size);
1075 return IMFSample_GetAllocatedBlob(sample->sample, key, buf, size);
1078 static HRESULT WINAPI video_sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out)
1080 struct video_sample *sample = impl_from_IMFSample(iface);
1082 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(key), debugstr_guid(riid), out);
1084 return IMFSample_GetUnknown(sample->sample, key, riid, out);
1087 static HRESULT WINAPI video_sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value)
1089 struct video_sample *sample = impl_from_IMFSample(iface);
1091 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), value);
1093 return IMFSample_SetItem(sample->sample, key, value);
1096 static HRESULT WINAPI video_sample_DeleteItem(IMFSample *iface, REFGUID key)
1098 struct video_sample *sample = impl_from_IMFSample(iface);
1100 TRACE("%p, %s.\n", iface, debugstr_guid(key));
1102 return IMFSample_DeleteItem(sample->sample, key);
1105 static HRESULT WINAPI video_sample_DeleteAllItems(IMFSample *iface)
1107 struct video_sample *sample = impl_from_IMFSample(iface);
1109 TRACE("%p.\n", iface);
1111 return IMFSample_DeleteAllItems(sample->sample);
1114 static HRESULT WINAPI video_sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value)
1116 struct video_sample *sample = impl_from_IMFSample(iface);
1118 TRACE("%p, %s, %u.\n", iface, debugstr_guid(key), value);
1120 return IMFSample_SetUINT32(sample->sample, key, value);
1123 static HRESULT WINAPI video_sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value)
1125 struct video_sample *sample = impl_from_IMFSample(iface);
1127 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), wine_dbgstr_longlong(value));
1129 return IMFSample_SetUINT64(sample->sample, key, value);
1132 static HRESULT WINAPI video_sample_SetDouble(IMFSample *iface, REFGUID key, double value)
1134 struct video_sample *sample = impl_from_IMFSample(iface);
1136 TRACE("%p, %s, %f.\n", iface, debugstr_guid(key), value);
1138 return IMFSample_SetDouble(sample->sample, key, value);
1141 static HRESULT WINAPI video_sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value)
1143 struct video_sample *sample = impl_from_IMFSample(iface);
1145 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_guid(value));
1147 return IMFSample_SetGUID(sample->sample, key, value);
1150 static HRESULT WINAPI video_sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value)
1152 struct video_sample *sample = impl_from_IMFSample(iface);
1154 TRACE("%p, %s, %s.\n", iface, debugstr_guid(key), debugstr_w(value));
1156 return IMFSample_SetString(sample->sample, key, value);
1159 static HRESULT WINAPI video_sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size)
1161 struct video_sample *sample = impl_from_IMFSample(iface);
1163 TRACE("%p, %s, %p, %u.\n", iface, debugstr_guid(key), buf, size);
1165 return IMFSample_SetBlob(sample->sample, key, buf, size);
1168 static HRESULT WINAPI video_sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown)
1170 struct video_sample *sample = impl_from_IMFSample(iface);
1172 TRACE("%p, %s, %p.\n", iface, debugstr_guid(key), unknown);
1174 return IMFSample_SetUnknown(sample->sample, key, unknown);
1177 static HRESULT WINAPI video_sample_LockStore(IMFSample *iface)
1179 struct video_sample *sample = impl_from_IMFSample(iface);
1181 TRACE("%p.\n", iface);
1183 return IMFSample_LockStore(sample->sample);
1186 static HRESULT WINAPI video_sample_UnlockStore(IMFSample *iface)
1188 struct video_sample *sample = impl_from_IMFSample(iface);
1190 TRACE("%p.\n", iface);
1192 return IMFSample_UnlockStore(sample->sample);
1195 static HRESULT WINAPI video_sample_GetCount(IMFSample *iface, UINT32 *count)
1197 struct video_sample *sample = impl_from_IMFSample(iface);
1199 TRACE("%p, %p.\n", iface, count);
1201 return IMFSample_GetCount(sample->sample, count);
1204 static HRESULT WINAPI video_sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value)
1206 struct video_sample *sample = impl_from_IMFSample(iface);
1208 TRACE("%p, %u, %p, %p.\n", iface, index, key, value);
1210 return IMFSample_GetItemByIndex(sample->sample, index, key, value);
1213 static HRESULT WINAPI video_sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest)
1215 struct video_sample *sample = impl_from_IMFSample(iface);
1217 TRACE("%p, %p.\n", iface, dest);
1219 return IMFSample_CopyAllItems(sample->sample, dest);
1222 static HRESULT WINAPI video_sample_GetSampleFlags(IMFSample *iface, DWORD *flags)
1224 struct video_sample *sample = impl_from_IMFSample(iface);
1226 TRACE("%p, %p.\n", iface, flags);
1228 return IMFSample_GetSampleFlags(sample->sample, flags);
1231 static HRESULT WINAPI video_sample_SetSampleFlags(IMFSample *iface, DWORD flags)
1233 struct video_sample *sample = impl_from_IMFSample(iface);
1235 TRACE("%p, %#x.\n", iface, flags);
1237 return IMFSample_SetSampleFlags(sample->sample, flags);
1240 static HRESULT WINAPI video_sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp)
1242 struct video_sample *sample = impl_from_IMFSample(iface);
1243 HRESULT hr = S_OK;
1245 TRACE("%p, %p.\n", iface, timestamp);
1247 EnterCriticalSection(&sample->cs);
1248 if (sample->flags & SAMPLE_PROP_HAS_TIMESTAMP)
1249 *timestamp = sample->timestamp;
1250 else
1251 hr = MF_E_NO_SAMPLE_TIMESTAMP;
1252 LeaveCriticalSection(&sample->cs);
1254 return hr;
1257 static HRESULT WINAPI video_sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp)
1259 struct video_sample *sample = impl_from_IMFSample(iface);
1261 TRACE("%p, %s.\n", iface, debugstr_time(timestamp));
1263 EnterCriticalSection(&sample->cs);
1264 sample->timestamp = timestamp;
1265 sample->flags |= SAMPLE_PROP_HAS_TIMESTAMP;
1266 LeaveCriticalSection(&sample->cs);
1268 return S_OK;
1271 static HRESULT WINAPI video_sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration)
1273 struct video_sample *sample = impl_from_IMFSample(iface);
1274 HRESULT hr = S_OK;
1276 TRACE("%p, %p.\n", iface, duration);
1278 EnterCriticalSection(&sample->cs);
1279 if (sample->flags & SAMPLE_PROP_HAS_DURATION)
1280 *duration = sample->duration;
1281 else
1282 hr = MF_E_NO_SAMPLE_DURATION;
1283 LeaveCriticalSection(&sample->cs);
1285 return hr;
1288 static HRESULT WINAPI video_sample_SetSampleDuration(IMFSample *iface, LONGLONG duration)
1290 struct video_sample *sample = impl_from_IMFSample(iface);
1292 TRACE("%p, %s.\n", iface, debugstr_time(duration));
1294 EnterCriticalSection(&sample->cs);
1295 sample->duration = duration;
1296 sample->flags |= SAMPLE_PROP_HAS_DURATION;
1297 LeaveCriticalSection(&sample->cs);
1299 return S_OK;
1302 static HRESULT WINAPI video_sample_GetBufferCount(IMFSample *iface, DWORD *count)
1304 struct video_sample *sample = impl_from_IMFSample(iface);
1306 TRACE("%p, %p.\n", iface, count);
1308 return IMFSample_GetBufferCount(sample->sample, count);
1311 static HRESULT WINAPI video_sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer)
1313 struct video_sample *sample = impl_from_IMFSample(iface);
1315 TRACE("%p, %u, %p.\n", iface, index, buffer);
1317 return IMFSample_GetBufferByIndex(sample->sample, index, buffer);
1320 static HRESULT WINAPI video_sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer)
1322 TRACE("%p, %p.\n", iface, buffer);
1324 return E_NOTIMPL;
1327 static HRESULT WINAPI video_sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1329 struct video_sample *sample = impl_from_IMFSample(iface);
1331 TRACE("%p, %p.\n", iface, buffer);
1333 return IMFSample_AddBuffer(sample->sample, buffer);
1336 static HRESULT WINAPI video_sample_RemoveBufferByIndex(IMFSample *iface, DWORD index)
1338 struct video_sample *sample = impl_from_IMFSample(iface);
1340 TRACE("%p, %u.\n", iface, index);
1342 return IMFSample_RemoveBufferByIndex(sample->sample, index);
1345 static HRESULT WINAPI video_sample_RemoveAllBuffers(IMFSample *iface)
1347 struct video_sample *sample = impl_from_IMFSample(iface);
1349 TRACE("%p.\n", iface);
1351 return IMFSample_RemoveAllBuffers(sample->sample);
1354 static HRESULT WINAPI video_sample_GetTotalLength(IMFSample *iface, DWORD *total_length)
1356 TRACE("%p, %p.\n", iface, total_length);
1358 *total_length = 0;
1360 return S_OK;
1363 static HRESULT WINAPI video_sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer)
1365 TRACE("%p, %p.\n", iface, buffer);
1367 return E_NOTIMPL;
1370 static const IMFSampleVtbl video_sample_vtbl =
1372 video_sample_QueryInterface,
1373 video_sample_AddRef,
1374 video_sample_Release,
1375 video_sample_GetItem,
1376 video_sample_GetItemType,
1377 video_sample_CompareItem,
1378 video_sample_Compare,
1379 video_sample_GetUINT32,
1380 video_sample_GetUINT64,
1381 video_sample_GetDouble,
1382 video_sample_GetGUID,
1383 video_sample_GetStringLength,
1384 video_sample_GetString,
1385 video_sample_GetAllocatedString,
1386 video_sample_GetBlobSize,
1387 video_sample_GetBlob,
1388 video_sample_GetAllocatedBlob,
1389 video_sample_GetUnknown,
1390 video_sample_SetItem,
1391 video_sample_DeleteItem,
1392 video_sample_DeleteAllItems,
1393 video_sample_SetUINT32,
1394 video_sample_SetUINT64,
1395 video_sample_SetDouble,
1396 video_sample_SetGUID,
1397 video_sample_SetString,
1398 video_sample_SetBlob,
1399 video_sample_SetUnknown,
1400 video_sample_LockStore,
1401 video_sample_UnlockStore,
1402 video_sample_GetCount,
1403 video_sample_GetItemByIndex,
1404 video_sample_CopyAllItems,
1405 video_sample_GetSampleFlags,
1406 video_sample_SetSampleFlags,
1407 video_sample_GetSampleTime,
1408 video_sample_SetSampleTime,
1409 video_sample_GetSampleDuration,
1410 video_sample_SetSampleDuration,
1411 video_sample_GetBufferCount,
1412 video_sample_GetBufferByIndex,
1413 video_sample_ConvertToContiguousBuffer,
1414 video_sample_AddBuffer,
1415 video_sample_RemoveBufferByIndex,
1416 video_sample_RemoveAllBuffers,
1417 video_sample_GetTotalLength,
1418 video_sample_CopyToBuffer,
1421 static HRESULT WINAPI tracked_video_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj)
1423 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1424 return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj);
1427 static ULONG WINAPI tracked_video_sample_AddRef(IMFTrackedSample *iface)
1429 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1430 return IMFSample_AddRef(&sample->IMFSample_iface);
1433 static ULONG WINAPI tracked_video_sample_Release(IMFTrackedSample *iface)
1435 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1436 return IMFSample_Release(&sample->IMFSample_iface);
1439 static HRESULT WINAPI tracked_video_sample_SetAllocator(IMFTrackedSample *iface,
1440 IMFAsyncCallback *sample_allocator, IUnknown *state)
1442 struct video_sample *sample = impl_from_IMFTrackedSample(iface);
1443 HRESULT hr = S_OK;
1445 TRACE("%p, %p, %p.\n", iface, sample_allocator, state);
1447 IMFSample_LockStore(sample->sample);
1449 if (sample->tracked_result)
1450 hr = MF_E_NOTACCEPTING;
1451 else
1453 if (SUCCEEDED(hr = create_async_result((IUnknown *)iface, sample_allocator, state, &sample->tracked_result)))
1455 /* Account for additional refcount brought by 'state' object. This threshold is used
1456 on Release() to invoke tracker callback. */
1457 sample->tracked_refcount = 1;
1458 if (state == (IUnknown *)&sample->IMFTrackedSample_iface ||
1459 state == (IUnknown *)&sample->IMFSample_iface)
1461 ++sample->tracked_refcount;
1466 IMFSample_UnlockStore(sample->sample);
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 %u.\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 %u.\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)
1750 IMFSample_AddBuffer(object->sample, buffer);
1752 video_sample_create_tracking_thread();
1754 *sample = &object->IMFSample_iface;
1756 return S_OK;