Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/Makefile.in | 3 +- dlls/mfplat/buffer.c | 982 -------------------------------------- dlls/mfplat/sample.c | 1007 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 1009 insertions(+), 983 deletions(-) create mode 100644 dlls/mfplat/sample.c
diff --git a/dlls/mfplat/Makefile.in b/dlls/mfplat/Makefile.in index cdb2b813340..bc04a440826 100644 --- a/dlls/mfplat/Makefile.in +++ b/dlls/mfplat/Makefile.in @@ -8,4 +8,5 @@ C_SRCS = \ buffer.c \ main.c \ mediatype.c \ - queue.c + queue.c \ + sample.c diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index b47d2a9ba16..adfa2d867c1 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -63,31 +63,6 @@ struct memory_buffer CRITICAL_SECTION cs; };
-enum sample_prop_flags -{ - SAMPLE_PROP_HAS_DURATION = 1 << 0, - SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1, -}; - -struct sample -{ - struct attributes attributes; - IMFSample IMFSample_iface; - IMFTrackedSample IMFTrackedSample_iface; - - IMFMediaBuffer **buffers; - size_t buffer_count; - size_t capacity; - DWORD flags; - DWORD prop_flags; - LONGLONG duration; - LONGLONG timestamp; - - /* Tracked sample functionality. */ - IRtwqAsyncResult *tracked_result; - LONG tracked_refcount; -}; - static inline struct memory_buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface) { return CONTAINING_RECORD(iface, struct memory_buffer, IMFMediaBuffer_iface); @@ -103,16 +78,6 @@ static struct memory_buffer *impl_from_IMFGetService(IMFGetService *iface) return CONTAINING_RECORD(iface, struct memory_buffer, IMFGetService_iface); }
-static inline struct sample *impl_from_IMFSample(IMFSample *iface) -{ - return CONTAINING_RECORD(iface, struct sample, IMFSample_iface); -} - -static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface) -{ - return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface); -} - static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) { struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); @@ -1080,950 +1045,3 @@ HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLO
return E_NOTIMPL; } - -static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); - - if (IsEqualIID(riid, &IID_IMFSample) || - IsEqualIID(riid, &IID_IMFAttributes) || - IsEqualIID(riid, &IID_IUnknown)) - { - *out = &sample->IMFSample_iface; - } - else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample)) - { - *out = &sample->IMFTrackedSample_iface; - } - else - { - WARN("Unsupported %s.\n", debugstr_guid(riid)); - *out = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown *)*out); - return S_OK; -} - -static ULONG WINAPI sample_AddRef(IMFSample *iface) -{ - struct sample *sample = impl_from_IMFSample(iface); - ULONG refcount = InterlockedIncrement(&sample->attributes.ref); - - TRACE("%p, refcount %u.\n", iface, refcount); - - return refcount; -} - -static void release_sample_object(struct sample *sample) -{ - size_t i; - - for (i = 0; i < sample->buffer_count; ++i) - IMFMediaBuffer_Release(sample->buffers[i]); - clear_attributes_object(&sample->attributes); - heap_free(sample->buffers); - heap_free(sample); -} - -static ULONG WINAPI sample_Release(IMFSample *iface) -{ - struct sample *sample = impl_from_IMFSample(iface); - ULONG refcount = InterlockedDecrement(&sample->attributes.ref); - - TRACE("%p, refcount %u.\n", iface, refcount); - - if (!refcount) - release_sample_object(sample); - - return refcount; -} - -static ULONG WINAPI sample_tracked_Release(IMFSample *iface) -{ - struct sample *sample = impl_from_IMFSample(iface); - ULONG refcount; - HRESULT hr; - - EnterCriticalSection(&sample->attributes.cs); - refcount = InterlockedDecrement(&sample->attributes.ref); - if (sample->tracked_result && sample->tracked_refcount == refcount) - { - /* Call could fail if queue system is not initialized, it's not critical. */ - if (FAILED(hr = RtwqInvokeCallback(sample->tracked_result))) - WARN("Failed to invoke tracking callback, hr %#x.\n", hr); - IRtwqAsyncResult_Release(sample->tracked_result); - sample->tracked_result = NULL; - sample->tracked_refcount = 0; - } - LeaveCriticalSection(&sample->attributes.cs); - - TRACE("%p, refcount %u.\n", iface, refcount); - - if (!refcount) - release_sample_object(sample); - - return refcount; -} - -static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); - - return attributes_GetItem(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type); - - return attributes_GetItemType(&sample->attributes, key, type); -} - -static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result); - - return attributes_CompareItem(&sample->attributes, key, value, result); -} - -static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type, - BOOL *result) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result); - - return attributes_Compare(&sample->attributes, theirs, type, result); -} - -static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); - - return attributes_GetUINT32(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); - - return attributes_GetUINT64(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); - - return attributes_GetDouble(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); - - return attributes_GetGUID(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length); - - return attributes_GetStringLength(&sample->attributes, key, length); -} - -static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length); - - return attributes_GetString(&sample->attributes, key, value, size, length); -} - -static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length); - - return attributes_GetAllocatedString(&sample->attributes, key, value, length); -} - -static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size); - - return attributes_GetBlobSize(&sample->attributes, key, size); -} - -static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize); - - return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize); -} - -static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size); - - return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size); -} - -static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out); - - return attributes_GetUnknown(&sample->attributes, key, riid, out); -} - -static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value)); - - return attributes_SetItem(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s.\n", iface, debugstr_attr(key)); - - return attributes_DeleteItem(&sample->attributes, key); -} - -static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p.\n", iface); - - return attributes_DeleteAllItems(&sample->attributes); -} - -static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value); - - return attributes_SetUINT32(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value)); - - return attributes_SetUINT64(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value); - - return attributes_SetDouble(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value)); - - return attributes_SetGUID(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value)); - - return attributes_SetString(&sample->attributes, key, value); -} - -static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size); - - return attributes_SetBlob(&sample->attributes, key, buf, size); -} - -static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown); - - return attributes_SetUnknown(&sample->attributes, key, unknown); -} - -static HRESULT WINAPI sample_LockStore(IMFSample *iface) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p.\n", iface); - - return attributes_LockStore(&sample->attributes); -} - -static HRESULT WINAPI sample_UnlockStore(IMFSample *iface) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p.\n", iface); - - return attributes_UnlockStore(&sample->attributes); -} - -static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %p.\n", iface, count); - - return attributes_GetCount(&sample->attributes, count); -} - -static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %u, %p, %p.\n", iface, index, key, value); - - return attributes_GetItemByIndex(&sample->attributes, index, key, value); -} - -static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %p.\n", iface, dest); - - return attributes_CopyAllItems(&sample->attributes, dest); -} - -static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %p.\n", iface, flags); - - EnterCriticalSection(&sample->attributes.cs); - *flags = sample->flags; - LeaveCriticalSection(&sample->attributes.cs); - - return S_OK; -} - -static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %#x.\n", iface, flags); - - EnterCriticalSection(&sample->attributes.cs); - sample->flags = flags; - LeaveCriticalSection(&sample->attributes.cs); - - return S_OK; -} - -static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp) -{ - struct sample *sample = impl_from_IMFSample(iface); - HRESULT hr = S_OK; - - TRACE("%p, %p.\n", iface, timestamp); - - EnterCriticalSection(&sample->attributes.cs); - if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP) - *timestamp = sample->timestamp; - else - hr = MF_E_NO_SAMPLE_TIMESTAMP; - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s.\n", iface, debugstr_time(timestamp)); - - EnterCriticalSection(&sample->attributes.cs); - sample->timestamp = timestamp; - sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP; - LeaveCriticalSection(&sample->attributes.cs); - - return S_OK; -} - -static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration) -{ - struct sample *sample = impl_from_IMFSample(iface); - HRESULT hr = S_OK; - - TRACE("%p, %p.\n", iface, duration); - - EnterCriticalSection(&sample->attributes.cs); - if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION) - *duration = sample->duration; - else - hr = MF_E_NO_SAMPLE_DURATION; - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %s.\n", iface, debugstr_time(duration)); - - EnterCriticalSection(&sample->attributes.cs); - sample->duration = duration; - sample->prop_flags |= SAMPLE_PROP_HAS_DURATION; - LeaveCriticalSection(&sample->attributes.cs); - - return S_OK; -} - -static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %p.\n", iface, count); - - if (!count) - return E_INVALIDARG; - - EnterCriticalSection(&sample->attributes.cs); - *count = sample->buffer_count; - LeaveCriticalSection(&sample->attributes.cs); - - return S_OK; -} - -static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer) -{ - struct sample *sample = impl_from_IMFSample(iface); - HRESULT hr = S_OK; - - TRACE("%p, %u, %p.\n", iface, index, buffer); - - EnterCriticalSection(&sample->attributes.cs); - if (index < sample->buffer_count) - { - *buffer = sample->buffers[index]; - IMFMediaBuffer_AddRef(*buffer); - } - else - hr = E_INVALIDARG; - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static unsigned int sample_get_total_length(struct sample *sample) -{ - DWORD total_length = 0, length; - size_t i; - - for (i = 0; i < sample->buffer_count; ++i) - { - length = 0; - if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length))) - total_length += length; - } - - return total_length; -} - -static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer) -{ - DWORD total_length, dst_length, dst_current_length, src_max_length, current_length; - BYTE *src_ptr, *dst_ptr; - BOOL locked; - HRESULT hr; - size_t i; - - total_length = sample_get_total_length(sample); - dst_current_length = 0; - - dst_ptr = NULL; - dst_length = current_length = 0; - locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length)); - if (locked) - { - if (dst_length < total_length) - hr = MF_E_BUFFERTOOSMALL; - else if (dst_ptr) - { - for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i) - { - src_ptr = NULL; - src_max_length = current_length = 0; - if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length))) - { - if (src_ptr) - { - if (current_length > dst_length) - hr = MF_E_BUFFERTOOSMALL; - else if (current_length) - { - memcpy(dst_ptr, src_ptr, current_length); - dst_length -= current_length; - dst_current_length += current_length; - dst_ptr += current_length; - } - } - IMFMediaBuffer_Unlock(sample->buffers[i]); - } - } - } - } - - if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length))) - WARN("Failed to set buffer length.\n"); - - if (locked) - IMFMediaBuffer_Unlock(buffer); - - return hr; -} - -static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer) -{ - struct sample *sample = impl_from_IMFSample(iface); - unsigned int total_length, i; - IMFMediaBuffer *dest_buffer; - HRESULT hr = S_OK; - - TRACE("%p, %p.\n", iface, buffer); - - EnterCriticalSection(&sample->attributes.cs); - - if (sample->buffer_count == 0) - hr = E_UNEXPECTED; - else if (sample->buffer_count > 1) - { - total_length = sample_get_total_length(sample); - if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer))) - { - if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer))) - { - for (i = 0; i < sample->buffer_count; ++i) - IMFMediaBuffer_Release(sample->buffers[i]); - - sample->buffers[0] = dest_buffer; - IMFMediaBuffer_AddRef(sample->buffers[0]); - - sample->buffer_count = 1; - } - IMFMediaBuffer_Release(dest_buffer); - } - } - - if (SUCCEEDED(hr) && buffer) - { - *buffer = sample->buffers[0]; - IMFMediaBuffer_AddRef(*buffer); - } - - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer) -{ - struct sample *sample = impl_from_IMFSample(iface); - HRESULT hr = S_OK; - - TRACE("%p, %p.\n", iface, buffer); - - EnterCriticalSection(&sample->attributes.cs); - if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1, - sizeof(*sample->buffers))) - hr = E_OUTOFMEMORY; - else - { - sample->buffers[sample->buffer_count++] = buffer; - IMFMediaBuffer_AddRef(buffer); - } - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index) -{ - struct sample *sample = impl_from_IMFSample(iface); - HRESULT hr = S_OK; - - TRACE("%p, %u.\n", iface, index); - - EnterCriticalSection(&sample->attributes.cs); - if (index < sample->buffer_count) - { - IMFMediaBuffer_Release(sample->buffers[index]); - if (index < sample->buffer_count - 1) - { - memmove(&sample->buffers[index], &sample->buffers[index+1], - (sample->buffer_count - index - 1) * sizeof(*sample->buffers)); - } - sample->buffer_count--; - } - else - hr = E_INVALIDARG; - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface) -{ - struct sample *sample = impl_from_IMFSample(iface); - size_t i; - - TRACE("%p.\n", iface); - - EnterCriticalSection(&sample->attributes.cs); - for (i = 0; i < sample->buffer_count; ++i) - IMFMediaBuffer_Release(sample->buffers[i]); - sample->buffer_count = 0; - LeaveCriticalSection(&sample->attributes.cs); - - return S_OK; -} - -static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length) -{ - struct sample *sample = impl_from_IMFSample(iface); - - TRACE("%p, %p.\n", iface, total_length); - - EnterCriticalSection(&sample->attributes.cs); - *total_length = sample_get_total_length(sample); - LeaveCriticalSection(&sample->attributes.cs); - - return S_OK; -} - -static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer) -{ - struct sample *sample = impl_from_IMFSample(iface); - DWORD total_length, dst_length, dst_current_length, src_max_length, current_length; - BYTE *src_ptr, *dst_ptr; - BOOL locked; - HRESULT hr; - size_t i; - - TRACE("%p, %p.\n", iface, buffer); - - EnterCriticalSection(&sample->attributes.cs); - - total_length = sample_get_total_length(sample); - dst_current_length = 0; - - dst_ptr = NULL; - dst_length = current_length = 0; - locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length)); - if (locked) - { - if (dst_length < total_length) - hr = MF_E_BUFFERTOOSMALL; - else if (dst_ptr) - { - for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i) - { - src_ptr = NULL; - src_max_length = current_length = 0; - if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length))) - { - if (src_ptr) - { - if (current_length > dst_length) - hr = MF_E_BUFFERTOOSMALL; - else if (current_length) - { - memcpy(dst_ptr, src_ptr, current_length); - dst_length -= current_length; - dst_current_length += current_length; - dst_ptr += current_length; - } - } - IMFMediaBuffer_Unlock(sample->buffers[i]); - } - } - } - } - - IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length); - - if (locked) - IMFMediaBuffer_Unlock(buffer); - - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static const IMFSampleVtbl samplevtbl = -{ - sample_QueryInterface, - sample_AddRef, - sample_Release, - sample_GetItem, - sample_GetItemType, - sample_CompareItem, - sample_Compare, - sample_GetUINT32, - sample_GetUINT64, - sample_GetDouble, - sample_GetGUID, - sample_GetStringLength, - sample_GetString, - sample_GetAllocatedString, - sample_GetBlobSize, - sample_GetBlob, - sample_GetAllocatedBlob, - sample_GetUnknown, - sample_SetItem, - sample_DeleteItem, - sample_DeleteAllItems, - sample_SetUINT32, - sample_SetUINT64, - sample_SetDouble, - sample_SetGUID, - sample_SetString, - sample_SetBlob, - sample_SetUnknown, - sample_LockStore, - sample_UnlockStore, - sample_GetCount, - sample_GetItemByIndex, - sample_CopyAllItems, - sample_GetSampleFlags, - sample_SetSampleFlags, - sample_GetSampleTime, - sample_SetSampleTime, - sample_GetSampleDuration, - sample_SetSampleDuration, - sample_GetBufferCount, - sample_GetBufferByIndex, - sample_ConvertToContiguousBuffer, - sample_AddBuffer, - sample_RemoveBufferByIndex, - sample_RemoveAllBuffers, - sample_GetTotalLength, - sample_CopyToBuffer, -}; - -static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj) -{ - struct sample *sample = impl_from_IMFTrackedSample(iface); - return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj); -} - -static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface) -{ - struct sample *sample = impl_from_IMFTrackedSample(iface); - return IMFSample_AddRef(&sample->IMFSample_iface); -} - -static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface) -{ - struct sample *sample = impl_from_IMFTrackedSample(iface); - return IMFSample_Release(&sample->IMFSample_iface); -} - -static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface, - IMFAsyncCallback *sample_allocator, IUnknown *state) -{ - struct sample *sample = impl_from_IMFTrackedSample(iface); - HRESULT hr = S_OK; - - TRACE("%p, %p, %p.\n", iface, sample_allocator, state); - - EnterCriticalSection(&sample->attributes.cs); - - if (sample->tracked_result) - hr = MF_E_NOTACCEPTING; - else - { - if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator, - state, &sample->tracked_result))) - { - /* Account for additional refcount brought by 'state' object. This threshold is used - on Release() to invoke tracker callback. */ - sample->tracked_refcount = 1; - if (state == (IUnknown *)&sample->IMFTrackedSample_iface || - state == (IUnknown *)&sample->IMFSample_iface) - { - ++sample->tracked_refcount; - } - } - } - - LeaveCriticalSection(&sample->attributes.cs); - - return hr; -} - -static const IMFTrackedSampleVtbl tracked_sample_vtbl = -{ - tracked_sample_QueryInterface, - tracked_sample_AddRef, - tracked_sample_Release, - tracked_sample_SetAllocator, -}; - -static const IMFSampleVtbl sample_tracked_vtbl = -{ - sample_QueryInterface, - sample_AddRef, - sample_tracked_Release, - sample_GetItem, - sample_GetItemType, - sample_CompareItem, - sample_Compare, - sample_GetUINT32, - sample_GetUINT64, - sample_GetDouble, - sample_GetGUID, - sample_GetStringLength, - sample_GetString, - sample_GetAllocatedString, - sample_GetBlobSize, - sample_GetBlob, - sample_GetAllocatedBlob, - sample_GetUnknown, - sample_SetItem, - sample_DeleteItem, - sample_DeleteAllItems, - sample_SetUINT32, - sample_SetUINT64, - sample_SetDouble, - sample_SetGUID, - sample_SetString, - sample_SetBlob, - sample_SetUnknown, - sample_LockStore, - sample_UnlockStore, - sample_GetCount, - sample_GetItemByIndex, - sample_CopyAllItems, - sample_GetSampleFlags, - sample_SetSampleFlags, - sample_GetSampleTime, - sample_SetSampleTime, - sample_GetSampleDuration, - sample_SetSampleDuration, - sample_GetBufferCount, - sample_GetBufferByIndex, - sample_ConvertToContiguousBuffer, - sample_AddBuffer, - sample_RemoveBufferByIndex, - sample_RemoveAllBuffers, - sample_GetTotalLength, - sample_CopyToBuffer, -}; - - -/*********************************************************************** - * MFCreateSample (mfplat.@) - */ -HRESULT WINAPI MFCreateSample(IMFSample **sample) -{ - struct sample *object; - HRESULT hr; - - TRACE("%p.\n", sample); - - object = heap_alloc_zero(sizeof(*object)); - if (!object) - return E_OUTOFMEMORY; - - if (FAILED(hr = init_attributes_object(&object->attributes, 0))) - { - heap_free(object); - return hr; - } - - object->IMFSample_iface.lpVtbl = &samplevtbl; - - *sample = &object->IMFSample_iface; - - TRACE("Created sample %p.\n", *sample); - - return S_OK; -} - -/*********************************************************************** - * MFCreateTrackedSample (mfplat.@) - */ -HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample) -{ - struct sample *object; - HRESULT hr; - - TRACE("%p.\n", sample); - - object = heap_alloc_zero(sizeof(*object)); - if (!object) - return E_OUTOFMEMORY; - - if (FAILED(hr = init_attributes_object(&object->attributes, 0))) - { - heap_free(object); - return hr; - } - - object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl; - object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl; - - *sample = &object->IMFTrackedSample_iface; - - return S_OK; -} diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c new file mode 100644 index 00000000000..bd67fb731fc --- /dev/null +++ b/dlls/mfplat/sample.c @@ -0,0 +1,1007 @@ +/* + * Copyright 2021 Nikolay Sivov for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "mfplat_private.h" +#include "rtworkq.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(mfplat); + +enum sample_prop_flags +{ + SAMPLE_PROP_HAS_DURATION = 1 << 0, + SAMPLE_PROP_HAS_TIMESTAMP = 1 << 1, +}; + +struct sample +{ + struct attributes attributes; + IMFSample IMFSample_iface; + IMFTrackedSample IMFTrackedSample_iface; + + IMFMediaBuffer **buffers; + size_t buffer_count; + size_t capacity; + DWORD flags; + DWORD prop_flags; + LONGLONG duration; + LONGLONG timestamp; + + /* Tracked sample functionality. */ + IRtwqAsyncResult *tracked_result; + LONG tracked_refcount; +}; + +static struct sample *impl_from_IMFSample(IMFSample *iface) +{ + return CONTAINING_RECORD(iface, struct sample, IMFSample_iface); +} + +static struct sample *impl_from_IMFTrackedSample(IMFTrackedSample *iface) +{ + return CONTAINING_RECORD(iface, struct sample, IMFTrackedSample_iface); +} + +static HRESULT WINAPI sample_QueryInterface(IMFSample *iface, REFIID riid, void **out) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFSample) || + IsEqualIID(riid, &IID_IMFAttributes) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &sample->IMFSample_iface; + } + else if (sample->IMFTrackedSample_iface.lpVtbl && IsEqualIID(riid, &IID_IMFTrackedSample)) + { + *out = &sample->IMFTrackedSample_iface; + } + else + { + WARN("Unsupported %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*out); + return S_OK; +} + +static ULONG WINAPI sample_AddRef(IMFSample *iface) +{ + struct sample *sample = impl_from_IMFSample(iface); + ULONG refcount = InterlockedIncrement(&sample->attributes.ref); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static void release_sample_object(struct sample *sample) +{ + size_t i; + + for (i = 0; i < sample->buffer_count; ++i) + IMFMediaBuffer_Release(sample->buffers[i]); + clear_attributes_object(&sample->attributes); + heap_free(sample->buffers); + heap_free(sample); +} + +static ULONG WINAPI sample_Release(IMFSample *iface) +{ + struct sample *sample = impl_from_IMFSample(iface); + ULONG refcount = InterlockedDecrement(&sample->attributes.ref); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + release_sample_object(sample); + + return refcount; +} + +static ULONG WINAPI sample_tracked_Release(IMFSample *iface) +{ + struct sample *sample = impl_from_IMFSample(iface); + ULONG refcount; + HRESULT hr; + + EnterCriticalSection(&sample->attributes.cs); + refcount = InterlockedDecrement(&sample->attributes.ref); + if (sample->tracked_result && sample->tracked_refcount == refcount) + { + /* Call could fail if queue system is not initialized, it's not critical. */ + if (FAILED(hr = RtwqInvokeCallback(sample->tracked_result))) + WARN("Failed to invoke tracking callback, hr %#x.\n", hr); + IRtwqAsyncResult_Release(sample->tracked_result); + sample->tracked_result = NULL; + sample->tracked_refcount = 0; + } + LeaveCriticalSection(&sample->attributes.cs); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + release_sample_object(sample); + + return refcount; +} + +static HRESULT WINAPI sample_GetItem(IMFSample *iface, REFGUID key, PROPVARIANT *value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); + + return attributes_GetItem(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_GetItemType(IMFSample *iface, REFGUID key, MF_ATTRIBUTE_TYPE *type) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), type); + + return attributes_GetItemType(&sample->attributes, key, type); +} + +static HRESULT WINAPI sample_CompareItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value, BOOL *result) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_propvar(value), result); + + return attributes_CompareItem(&sample->attributes, key, value, result); +} + +static HRESULT WINAPI sample_Compare(IMFSample *iface, IMFAttributes *theirs, MF_ATTRIBUTES_MATCH_TYPE type, + BOOL *result) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %p, %d, %p.\n", iface, theirs, type, result); + + return attributes_Compare(&sample->attributes, theirs, type, result); +} + +static HRESULT WINAPI sample_GetUINT32(IMFSample *iface, REFGUID key, UINT32 *value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); + + return attributes_GetUINT32(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_GetUINT64(IMFSample *iface, REFGUID key, UINT64 *value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); + + return attributes_GetUINT64(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_GetDouble(IMFSample *iface, REFGUID key, double *value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); + + return attributes_GetDouble(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_GetGUID(IMFSample *iface, REFGUID key, GUID *value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), value); + + return attributes_GetGUID(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_GetStringLength(IMFSample *iface, REFGUID key, UINT32 *length) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), length); + + return attributes_GetStringLength(&sample->attributes, key, length); +} + +static HRESULT WINAPI sample_GetString(IMFSample *iface, REFGUID key, WCHAR *value, UINT32 size, UINT32 *length) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), value, size, length); + + return attributes_GetString(&sample->attributes, key, value, size, length); +} + +static HRESULT WINAPI sample_GetAllocatedString(IMFSample *iface, REFGUID key, WCHAR **value, UINT32 *length) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), value, length); + + return attributes_GetAllocatedString(&sample->attributes, key, value, length); +} + +static HRESULT WINAPI sample_GetBlobSize(IMFSample *iface, REFGUID key, UINT32 *size) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), size); + + return attributes_GetBlobSize(&sample->attributes, key, size); +} + +static HRESULT WINAPI sample_GetBlob(IMFSample *iface, REFGUID key, UINT8 *buf, UINT32 bufsize, UINT32 *blobsize) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p, %u, %p.\n", iface, debugstr_attr(key), buf, bufsize, blobsize); + + return attributes_GetBlob(&sample->attributes, key, buf, bufsize, blobsize); +} + +static HRESULT WINAPI sample_GetAllocatedBlob(IMFSample *iface, REFGUID key, UINT8 **buf, UINT32 *size) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p, %p.\n", iface, debugstr_attr(key), buf, size); + + return attributes_GetAllocatedBlob(&sample->attributes, key, buf, size); +} + +static HRESULT WINAPI sample_GetUnknown(IMFSample *iface, REFGUID key, REFIID riid, void **out) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %s, %p.\n", iface, debugstr_attr(key), debugstr_guid(riid), out); + + return attributes_GetUnknown(&sample->attributes, key, riid, out); +} + +static HRESULT WINAPI sample_SetItem(IMFSample *iface, REFGUID key, REFPROPVARIANT value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_propvar(value)); + + return attributes_SetItem(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_DeleteItem(IMFSample *iface, REFGUID key) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s.\n", iface, debugstr_attr(key)); + + return attributes_DeleteItem(&sample->attributes, key); +} + +static HRESULT WINAPI sample_DeleteAllItems(IMFSample *iface) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p.\n", iface); + + return attributes_DeleteAllItems(&sample->attributes); +} + +static HRESULT WINAPI sample_SetUINT32(IMFSample *iface, REFGUID key, UINT32 value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %u.\n", iface, debugstr_attr(key), value); + + return attributes_SetUINT32(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_SetUINT64(IMFSample *iface, REFGUID key, UINT64 value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), wine_dbgstr_longlong(value)); + + return attributes_SetUINT64(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_SetDouble(IMFSample *iface, REFGUID key, double value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %f.\n", iface, debugstr_attr(key), value); + + return attributes_SetDouble(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_SetGUID(IMFSample *iface, REFGUID key, REFGUID value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_mf_guid(value)); + + return attributes_SetGUID(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_SetString(IMFSample *iface, REFGUID key, const WCHAR *value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %s.\n", iface, debugstr_attr(key), debugstr_w(value)); + + return attributes_SetString(&sample->attributes, key, value); +} + +static HRESULT WINAPI sample_SetBlob(IMFSample *iface, REFGUID key, const UINT8 *buf, UINT32 size) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p, %u.\n", iface, debugstr_attr(key), buf, size); + + return attributes_SetBlob(&sample->attributes, key, buf, size); +} + +static HRESULT WINAPI sample_SetUnknown(IMFSample *iface, REFGUID key, IUnknown *unknown) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_attr(key), unknown); + + return attributes_SetUnknown(&sample->attributes, key, unknown); +} + +static HRESULT WINAPI sample_LockStore(IMFSample *iface) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p.\n", iface); + + return attributes_LockStore(&sample->attributes); +} + +static HRESULT WINAPI sample_UnlockStore(IMFSample *iface) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p.\n", iface); + + return attributes_UnlockStore(&sample->attributes); +} + +static HRESULT WINAPI sample_GetCount(IMFSample *iface, UINT32 *count) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %p.\n", iface, count); + + return attributes_GetCount(&sample->attributes, count); +} + +static HRESULT WINAPI sample_GetItemByIndex(IMFSample *iface, UINT32 index, GUID *key, PROPVARIANT *value) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %u, %p, %p.\n", iface, index, key, value); + + return attributes_GetItemByIndex(&sample->attributes, index, key, value); +} + +static HRESULT WINAPI sample_CopyAllItems(IMFSample *iface, IMFAttributes *dest) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %p.\n", iface, dest); + + return attributes_CopyAllItems(&sample->attributes, dest); +} + +static HRESULT WINAPI sample_GetSampleFlags(IMFSample *iface, DWORD *flags) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %p.\n", iface, flags); + + EnterCriticalSection(&sample->attributes.cs); + *flags = sample->flags; + LeaveCriticalSection(&sample->attributes.cs); + + return S_OK; +} + +static HRESULT WINAPI sample_SetSampleFlags(IMFSample *iface, DWORD flags) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %#x.\n", iface, flags); + + EnterCriticalSection(&sample->attributes.cs); + sample->flags = flags; + LeaveCriticalSection(&sample->attributes.cs); + + return S_OK; +} + +static HRESULT WINAPI sample_GetSampleTime(IMFSample *iface, LONGLONG *timestamp) +{ + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, timestamp); + + EnterCriticalSection(&sample->attributes.cs); + if (sample->prop_flags & SAMPLE_PROP_HAS_TIMESTAMP) + *timestamp = sample->timestamp; + else + hr = MF_E_NO_SAMPLE_TIMESTAMP; + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static HRESULT WINAPI sample_SetSampleTime(IMFSample *iface, LONGLONG timestamp) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s.\n", iface, debugstr_time(timestamp)); + + EnterCriticalSection(&sample->attributes.cs); + sample->timestamp = timestamp; + sample->prop_flags |= SAMPLE_PROP_HAS_TIMESTAMP; + LeaveCriticalSection(&sample->attributes.cs); + + return S_OK; +} + +static HRESULT WINAPI sample_GetSampleDuration(IMFSample *iface, LONGLONG *duration) +{ + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, duration); + + EnterCriticalSection(&sample->attributes.cs); + if (sample->prop_flags & SAMPLE_PROP_HAS_DURATION) + *duration = sample->duration; + else + hr = MF_E_NO_SAMPLE_DURATION; + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static HRESULT WINAPI sample_SetSampleDuration(IMFSample *iface, LONGLONG duration) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %s.\n", iface, debugstr_time(duration)); + + EnterCriticalSection(&sample->attributes.cs); + sample->duration = duration; + sample->prop_flags |= SAMPLE_PROP_HAS_DURATION; + LeaveCriticalSection(&sample->attributes.cs); + + return S_OK; +} + +static HRESULT WINAPI sample_GetBufferCount(IMFSample *iface, DWORD *count) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_INVALIDARG; + + EnterCriticalSection(&sample->attributes.cs); + *count = sample->buffer_count; + LeaveCriticalSection(&sample->attributes.cs); + + return S_OK; +} + +static HRESULT WINAPI sample_GetBufferByIndex(IMFSample *iface, DWORD index, IMFMediaBuffer **buffer) +{ + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; + + TRACE("%p, %u, %p.\n", iface, index, buffer); + + EnterCriticalSection(&sample->attributes.cs); + if (index < sample->buffer_count) + { + *buffer = sample->buffers[index]; + IMFMediaBuffer_AddRef(*buffer); + } + else + hr = E_INVALIDARG; + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static unsigned int sample_get_total_length(struct sample *sample) +{ + DWORD total_length = 0, length; + size_t i; + + for (i = 0; i < sample->buffer_count; ++i) + { + length = 0; + if (SUCCEEDED(IMFMediaBuffer_GetCurrentLength(sample->buffers[i], &length))) + total_length += length; + } + + return total_length; +} + +static HRESULT sample_copy_to_buffer(struct sample *sample, IMFMediaBuffer *buffer) +{ + DWORD total_length, dst_length, dst_current_length, src_max_length, current_length; + BYTE *src_ptr, *dst_ptr; + BOOL locked; + HRESULT hr; + size_t i; + + total_length = sample_get_total_length(sample); + dst_current_length = 0; + + dst_ptr = NULL; + dst_length = current_length = 0; + locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length)); + if (locked) + { + if (dst_length < total_length) + hr = MF_E_BUFFERTOOSMALL; + else if (dst_ptr) + { + for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i) + { + src_ptr = NULL; + src_max_length = current_length = 0; + if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length))) + { + if (src_ptr) + { + if (current_length > dst_length) + hr = MF_E_BUFFERTOOSMALL; + else if (current_length) + { + memcpy(dst_ptr, src_ptr, current_length); + dst_length -= current_length; + dst_current_length += current_length; + dst_ptr += current_length; + } + } + IMFMediaBuffer_Unlock(sample->buffers[i]); + } + } + } + } + + if (FAILED(IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length))) + WARN("Failed to set buffer length.\n"); + + if (locked) + IMFMediaBuffer_Unlock(buffer); + + return hr; +} + +static HRESULT WINAPI sample_ConvertToContiguousBuffer(IMFSample *iface, IMFMediaBuffer **buffer) +{ + struct sample *sample = impl_from_IMFSample(iface); + unsigned int total_length, i; + IMFMediaBuffer *dest_buffer; + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, buffer); + + EnterCriticalSection(&sample->attributes.cs); + + if (sample->buffer_count == 0) + hr = E_UNEXPECTED; + else if (sample->buffer_count > 1) + { + total_length = sample_get_total_length(sample); + if (SUCCEEDED(hr = MFCreateMemoryBuffer(total_length, &dest_buffer))) + { + if (SUCCEEDED(hr = sample_copy_to_buffer(sample, dest_buffer))) + { + for (i = 0; i < sample->buffer_count; ++i) + IMFMediaBuffer_Release(sample->buffers[i]); + + sample->buffers[0] = dest_buffer; + IMFMediaBuffer_AddRef(sample->buffers[0]); + + sample->buffer_count = 1; + } + IMFMediaBuffer_Release(dest_buffer); + } + } + + if (SUCCEEDED(hr) && buffer) + { + *buffer = sample->buffers[0]; + IMFMediaBuffer_AddRef(*buffer); + } + + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static HRESULT WINAPI sample_AddBuffer(IMFSample *iface, IMFMediaBuffer *buffer) +{ + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p.\n", iface, buffer); + + EnterCriticalSection(&sample->attributes.cs); + if (!mf_array_reserve((void **)&sample->buffers, &sample->capacity, sample->buffer_count + 1, + sizeof(*sample->buffers))) + hr = E_OUTOFMEMORY; + else + { + sample->buffers[sample->buffer_count++] = buffer; + IMFMediaBuffer_AddRef(buffer); + } + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static HRESULT WINAPI sample_RemoveBufferByIndex(IMFSample *iface, DWORD index) +{ + struct sample *sample = impl_from_IMFSample(iface); + HRESULT hr = S_OK; + + TRACE("%p, %u.\n", iface, index); + + EnterCriticalSection(&sample->attributes.cs); + if (index < sample->buffer_count) + { + IMFMediaBuffer_Release(sample->buffers[index]); + if (index < sample->buffer_count - 1) + { + memmove(&sample->buffers[index], &sample->buffers[index+1], + (sample->buffer_count - index - 1) * sizeof(*sample->buffers)); + } + sample->buffer_count--; + } + else + hr = E_INVALIDARG; + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static HRESULT WINAPI sample_RemoveAllBuffers(IMFSample *iface) +{ + struct sample *sample = impl_from_IMFSample(iface); + size_t i; + + TRACE("%p.\n", iface); + + EnterCriticalSection(&sample->attributes.cs); + for (i = 0; i < sample->buffer_count; ++i) + IMFMediaBuffer_Release(sample->buffers[i]); + sample->buffer_count = 0; + LeaveCriticalSection(&sample->attributes.cs); + + return S_OK; +} + +static HRESULT WINAPI sample_GetTotalLength(IMFSample *iface, DWORD *total_length) +{ + struct sample *sample = impl_from_IMFSample(iface); + + TRACE("%p, %p.\n", iface, total_length); + + EnterCriticalSection(&sample->attributes.cs); + *total_length = sample_get_total_length(sample); + LeaveCriticalSection(&sample->attributes.cs); + + return S_OK; +} + +static HRESULT WINAPI sample_CopyToBuffer(IMFSample *iface, IMFMediaBuffer *buffer) +{ + struct sample *sample = impl_from_IMFSample(iface); + DWORD total_length, dst_length, dst_current_length, src_max_length, current_length; + BYTE *src_ptr, *dst_ptr; + BOOL locked; + HRESULT hr; + size_t i; + + TRACE("%p, %p.\n", iface, buffer); + + EnterCriticalSection(&sample->attributes.cs); + + total_length = sample_get_total_length(sample); + dst_current_length = 0; + + dst_ptr = NULL; + dst_length = current_length = 0; + locked = SUCCEEDED(hr = IMFMediaBuffer_Lock(buffer, &dst_ptr, &dst_length, ¤t_length)); + if (locked) + { + if (dst_length < total_length) + hr = MF_E_BUFFERTOOSMALL; + else if (dst_ptr) + { + for (i = 0; i < sample->buffer_count && SUCCEEDED(hr); ++i) + { + src_ptr = NULL; + src_max_length = current_length = 0; + if (SUCCEEDED(hr = IMFMediaBuffer_Lock(sample->buffers[i], &src_ptr, &src_max_length, ¤t_length))) + { + if (src_ptr) + { + if (current_length > dst_length) + hr = MF_E_BUFFERTOOSMALL; + else if (current_length) + { + memcpy(dst_ptr, src_ptr, current_length); + dst_length -= current_length; + dst_current_length += current_length; + dst_ptr += current_length; + } + } + IMFMediaBuffer_Unlock(sample->buffers[i]); + } + } + } + } + + IMFMediaBuffer_SetCurrentLength(buffer, dst_current_length); + + if (locked) + IMFMediaBuffer_Unlock(buffer); + + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static const IMFSampleVtbl samplevtbl = +{ + sample_QueryInterface, + sample_AddRef, + sample_Release, + sample_GetItem, + sample_GetItemType, + sample_CompareItem, + sample_Compare, + sample_GetUINT32, + sample_GetUINT64, + sample_GetDouble, + sample_GetGUID, + sample_GetStringLength, + sample_GetString, + sample_GetAllocatedString, + sample_GetBlobSize, + sample_GetBlob, + sample_GetAllocatedBlob, + sample_GetUnknown, + sample_SetItem, + sample_DeleteItem, + sample_DeleteAllItems, + sample_SetUINT32, + sample_SetUINT64, + sample_SetDouble, + sample_SetGUID, + sample_SetString, + sample_SetBlob, + sample_SetUnknown, + sample_LockStore, + sample_UnlockStore, + sample_GetCount, + sample_GetItemByIndex, + sample_CopyAllItems, + sample_GetSampleFlags, + sample_SetSampleFlags, + sample_GetSampleTime, + sample_SetSampleTime, + sample_GetSampleDuration, + sample_SetSampleDuration, + sample_GetBufferCount, + sample_GetBufferByIndex, + sample_ConvertToContiguousBuffer, + sample_AddBuffer, + sample_RemoveBufferByIndex, + sample_RemoveAllBuffers, + sample_GetTotalLength, + sample_CopyToBuffer, +}; + +static HRESULT WINAPI tracked_sample_QueryInterface(IMFTrackedSample *iface, REFIID riid, void **obj) +{ + struct sample *sample = impl_from_IMFTrackedSample(iface); + return IMFSample_QueryInterface(&sample->IMFSample_iface, riid, obj); +} + +static ULONG WINAPI tracked_sample_AddRef(IMFTrackedSample *iface) +{ + struct sample *sample = impl_from_IMFTrackedSample(iface); + return IMFSample_AddRef(&sample->IMFSample_iface); +} + +static ULONG WINAPI tracked_sample_Release(IMFTrackedSample *iface) +{ + struct sample *sample = impl_from_IMFTrackedSample(iface); + return IMFSample_Release(&sample->IMFSample_iface); +} + +static HRESULT WINAPI tracked_sample_SetAllocator(IMFTrackedSample *iface, + IMFAsyncCallback *sample_allocator, IUnknown *state) +{ + struct sample *sample = impl_from_IMFTrackedSample(iface); + HRESULT hr = S_OK; + + TRACE("%p, %p, %p.\n", iface, sample_allocator, state); + + EnterCriticalSection(&sample->attributes.cs); + + if (sample->tracked_result) + hr = MF_E_NOTACCEPTING; + else + { + if (SUCCEEDED(hr = RtwqCreateAsyncResult((IUnknown *)iface, (IRtwqAsyncCallback *)sample_allocator, + state, &sample->tracked_result))) + { + /* Account for additional refcount brought by 'state' object. This threshold is used + on Release() to invoke tracker callback. */ + sample->tracked_refcount = 1; + if (state == (IUnknown *)&sample->IMFTrackedSample_iface || + state == (IUnknown *)&sample->IMFSample_iface) + { + ++sample->tracked_refcount; + } + } + } + + LeaveCriticalSection(&sample->attributes.cs); + + return hr; +} + +static const IMFTrackedSampleVtbl tracked_sample_vtbl = +{ + tracked_sample_QueryInterface, + tracked_sample_AddRef, + tracked_sample_Release, + tracked_sample_SetAllocator, +}; + +static const IMFSampleVtbl sample_tracked_vtbl = +{ + sample_QueryInterface, + sample_AddRef, + sample_tracked_Release, + sample_GetItem, + sample_GetItemType, + sample_CompareItem, + sample_Compare, + sample_GetUINT32, + sample_GetUINT64, + sample_GetDouble, + sample_GetGUID, + sample_GetStringLength, + sample_GetString, + sample_GetAllocatedString, + sample_GetBlobSize, + sample_GetBlob, + sample_GetAllocatedBlob, + sample_GetUnknown, + sample_SetItem, + sample_DeleteItem, + sample_DeleteAllItems, + sample_SetUINT32, + sample_SetUINT64, + sample_SetDouble, + sample_SetGUID, + sample_SetString, + sample_SetBlob, + sample_SetUnknown, + sample_LockStore, + sample_UnlockStore, + sample_GetCount, + sample_GetItemByIndex, + sample_CopyAllItems, + sample_GetSampleFlags, + sample_SetSampleFlags, + sample_GetSampleTime, + sample_SetSampleTime, + sample_GetSampleDuration, + sample_SetSampleDuration, + sample_GetBufferCount, + sample_GetBufferByIndex, + sample_ConvertToContiguousBuffer, + sample_AddBuffer, + sample_RemoveBufferByIndex, + sample_RemoveAllBuffers, + sample_GetTotalLength, + sample_CopyToBuffer, +}; + +/*********************************************************************** + * MFCreateSample (mfplat.@) + */ +HRESULT WINAPI MFCreateSample(IMFSample **sample) +{ + struct sample *object; + HRESULT hr; + + TRACE("%p.\n", sample); + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + if (FAILED(hr = init_attributes_object(&object->attributes, 0))) + { + heap_free(object); + return hr; + } + + object->IMFSample_iface.lpVtbl = &samplevtbl; + + *sample = &object->IMFSample_iface; + + TRACE("Created sample %p.\n", *sample); + + return S_OK; +} + +/*********************************************************************** + * MFCreateTrackedSample (mfplat.@) + */ +HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample) +{ + struct sample *object; + HRESULT hr; + + TRACE("%p.\n", sample); + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + if (FAILED(hr = init_attributes_object(&object->attributes, 0))) + { + heap_free(object); + return hr; + } + + object->IMFSample_iface.lpVtbl = &sample_tracked_vtbl; + object->IMFTrackedSample_iface.lpVtbl = &tracked_sample_vtbl; + + *sample = &object->IMFTrackedSample_iface; + + return S_OK; +}
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 88 ++++++++++++++++++++++++++++++++++++++ dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/tests/mfplat.c | 68 +++++++++++++++++++++++++++++ include/mfapi.h | 1 + 4 files changed, 158 insertions(+)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 2bf9b674ea7..7c252147679 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -3316,3 +3316,91 @@ DWORD WINAPI MFMapDXGIFormatToDX9Format(DXGI_FORMAT dxgi_format) return 0; } } + +/*********************************************************************** + * MFMapDX9FormatToDXGIFormat (mfplat.@) + */ +DXGI_FORMAT WINAPI MFMapDX9FormatToDXGIFormat(DWORD format) +{ + switch (format) + { + case D3DFMT_A32B32G32R32F: + return DXGI_FORMAT_R32G32B32A32_FLOAT; + case D3DFMT_A16B16G16R16F: + return DXGI_FORMAT_R16G16B16A16_FLOAT; + case D3DFMT_A16B16G16R16: + return DXGI_FORMAT_R16G16B16A16_UNORM; + case D3DFMT_Q16W16V16U16: + return DXGI_FORMAT_R16G16B16A16_SNORM; + case D3DFMT_G32R32F: + return DXGI_FORMAT_R32G32_FLOAT; + case D3DFMT_A2B10G10R10: + return DXGI_FORMAT_R10G10B10A2_UNORM; + case D3DFMT_Q8W8V8U8: + return DXGI_FORMAT_R8G8B8A8_SNORM; + case D3DFMT_G16R16F: + return DXGI_FORMAT_R16G16_FLOAT; + case D3DFMT_G16R16: + return DXGI_FORMAT_R16G16_UNORM; + case D3DFMT_V16U16: + return DXGI_FORMAT_R16G16_SNORM; + case D3DFMT_D32F_LOCKABLE: + return DXGI_FORMAT_D32_FLOAT; + case D3DFMT_R32F: + return DXGI_FORMAT_R32_FLOAT; + case D3DFMT_D24S8: + return DXGI_FORMAT_D24_UNORM_S8_UINT; + case D3DFMT_V8U8: + return DXGI_FORMAT_R8G8_SNORM; + case D3DFMT_R16F: + return DXGI_FORMAT_R16_FLOAT; + case D3DFMT_L16: + return DXGI_FORMAT_R16_UNORM; + case D3DFMT_L8: + return DXGI_FORMAT_R8_UNORM; + case D3DFMT_A8: + return DXGI_FORMAT_A8_UNORM; + case D3DFMT_DXT1: + return DXGI_FORMAT_BC1_UNORM; + case D3DFMT_DXT2: + return DXGI_FORMAT_BC2_UNORM; + case D3DFMT_DXT4: + return DXGI_FORMAT_BC3_UNORM; + case D3DFMT_A8R8G8B8: + return DXGI_FORMAT_B8G8R8A8_UNORM; + case D3DFMT_X8R8G8B8: + return DXGI_FORMAT_B8G8R8X8_UNORM; + case MAKEFOURCC('A','Y','U','V'): + return DXGI_FORMAT_AYUV; + case MAKEFOURCC('Y','4','1','0'): + return DXGI_FORMAT_Y410; + case MAKEFOURCC('Y','4','1','6'): + return DXGI_FORMAT_Y416; + case MAKEFOURCC('N','V','1','2'): + return DXGI_FORMAT_NV12; + case MAKEFOURCC('P','0','1','0'): + return DXGI_FORMAT_P010; + case MAKEFOURCC('P','0','1','6'): + return DXGI_FORMAT_P016; + case MAKEFOURCC('4','2','0','O'): + return DXGI_FORMAT_420_OPAQUE; + case D3DFMT_YUY2: + return DXGI_FORMAT_YUY2; + case MAKEFOURCC('Y','2','1','0'): + return DXGI_FORMAT_Y210; + case MAKEFOURCC('Y','2','1','6'): + return DXGI_FORMAT_Y216; + case MAKEFOURCC('N','V','1','1'): + return DXGI_FORMAT_NV11; + case MAKEFOURCC('A','I','4','4'): + return DXGI_FORMAT_AI44; + case MAKEFOURCC('I','A','4','4'): + return DXGI_FORMAT_IA44; + case D3DFMT_P8: + return DXGI_FORMAT_P8; + case D3DFMT_A8P8: + return DXGI_FORMAT_A8P8; + default: + return DXGI_FORMAT_UNKNOWN; + } +} diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 8ef40dd20c8..809903c4b22 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -131,6 +131,7 @@ @ stdcall MFJoinWorkQueue(long long ptr) rtworkq.RtwqJoinWorkQueue @ stdcall MFLockPlatform() rtworkq.RtwqLockPlatform @ stdcall MFLockWorkQueue(long) rtworkq.RtwqLockWorkQueue +@ stdcall MFMapDX9FormatToDXGIFormat(long) @ stdcall MFMapDXGIFormatToDX9Format(long) @ stdcall MFPutWaitingWorkItem(long long ptr ptr) rtworkq.RtwqPutWaitingWorkItem @ stdcall MFPutWorkItem(long ptr ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 3f4dd48b2a8..949e8e5feed 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -131,6 +131,7 @@ static HRESULT (WINAPI *pMFCreateMediaBufferFromMediaType)(IMFMediaType *media_t static HRESULT (WINAPI *pMFCreateDXSurfaceBuffer)(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer); static HRESULT (WINAPI *pMFCreateTrackedSample)(IMFTrackedSample **sample); static DWORD (WINAPI *pMFMapDXGIFormatToDX9Format)(DXGI_FORMAT dxgi_format); +static DXGI_FORMAT (WINAPI *pMFMapDX9FormatToDXGIFormat)(DWORD format); static HRESULT (WINAPI *pMFCreateVideoSampleAllocatorEx)(REFIID riid, void **allocator); static HRESULT (WINAPI *pMFCreateDXGISurfaceBuffer)(REFIID riid, IUnknown *surface, UINT subresource, BOOL bottomup, IMFMediaBuffer **buffer); @@ -800,6 +801,7 @@ static void init_functions(void) X(MFCreateVideoSampleAllocatorEx); X(MFGetPlaneSize); X(MFGetStrideForBitmapInfoHeader); + X(MFMapDX9FormatToDXGIFormat); X(MFMapDXGIFormatToDX9Format); X(MFPutWaitingWorkItem); X(MFRegisterLocalByteStreamHandler); @@ -6038,6 +6040,71 @@ static void test_MFMapDXGIFormatToDX9Format(void) } }
+static void test_MFMapDX9FormatToDXGIFormat(void) +{ + static const struct format_pair + { + DXGI_FORMAT dxgi_format; + DWORD d3d9_format; + } + formats_map[] = + { + { DXGI_FORMAT_R32G32B32A32_FLOAT, D3DFMT_A32B32G32R32F }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, D3DFMT_A16B16G16R16F }, + { DXGI_FORMAT_R16G16B16A16_UNORM, D3DFMT_A16B16G16R16 }, + { DXGI_FORMAT_R16G16B16A16_SNORM, D3DFMT_Q16W16V16U16 }, + { DXGI_FORMAT_R32G32_FLOAT, D3DFMT_G32R32F }, + { DXGI_FORMAT_R10G10B10A2_UNORM, D3DFMT_A2B10G10R10 }, + { DXGI_FORMAT_R8G8B8A8_SNORM, D3DFMT_Q8W8V8U8 }, + { DXGI_FORMAT_R16G16_FLOAT, D3DFMT_G16R16F }, + { DXGI_FORMAT_R16G16_UNORM, D3DFMT_G16R16 }, + { DXGI_FORMAT_R16G16_SNORM, D3DFMT_V16U16 }, + { DXGI_FORMAT_D32_FLOAT, D3DFMT_D32F_LOCKABLE }, + { DXGI_FORMAT_R32_FLOAT, D3DFMT_R32F }, + { DXGI_FORMAT_D24_UNORM_S8_UINT, D3DFMT_D24S8 }, + { DXGI_FORMAT_R8G8_SNORM, D3DFMT_V8U8 }, + { DXGI_FORMAT_R16_FLOAT, D3DFMT_R16F }, + { DXGI_FORMAT_R16_UNORM, D3DFMT_L16 }, + { DXGI_FORMAT_R8_UNORM, D3DFMT_L8 }, + { DXGI_FORMAT_A8_UNORM, D3DFMT_A8 }, + { DXGI_FORMAT_BC1_UNORM, D3DFMT_DXT1 }, + { DXGI_FORMAT_BC2_UNORM, D3DFMT_DXT2 }, + { DXGI_FORMAT_BC3_UNORM, D3DFMT_DXT4 }, + { DXGI_FORMAT_B8G8R8A8_UNORM, D3DFMT_A8R8G8B8 }, + { DXGI_FORMAT_B8G8R8X8_UNORM, D3DFMT_X8R8G8B8 }, + { DXGI_FORMAT_AYUV, MAKEFOURCC('A','Y','U','V') }, + { DXGI_FORMAT_Y410, MAKEFOURCC('Y','4','1','0') }, + { DXGI_FORMAT_Y416, MAKEFOURCC('Y','4','1','6') }, + { DXGI_FORMAT_NV12, MAKEFOURCC('N','V','1','2') }, + { DXGI_FORMAT_P010, MAKEFOURCC('P','0','1','0') }, + { DXGI_FORMAT_P016, MAKEFOURCC('P','0','1','6') }, + { DXGI_FORMAT_420_OPAQUE, MAKEFOURCC('4','2','0','O') }, + { DXGI_FORMAT_YUY2, D3DFMT_YUY2 }, + { DXGI_FORMAT_Y210, MAKEFOURCC('Y','2','1','0') }, + { DXGI_FORMAT_Y216, MAKEFOURCC('Y','2','1','6') }, + { DXGI_FORMAT_NV11, MAKEFOURCC('N','V','1','1') }, + { DXGI_FORMAT_AI44, MAKEFOURCC('A','I','4','4') }, + { DXGI_FORMAT_IA44, MAKEFOURCC('I','A','4','4') }, + { DXGI_FORMAT_P8, D3DFMT_P8 }, + { DXGI_FORMAT_A8P8, D3DFMT_A8P8 }, + }; + DXGI_FORMAT format; + unsigned int i; + + if (!pMFMapDX9FormatToDXGIFormat) + { + win_skip("MFMapDX9FormatToDXGIFormat() is not available.\n"); + return; + } + + for (i = 0; i < ARRAY_SIZE(formats_map); ++i) + { + format = pMFMapDX9FormatToDXGIFormat(formats_map[i].d3d9_format); + ok(format == formats_map[i].dxgi_format, "Unexpected DXGI format %#x, d3d9 format %#x.\n", + format, formats_map[i].d3d9_format); + } +} + static HRESULT WINAPI test_notify_callback_QueryInterface(IMFVideoSampleAllocatorNotify *iface, REFIID riid, void **obj) { @@ -6506,6 +6573,7 @@ START_TEST(mfplat) test_MFMapDXGIFormatToDX9Format(); test_dxgi_surface_buffer(); test_sample_allocator(); + test_MFMapDX9FormatToDXGIFormat();
CoUninitialize(); } diff --git a/include/mfapi.h b/include/mfapi.h index 7bac3e21fa9..364bea1eea9 100644 --- a/include/mfapi.h +++ b/include/mfapi.h @@ -553,6 +553,7 @@ HRESULT WINAPI MFInitAttributesFromBlob(IMFAttributes *attributes, const UINT8 * HRESULT WINAPI MFInitMediaTypeFromWaveFormatEx(IMFMediaType *mediatype, const WAVEFORMATEX *format, UINT32 size); HRESULT WINAPI MFInvokeCallback(IMFAsyncResult *result); HRESULT WINAPI MFLockPlatform(void); +DXGI_FORMAT WINAPI MFMapDX9FormatToDXGIFormat(DWORD format); DWORD WINAPI MFMapDXGIFormatToDX9Format(DXGI_FORMAT dxgi_format); HRESULT WINAPI MFPutWaitingWorkItem(HANDLE event, LONG priority, IMFAsyncResult *result, MFWORKITEM_KEY *key); HRESULT WINAPI MFPutWorkItem(DWORD queue, IMFAsyncCallback *callback, IUnknown *state);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84990
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 949e8e5feed..71294686ae0 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6212,7 +6212,7 @@ static void test_dxgi_surface_buffer(void) desc.Width = 64; desc.Height = 64; desc.ArraySize = 1; - desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; + desc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0;
@@ -6220,14 +6220,7 @@ static void test_dxgi_surface_buffer(void) ok(hr == S_OK, "Failed to create a texture, hr %#x.\n", hr);
hr = pMFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer); - ok(hr == S_OK || broken(hr == MF_E_INVALIDMEDIATYPE) /* Win8 */, "Failed to create a buffer, hr %#x.\n", hr); - - if (FAILED(hr)) - { - ID3D11Texture2D_Release(texture); - ID3D11Device_Release(device); - return; - } + ok(hr == S_OK, "Failed to create a buffer, hr %#x.\n", hr);
check_interface(buffer, &IID_IMF2DBuffer, TRUE); check_interface(buffer, &IID_IMF2DBuffer2, TRUE);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84991
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/tests/mfplat.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 71294686ae0..a548e307783 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -5083,15 +5083,19 @@ static void test_queue_com_state(const char *name) queue_type = name[1] - '0';
hr = pMFAllocateWorkQueueEx(queue_type, &queue); - ok(hr == S_OK, "Failed to allocate a queue, hr %#x.\n", hr); + ok(hr == S_OK || broken(queue_type == MF_MULTITHREADED_WORKQUEUE && hr == E_INVALIDARG) /* Win7 */, + "Failed to allocate a queue of type %u, hr %#x.\n", queue_type, hr);
- callback.param = queue; - hr = MFPutWorkItem(queue, &callback.IMFAsyncCallback_iface, NULL); - ok(SUCCEEDED(hr), "Failed to queue work item, hr %#x.\n", hr); - WaitForSingleObject(callback.event, INFINITE); + if (SUCCEEDED(hr)) + { + callback.param = queue; + hr = MFPutWorkItem(queue, &callback.IMFAsyncCallback_iface, NULL); + ok(SUCCEEDED(hr), "Failed to queue work item, hr %#x.\n", hr); + WaitForSingleObject(callback.event, INFINITE);
- hr = MFUnlockWorkQueue(queue); - ok(hr == S_OK, "Failed to unlock the queue, hr %#x.\n", hr); + hr = MFUnlockWorkQueue(queue); + ok(hr == S_OK, "Failed to unlock the queue, hr %#x.\n", hr); + } }
CloseHandle(callback.event);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84992
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/buffer.c | 279 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/main.c | 2 +- dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/tests/mfplat.c | 8 +- 4 files changed, 288 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/buffer.c b/dlls/mfplat/buffer.c index adfa2d867c1..6a4f4605450 100644 --- a/dlls/mfplat/buffer.c +++ b/dlls/mfplat/buffer.c @@ -21,6 +21,7 @@ #include "mfplat_private.h" #include "rtworkq.h"
+#include "d3d11.h" #include "initguid.h" #include "d3d9.h" #include "evr.h" @@ -35,6 +36,7 @@ struct memory_buffer { IMFMediaBuffer IMFMediaBuffer_iface; IMF2DBuffer2 IMF2DBuffer2_iface; + IMFDXGIBuffer IMFDXGIBuffer_iface; IMFGetService IMFGetService_iface; LONG refcount;
@@ -59,6 +61,12 @@ struct memory_buffer IDirect3DSurface9 *surface; D3DLOCKED_RECT rect; } d3d9_surface; + struct + { + IUnknown *surface; + unsigned int subresource; + struct attributes attributes; + } dxgi_surface;
CRITICAL_SECTION cs; }; @@ -78,6 +86,11 @@ static struct memory_buffer *impl_from_IMFGetService(IMFGetService *iface) return CONTAINING_RECORD(iface, struct memory_buffer, IMFGetService_iface); }
+static struct memory_buffer *impl_from_IMFDXGIBuffer(IMFDXGIBuffer *iface) +{ + return CONTAINING_RECORD(iface, struct memory_buffer, IMFDXGIBuffer_iface); +} + static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) { struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); @@ -118,6 +131,11 @@ static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface) { if (buffer->d3d9_surface.surface) IDirect3DSurface9_Release(buffer->d3d9_surface.surface); + if (buffer->dxgi_surface.surface) + { + IUnknown_Release(buffer->dxgi_surface.surface); + clear_attributes_object(&buffer->dxgi_surface.attributes); + } DeleteCriticalSection(&buffer->cs); heap_free(buffer->_2d.linear_buffer); heap_free(buffer->data); @@ -781,6 +799,204 @@ static const IMFGetServiceVtbl d3d9_surface_buffer_gs_vtbl = d3d9_surface_buffer_gs_GetService, };
+static HRESULT WINAPI dxgi_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out) +{ + struct memory_buffer *buffer = impl_from_IMFMediaBuffer(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out); + + if (IsEqualIID(riid, &IID_IMFMediaBuffer) || + IsEqualIID(riid, &IID_IUnknown)) + { + *out = &buffer->IMFMediaBuffer_iface; + } + else if (IsEqualIID(riid, &IID_IMF2DBuffer2) || + IsEqualIID(riid, &IID_IMF2DBuffer)) + { + *out = &buffer->IMF2DBuffer2_iface; + } + else if (IsEqualIID(riid, &IID_IMFDXGIBuffer)) + { + *out = &buffer->IMFDXGIBuffer_iface; + } + else + { + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *out = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*out); + return S_OK; +} + +static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, + DWORD *current_length) +{ + FIXME("%p, %p, %p, %p.\n", iface, data, max_length, current_length); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dxgi_surface_buffer_Unlock(IMFMediaBuffer *iface) +{ + FIXME("%p.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dxgi_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) +{ + FIXME("%p, %p, %p.\n", iface, scanline0, pitch); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dxgi_surface_buffer_Unlock2D(IMF2DBuffer2 *iface) +{ + FIXME("%p.\n", iface); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dxgi_surface_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch) +{ + FIXME("%p, %p, %p.\n", iface, scanline0, pitch); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dxgi_surface_buffer_GetContiguousLength(IMF2DBuffer2 *iface, DWORD *length) +{ + FIXME("%p, %p.\n", iface, length); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dxgi_surface_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, + BYTE **scanline0, LONG *pitch, BYTE **buffer_start, DWORD *buffer_length) +{ + FIXME("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length); + + return E_NOTIMPL; +} + +static HRESULT WINAPI dxgi_buffer_QueryInterface(IMFDXGIBuffer *iface, REFIID riid, void **obj) +{ + struct memory_buffer *buffer = impl_from_IMFDXGIBuffer(iface); + return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj); +} + +static ULONG WINAPI dxgi_buffer_AddRef(IMFDXGIBuffer *iface) +{ + struct memory_buffer *buffer = impl_from_IMFDXGIBuffer(iface); + return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface); +} + +static ULONG WINAPI dxgi_buffer_Release(IMFDXGIBuffer *iface) +{ + struct memory_buffer *buffer = impl_from_IMFDXGIBuffer(iface); + return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface); +} + +static HRESULT WINAPI dxgi_buffer_GetResource(IMFDXGIBuffer *iface, REFIID riid, void **obj) +{ + struct memory_buffer *buffer = impl_from_IMFDXGIBuffer(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + return IUnknown_QueryInterface(buffer->dxgi_surface.surface, riid, obj); +} + +static HRESULT WINAPI dxgi_buffer_GetSubresourceIndex(IMFDXGIBuffer *iface, UINT *index) +{ + struct memory_buffer *buffer = impl_from_IMFDXGIBuffer(iface); + + TRACE("%p, %p.\n", iface, index); + + if (!index) + return E_POINTER; + + *index = buffer->dxgi_surface.subresource; + + return S_OK; +} + +static HRESULT WINAPI dxgi_buffer_GetUnknown(IMFDXGIBuffer *iface, REFIID guid, REFIID riid, void **object) +{ + struct memory_buffer *buffer = impl_from_IMFDXGIBuffer(iface); + + TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(guid), debugstr_guid(riid), object); + + if (attributes_GetUnknown(&buffer->dxgi_surface.attributes, guid, riid, object) == MF_E_ATTRIBUTENOTFOUND) + return MF_E_NOT_FOUND; + + return S_OK; +} + +static HRESULT WINAPI dxgi_buffer_SetUnknown(IMFDXGIBuffer *iface, REFIID guid, IUnknown *data) +{ + struct memory_buffer *buffer = impl_from_IMFDXGIBuffer(iface); + HRESULT hr = S_OK; + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(guid), data); + + EnterCriticalSection(&buffer->dxgi_surface.attributes.cs); + if (data) + { + if (SUCCEEDED(attributes_GetItem(&buffer->dxgi_surface.attributes, guid, NULL))) + hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS); + else + hr = attributes_SetUnknown(&buffer->dxgi_surface.attributes, guid, data); + } + else + { + attributes_DeleteItem(&buffer->dxgi_surface.attributes, guid); + } + LeaveCriticalSection(&buffer->dxgi_surface.attributes.cs); + + return hr; +} + +static const IMFMediaBufferVtbl dxgi_surface_1d_buffer_vtbl = +{ + dxgi_1d_2d_buffer_QueryInterface, + memory_buffer_AddRef, + memory_buffer_Release, + dxgi_surface_buffer_Lock, + dxgi_surface_buffer_Unlock, + memory_buffer_GetCurrentLength, + memory_buffer_SetCurrentLength, + memory_buffer_GetMaxLength, +}; + +static const IMF2DBuffer2Vtbl dxgi_surface_buffer_vtbl = +{ + memory_2d_buffer_QueryInterface, + memory_2d_buffer_AddRef, + memory_2d_buffer_Release, + dxgi_surface_buffer_Lock2D, + dxgi_surface_buffer_Unlock2D, + dxgi_surface_buffer_GetScanline0AndPitch, + memory_2d_buffer_IsContiguousFormat, + dxgi_surface_buffer_GetContiguousLength, + memory_2d_buffer_ContiguousCopyTo, + memory_2d_buffer_ContiguousCopyFrom, + dxgi_surface_buffer_Lock2DSize, + memory_2d_buffer_Copy2DTo, +}; + +static const IMFDXGIBufferVtbl dxgi_buffer_vtbl = +{ + dxgi_buffer_QueryInterface, + dxgi_buffer_AddRef, + dxgi_buffer_Release, + dxgi_buffer_GetResource, + dxgi_buffer_GetSubresourceIndex, + dxgi_buffer_GetUnknown, + dxgi_buffer_SetUnknown, +}; + static HRESULT memory_buffer_init(struct memory_buffer *buffer, DWORD max_length, DWORD alignment, const IMFMediaBufferVtbl *vtbl) { @@ -941,6 +1157,55 @@ static HRESULT create_d3d9_surface_buffer(IUnknown *surface, BOOL bottom_up, IMF return S_OK; }
+static HRESULT create_dxgi_surface_buffer(IUnknown *surface, UINT subresource, BOOL bottom_up, + IMFMediaBuffer **buffer) +{ + struct memory_buffer *object; + D3D11_TEXTURE2D_DESC desc; + unsigned int stride; + D3DFORMAT format; + GUID subtype; + BOOL is_yuv; + HRESULT hr; + + ID3D11Texture2D_GetDesc((ID3D11Texture2D *)surface, &desc); + TRACE("format %#x, %u x %u.\n", desc.Format, desc.Width, desc.Height); + + memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype)); + subtype.Data1 = format = MFMapDXGIFormatToDX9Format(desc.Format); + + if (!(stride = mf_format_get_stride(&subtype, desc.Width, &is_yuv))) + return MF_E_INVALIDMEDIATYPE; + + object = heap_alloc_zero(sizeof(*object)); + if (!object) + return E_OUTOFMEMORY; + + object->IMFMediaBuffer_iface.lpVtbl = &dxgi_surface_1d_buffer_vtbl; + object->IMF2DBuffer2_iface.lpVtbl = &dxgi_surface_buffer_vtbl; + object->IMFDXGIBuffer_iface.lpVtbl = &dxgi_buffer_vtbl; + object->refcount = 1; + InitializeCriticalSection(&object->cs); + object->dxgi_surface.surface = surface; + IUnknown_AddRef(surface); + object->dxgi_surface.subresource = subresource; + + MFGetPlaneSize(format, desc.Width, desc.Height, &object->_2d.plane_size); + object->_2d.width = stride; + object->_2d.height = desc.Height; + object->max_length = object->_2d.plane_size; + + if (FAILED(hr = init_attributes_object(&object->dxgi_surface.attributes, 0))) + { + IMFMediaBuffer_Release(&object->IMFMediaBuffer_iface); + return hr; + } + + *buffer = &object->IMFMediaBuffer_iface; + + return S_OK; +} + /*********************************************************************** * MFCreateMemoryBuffer (mfplat.@) */ @@ -984,6 +1249,20 @@ HRESULT WINAPI MFCreateDXSurfaceBuffer(REFIID riid, IUnknown *surface, BOOL bott return create_d3d9_surface_buffer(surface, bottom_up, buffer); }
+/*********************************************************************** + * MFCreateDXGISurfaceBuffer (mfplat.@) + */ +HRESULT WINAPI MFCreateDXGISurfaceBuffer(REFIID riid, IUnknown *surface, UINT subresource, BOOL bottom_up, + IMFMediaBuffer **buffer) +{ + TRACE("%s, %p, %u, %d, %p.\n", debugstr_guid(riid), surface, subresource, bottom_up, buffer); + + if (!IsEqualIID(riid, &IID_ID3D11Texture2D)) + return E_INVALIDARG; + + return create_dxgi_surface_buffer(surface, subresource, bottom_up, buffer); +} + static unsigned int buffer_get_aligned_length(unsigned int length, unsigned int alignment) { length = (length + alignment) / alignment; diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c index 3d294ad45f0..b78cfc33e60 100644 --- a/dlls/mfplat/main.c +++ b/dlls/mfplat/main.c @@ -32,7 +32,7 @@ #include "rtworkq.h" #include "ole2.h" #include "propsys.h" -#include "dxgi.h" +#include "d3d11.h" #include "uuids.h"
#include "wine/debug.h" diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index 809903c4b22..f51c65c5b85 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -46,6 +46,7 @@ @ stub MFCreateAudioMediaType @ stdcall MFCreateCollection(ptr) @ stdcall MFCreateDXGIDeviceManager(ptr ptr) +@ stdcall MFCreateDXGISurfaceBuffer(ptr ptr long long ptr) @ stdcall MFCreateDXSurfaceBuffer(ptr ptr long ptr) @ stdcall MFCreateEventQueue(ptr) @ stdcall MFCreateFile(long long long wstr ptr) diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index a548e307783..d4a461a2df8 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6206,7 +6206,7 @@ static void test_dxgi_surface_buffer(void)
if (!pMFCreateDXGISurfaceBuffer) { - skip("MFCreateDXGISurfaceBuffer() is not available.\n"); + win_skip("MFCreateDXGISurfaceBuffer() is not available.\n"); return; }
@@ -6248,9 +6248,15 @@ static void test_dxgi_surface_buffer(void) ok(hr == S_OK, "Unexpected hr %#x.\n", hr); ok(index == 0, "Unexpected subresource index.\n");
+ hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, NULL); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, (void *)device); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ hr = IMFDXGIBuffer_SetUnknown(dxgi_buffer, &IID_IMFDXGIBuffer, (void *)device); + ok(hr == HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS), "Unexpected hr %#x.\n", hr); + hr = ID3D11Texture2D_GetPrivateData(texture, &IID_IMFDXGIBuffer, &size, &data); ok(hr == DXGI_ERROR_NOT_FOUND, "Unexpected hr %#x.\n", hr);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84993
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/mediatype.c | 2 +- dlls/mfplat/mfplat.spec | 1 + dlls/mfplat/sample.c | 671 +++++++++++++++++++++++++++++++++++++ dlls/mfplat/tests/mfplat.c | 5 +- 4 files changed, 677 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/mediatype.c b/dlls/mfplat/mediatype.c index 7c252147679..85219c74dd5 100644 --- a/dlls/mfplat/mediatype.c +++ b/dlls/mfplat/mediatype.c @@ -20,10 +20,10 @@
#include "mfplat_private.h"
+#include "dxva2api.h" #include "initguid.h" #include "ks.h" #include "ksmedia.h" -#include "dxva2api.h"
#include "wine/debug.h"
diff --git a/dlls/mfplat/mfplat.spec b/dlls/mfplat/mfplat.spec index f51c65c5b85..7d014e334c8 100644 --- a/dlls/mfplat/mfplat.spec +++ b/dlls/mfplat/mfplat.spec @@ -82,6 +82,7 @@ @ stdcall MFCreateVideoMediaTypeFromSubtype(ptr ptr) @ stub MFCreateVideoMediaTypeFromVideoInfoHeader2 @ stub MFCreateVideoMediaTypeFromVideoInfoHeader +@ stdcall MFCreateVideoSampleAllocatorEx(ptr ptr) @ stdcall MFCreateWaveFormatExFromMFMediaType(ptr ptr ptr long) @ stub MFDeserializeAttributesFromStream @ stub MFDeserializeEvent diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index bd67fb731fc..266bb6f0726 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -20,8 +20,13 @@
#include "mfplat_private.h" #include "rtworkq.h" +#include "d3d9.h" +#include "d3d11.h" +#include "initguid.h" +#include "dxva2api.h"
#include "wine/debug.h" +#include "wine/list.h"
WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
@@ -50,6 +55,54 @@ struct sample LONG tracked_refcount; };
+struct sample_allocator +{ + IMFVideoSampleAllocatorEx IMFVideoSampleAllocatorEx_iface; + IMFVideoSampleAllocatorCallback IMFVideoSampleAllocatorCallback_iface; + IMFAsyncCallback tracking_callback; + LONG refcount; + + IMFVideoSampleAllocatorNotify *callback; + IDirect3DDeviceManager9 *d3d9_device_manager; + IMFDXGIDeviceManager *dxgi_device_manager; + + struct + { + unsigned int width; + unsigned int height; + D3DFORMAT d3d9_format; + DXGI_FORMAT dxgi_format; + unsigned int buffer_count; + } frame_desc; + + unsigned int free_sample_count; + unsigned int cold_sample_count; + struct list free_samples; + struct list used_samples; + CRITICAL_SECTION cs; +}; + +struct queued_sample +{ + struct list entry; + IMFSample *sample; +}; + +static struct sample_allocator *impl_from_IMFVideoSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface) +{ + return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorEx_iface); +} + +static struct sample_allocator *impl_from_IMFVideoSampleAllocatorCallback(IMFVideoSampleAllocatorCallback *iface) +{ + return CONTAINING_RECORD(iface, struct sample_allocator, IMFVideoSampleAllocatorCallback_iface); +} + +static struct sample_allocator *impl_from_IMFAsyncCallback(IMFAsyncCallback *iface) +{ + return CONTAINING_RECORD(iface, struct sample_allocator, tracking_callback); +} + static struct sample *impl_from_IMFSample(IMFSample *iface) { return CONTAINING_RECORD(iface, struct sample, IMFSample_iface); @@ -1005,3 +1058,621 @@ HRESULT WINAPI MFCreateTrackedSample(IMFTrackedSample **sample)
return S_OK; } + +static HRESULT WINAPI sample_allocator_QueryInterface(IMFVideoSampleAllocatorEx *iface, REFIID riid, void **obj) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + + TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj); + + if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorEx) || + IsEqualIID(riid, &IID_IMFVideoSampleAllocator) || + IsEqualIID(riid, &IID_IUnknown)) + { + *obj = &allocator->IMFVideoSampleAllocatorEx_iface; + } + else if (IsEqualIID(riid, &IID_IMFVideoSampleAllocatorCallback)) + { + *obj = &allocator->IMFVideoSampleAllocatorCallback_iface; + } + else + { + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI sample_allocator_AddRef(IMFVideoSampleAllocatorEx *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + ULONG refcount = InterlockedIncrement(&allocator->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + return refcount; +} + +static void sample_allocator_release_samples(struct sample_allocator *allocator) +{ + struct queued_sample *iter, *iter2; + + LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->free_samples, struct queued_sample, entry) + { + list_remove(&iter->entry); + IMFSample_Release(iter->sample); + heap_free(iter); + } + + LIST_FOR_EACH_ENTRY_SAFE(iter, iter2, &allocator->used_samples, struct queued_sample, entry) + { + list_remove(&iter->entry); + heap_free(iter); + } +} + +static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocatorEx *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + ULONG refcount = InterlockedDecrement(&allocator->refcount); + + TRACE("%p, refcount %u.\n", iface, refcount); + + if (!refcount) + { + if (allocator->callback) + IMFVideoSampleAllocatorNotify_Release(allocator->callback); + if (allocator->d3d9_device_manager) + IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager); + if (allocator->dxgi_device_manager) + IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager); + sample_allocator_release_samples(allocator); + DeleteCriticalSection(&allocator->cs); + heap_free(allocator); + } + + return refcount; +} + +static HRESULT WINAPI sample_allocator_SetDirectXManager(IMFVideoSampleAllocatorEx *iface, + IUnknown *manager) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + IDirect3DDeviceManager9 *d3d9_device_manager = NULL; + IMFDXGIDeviceManager *dxgi_device_manager = NULL; + HRESULT hr; + + TRACE("%p, %p.\n", iface, manager); + + if (manager) + { + if (FAILED(hr = IUnknown_QueryInterface(manager, &IID_IMFDXGIDeviceManager, (void **)&dxgi_device_manager))) + { + hr = IUnknown_QueryInterface(manager, &IID_IDirect3DDeviceManager9, (void **)&d3d9_device_manager); + } + + if (FAILED(hr)) + return hr; + } + + EnterCriticalSection(&allocator->cs); + + if (allocator->d3d9_device_manager) + IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager); + if (allocator->dxgi_device_manager) + IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager); + allocator->d3d9_device_manager = NULL; + allocator->dxgi_device_manager = NULL; + + if (dxgi_device_manager) + allocator->dxgi_device_manager = dxgi_device_manager; + else if (d3d9_device_manager) + allocator->d3d9_device_manager = d3d9_device_manager; + + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static HRESULT WINAPI sample_allocator_UninitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + + TRACE("%p.\n", iface); + + EnterCriticalSection(&allocator->cs); + + sample_allocator_release_samples(allocator); + allocator->free_sample_count = 0; + + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +struct surface_service +{ + IDirectXVideoProcessorService *dxva_service; + ID3D11Device *d3d11_device; + HANDLE hdevice; +}; + +static HRESULT sample_allocator_get_surface_service(struct sample_allocator *allocator, struct surface_service *service) +{ + HRESULT hr = S_OK; + + memset(service, 0, sizeof(*service)); + + if (allocator->d3d9_device_manager) + { + if (SUCCEEDED(hr = IDirect3DDeviceManager9_OpenDeviceHandle(allocator->d3d9_device_manager, &service->hdevice))) + { + if (FAILED(hr = IDirect3DDeviceManager9_GetVideoService(allocator->d3d9_device_manager, service->hdevice, + &IID_IDirectXVideoProcessorService, (void **)&service->dxva_service))) + { + WARN("Failed to get DXVA processor service, hr %#x.\n", hr); + IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice); + } + } + } + else if (allocator->dxgi_device_manager) + { + if (SUCCEEDED(hr = IMFDXGIDeviceManager_OpenDeviceHandle(allocator->dxgi_device_manager, &service->hdevice))) + { + if (FAILED(hr = IMFDXGIDeviceManager_GetVideoService(allocator->dxgi_device_manager, service->hdevice, + &IID_ID3D11Device, (void **)&service->d3d11_device))) + { + WARN("Failed to get D3D11 device, hr %#x.\n", hr); + IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice); + } + } + } + + if (FAILED(hr)) + memset(service, 0, sizeof(*service)); + + return hr; +} + +static void sample_allocator_release_surface_service(struct sample_allocator *allocator, + struct surface_service *service) +{ + if (service->dxva_service) + IDirectXVideoProcessorService_Release(service->dxva_service); + if (service->d3d11_device) + ID3D11Device_Release(service->d3d11_device); + + if (allocator->d3d9_device_manager) + IDirect3DDeviceManager9_CloseDeviceHandle(allocator->d3d9_device_manager, service->hdevice); + else if (allocator->dxgi_device_manager) + IMFDXGIDeviceManager_CloseDeviceHandle(allocator->dxgi_device_manager, service->hdevice); +} + +static HRESULT sample_allocator_allocate_sample(struct sample_allocator *allocator, const struct surface_service *service, + IMFSample **sample) +{ + struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample)); + IMFTrackedSample *tracked_sample; + IMFMediaBuffer *buffer; + unsigned int i; + HRESULT hr; + + if (FAILED(hr = MFCreateTrackedSample(&tracked_sample))) + { + return hr; + } + + IMFTrackedSample_QueryInterface(tracked_sample, &IID_IMFSample, (void **)sample); + IMFTrackedSample_Release(tracked_sample); + + for (i = 0; i < allocator->frame_desc.buffer_count; ++i) + { + if (service->dxva_service) + { + IDirect3DSurface9 *surface; + + if (SUCCEEDED(hr = IDirectXVideoProcessorService_CreateSurface(service->dxva_service, allocator->frame_desc.width, + allocator->frame_desc.height, 0, allocator->frame_desc.d3d9_format, D3DPOOL_DEFAULT, 0, + DXVA2_VideoProcessorRenderTarget, &surface, NULL))) + { + hr = MFCreateDXSurfaceBuffer(&IID_IDirect3DSurface9, (IUnknown *)surface, FALSE, &buffer); + IDirect3DSurface9_Release(surface); + } + } + else if (service->d3d11_device) + { + D3D11_TEXTURE2D_DESC desc = { 0 }; + ID3D11Texture2D *texture; + + desc.Width = allocator->frame_desc.width; + desc.Height = allocator->frame_desc.height; + desc.MipLevels = 1; + desc.ArraySize = 1; + desc.Format = allocator->frame_desc.dxgi_format; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = 0; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; + + if (SUCCEEDED(hr = ID3D11Device_CreateTexture2D(service->d3d11_device, &desc, NULL, &texture))) + { + hr = MFCreateDXGISurfaceBuffer(&IID_ID3D11Texture2D, (IUnknown *)texture, 0, FALSE, &buffer); + ID3D11Texture2D_Release(texture); + } + } + else + { + hr = MFCreate2DMediaBuffer(allocator->frame_desc.width, allocator->frame_desc.height, + allocator->frame_desc.d3d9_format, FALSE, &buffer); + } + + if (SUCCEEDED(hr)) + { + hr = IMFSample_AddBuffer(*sample, buffer); + IMFMediaBuffer_Release(buffer); + } + } + + return hr; +} + +static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, unsigned int sample_count, + unsigned int max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type) +{ + struct surface_service service; + unsigned int i; + GUID major, subtype; + UINT64 frame_size; + IMFSample *sample; + HRESULT hr; + + if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major))) + return hr; + + if (!IsEqualGUID(&major, &MFMediaType_Video)) + return MF_E_INVALIDMEDIATYPE; + + if (FAILED(hr = IMFMediaType_GetUINT64(media_type, &MF_MT_FRAME_SIZE, &frame_size))) + return hr; + + if (FAILED(hr = IMFMediaType_GetGUID(media_type, &MF_MT_SUBTYPE, &subtype))) + return hr; + + if (sample_count > max_sample_count) + return E_INVALIDARG; + + sample_count = max(1, sample_count); + max_sample_count = max(1, max_sample_count); + + if (attributes) + FIXME("Initialization attributes ignored.\n"); + + allocator->frame_desc.d3d9_format = subtype.Data1; + allocator->frame_desc.dxgi_format = MFMapDX9FormatToDXGIFormat(allocator->frame_desc.d3d9_format); + allocator->frame_desc.width = frame_size >> 32; + allocator->frame_desc.height = frame_size; + + if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service))) + return hr; + + sample_allocator_release_samples(allocator); + + for (i = 0; i < sample_count; ++i) + { + struct queued_sample *queued_sample; + + if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample))) + { + queued_sample = heap_alloc(sizeof(*queued_sample)); + queued_sample->sample = sample; + list_add_tail(&allocator->free_samples, &queued_sample->entry); + allocator->free_sample_count++; + } + } + allocator->cold_sample_count = max_sample_count - allocator->free_sample_count; + + sample_allocator_release_surface_service(allocator, &service); + + return hr; +} + +static HRESULT WINAPI sample_allocator_InitializeSampleAllocator(IMFVideoSampleAllocatorEx *iface, + DWORD sample_count, IMFMediaType *media_type) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + HRESULT hr; + + TRACE("%p, %u, %p.\n", iface, sample_count, media_type); + + if (!sample_count) + return E_INVALIDARG; + + EnterCriticalSection(&allocator->cs); + + hr = sample_allocator_initialize(allocator, sample_count, sample_count, NULL, media_type); + + LeaveCriticalSection(&allocator->cs); + + return hr; +} + +static HRESULT sample_allocator_track_sample(struct sample_allocator *allocator, IMFSample *sample) +{ + IMFTrackedSample *tracked_sample; + HRESULT hr; + + if (SUCCEEDED(hr = IMFSample_QueryInterface(sample, &IID_IMFTrackedSample, (void **)&tracked_sample))) + { + hr = IMFTrackedSample_SetAllocator(tracked_sample, &allocator->tracking_callback, NULL); + IMFTrackedSample_Release(tracked_sample); + } + + return hr; +} + +static HRESULT WINAPI sample_allocator_AllocateSample(IMFVideoSampleAllocatorEx *iface, IMFSample **out) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + IMFSample *sample; + HRESULT hr; + + TRACE("%p, %p.\n", iface, out); + + EnterCriticalSection(&allocator->cs); + + if (list_empty(&allocator->free_samples) && list_empty(&allocator->used_samples)) + hr = MF_E_NOT_INITIALIZED; + else if (list_empty(&allocator->free_samples) && !allocator->cold_sample_count) + hr = MF_E_SAMPLEALLOCATOR_EMPTY; + else if (!list_empty(&allocator->free_samples)) + { + struct list *head = list_head(&allocator->free_samples); + + sample = LIST_ENTRY(head, struct queued_sample, entry)->sample; + + if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample))) + { + list_remove(head); + list_add_tail(&allocator->used_samples, head); + allocator->free_sample_count--; + + /* Reference counter is not increased when sample is returned, so next release could trigger + tracking condition. This is balanced by incremented reference counter when sample is returned + back to the free list. */ + *out = sample; + } + } + else /* allocator->cold_sample_count != 0 */ + { + struct surface_service service; + + if (SUCCEEDED(hr = sample_allocator_get_surface_service(allocator, &service))) + { + if (SUCCEEDED(hr = sample_allocator_allocate_sample(allocator, &service, &sample))) + { + if (SUCCEEDED(hr = sample_allocator_track_sample(allocator, sample))) + { + struct queued_sample *queued_sample = heap_alloc(sizeof(*queued_sample)); + + queued_sample->sample = sample; + list_add_tail(&allocator->used_samples, &queued_sample->entry); + allocator->cold_sample_count--; + + *out = queued_sample->sample; + } + } + + sample_allocator_release_surface_service(allocator, &service); + } + } + + LeaveCriticalSection(&allocator->cs); + + return hr; +} + +static HRESULT WINAPI sample_allocator_InitializeSampleAllocatorEx(IMFVideoSampleAllocatorEx *iface, DWORD initial_sample_count, + DWORD max_sample_count, IMFAttributes *attributes, IMFMediaType *media_type) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorEx(iface); + HRESULT hr; + + TRACE("%p, %u, %u, %p, %p.\n", iface, initial_sample_count, max_sample_count, attributes, media_type); + + EnterCriticalSection(&allocator->cs); + + hr = sample_allocator_initialize(allocator, initial_sample_count, max_sample_count, attributes, media_type); + + LeaveCriticalSection(&allocator->cs); + + return hr; +} + +static const IMFVideoSampleAllocatorExVtbl sample_allocator_vtbl = +{ + sample_allocator_QueryInterface, + sample_allocator_AddRef, + sample_allocator_Release, + sample_allocator_SetDirectXManager, + sample_allocator_UninitializeSampleAllocator, + sample_allocator_InitializeSampleAllocator, + sample_allocator_AllocateSample, + sample_allocator_InitializeSampleAllocatorEx, +}; + +static HRESULT WINAPI sample_allocator_callback_QueryInterface(IMFVideoSampleAllocatorCallback *iface, + REFIID riid, void **obj) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + return IMFVideoSampleAllocatorEx_QueryInterface(&allocator->IMFVideoSampleAllocatorEx_iface, riid, obj); +} + +static ULONG WINAPI sample_allocator_callback_AddRef(IMFVideoSampleAllocatorCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static ULONG WINAPI sample_allocator_callback_Release(IMFVideoSampleAllocatorCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static HRESULT WINAPI sample_allocator_callback_SetCallback(IMFVideoSampleAllocatorCallback *iface, + IMFVideoSampleAllocatorNotify *callback) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + + TRACE("%p, %p.\n", iface, callback); + + EnterCriticalSection(&allocator->cs); + if (allocator->callback) + IMFVideoSampleAllocatorNotify_Release(allocator->callback); + allocator->callback = callback; + if (allocator->callback) + IMFVideoSampleAllocatorNotify_AddRef(allocator->callback); + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static HRESULT WINAPI sample_allocator_callback_GetFreeSampleCount(IMFVideoSampleAllocatorCallback *iface, + LONG *count) +{ + struct sample_allocator *allocator = impl_from_IMFVideoSampleAllocatorCallback(iface); + + TRACE("%p, %p.\n", iface, count); + + if (!count) + return E_POINTER; + + EnterCriticalSection(&allocator->cs); + *count = allocator->free_sample_count; + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static const IMFVideoSampleAllocatorCallbackVtbl sample_allocator_callback_vtbl = +{ + sample_allocator_callback_QueryInterface, + sample_allocator_callback_AddRef, + sample_allocator_callback_Release, + sample_allocator_callback_SetCallback, + sample_allocator_callback_GetFreeSampleCount, +}; + +static HRESULT WINAPI sample_allocator_tracking_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; + } + + WARN("Unsupported interface %s.\n", debugstr_guid(riid)); + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI sample_allocator_tracking_callback_AddRef(IMFAsyncCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface); + return IMFVideoSampleAllocatorEx_AddRef(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static ULONG WINAPI sample_allocator_tracking_callback_Release(IMFAsyncCallback *iface) +{ + struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface); + return IMFVideoSampleAllocatorEx_Release(&allocator->IMFVideoSampleAllocatorEx_iface); +} + +static HRESULT WINAPI sample_allocator_tracking_callback_GetParameters(IMFAsyncCallback *iface, + DWORD *flags, DWORD *queue) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI sample_allocator_tracking_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) +{ + struct sample_allocator *allocator = impl_from_IMFAsyncCallback(iface); + struct queued_sample *iter; + IUnknown *object = NULL; + IMFSample *sample = NULL; + HRESULT hr; + + if (FAILED(IMFAsyncResult_GetObject(result, &object))) + return E_UNEXPECTED; + + hr = IUnknown_QueryInterface(object, &IID_IMFSample, (void **)&sample); + IUnknown_Release(object); + if (FAILED(hr)) + return E_UNEXPECTED; + + EnterCriticalSection(&allocator->cs); + + LIST_FOR_EACH_ENTRY(iter, &allocator->used_samples, struct queued_sample, entry) + { + if (sample == iter->sample) + { + list_remove(&iter->entry); + list_add_tail(&allocator->free_samples, &iter->entry); + IMFSample_AddRef(iter->sample); + allocator->free_sample_count++; + break; + } + } + + IMFSample_Release(sample); + + if (allocator->callback) + IMFVideoSampleAllocatorNotify_NotifyRelease(allocator->callback); + + LeaveCriticalSection(&allocator->cs); + + return S_OK; +} + +static const IMFAsyncCallbackVtbl sample_allocator_tracking_callback_vtbl = +{ + sample_allocator_tracking_callback_QueryInterface, + sample_allocator_tracking_callback_AddRef, + sample_allocator_tracking_callback_Release, + sample_allocator_tracking_callback_GetParameters, + sample_allocator_tracking_callback_Invoke, +}; + +/*********************************************************************** + * MFCreateVideoSampleAllocatorEx (mfplat.@) + */ +HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj) +{ + struct sample_allocator *object; + HRESULT hr; + + TRACE("%s, %p.\n", debugstr_guid(riid), obj); + + if (!(object = heap_alloc_zero(sizeof(*object)))) + return E_OUTOFMEMORY; + + object->IMFVideoSampleAllocatorEx_iface.lpVtbl = &sample_allocator_vtbl; + object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl; + object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl; + object->refcount = 1; + object->frame_desc.buffer_count = 1; + list_init(&object->used_samples); + list_init(&object->free_samples); + InitializeCriticalSection(&object->cs); + + hr = IMFVideoSampleAllocatorEx_QueryInterface(&object->IMFVideoSampleAllocatorEx_iface, riid, obj); + IMFVideoSampleAllocatorEx_Release(&object->IMFVideoSampleAllocatorEx_iface); + + return hr; +} diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index d4a461a2df8..2e2610a3827 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6302,7 +6302,7 @@ static void test_sample_allocator(void)
if (!pMFCreateVideoSampleAllocatorEx) { - skip("MFCreateVideoSampleAllocatorEx() is not available.\n"); + win_skip("MFCreateVideoSampleAllocatorEx() is not available.\n"); return; }
@@ -6392,6 +6392,7 @@ static void test_sample_allocator(void)
hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine ok(!count, "Unexpected count %d.\n", count);
check_interface(sample, &IID_IMFTrackedSample, TRUE); @@ -6500,9 +6501,11 @@ static void test_sample_allocator(void) IMFDXGIBuffer_Release(dxgi_buffer);
hr = IMFMediaBuffer_Lock(buffer, &data, NULL, NULL); +todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMFMediaBuffer_Unlock(buffer); +todo_wine ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
IMFSample_Release(sample);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84994
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/tests/Makefile.in | 2 +- dlls/mfplat/tests/mfplat.c | 81 +++++++++++++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 5 deletions(-)
diff --git a/dlls/mfplat/tests/Makefile.in b/dlls/mfplat/tests/Makefile.in index 4e9413e8da0..ae9cc378933 100644 --- a/dlls/mfplat/tests/Makefile.in +++ b/dlls/mfplat/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = mfplat.dll -IMPORTS = ole32 mfplat user32 d3d9 mfuuid propsys uuid strmiids +IMPORTS = ole32 mfplat user32 d3d9 dxva2 mfuuid propsys uuid strmiids
C_SRCS = \ mfplat.c diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 2e2610a3827..3d6e553ce35 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -46,6 +46,7 @@ #include "d3d9types.h" #include "ks.h" #include "ksmedia.h" +#include "dxva2api.h"
DEFINE_GUID(DUMMY_CLSID, 0x12345678,0x1234,0x1234,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19); DEFINE_GUID(DUMMY_GUID1, 0x12345678,0x1234,0x1234,0x21,0x21,0x21,0x21,0x21,0x21,0x21,0x21); @@ -6290,15 +6291,20 @@ static void test_sample_allocator(void) IMFDXGIDeviceManager *manager; IMFSample *sample, *sample2; IMFDXGIBuffer *dxgi_buffer; + IMFAttributes *attributes; D3D11_TEXTURE2D_DESC desc; + unsigned int buffer_count, token; ID3D11Texture2D *texture; IMFMediaBuffer *buffer; ID3D11Device *device; LONG refcount, count; - unsigned int token; IUnknown *unk; HRESULT hr; BYTE *data; + IDirect3D9 *d3d9; + HWND window; + IDirect3DDeviceManager9 *d3d9_manager; + IDirect3DDevice9 *d3d9_device;
if (!pMFCreateVideoSampleAllocatorEx) { @@ -6407,12 +6413,20 @@ todo_wine check_interface(buffer, &IID_IMFDXGIBuffer, FALSE);
IMFMediaBuffer_Release(buffer); + + hr = IMFSample_GetBufferCount(sample, &buffer_count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(buffer_count == 1, "Unexpected buffer count %u.\n", buffer_count); + IMFSample_Release(sample);
IMFVideoSampleAllocatorCallback_Release(allocator_cb); IMFVideoSampleAllocator_Release(allocator);
/* IMFVideoSampleAllocatorEx */ + hr = MFCreateAttributes(&attributes, 0); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = pMFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocatorEx, (void **)&allocatorex); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
@@ -6422,9 +6436,15 @@ todo_wine hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocatorex, 1, 0, NULL, video_type); ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr);
- hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocatorex, 0, 0, NULL, video_type); + hr = IMFAttributes_SetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, 2); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ EXPECT_REF(attributes, 1); + hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocatorex, 0, 0, attributes, video_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine + EXPECT_REF(attributes, 2); + count = 0; hr = IMFVideoSampleAllocatorCallback_GetFreeSampleCount(allocator_cb, &count); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); @@ -6433,6 +6453,11 @@ todo_wine hr = IMFVideoSampleAllocatorEx_AllocateSample(allocatorex, &sample); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ hr = IMFSample_GetBufferCount(sample, &buffer_count); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); +todo_wine + ok(buffer_count == 2, "Unexpected buffer count %u.\n", buffer_count); + hr = IMFVideoSampleAllocatorEx_AllocateSample(allocatorex, &sample2); ok(hr == MF_E_SAMPLEALLOCATOR_EMPTY, "Unexpected hr %#x.\n", hr);
@@ -6440,6 +6465,7 @@ todo_wine
IMFVideoSampleAllocatorCallback_Release(allocator_cb); IMFVideoSampleAllocatorEx_Release(allocatorex); + IMFAttributes_Release(attributes);
/* Using device manager */ if (!(device = create_d3d11_device())) @@ -6511,10 +6537,57 @@ todo_wine IMFSample_Release(sample);
IMFVideoSampleAllocator_Release(allocator); - - IMFMediaType_Release(media_type); IMFDXGIDeviceManager_Release(manager); ID3D11Device_Release(device); + + /* Use D3D9 device manager. */ + window = create_window(); + d3d9 = Direct3DCreate9(D3D_SDK_VERSION); + ok(!!d3d9, "Failed to create a D3D9 object.\n"); + if (!(d3d9_device = create_device(d3d9, window))) + { + skip("Failed to create a D3D9 device, skipping tests.\n"); + goto done; + } + + hr = DXVA2CreateDirect3DDeviceManager9(&token, &d3d9_manager); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IDirect3DDeviceManager9_ResetDevice(d3d9_manager, d3d9_device, token); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = pMFCreateVideoSampleAllocatorEx(&IID_IMFVideoSampleAllocator, (void **)&allocator); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_SetDirectXManager(allocator, (IUnknown *)d3d9_manager); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_InitializeSampleAllocator(allocator, 1, video_type); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = IMFVideoSampleAllocator_AllocateSample(allocator, &sample); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + check_interface(sample, &IID_IMFTrackedSample, TRUE); + check_interface(sample, &IID_IMFDesiredSample, FALSE); + + hr = IMFSample_GetBufferByIndex(sample, 0, &buffer); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + check_interface(buffer, &IID_IMF2DBuffer, TRUE); + check_interface(buffer, &IID_IMF2DBuffer2, TRUE); + check_interface(buffer, &IID_IMFGetService, TRUE); + check_interface(buffer, &IID_IMFDXGIBuffer, FALSE); + + IMFSample_Release(sample); + IMFMediaBuffer_Release(buffer); + + IMFVideoSampleAllocator_Release(allocator); + IMFMediaType_Release(media_type); + +done: + IDirect3D9_Release(d3d9); + DestroyWindow(window); }
START_TEST(mfplat)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84995
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/sample.c | 9 ++++++++- dlls/mfplat/tests/mfplat.c | 1 - 2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 266bb6f0726..8a0281abf6c 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -75,6 +75,8 @@ struct sample_allocator unsigned int buffer_count; } frame_desc;
+ IMFAttributes *attributes; + unsigned int free_sample_count; unsigned int cold_sample_count; struct list free_samples; @@ -1129,6 +1131,8 @@ static ULONG WINAPI sample_allocator_Release(IMFVideoSampleAllocatorEx *iface) IDirect3DDeviceManager9_Release(allocator->d3d9_device_manager); if (allocator->dxgi_device_manager) IMFDXGIDeviceManager_Release(allocator->dxgi_device_manager); + if (allocator->attributes) + IMFAttributes_Release(allocator->attributes); sample_allocator_release_samples(allocator); DeleteCriticalSection(&allocator->cs); heap_free(allocator); @@ -1348,7 +1352,10 @@ static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, u max_sample_count = max(1, max_sample_count);
if (attributes) - FIXME("Initialization attributes ignored.\n"); + { + allocator->attributes = attributes; + IMFAttributes_AddRef(allocator->attributes); + }
allocator->frame_desc.d3d9_format = subtype.Data1; allocator->frame_desc.dxgi_format = MFMapDX9FormatToDXGIFormat(allocator->frame_desc.d3d9_format); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index 3d6e553ce35..ed862ab9bdb 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6442,7 +6442,6 @@ todo_wine EXPECT_REF(attributes, 1); hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocatorex, 0, 0, attributes, video_type); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); -todo_wine EXPECT_REF(attributes, 2);
count = 0;
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84996
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/mfplat/sample.c | 4 +++- dlls/mfplat/tests/mfplat.c | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-)
diff --git a/dlls/mfplat/sample.c b/dlls/mfplat/sample.c index 8a0281abf6c..acdc8836cc8 100644 --- a/dlls/mfplat/sample.c +++ b/dlls/mfplat/sample.c @@ -1355,12 +1355,15 @@ static HRESULT sample_allocator_initialize(struct sample_allocator *allocator, u { allocator->attributes = attributes; IMFAttributes_AddRef(allocator->attributes); + + IMFAttributes_GetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, &allocator->frame_desc.buffer_count); }
allocator->frame_desc.d3d9_format = subtype.Data1; allocator->frame_desc.dxgi_format = MFMapDX9FormatToDXGIFormat(allocator->frame_desc.d3d9_format); allocator->frame_desc.width = frame_size >> 32; allocator->frame_desc.height = frame_size; + allocator->frame_desc.buffer_count = max(1, allocator->frame_desc.buffer_count);
if (FAILED(hr = sample_allocator_get_surface_service(allocator, &service))) return hr; @@ -1673,7 +1676,6 @@ HRESULT WINAPI MFCreateVideoSampleAllocatorEx(REFIID riid, void **obj) object->IMFVideoSampleAllocatorCallback_iface.lpVtbl = &sample_allocator_callback_vtbl; object->tracking_callback.lpVtbl = &sample_allocator_tracking_callback_vtbl; object->refcount = 1; - object->frame_desc.buffer_count = 1; list_init(&object->used_samples); list_init(&object->free_samples); InitializeCriticalSection(&object->cs); diff --git a/dlls/mfplat/tests/mfplat.c b/dlls/mfplat/tests/mfplat.c index ed862ab9bdb..deb9e78efba 100644 --- a/dlls/mfplat/tests/mfplat.c +++ b/dlls/mfplat/tests/mfplat.c @@ -6439,6 +6439,9 @@ todo_wine hr = IMFAttributes_SetUINT32(attributes, &MF_SA_BUFFERS_PER_SAMPLE, 2); ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
+ hr = IMFVideoSampleAllocatorEx_AllocateSample(allocatorex, &sample); + ok(hr == MF_E_NOT_INITIALIZED, "Unexpected hr %#x.\n", hr); + EXPECT_REF(attributes, 1); hr = IMFVideoSampleAllocatorEx_InitializeSampleAllocatorEx(allocatorex, 0, 0, attributes, video_type); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); @@ -6454,7 +6457,6 @@ todo_wine
hr = IMFSample_GetBufferCount(sample, &buffer_count); ok(hr == S_OK, "Unexpected hr %#x.\n", hr); -todo_wine ok(buffer_count == 2, "Unexpected buffer count %u.\n", buffer_count);
hr = IMFVideoSampleAllocatorEx_AllocateSample(allocatorex, &sample2);
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=84997
Your paranoid android.
=== wvistau64 (64 bit report) ===
mfplat: mfplat: Timeout