mfplat: Implement async file stream creation API.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
cfe9314b64
commit
1cf021f45e
|
@ -6713,3 +6713,260 @@ HRESULT WINAPI MFCreateSystemTimeSource(IMFPresentationTimeSource **time_source)
|
|||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
struct async_create_file
|
||||
{
|
||||
IMFAsyncCallback IMFAsyncCallback_iface;
|
||||
LONG refcount;
|
||||
MF_FILE_ACCESSMODE access_mode;
|
||||
MF_FILE_OPENMODE open_mode;
|
||||
MF_FILE_FLAGS flags;
|
||||
WCHAR *path;
|
||||
};
|
||||
|
||||
struct async_create_file_result
|
||||
{
|
||||
struct list entry;
|
||||
IMFAsyncResult *result;
|
||||
IMFByteStream *stream;
|
||||
};
|
||||
|
||||
static struct list async_create_file_results = LIST_INIT(async_create_file_results);
|
||||
static CRITICAL_SECTION async_create_file_cs = { NULL, -1, 0, 0, 0, 0 };
|
||||
|
||||
static struct async_create_file *impl_from_create_file_IMFAsyncCallback(IMFAsyncCallback *iface)
|
||||
{
|
||||
return CONTAINING_RECORD(iface, struct async_create_file, IMFAsyncCallback_iface);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI async_create_file_callback_QueryInterface(IMFAsyncCallback *iface, REFIID riid, void **obj)
|
||||
{
|
||||
if (IsEqualIID(riid, &IID_IMFAsyncCallback) ||
|
||||
IsEqualIID(riid, &IID_IUnknown))
|
||||
{
|
||||
*obj = iface;
|
||||
IMFAsyncCallback_AddRef(iface);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
*obj = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
static ULONG WINAPI async_create_file_callback_AddRef(IMFAsyncCallback *iface)
|
||||
{
|
||||
struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface);
|
||||
ULONG refcount = InterlockedIncrement(&async->refcount);
|
||||
|
||||
TRACE("%p, refcount %u.\n", iface, refcount);
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
||||
static ULONG WINAPI async_create_file_callback_Release(IMFAsyncCallback *iface)
|
||||
{
|
||||
struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface);
|
||||
ULONG refcount = InterlockedDecrement(&async->refcount);
|
||||
|
||||
TRACE("%p, refcount %u.\n", iface, refcount);
|
||||
|
||||
if (!refcount)
|
||||
{
|
||||
heap_free(async->path);
|
||||
heap_free(async);
|
||||
}
|
||||
|
||||
return refcount;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI async_create_file_callback_GetParameters(IMFAsyncCallback *iface, DWORD *flags, DWORD *queue)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
static HRESULT WINAPI async_create_file_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
||||
{
|
||||
struct async_create_file *async = impl_from_create_file_IMFAsyncCallback(iface);
|
||||
IMFAsyncResult *caller;
|
||||
IMFByteStream *stream;
|
||||
HRESULT hr;
|
||||
|
||||
caller = (IMFAsyncResult *)IMFAsyncResult_GetStateNoAddRef(result);
|
||||
|
||||
hr = MFCreateFile(async->access_mode, async->open_mode, async->flags, async->path, &stream);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
struct async_create_file_result *result_item;
|
||||
|
||||
result_item = heap_alloc(sizeof(*result_item));
|
||||
if (result_item)
|
||||
{
|
||||
result_item->result = caller;
|
||||
IMFAsyncResult_AddRef(caller);
|
||||
result_item->stream = stream;
|
||||
IMFByteStream_AddRef(stream);
|
||||
|
||||
EnterCriticalSection(&async_create_file_cs);
|
||||
list_add_tail(&async_create_file_results, &result_item->entry);
|
||||
LeaveCriticalSection(&async_create_file_cs);
|
||||
}
|
||||
|
||||
IMFByteStream_Release(stream);
|
||||
}
|
||||
else
|
||||
IMFAsyncResult_SetStatus(caller, hr);
|
||||
|
||||
MFInvokeCallback(caller);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IMFAsyncCallbackVtbl async_create_file_callback_vtbl =
|
||||
{
|
||||
async_create_file_callback_QueryInterface,
|
||||
async_create_file_callback_AddRef,
|
||||
async_create_file_callback_Release,
|
||||
async_create_file_callback_GetParameters,
|
||||
async_create_file_callback_Invoke,
|
||||
};
|
||||
|
||||
static WCHAR *heap_strdupW(const WCHAR *str)
|
||||
{
|
||||
WCHAR *ret = NULL;
|
||||
|
||||
if (str)
|
||||
{
|
||||
unsigned int size;
|
||||
|
||||
size = (strlenW(str) + 1) * sizeof(WCHAR);
|
||||
ret = heap_alloc(size);
|
||||
if (ret)
|
||||
memcpy(ret, str, size);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MFBeginCreateFile (mfplat.@)
|
||||
*/
|
||||
HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMODE open_mode, MF_FILE_FLAGS flags,
|
||||
const WCHAR *path, IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_cookie)
|
||||
{
|
||||
struct async_create_file *async = NULL;
|
||||
IMFAsyncResult *caller, *item = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%#x, %#x, %#x, %s, %p, %p, %p.\n", access_mode, open_mode, flags, debugstr_w(path), callback, state,
|
||||
cancel_cookie);
|
||||
|
||||
if (cancel_cookie)
|
||||
*cancel_cookie = NULL;
|
||||
|
||||
if (FAILED(hr = MFCreateAsyncResult(NULL, callback, state, &caller)))
|
||||
return hr;
|
||||
|
||||
async = heap_alloc(sizeof(*async));
|
||||
if (!async)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
async->IMFAsyncCallback_iface.lpVtbl = &async_create_file_callback_vtbl;
|
||||
async->refcount = 1;
|
||||
async->access_mode = access_mode;
|
||||
async->open_mode = open_mode;
|
||||
async->flags = flags;
|
||||
async->path = heap_strdupW(path);
|
||||
if (!async->path)
|
||||
{
|
||||
hr = E_OUTOFMEMORY;
|
||||
goto failed;
|
||||
}
|
||||
|
||||
hr = MFCreateAsyncResult(NULL, &async->IMFAsyncCallback_iface, (IUnknown *)caller, &item);
|
||||
if (FAILED(hr))
|
||||
goto failed;
|
||||
|
||||
if (cancel_cookie)
|
||||
{
|
||||
*cancel_cookie = (IUnknown *)caller;
|
||||
IUnknown_AddRef(*cancel_cookie);
|
||||
}
|
||||
|
||||
hr = MFInvokeCallback(item);
|
||||
|
||||
failed:
|
||||
if (async)
|
||||
IMFAsyncCallback_Release(&async->IMFAsyncCallback_iface);
|
||||
if (item)
|
||||
IMFAsyncResult_Release(item);
|
||||
if (caller)
|
||||
IMFAsyncResult_Release(caller);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT async_create_file_pull_result(IUnknown *unk, IMFByteStream **stream)
|
||||
{
|
||||
struct async_create_file_result *item;
|
||||
HRESULT hr = MF_E_UNEXPECTED;
|
||||
IMFAsyncResult *result;
|
||||
|
||||
*stream = NULL;
|
||||
|
||||
if (FAILED(IUnknown_QueryInterface(unk, &IID_IMFAsyncResult, (void **)&result)))
|
||||
return hr;
|
||||
|
||||
EnterCriticalSection(&async_create_file_cs);
|
||||
|
||||
LIST_FOR_EACH_ENTRY(item, &async_create_file_results, struct async_create_file_result, entry)
|
||||
{
|
||||
if (result == item->result)
|
||||
{
|
||||
*stream = item->stream;
|
||||
IMFAsyncResult_Release(item->result);
|
||||
list_remove(&item->entry);
|
||||
heap_free(item);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&async_create_file_cs);
|
||||
|
||||
if (*stream)
|
||||
hr = IMFAsyncResult_GetStatus(result);
|
||||
|
||||
IMFAsyncResult_Release(result);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MFEndCreateFile (mfplat.@)
|
||||
*/
|
||||
HRESULT WINAPI MFEndCreateFile(IMFAsyncResult *result, IMFByteStream **stream)
|
||||
{
|
||||
TRACE("%p, %p.\n", result, stream);
|
||||
|
||||
return async_create_file_pull_result((IUnknown *)result, stream);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* MFCancelCreateFile (mfplat.@)
|
||||
*/
|
||||
HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie)
|
||||
{
|
||||
IMFByteStream *stream = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("%p.\n", cancel_cookie);
|
||||
|
||||
hr = async_create_file_pull_result(cancel_cookie, &stream);
|
||||
|
||||
if (stream)
|
||||
IMFByteStream_Release(stream);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
|
|
@ -20,14 +20,14 @@
|
|||
@ stdcall MFAllocateWorkQueueEx(long ptr)
|
||||
@ stub MFAppendCollection
|
||||
@ stub MFAverageTimePerFrameToFrameRate
|
||||
@ stub MFBeginCreateFile
|
||||
@ stdcall MFBeginCreateFile(long long long wstr ptr ptr ptr)
|
||||
@ stub MFBeginGetHostByName
|
||||
@ stub MFBeginRegisterWorkQueueWithMMCSS
|
||||
@ stub MFBeginUnregisterWorkQueueWithMMCSS
|
||||
@ stub MFBlockThread
|
||||
@ stub MFCalculateBitmapImageSize
|
||||
@ stdcall MFCalculateImageSize(ptr long long ptr)
|
||||
@ stub MFCancelCreateFile
|
||||
@ stdcall MFCancelCreateFile(ptr)
|
||||
@ stdcall MFCancelWorkItem(int64)
|
||||
@ stdcall MFCompareFullToPartialMediaType(ptr ptr)
|
||||
@ stub MFCompareSockaddrAddresses
|
||||
|
@ -79,7 +79,7 @@
|
|||
@ stub MFDeserializeEvent
|
||||
@ stub MFDeserializeMediaTypeFromStream
|
||||
@ stub MFDeserializePresentationDescriptor
|
||||
@ stub MFEndCreateFile
|
||||
@ stdcall MFEndCreateFile(ptr ptr)
|
||||
@ stub MFEndGetHostByName
|
||||
@ stub MFEndRegisterWorkQueueWithMMCSS
|
||||
@ stub MFEndUnregisterWorkQueueWithMMCSS
|
||||
|
|
|
@ -2886,6 +2886,72 @@ static void test_MFCreateWaveFormatExFromMFMediaType(void)
|
|||
IMFMediaType_Release(mediatype);
|
||||
}
|
||||
|
||||
static HRESULT WINAPI test_create_file_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result)
|
||||
{
|
||||
struct test_callback *callback = impl_from_IMFAsyncCallback(iface);
|
||||
IMFByteStream *stream;
|
||||
IUnknown *object;
|
||||
HRESULT hr;
|
||||
|
||||
ok(!!result, "Unexpected result object.\n");
|
||||
|
||||
ok((IUnknown *)iface == IMFAsyncResult_GetStateNoAddRef(result), "Unexpected result state.\n");
|
||||
|
||||
hr = IMFAsyncResult_GetObject(result, &object);
|
||||
ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr);
|
||||
|
||||
hr = MFEndCreateFile(result, &stream);
|
||||
ok(hr == S_OK, "Failed to get file stream, hr %#x.\n", hr);
|
||||
IMFByteStream_Release(stream);
|
||||
|
||||
SetEvent(callback->event);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
static const IMFAsyncCallbackVtbl test_create_file_callback_vtbl =
|
||||
{
|
||||
testcallback_QueryInterface,
|
||||
testcallback_AddRef,
|
||||
testcallback_Release,
|
||||
testcallback_GetParameters,
|
||||
test_create_file_callback_Invoke,
|
||||
};
|
||||
|
||||
static void test_async_create_file(void)
|
||||
{
|
||||
struct test_callback callback = { { &test_create_file_callback_vtbl } };
|
||||
WCHAR pathW[MAX_PATH], fileW[MAX_PATH];
|
||||
IUnknown *cancel_cookie;
|
||||
HRESULT hr;
|
||||
BOOL ret;
|
||||
|
||||
hr = MFStartup(MF_VERSION, MFSTARTUP_FULL);
|
||||
ok(hr == S_OK, "Fail to start up, hr %#x.\n", hr);
|
||||
|
||||
callback.event = CreateEventA(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
GetTempPathW(ARRAY_SIZE(pathW), pathW);
|
||||
GetTempFileNameW(pathW, NULL, 0, fileW);
|
||||
|
||||
hr = MFBeginCreateFile(MF_ACCESSMODE_READWRITE, MF_OPENMODE_DELETE_IF_EXIST, MF_FILEFLAGS_NONE, fileW,
|
||||
&callback.IMFAsyncCallback_iface, (IUnknown *)&callback.IMFAsyncCallback_iface, &cancel_cookie);
|
||||
ok(hr == S_OK, "Async create request failed, hr %#x.\n", hr);
|
||||
ok(cancel_cookie != NULL, "Unexpected cancellation object.\n");
|
||||
|
||||
WaitForSingleObject(callback.event, INFINITE);
|
||||
|
||||
IUnknown_Release(cancel_cookie);
|
||||
|
||||
CloseHandle(callback.event);
|
||||
|
||||
hr = MFShutdown();
|
||||
ok(hr == S_OK, "Failed to shut down, hr %#x.\n", hr);
|
||||
|
||||
ret = DeleteFileW(fileW);
|
||||
ok(ret, "Failed to delete test file.\n");
|
||||
}
|
||||
|
||||
START_TEST(mfplat)
|
||||
{
|
||||
CoInitialize(NULL);
|
||||
|
@ -2920,6 +2986,7 @@ START_TEST(mfplat)
|
|||
test_attributes_serialization();
|
||||
test_wrapped_media_type();
|
||||
test_MFCreateWaveFormatExFromMFMediaType();
|
||||
test_async_create_file();
|
||||
|
||||
CoUninitialize();
|
||||
}
|
||||
|
|
|
@ -353,7 +353,10 @@ typedef enum _MFWaveFormatExConvertFlags
|
|||
HRESULT WINAPI MFAddPeriodicCallback(MFPERIODICCALLBACK callback, IUnknown *context, DWORD *key);
|
||||
HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
|
||||
HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
|
||||
HRESULT WINAPI MFBeginCreateFile(MF_FILE_ACCESSMODE access_mode, MF_FILE_OPENMODE open_mode, MF_FILE_FLAGS flags,
|
||||
const WCHAR *path, IMFAsyncCallback *callback, IUnknown *state, IUnknown **cancel_cookie);
|
||||
HRESULT WINAPI MFCalculateImageSize(REFGUID subtype, UINT32 width, UINT32 height, UINT32 *size);
|
||||
HRESULT WINAPI MFCancelCreateFile(IUnknown *cancel_cookie);
|
||||
HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key);
|
||||
BOOL WINAPI MFCompareFullToPartialMediaType(IMFMediaType *full_type, IMFMediaType *partial_type);
|
||||
HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines);
|
||||
|
@ -370,6 +373,7 @@ HRESULT WINAPI MFCreateMediaType(IMFMediaType **type);
|
|||
HRESULT WINAPI MFCreateSample(IMFSample **sample);
|
||||
HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer);
|
||||
HRESULT WINAPI MFCreateWaveFormatExFromMFMediaType(IMFMediaType *type, WAVEFORMATEX **format, UINT32 *size, UINT32 flags);
|
||||
HRESULT WINAPI MFEndCreateFile(IMFAsyncResult *result, IMFByteStream **stream);
|
||||
void * WINAPI MFHeapAlloc(SIZE_T size, ULONG flags, char *file, int line, EAllocationType type);
|
||||
void WINAPI MFHeapFree(void *ptr);
|
||||
HRESULT WINAPI MFGetAttributesAsBlob(IMFAttributes *attributes, UINT8 *buffer, UINT size);
|
||||
|
|
Loading…
Reference in New Issue