include: Be consistent in naming regarding MSF's block.
[wine.git] / dlls / mfplat / buffer.c
blobe3d38438b8800d6edcbf27e1e97b6dc8103ad3b9
1 /*
2 * Copyright 2018 Alistair Leslie-Hughes
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include <malloc.h>
23 #include "mfplat_private.h"
24 #include "rtworkq.h"
26 #include "d3d11.h"
27 #include "initguid.h"
28 #include "d3d9.h"
29 #include "evr.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
33 #define ALIGN_SIZE(size, alignment) (((size) + (alignment)) & ~((alignment)))
35 typedef void (*p_copy_image_func)(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines);
37 struct buffer
39 IMFMediaBuffer IMFMediaBuffer_iface;
40 IMF2DBuffer2 IMF2DBuffer2_iface;
41 IMFDXGIBuffer IMFDXGIBuffer_iface;
42 IMFGetService IMFGetService_iface;
43 LONG refcount;
45 BYTE *data;
46 DWORD max_length;
47 DWORD current_length;
49 struct
51 BYTE *linear_buffer;
52 DWORD plane_size;
54 BYTE *scanline0;
55 unsigned int width;
56 unsigned int height;
57 int pitch;
58 unsigned int locks;
59 p_copy_image_func copy_image;
60 } _2d;
61 struct
63 IDirect3DSurface9 *surface;
64 D3DLOCKED_RECT rect;
65 } d3d9_surface;
66 struct
68 ID3D11Texture2D *texture;
69 unsigned int sub_resource_idx;
70 ID3D11Texture2D *rb_texture;
71 D3D11_MAPPED_SUBRESOURCE map_desc;
72 struct attributes attributes;
73 } dxgi_surface;
75 CRITICAL_SECTION cs;
78 static void copy_image(const struct buffer *buffer, BYTE *dest, LONG dest_stride, const BYTE *src,
79 LONG src_stride, DWORD width, DWORD lines)
81 MFCopyImage(dest, dest_stride, src, src_stride, width, lines);
83 if (buffer->_2d.copy_image)
85 dest += dest_stride * lines;
86 src += src_stride * lines;
87 buffer->_2d.copy_image(dest, dest_stride, src, src_stride, width, lines);
91 static void copy_image_nv12(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines)
93 MFCopyImage(dest, dest_stride, src, src_stride, width, lines / 2);
96 static void copy_image_imc1(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines)
98 MFCopyImage(dest, dest_stride, src, src_stride, width / 2, lines);
101 static void copy_image_imc2(BYTE *dest, LONG dest_stride, const BYTE *src, LONG src_stride, DWORD width, DWORD lines)
103 MFCopyImage(dest, dest_stride / 2, src, src_stride / 2, width / 2, lines);
106 static inline struct buffer *impl_from_IMFMediaBuffer(IMFMediaBuffer *iface)
108 return CONTAINING_RECORD(iface, struct buffer, IMFMediaBuffer_iface);
111 static struct buffer *impl_from_IMF2DBuffer2(IMF2DBuffer2 *iface)
113 return CONTAINING_RECORD(iface, struct buffer, IMF2DBuffer2_iface);
116 static struct buffer *impl_from_IMFGetService(IMFGetService *iface)
118 return CONTAINING_RECORD(iface, struct buffer, IMFGetService_iface);
121 static struct buffer *impl_from_IMFDXGIBuffer(IMFDXGIBuffer *iface)
123 return CONTAINING_RECORD(iface, struct buffer, IMFDXGIBuffer_iface);
126 static HRESULT WINAPI memory_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out)
128 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
130 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
132 if (IsEqualIID(riid, &IID_IMFMediaBuffer) ||
133 IsEqualIID(riid, &IID_IUnknown))
135 *out = &buffer->IMFMediaBuffer_iface;
136 IMFMediaBuffer_AddRef(iface);
137 return S_OK;
140 WARN("Unsupported %s.\n", debugstr_guid(riid));
141 *out = NULL;
142 return E_NOINTERFACE;
145 static ULONG WINAPI memory_buffer_AddRef(IMFMediaBuffer *iface)
147 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
148 ULONG refcount = InterlockedIncrement(&buffer->refcount);
150 TRACE("%p, refcount %lu.\n", buffer, refcount);
152 return refcount;
155 static ULONG WINAPI memory_buffer_Release(IMFMediaBuffer *iface)
157 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
158 ULONG refcount = InterlockedDecrement(&buffer->refcount);
160 TRACE("%p, refcount %lu.\n", iface, refcount);
162 if (!refcount)
164 if (buffer->d3d9_surface.surface)
165 IDirect3DSurface9_Release(buffer->d3d9_surface.surface);
166 if (buffer->dxgi_surface.texture)
168 ID3D11Texture2D_Release(buffer->dxgi_surface.texture);
169 if (buffer->dxgi_surface.rb_texture)
170 ID3D11Texture2D_Release(buffer->dxgi_surface.rb_texture);
171 clear_attributes_object(&buffer->dxgi_surface.attributes);
173 DeleteCriticalSection(&buffer->cs);
174 free(buffer->_2d.linear_buffer);
175 _aligned_free(buffer->data);
176 free(buffer);
179 return refcount;
182 static HRESULT WINAPI memory_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length)
184 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
186 TRACE("%p, %p %p, %p.\n", iface, data, max_length, current_length);
188 if (!data)
189 return E_INVALIDARG;
191 *data = buffer->data;
192 if (max_length)
193 *max_length = buffer->max_length;
194 if (current_length)
195 *current_length = buffer->current_length;
197 return S_OK;
200 static HRESULT WINAPI memory_buffer_Unlock(IMFMediaBuffer *iface)
202 TRACE("%p.\n", iface);
204 return S_OK;
207 static HRESULT WINAPI memory_buffer_GetCurrentLength(IMFMediaBuffer *iface, DWORD *current_length)
209 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
211 TRACE("%p.\n", iface);
213 if (!current_length)
214 return E_INVALIDARG;
216 *current_length = buffer->current_length;
218 return S_OK;
221 static HRESULT WINAPI memory_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD current_length)
223 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
225 TRACE("%p, %lu.\n", iface, current_length);
227 if (current_length > buffer->max_length)
228 return E_INVALIDARG;
230 buffer->current_length = current_length;
232 return S_OK;
235 static HRESULT WINAPI memory_buffer_GetMaxLength(IMFMediaBuffer *iface, DWORD *max_length)
237 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
239 TRACE("%p, %p.\n", iface, max_length);
241 if (!max_length)
242 return E_INVALIDARG;
244 *max_length = buffer->max_length;
246 return S_OK;
249 static const IMFMediaBufferVtbl memory_1d_buffer_vtbl =
251 memory_buffer_QueryInterface,
252 memory_buffer_AddRef,
253 memory_buffer_Release,
254 memory_buffer_Lock,
255 memory_buffer_Unlock,
256 memory_buffer_GetCurrentLength,
257 memory_buffer_SetCurrentLength,
258 memory_buffer_GetMaxLength,
261 static HRESULT WINAPI memory_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out)
263 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
265 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
267 if (IsEqualIID(riid, &IID_IMFMediaBuffer) ||
268 IsEqualIID(riid, &IID_IUnknown))
270 *out = &buffer->IMFMediaBuffer_iface;
272 else if (IsEqualIID(riid, &IID_IMF2DBuffer2) ||
273 IsEqualIID(riid, &IID_IMF2DBuffer))
275 *out = &buffer->IMF2DBuffer2_iface;
277 else if (IsEqualIID(riid, &IID_IMFGetService))
279 *out = &buffer->IMFGetService_iface;
281 else
283 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
284 *out = NULL;
285 return E_NOINTERFACE;
288 IUnknown_AddRef((IUnknown*)*out);
289 return S_OK;
292 static HRESULT WINAPI memory_1d_2d_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length)
294 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
295 HRESULT hr = S_OK;
297 TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length);
299 if (!data)
300 return E_POINTER;
302 /* Allocate linear buffer and return it as a copy of current content. Maximum and current length are
303 unrelated to 2D buffer maximum allocate length, or maintained current length. */
305 EnterCriticalSection(&buffer->cs);
307 if (!buffer->_2d.linear_buffer && buffer->_2d.locks)
308 hr = MF_E_INVALIDREQUEST;
309 else if (!buffer->_2d.linear_buffer)
311 if (!(buffer->_2d.linear_buffer = malloc(buffer->_2d.plane_size)))
312 hr = E_OUTOFMEMORY;
314 if (SUCCEEDED(hr))
315 copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->data, buffer->_2d.pitch,
316 buffer->_2d.width, buffer->_2d.height);
319 if (SUCCEEDED(hr))
321 ++buffer->_2d.locks;
322 *data = buffer->_2d.linear_buffer;
323 if (max_length)
324 *max_length = buffer->_2d.plane_size;
325 if (current_length)
326 *current_length = buffer->_2d.plane_size;
329 LeaveCriticalSection(&buffer->cs);
331 return hr;
334 static HRESULT WINAPI memory_1d_2d_buffer_Unlock(IMFMediaBuffer *iface)
336 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
338 TRACE("%p.\n", iface);
340 EnterCriticalSection(&buffer->cs);
342 if (buffer->_2d.linear_buffer && !--buffer->_2d.locks)
344 copy_image(buffer, buffer->data, buffer->_2d.pitch, buffer->_2d.linear_buffer, buffer->_2d.width,
345 buffer->_2d.width, buffer->_2d.height);
347 free(buffer->_2d.linear_buffer);
348 buffer->_2d.linear_buffer = NULL;
351 LeaveCriticalSection(&buffer->cs);
353 return S_OK;
356 static const IMFMediaBufferVtbl memory_1d_2d_buffer_vtbl =
358 memory_1d_2d_buffer_QueryInterface,
359 memory_buffer_AddRef,
360 memory_buffer_Release,
361 memory_1d_2d_buffer_Lock,
362 memory_1d_2d_buffer_Unlock,
363 memory_buffer_GetCurrentLength,
364 memory_buffer_SetCurrentLength,
365 memory_buffer_GetMaxLength,
368 static HRESULT WINAPI d3d9_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length, DWORD *current_length)
370 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
371 HRESULT hr = S_OK;
373 TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length);
375 if (!data)
376 return E_POINTER;
378 EnterCriticalSection(&buffer->cs);
380 if (!buffer->_2d.linear_buffer && buffer->_2d.locks)
381 hr = MF_E_INVALIDREQUEST;
382 else if (!buffer->_2d.linear_buffer)
384 D3DLOCKED_RECT rect;
386 if (!(buffer->_2d.linear_buffer = malloc(buffer->_2d.plane_size)))
387 hr = E_OUTOFMEMORY;
389 if (SUCCEEDED(hr))
391 hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0);
392 if (SUCCEEDED(hr))
394 copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, rect.pBits, rect.Pitch,
395 buffer->_2d.width, buffer->_2d.height);
396 IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
401 if (SUCCEEDED(hr))
403 ++buffer->_2d.locks;
404 *data = buffer->_2d.linear_buffer;
405 if (max_length)
406 *max_length = buffer->_2d.plane_size;
407 if (current_length)
408 *current_length = buffer->_2d.plane_size;
411 LeaveCriticalSection(&buffer->cs);
413 return hr;
416 static HRESULT WINAPI d3d9_surface_buffer_Unlock(IMFMediaBuffer *iface)
418 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
419 HRESULT hr = S_OK;
421 TRACE("%p.\n", iface);
423 EnterCriticalSection(&buffer->cs);
425 if (!buffer->_2d.linear_buffer)
426 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
427 else if (!--buffer->_2d.locks)
429 D3DLOCKED_RECT rect;
431 if (SUCCEEDED(hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &rect, NULL, 0)))
433 copy_image(buffer, rect.pBits, rect.Pitch, buffer->_2d.linear_buffer, buffer->_2d.width,
434 buffer->_2d.width, buffer->_2d.height);
435 IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
438 free(buffer->_2d.linear_buffer);
439 buffer->_2d.linear_buffer = NULL;
442 LeaveCriticalSection(&buffer->cs);
444 return hr;
447 static HRESULT WINAPI d3d9_surface_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD current_length)
449 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
451 TRACE("%p, %lu.\n", iface, current_length);
453 buffer->current_length = current_length;
455 return S_OK;
458 static const IMFMediaBufferVtbl d3d9_surface_1d_buffer_vtbl =
460 memory_1d_2d_buffer_QueryInterface,
461 memory_buffer_AddRef,
462 memory_buffer_Release,
463 d3d9_surface_buffer_Lock,
464 d3d9_surface_buffer_Unlock,
465 memory_buffer_GetCurrentLength,
466 d3d9_surface_buffer_SetCurrentLength,
467 memory_buffer_GetMaxLength,
470 static HRESULT WINAPI memory_2d_buffer_QueryInterface(IMF2DBuffer2 *iface, REFIID riid, void **obj)
472 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
473 return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
476 static ULONG WINAPI memory_2d_buffer_AddRef(IMF2DBuffer2 *iface)
478 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
479 return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
482 static ULONG WINAPI memory_2d_buffer_Release(IMF2DBuffer2 *iface)
484 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
485 return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
488 static HRESULT memory_2d_buffer_lock(struct buffer *buffer, BYTE **scanline0, LONG *pitch,
489 BYTE **buffer_start, DWORD *buffer_length)
491 HRESULT hr = S_OK;
493 if (buffer->_2d.linear_buffer)
494 hr = MF_E_UNEXPECTED;
495 else
497 ++buffer->_2d.locks;
498 *scanline0 = buffer->_2d.scanline0;
499 *pitch = buffer->_2d.pitch;
500 if (buffer_start)
501 *buffer_start = buffer->data;
502 if (buffer_length)
503 *buffer_length = buffer->max_length;
506 return hr;
509 static HRESULT WINAPI memory_2d_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
511 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
512 HRESULT hr;
514 TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
516 if (!scanline0 || !pitch)
517 return E_POINTER;
519 EnterCriticalSection(&buffer->cs);
521 hr = memory_2d_buffer_lock(buffer, scanline0, pitch, NULL, NULL);
523 LeaveCriticalSection(&buffer->cs);
525 return hr;
528 static HRESULT WINAPI memory_2d_buffer_Unlock2D(IMF2DBuffer2 *iface)
530 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
531 HRESULT hr = S_OK;
533 TRACE("%p.\n", iface);
535 EnterCriticalSection(&buffer->cs);
537 if (!buffer->_2d.linear_buffer)
539 if (buffer->_2d.locks)
540 --buffer->_2d.locks;
541 else
542 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
545 LeaveCriticalSection(&buffer->cs);
547 return hr;
550 static HRESULT WINAPI memory_2d_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
552 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
553 HRESULT hr = S_OK;
555 TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
557 if (!scanline0 || !pitch)
558 return E_POINTER;
560 EnterCriticalSection(&buffer->cs);
562 if (buffer->_2d.linear_buffer || !buffer->_2d.locks)
563 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
564 else
566 *scanline0 = buffer->_2d.scanline0;
567 *pitch = buffer->_2d.pitch;
570 LeaveCriticalSection(&buffer->cs);
572 return hr;
575 static HRESULT WINAPI memory_2d_buffer_IsContiguousFormat(IMF2DBuffer2 *iface, BOOL *is_contiguous)
577 TRACE("%p, %p.\n", iface, is_contiguous);
579 if (!is_contiguous)
580 return E_POINTER;
582 *is_contiguous = FALSE;
584 return S_OK;
587 static HRESULT WINAPI memory_2d_buffer_GetContiguousLength(IMF2DBuffer2 *iface, DWORD *length)
589 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
591 TRACE("%p, %p.\n", iface, length);
593 if (!length)
594 return E_POINTER;
596 *length = buffer->_2d.plane_size;
598 return S_OK;
601 static HRESULT WINAPI memory_2d_buffer_ContiguousCopyTo(IMF2DBuffer2 *iface, BYTE *dest_buffer, DWORD dest_length)
603 FIXME("%p, %p, %lu.\n", iface, dest_buffer, dest_length);
605 return E_NOTIMPL;
608 static HRESULT WINAPI memory_2d_buffer_ContiguousCopyFrom(IMF2DBuffer2 *iface, const BYTE *src_buffer, DWORD src_length)
610 FIXME("%p, %p, %lu.\n", iface, src_buffer, src_length);
612 return E_NOTIMPL;
615 static HRESULT WINAPI memory_2d_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0,
616 LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
618 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
619 HRESULT hr;
621 TRACE("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length);
623 if (!scanline0 || !pitch || !buffer_start || !buffer_length)
624 return E_POINTER;
626 EnterCriticalSection(&buffer->cs);
628 hr = memory_2d_buffer_lock(buffer, scanline0, pitch, buffer_start, buffer_length);
630 LeaveCriticalSection(&buffer->cs);
632 return hr;
635 static HRESULT WINAPI memory_2d_buffer_Copy2DTo(IMF2DBuffer2 *iface, IMF2DBuffer2 *dest_buffer)
637 FIXME("%p, %p.\n", iface, dest_buffer);
639 return E_NOTIMPL;
642 static const IMF2DBuffer2Vtbl memory_2d_buffer_vtbl =
644 memory_2d_buffer_QueryInterface,
645 memory_2d_buffer_AddRef,
646 memory_2d_buffer_Release,
647 memory_2d_buffer_Lock2D,
648 memory_2d_buffer_Unlock2D,
649 memory_2d_buffer_GetScanline0AndPitch,
650 memory_2d_buffer_IsContiguousFormat,
651 memory_2d_buffer_GetContiguousLength,
652 memory_2d_buffer_ContiguousCopyTo,
653 memory_2d_buffer_ContiguousCopyFrom,
654 memory_2d_buffer_Lock2DSize,
655 memory_2d_buffer_Copy2DTo,
658 static HRESULT d3d9_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFlags flags, BYTE **scanline0,
659 LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
661 HRESULT hr = S_OK;
663 if (buffer->_2d.linear_buffer)
664 hr = MF_E_UNEXPECTED;
665 else if (!buffer->_2d.locks)
667 hr = IDirect3DSurface9_LockRect(buffer->d3d9_surface.surface, &buffer->d3d9_surface.rect, NULL, 0);
670 if (SUCCEEDED(hr))
672 buffer->_2d.locks++;
673 *scanline0 = buffer->d3d9_surface.rect.pBits;
674 *pitch = buffer->d3d9_surface.rect.Pitch;
675 if (buffer_start)
676 *buffer_start = *scanline0;
677 if (buffer_length)
678 *buffer_length = buffer->d3d9_surface.rect.Pitch * buffer->_2d.height;
681 return hr;
684 static HRESULT WINAPI d3d9_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
686 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
687 HRESULT hr;
689 TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
691 if (!scanline0 || !pitch)
692 return E_POINTER;
694 EnterCriticalSection(&buffer->cs);
696 hr = d3d9_surface_buffer_lock(buffer, MF2DBuffer_LockFlags_ReadWrite, scanline0, pitch, NULL, NULL);
698 LeaveCriticalSection(&buffer->cs);
700 return hr;
703 static HRESULT WINAPI d3d9_surface_buffer_Unlock2D(IMF2DBuffer2 *iface)
705 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
706 HRESULT hr = S_OK;
708 TRACE("%p.\n", iface);
710 EnterCriticalSection(&buffer->cs);
712 if (buffer->_2d.locks)
714 if (!--buffer->_2d.locks)
716 IDirect3DSurface9_UnlockRect(buffer->d3d9_surface.surface);
717 memset(&buffer->d3d9_surface.rect, 0, sizeof(buffer->d3d9_surface.rect));
720 else
721 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
723 LeaveCriticalSection(&buffer->cs);
725 return hr;
728 static HRESULT WINAPI d3d9_surface_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
730 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
731 HRESULT hr = S_OK;
733 TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
735 if (!scanline0 || !pitch)
736 return E_POINTER;
738 EnterCriticalSection(&buffer->cs);
740 if (!buffer->_2d.locks)
742 *scanline0 = NULL;
743 *pitch = 0;
744 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
746 else
748 *scanline0 = buffer->d3d9_surface.rect.pBits;
749 *pitch = buffer->d3d9_surface.rect.Pitch;
752 LeaveCriticalSection(&buffer->cs);
754 return hr;
757 static HRESULT WINAPI d3d9_surface_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags, BYTE **scanline0,
758 LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
760 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
761 HRESULT hr;
763 TRACE("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length);
765 if (!scanline0 || !pitch || !buffer_start || !buffer_length)
766 return E_POINTER;
768 EnterCriticalSection(&buffer->cs);
770 hr = d3d9_surface_buffer_lock(buffer, flags, scanline0, pitch, buffer_start, buffer_length);
772 LeaveCriticalSection(&buffer->cs);
774 return hr;
777 static const IMF2DBuffer2Vtbl d3d9_surface_buffer_vtbl =
779 memory_2d_buffer_QueryInterface,
780 memory_2d_buffer_AddRef,
781 memory_2d_buffer_Release,
782 d3d9_surface_buffer_Lock2D,
783 d3d9_surface_buffer_Unlock2D,
784 d3d9_surface_buffer_GetScanline0AndPitch,
785 memory_2d_buffer_IsContiguousFormat,
786 memory_2d_buffer_GetContiguousLength,
787 memory_2d_buffer_ContiguousCopyTo,
788 memory_2d_buffer_ContiguousCopyFrom,
789 d3d9_surface_buffer_Lock2DSize,
790 memory_2d_buffer_Copy2DTo,
793 static HRESULT WINAPI memory_2d_buffer_gs_QueryInterface(IMFGetService *iface, REFIID riid, void **obj)
795 struct buffer *buffer = impl_from_IMFGetService(iface);
796 return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
799 static ULONG WINAPI memory_2d_buffer_gs_AddRef(IMFGetService *iface)
801 struct buffer *buffer = impl_from_IMFGetService(iface);
802 return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
805 static ULONG WINAPI memory_2d_buffer_gs_Release(IMFGetService *iface)
807 struct buffer *buffer = impl_from_IMFGetService(iface);
808 return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
811 static HRESULT WINAPI memory_2d_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
813 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
815 return E_NOTIMPL;
818 static const IMFGetServiceVtbl memory_2d_buffer_gs_vtbl =
820 memory_2d_buffer_gs_QueryInterface,
821 memory_2d_buffer_gs_AddRef,
822 memory_2d_buffer_gs_Release,
823 memory_2d_buffer_gs_GetService,
826 static HRESULT WINAPI d3d9_surface_buffer_gs_GetService(IMFGetService *iface, REFGUID service, REFIID riid, void **obj)
828 struct buffer *buffer = impl_from_IMFGetService(iface);
830 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(service), debugstr_guid(riid), obj);
832 if (IsEqualGUID(service, &MR_BUFFER_SERVICE))
834 return IDirect3DSurface9_QueryInterface(buffer->d3d9_surface.surface, riid, obj);
837 return E_NOTIMPL;
840 static const IMFGetServiceVtbl d3d9_surface_buffer_gs_vtbl =
842 memory_2d_buffer_gs_QueryInterface,
843 memory_2d_buffer_gs_AddRef,
844 memory_2d_buffer_gs_Release,
845 d3d9_surface_buffer_gs_GetService,
848 static HRESULT WINAPI dxgi_1d_2d_buffer_QueryInterface(IMFMediaBuffer *iface, REFIID riid, void **out)
850 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
852 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), out);
854 if (IsEqualIID(riid, &IID_IMFMediaBuffer) ||
855 IsEqualIID(riid, &IID_IUnknown))
857 *out = &buffer->IMFMediaBuffer_iface;
859 else if (IsEqualIID(riid, &IID_IMF2DBuffer2) ||
860 IsEqualIID(riid, &IID_IMF2DBuffer))
862 *out = &buffer->IMF2DBuffer2_iface;
864 else if (IsEqualIID(riid, &IID_IMFDXGIBuffer))
866 *out = &buffer->IMFDXGIBuffer_iface;
868 else
870 WARN("Unsupported interface %s.\n", debugstr_guid(riid));
871 *out = NULL;
872 return E_NOINTERFACE;
875 IUnknown_AddRef((IUnknown*)*out);
876 return S_OK;
879 static HRESULT dxgi_surface_buffer_create_readback_texture(struct buffer *buffer)
881 D3D11_TEXTURE2D_DESC texture_desc;
882 ID3D11Device *device;
883 HRESULT hr;
885 if (buffer->dxgi_surface.rb_texture)
886 return S_OK;
888 ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device);
890 ID3D11Texture2D_GetDesc(buffer->dxgi_surface.texture, &texture_desc);
891 texture_desc.Usage = D3D11_USAGE_STAGING;
892 texture_desc.BindFlags = 0;
893 texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
894 texture_desc.MiscFlags = 0;
895 texture_desc.MipLevels = 1;
896 if (FAILED(hr = ID3D11Device_CreateTexture2D(device, &texture_desc, NULL, &buffer->dxgi_surface.rb_texture)))
897 WARN("Failed to create readback texture, hr %#lx.\n", hr);
899 ID3D11Device_Release(device);
901 return hr;
904 static HRESULT dxgi_surface_buffer_map(struct buffer *buffer)
906 ID3D11DeviceContext *immediate_context;
907 ID3D11Device *device;
908 HRESULT hr;
910 if (FAILED(hr = dxgi_surface_buffer_create_readback_texture(buffer)))
911 return hr;
913 ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device);
914 ID3D11Device_GetImmediateContext(device, &immediate_context);
915 ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture,
916 0, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.texture, buffer->dxgi_surface.sub_resource_idx, NULL);
918 memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc));
919 if (FAILED(hr = ID3D11DeviceContext_Map(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture,
920 0, D3D11_MAP_READ_WRITE, 0, &buffer->dxgi_surface.map_desc)))
922 WARN("Failed to map readback texture, hr %#lx.\n", hr);
925 ID3D11DeviceContext_Release(immediate_context);
926 ID3D11Device_Release(device);
928 return hr;
931 static void dxgi_surface_buffer_unmap(struct buffer *buffer)
933 ID3D11DeviceContext *immediate_context;
934 ID3D11Device *device;
936 ID3D11Texture2D_GetDevice(buffer->dxgi_surface.texture, &device);
937 ID3D11Device_GetImmediateContext(device, &immediate_context);
938 ID3D11DeviceContext_Unmap(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0);
939 memset(&buffer->dxgi_surface.map_desc, 0, sizeof(buffer->dxgi_surface.map_desc));
941 ID3D11DeviceContext_CopySubresourceRegion(immediate_context, (ID3D11Resource *)buffer->dxgi_surface.texture,
942 buffer->dxgi_surface.sub_resource_idx, 0, 0, 0, (ID3D11Resource *)buffer->dxgi_surface.rb_texture, 0, NULL);
944 ID3D11DeviceContext_Release(immediate_context);
945 ID3D11Device_Release(device);
948 static HRESULT WINAPI dxgi_surface_buffer_Lock(IMFMediaBuffer *iface, BYTE **data, DWORD *max_length,
949 DWORD *current_length)
951 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
952 HRESULT hr = S_OK;
954 TRACE("%p, %p, %p, %p.\n", iface, data, max_length, current_length);
956 if (!data)
957 return E_POINTER;
959 EnterCriticalSection(&buffer->cs);
961 if (!buffer->_2d.linear_buffer && buffer->_2d.locks)
962 hr = MF_E_INVALIDREQUEST;
963 else if (!buffer->_2d.linear_buffer)
965 if (!(buffer->_2d.linear_buffer = malloc(buffer->_2d.plane_size)))
966 hr = E_OUTOFMEMORY;
968 if (SUCCEEDED(hr))
970 hr = dxgi_surface_buffer_map(buffer);
971 if (SUCCEEDED(hr))
973 copy_image(buffer, buffer->_2d.linear_buffer, buffer->_2d.width, buffer->dxgi_surface.map_desc.pData,
974 buffer->dxgi_surface.map_desc.RowPitch, buffer->_2d.width, buffer->_2d.height);
979 if (SUCCEEDED(hr))
981 ++buffer->_2d.locks;
982 *data = buffer->_2d.linear_buffer;
983 if (max_length)
984 *max_length = buffer->_2d.plane_size;
985 if (current_length)
986 *current_length = buffer->_2d.plane_size;
989 LeaveCriticalSection(&buffer->cs);
991 return hr;
994 static HRESULT WINAPI dxgi_surface_buffer_Unlock(IMFMediaBuffer *iface)
996 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
997 HRESULT hr = S_OK;
999 TRACE("%p.\n", iface);
1001 EnterCriticalSection(&buffer->cs);
1003 if (!buffer->_2d.linear_buffer)
1004 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
1005 else if (!--buffer->_2d.locks)
1007 copy_image(buffer, buffer->dxgi_surface.map_desc.pData, buffer->dxgi_surface.map_desc.RowPitch,
1008 buffer->_2d.linear_buffer, buffer->_2d.width, buffer->_2d.width, buffer->_2d.height);
1009 dxgi_surface_buffer_unmap(buffer);
1011 free(buffer->_2d.linear_buffer);
1012 buffer->_2d.linear_buffer = NULL;
1015 LeaveCriticalSection(&buffer->cs);
1017 return hr;
1020 static HRESULT WINAPI dxgi_surface_buffer_SetCurrentLength(IMFMediaBuffer *iface, DWORD current_length)
1022 struct buffer *buffer = impl_from_IMFMediaBuffer(iface);
1024 TRACE("%p, %lu.\n", iface, current_length);
1026 buffer->current_length = current_length;
1028 return S_OK;
1031 static HRESULT dxgi_surface_buffer_lock(struct buffer *buffer, MF2DBuffer_LockFlags flags,
1032 BYTE **scanline0, LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
1034 HRESULT hr = S_OK;
1036 if (buffer->_2d.linear_buffer)
1037 hr = MF_E_UNEXPECTED;
1038 else if (!buffer->_2d.locks++)
1039 hr = dxgi_surface_buffer_map(buffer);
1041 if (SUCCEEDED(hr))
1043 *scanline0 = buffer->dxgi_surface.map_desc.pData;
1044 *pitch = buffer->dxgi_surface.map_desc.RowPitch;
1045 if (buffer_start)
1046 *buffer_start = *scanline0;
1047 if (buffer_length)
1048 *buffer_length = buffer->dxgi_surface.map_desc.RowPitch * buffer->_2d.height;
1051 return hr;
1054 static HRESULT WINAPI dxgi_surface_buffer_Lock2D(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
1056 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
1057 HRESULT hr;
1059 TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
1061 if (!scanline0 || !pitch)
1062 return E_POINTER;
1064 EnterCriticalSection(&buffer->cs);
1066 hr = dxgi_surface_buffer_lock(buffer, MF2DBuffer_LockFlags_ReadWrite, scanline0, pitch, NULL, NULL);
1068 LeaveCriticalSection(&buffer->cs);
1070 return hr;
1073 static HRESULT WINAPI dxgi_surface_buffer_Unlock2D(IMF2DBuffer2 *iface)
1075 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
1076 HRESULT hr = S_OK;
1078 TRACE("%p.\n", iface);
1080 EnterCriticalSection(&buffer->cs);
1082 if (buffer->_2d.locks)
1084 if (!--buffer->_2d.locks)
1085 dxgi_surface_buffer_unmap(buffer);
1087 else
1088 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
1090 LeaveCriticalSection(&buffer->cs);
1092 return hr;
1095 static HRESULT WINAPI dxgi_surface_buffer_GetScanline0AndPitch(IMF2DBuffer2 *iface, BYTE **scanline0, LONG *pitch)
1097 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
1098 HRESULT hr = S_OK;
1100 TRACE("%p, %p, %p.\n", iface, scanline0, pitch);
1102 if (!scanline0 || !pitch)
1103 return E_POINTER;
1105 EnterCriticalSection(&buffer->cs);
1107 if (!buffer->_2d.locks)
1109 *scanline0 = NULL;
1110 *pitch = 0;
1111 hr = HRESULT_FROM_WIN32(ERROR_WAS_UNLOCKED);
1113 else
1115 *scanline0 = buffer->dxgi_surface.map_desc.pData;
1116 *pitch = buffer->dxgi_surface.map_desc.RowPitch;
1119 LeaveCriticalSection(&buffer->cs);
1121 return hr;
1124 static HRESULT WINAPI dxgi_surface_buffer_Lock2DSize(IMF2DBuffer2 *iface, MF2DBuffer_LockFlags flags,
1125 BYTE **scanline0, LONG *pitch, BYTE **buffer_start, DWORD *buffer_length)
1127 struct buffer *buffer = impl_from_IMF2DBuffer2(iface);
1128 HRESULT hr;
1130 TRACE("%p, %#x, %p, %p, %p, %p.\n", iface, flags, scanline0, pitch, buffer_start, buffer_length);
1132 if (!scanline0 || !pitch || !buffer_start || !buffer_length)
1133 return E_POINTER;
1135 EnterCriticalSection(&buffer->cs);
1137 hr = dxgi_surface_buffer_lock(buffer, flags, scanline0, pitch, buffer_start, buffer_length);
1139 LeaveCriticalSection(&buffer->cs);
1141 return hr;
1144 static HRESULT WINAPI dxgi_buffer_QueryInterface(IMFDXGIBuffer *iface, REFIID riid, void **obj)
1146 struct buffer *buffer = impl_from_IMFDXGIBuffer(iface);
1147 return IMFMediaBuffer_QueryInterface(&buffer->IMFMediaBuffer_iface, riid, obj);
1150 static ULONG WINAPI dxgi_buffer_AddRef(IMFDXGIBuffer *iface)
1152 struct buffer *buffer = impl_from_IMFDXGIBuffer(iface);
1153 return IMFMediaBuffer_AddRef(&buffer->IMFMediaBuffer_iface);
1156 static ULONG WINAPI dxgi_buffer_Release(IMFDXGIBuffer *iface)
1158 struct buffer *buffer = impl_from_IMFDXGIBuffer(iface);
1159 return IMFMediaBuffer_Release(&buffer->IMFMediaBuffer_iface);
1162 static HRESULT WINAPI dxgi_buffer_GetResource(IMFDXGIBuffer *iface, REFIID riid, void **obj)
1164 struct buffer *buffer = impl_from_IMFDXGIBuffer(iface);
1166 TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
1168 return ID3D11Texture2D_QueryInterface(buffer->dxgi_surface.texture, riid, obj);
1171 static HRESULT WINAPI dxgi_buffer_GetSubresourceIndex(IMFDXGIBuffer *iface, UINT *index)
1173 struct buffer *buffer = impl_from_IMFDXGIBuffer(iface);
1175 TRACE("%p, %p.\n", iface, index);
1177 if (!index)
1178 return E_POINTER;
1180 *index = buffer->dxgi_surface.sub_resource_idx;
1182 return S_OK;
1185 static HRESULT WINAPI dxgi_buffer_GetUnknown(IMFDXGIBuffer *iface, REFIID guid, REFIID riid, void **object)
1187 struct buffer *buffer = impl_from_IMFDXGIBuffer(iface);
1189 TRACE("%p, %s, %s, %p.\n", iface, debugstr_guid(guid), debugstr_guid(riid), object);
1191 if (attributes_GetUnknown(&buffer->dxgi_surface.attributes, guid, riid, object) == MF_E_ATTRIBUTENOTFOUND)
1192 return MF_E_NOT_FOUND;
1194 return S_OK;
1197 static HRESULT WINAPI dxgi_buffer_SetUnknown(IMFDXGIBuffer *iface, REFIID guid, IUnknown *data)
1199 struct buffer *buffer = impl_from_IMFDXGIBuffer(iface);
1200 HRESULT hr = S_OK;
1202 TRACE("%p, %s, %p.\n", iface, debugstr_guid(guid), data);
1204 EnterCriticalSection(&buffer->dxgi_surface.attributes.cs);
1205 if (data)
1207 if (SUCCEEDED(attributes_GetItem(&buffer->dxgi_surface.attributes, guid, NULL)))
1208 hr = HRESULT_FROM_WIN32(ERROR_OBJECT_ALREADY_EXISTS);
1209 else
1210 hr = attributes_SetUnknown(&buffer->dxgi_surface.attributes, guid, data);
1212 else
1214 attributes_DeleteItem(&buffer->dxgi_surface.attributes, guid);
1216 LeaveCriticalSection(&buffer->dxgi_surface.attributes.cs);
1218 return hr;
1221 static const IMFMediaBufferVtbl dxgi_surface_1d_buffer_vtbl =
1223 dxgi_1d_2d_buffer_QueryInterface,
1224 memory_buffer_AddRef,
1225 memory_buffer_Release,
1226 dxgi_surface_buffer_Lock,
1227 dxgi_surface_buffer_Unlock,
1228 memory_buffer_GetCurrentLength,
1229 dxgi_surface_buffer_SetCurrentLength,
1230 memory_buffer_GetMaxLength,
1233 static const IMF2DBuffer2Vtbl dxgi_surface_buffer_vtbl =
1235 memory_2d_buffer_QueryInterface,
1236 memory_2d_buffer_AddRef,
1237 memory_2d_buffer_Release,
1238 dxgi_surface_buffer_Lock2D,
1239 dxgi_surface_buffer_Unlock2D,
1240 dxgi_surface_buffer_GetScanline0AndPitch,
1241 memory_2d_buffer_IsContiguousFormat,
1242 memory_2d_buffer_GetContiguousLength,
1243 memory_2d_buffer_ContiguousCopyTo,
1244 memory_2d_buffer_ContiguousCopyFrom,
1245 dxgi_surface_buffer_Lock2DSize,
1246 memory_2d_buffer_Copy2DTo,
1249 static const IMFDXGIBufferVtbl dxgi_buffer_vtbl =
1251 dxgi_buffer_QueryInterface,
1252 dxgi_buffer_AddRef,
1253 dxgi_buffer_Release,
1254 dxgi_buffer_GetResource,
1255 dxgi_buffer_GetSubresourceIndex,
1256 dxgi_buffer_GetUnknown,
1257 dxgi_buffer_SetUnknown,
1260 static HRESULT memory_buffer_init(struct buffer *buffer, DWORD max_length, DWORD alignment,
1261 const IMFMediaBufferVtbl *vtbl)
1263 if (alignment < MF_16_BYTE_ALIGNMENT)
1264 alignment = MF_16_BYTE_ALIGNMENT;
1265 alignment++;
1267 if (alignment & (alignment - 1))
1269 alignment--;
1270 alignment |= alignment >> 1;
1271 alignment |= alignment >> 2;
1272 alignment |= alignment >> 4;
1273 alignment |= alignment >> 8;
1274 alignment |= alignment >> 16;
1275 alignment++;
1278 if (!(buffer->data = _aligned_malloc(max_length, alignment)))
1279 return E_OUTOFMEMORY;
1280 memset(buffer->data, 0, max_length);
1282 buffer->IMFMediaBuffer_iface.lpVtbl = vtbl;
1283 buffer->refcount = 1;
1284 buffer->max_length = max_length;
1285 buffer->current_length = 0;
1286 InitializeCriticalSection(&buffer->cs);
1288 return S_OK;
1291 static HRESULT create_1d_buffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer)
1293 struct buffer *object;
1294 HRESULT hr;
1296 if (!buffer)
1297 return E_POINTER;
1299 *buffer = NULL;
1301 if (!(object = calloc(1, sizeof(*object))))
1302 return E_OUTOFMEMORY;
1304 hr = memory_buffer_init(object, max_length, alignment, &memory_1d_buffer_vtbl);
1305 if (FAILED(hr))
1307 free(object);
1308 return hr;
1311 *buffer = &object->IMFMediaBuffer_iface;
1313 return S_OK;
1316 static p_copy_image_func get_2d_buffer_copy_func(DWORD fourcc)
1318 if (fourcc == MAKEFOURCC('N','V','1','2'))
1319 return copy_image_nv12;
1320 if (fourcc == MAKEFOURCC('I','M','C','1') || fourcc == MAKEFOURCC('I','M','C','3'))
1321 return copy_image_imc1;
1322 if (fourcc == MAKEFOURCC('I','M','C','2') || fourcc == MAKEFOURCC('I','M','C','4'))
1323 return copy_image_imc2;
1324 return NULL;
1327 static HRESULT create_2d_buffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer)
1329 unsigned int stride, max_length;
1330 unsigned int row_alignment;
1331 struct buffer *object;
1332 DWORD plane_size;
1333 GUID subtype;
1334 BOOL is_yuv;
1335 HRESULT hr;
1336 int pitch;
1338 if (!buffer)
1339 return E_POINTER;
1341 *buffer = NULL;
1343 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1344 subtype.Data1 = fourcc;
1346 if (!(stride = mf_format_get_stride(&subtype, width, &is_yuv)))
1347 return MF_E_INVALIDMEDIATYPE;
1349 if (is_yuv && bottom_up)
1350 return MF_E_INVALIDMEDIATYPE;
1352 switch (fourcc)
1354 case MAKEFOURCC('I','M','C','1'):
1355 case MAKEFOURCC('I','M','C','3'):
1356 plane_size = stride * height * 2;
1357 break;
1358 case MAKEFOURCC('I','M','C','2'):
1359 case MAKEFOURCC('I','M','C','4'):
1360 plane_size = stride * 3 / 2 * height;
1361 break;
1362 case MAKEFOURCC('N','V','1','2'):
1363 case MAKEFOURCC('Y','V','1','2'):
1364 case MAKEFOURCC('I','4','2','0'):
1365 case MAKEFOURCC('I','Y','U','V'):
1366 plane_size = stride * height * 3 / 2;
1367 break;
1368 default:
1369 plane_size = stride * height;
1372 if (!(object = calloc(1, sizeof(*object))))
1373 return E_OUTOFMEMORY;
1375 switch (fourcc)
1377 case MAKEFOURCC('I','M','C','1'):
1378 case MAKEFOURCC('I','M','C','2'):
1379 case MAKEFOURCC('I','M','C','3'):
1380 case MAKEFOURCC('I','M','C','4'):
1381 case MAKEFOURCC('Y','V','1','2'):
1382 row_alignment = MF_128_BYTE_ALIGNMENT;
1383 break;
1384 default:
1385 row_alignment = MF_64_BYTE_ALIGNMENT;
1388 pitch = ALIGN_SIZE(stride, row_alignment);
1390 switch (fourcc)
1392 case MAKEFOURCC('I','M','C','1'):
1393 case MAKEFOURCC('I','M','C','3'):
1394 max_length = pitch * height * 2;
1395 break;
1396 case MAKEFOURCC('N','V','1','2'):
1397 case MAKEFOURCC('Y','V','1','2'):
1398 case MAKEFOURCC('I','M','C','2'):
1399 case MAKEFOURCC('I','M','C','4'):
1400 max_length = pitch * height * 3 / 2;
1401 break;
1402 default:
1403 max_length = pitch * height;
1406 if (FAILED(hr = memory_buffer_init(object, max_length, row_alignment, &memory_1d_2d_buffer_vtbl)))
1408 free(object);
1409 return hr;
1412 object->IMF2DBuffer2_iface.lpVtbl = &memory_2d_buffer_vtbl;
1413 object->IMFGetService_iface.lpVtbl = &memory_2d_buffer_gs_vtbl;
1414 object->_2d.plane_size = plane_size;
1415 object->_2d.width = stride;
1416 object->_2d.height = height;
1417 object->_2d.pitch = bottom_up ? -pitch : pitch;
1418 object->_2d.scanline0 = bottom_up ? object->data + pitch * (object->_2d.height - 1) : object->data;
1419 object->_2d.copy_image = get_2d_buffer_copy_func(fourcc);
1421 *buffer = &object->IMFMediaBuffer_iface;
1423 return S_OK;
1426 static HRESULT create_d3d9_surface_buffer(IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer)
1428 struct buffer *object;
1429 D3DSURFACE_DESC desc;
1430 unsigned int stride;
1431 GUID subtype;
1432 BOOL is_yuv;
1434 IDirect3DSurface9_GetDesc((IDirect3DSurface9 *)surface, &desc);
1435 TRACE("format %#x, %u x %u.\n", desc.Format, desc.Width, desc.Height);
1437 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1438 subtype.Data1 = desc.Format;
1440 if (!(stride = mf_format_get_stride(&subtype, desc.Width, &is_yuv)))
1441 return MF_E_INVALIDMEDIATYPE;
1443 if (!(object = calloc(1, sizeof(*object))))
1444 return E_OUTOFMEMORY;
1446 object->IMFMediaBuffer_iface.lpVtbl = &d3d9_surface_1d_buffer_vtbl;
1447 object->IMF2DBuffer2_iface.lpVtbl = &d3d9_surface_buffer_vtbl;
1448 object->IMFGetService_iface.lpVtbl = &d3d9_surface_buffer_gs_vtbl;
1449 object->refcount = 1;
1450 InitializeCriticalSection(&object->cs);
1451 object->d3d9_surface.surface = (IDirect3DSurface9 *)surface;
1452 IUnknown_AddRef(surface);
1454 MFGetPlaneSize(desc.Format, desc.Width, desc.Height, &object->_2d.plane_size);
1455 object->_2d.width = stride;
1456 object->_2d.height = desc.Height;
1457 object->max_length = object->_2d.plane_size;
1458 object->_2d.copy_image = get_2d_buffer_copy_func(desc.Format);
1460 *buffer = &object->IMFMediaBuffer_iface;
1462 return S_OK;
1465 static HRESULT create_dxgi_surface_buffer(IUnknown *surface, unsigned int sub_resource_idx,
1466 BOOL bottom_up, IMFMediaBuffer **buffer)
1468 struct buffer *object;
1469 D3D11_TEXTURE2D_DESC desc;
1470 ID3D11Texture2D *texture;
1471 unsigned int stride;
1472 D3DFORMAT format;
1473 GUID subtype;
1474 BOOL is_yuv;
1475 HRESULT hr;
1477 if (FAILED(hr = IUnknown_QueryInterface(surface, &IID_ID3D11Texture2D, (void **)&texture)))
1479 WARN("Failed to get texture interface, hr %#lx.\n", hr);
1480 return hr;
1483 ID3D11Texture2D_GetDesc(texture, &desc);
1484 TRACE("format %#x, %u x %u.\n", desc.Format, desc.Width, desc.Height);
1486 memcpy(&subtype, &MFVideoFormat_Base, sizeof(subtype));
1487 subtype.Data1 = format = MFMapDXGIFormatToDX9Format(desc.Format);
1489 if (!(stride = mf_format_get_stride(&subtype, desc.Width, &is_yuv)))
1491 ID3D11Texture2D_Release(texture);
1492 return MF_E_INVALIDMEDIATYPE;
1495 if (!(object = calloc(1, sizeof(*object))))
1497 ID3D11Texture2D_Release(texture);
1498 return E_OUTOFMEMORY;
1501 object->IMFMediaBuffer_iface.lpVtbl = &dxgi_surface_1d_buffer_vtbl;
1502 object->IMF2DBuffer2_iface.lpVtbl = &dxgi_surface_buffer_vtbl;
1503 object->IMFDXGIBuffer_iface.lpVtbl = &dxgi_buffer_vtbl;
1504 object->refcount = 1;
1505 InitializeCriticalSection(&object->cs);
1506 object->dxgi_surface.texture = texture;
1507 object->dxgi_surface.sub_resource_idx = sub_resource_idx;
1509 MFGetPlaneSize(format, desc.Width, desc.Height, &object->_2d.plane_size);
1510 object->_2d.width = stride;
1511 object->_2d.height = desc.Height;
1512 object->max_length = object->_2d.plane_size;
1513 object->_2d.copy_image = get_2d_buffer_copy_func(format);
1515 if (FAILED(hr = init_attributes_object(&object->dxgi_surface.attributes, 0)))
1517 IMFMediaBuffer_Release(&object->IMFMediaBuffer_iface);
1518 return hr;
1521 *buffer = &object->IMFMediaBuffer_iface;
1523 return S_OK;
1526 /***********************************************************************
1527 * MFCreateMemoryBuffer (mfplat.@)
1529 HRESULT WINAPI MFCreateMemoryBuffer(DWORD max_length, IMFMediaBuffer **buffer)
1531 TRACE("%lu, %p.\n", max_length, buffer);
1533 return create_1d_buffer(max_length, MF_1_BYTE_ALIGNMENT, buffer);
1536 /***********************************************************************
1537 * MFCreateAlignedMemoryBuffer (mfplat.@)
1539 HRESULT WINAPI MFCreateAlignedMemoryBuffer(DWORD max_length, DWORD alignment, IMFMediaBuffer **buffer)
1541 TRACE("%lu, %lu, %p.\n", max_length, alignment, buffer);
1543 return create_1d_buffer(max_length, alignment, buffer);
1546 /***********************************************************************
1547 * MFCreate2DMediaBuffer (mfplat.@)
1549 HRESULT WINAPI MFCreate2DMediaBuffer(DWORD width, DWORD height, DWORD fourcc, BOOL bottom_up, IMFMediaBuffer **buffer)
1551 TRACE("%lu, %lu, %s, %d, %p.\n", width, height, debugstr_fourcc(fourcc), bottom_up, buffer);
1553 return create_2d_buffer(width, height, fourcc, bottom_up, buffer);
1556 /***********************************************************************
1557 * MFCreateDXSurfaceBuffer (mfplat.@)
1559 HRESULT WINAPI MFCreateDXSurfaceBuffer(REFIID riid, IUnknown *surface, BOOL bottom_up, IMFMediaBuffer **buffer)
1561 TRACE("%s, %p, %d, %p.\n", debugstr_guid(riid), surface, bottom_up, buffer);
1563 if (!IsEqualIID(riid, &IID_IDirect3DSurface9))
1564 return E_INVALIDARG;
1566 return create_d3d9_surface_buffer(surface, bottom_up, buffer);
1569 /***********************************************************************
1570 * MFCreateDXGISurfaceBuffer (mfplat.@)
1572 HRESULT WINAPI MFCreateDXGISurfaceBuffer(REFIID riid, IUnknown *surface, UINT subresource, BOOL bottom_up,
1573 IMFMediaBuffer **buffer)
1575 TRACE("%s, %p, %u, %d, %p.\n", debugstr_guid(riid), surface, subresource, bottom_up, buffer);
1577 if (!IsEqualIID(riid, &IID_ID3D11Texture2D))
1578 return E_INVALIDARG;
1580 return create_dxgi_surface_buffer(surface, subresource, bottom_up, buffer);
1583 static unsigned int buffer_get_aligned_length(unsigned int length, unsigned int alignment)
1585 length = (length + alignment) / alignment;
1586 length *= alignment;
1588 return length;
1591 HRESULT WINAPI MFCreateMediaBufferFromMediaType(IMFMediaType *media_type, LONGLONG duration, DWORD min_length,
1592 DWORD alignment, IMFMediaBuffer **buffer)
1594 UINT32 length = 0, block_alignment;
1595 LONGLONG avg_length;
1596 HRESULT hr;
1597 GUID major;
1599 TRACE("%p, %s, %lu, %lu, %p.\n", media_type, debugstr_time(duration), min_length, alignment, buffer);
1601 if (!media_type)
1602 return E_INVALIDARG;
1604 if (FAILED(hr = IMFMediaType_GetMajorType(media_type, &major)))
1605 return hr;
1607 if (IsEqualGUID(&major, &MFMediaType_Audio))
1609 block_alignment = 0;
1610 if (FAILED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_BLOCK_ALIGNMENT, &block_alignment)))
1611 WARN("Block alignment was not specified.\n");
1613 alignment = max(16, alignment);
1615 if (block_alignment)
1617 avg_length = 0;
1619 if (duration)
1621 length = 0;
1622 if (SUCCEEDED(IMFMediaType_GetUINT32(media_type, &MF_MT_AUDIO_AVG_BYTES_PER_SECOND, &length)))
1624 /* 100 ns -> 1 s */
1625 avg_length = length * duration / (10 * 1000 * 1000);
1629 length = buffer_get_aligned_length(avg_length + 1, alignment);
1630 length = buffer_get_aligned_length(length, block_alignment);
1632 else
1633 length = 0;
1635 length = max(length, min_length);
1637 return create_1d_buffer(length, alignment - 1, buffer);
1639 else
1640 FIXME("Major type %s is not supported.\n", debugstr_guid(&major));
1642 return E_NOTIMPL;