diff --git a/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfgstbuffer.cpp b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfgstbuffer.cpp
new file mode 100644
index 00000000000..95c03612f7f
--- /dev/null
+++ b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfgstbuffer.cpp
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "mfgstbuffer.h"
+
+CMFGSTBuffer::CMFGSTBuffer(DWORD cbMaxLength)
+{
+    m_ulRefCount = 0;
+
+    m_ulLockCount = 0;
+    InitializeCriticalSection(&m_csBufferLock);
+
+    m_cbMaxLength = cbMaxLength;
+    m_cbCurrentLength = 0;
+    m_pbBuffer = NULL;
+
+    m_pGstBuffer = NULL;
+    m_bUnmapGstBuffer = FALSE;
+
+    ZeroMemory(&m_CallbackData, sizeof(sCallbackData));
+    GetGstBufferCallback = NULL;
+}
+
+CMFGSTBuffer::~CMFGSTBuffer()
+{
+    if (m_pbBuffer != NULL)
+    {
+        delete [] m_pbBuffer;
+        m_pbBuffer = NULL;
+    }
+
+    if (m_bUnmapGstBuffer)
+    {
+        gst_buffer_unmap(m_pGstBuffer, &m_GstMapInfo);
+        m_bUnmapGstBuffer = FALSE;
+    }
+
+    if (m_pGstBuffer != NULL)
+    {
+        // INLINE - gst_buffer_unref()
+        gst_buffer_unref(m_pGstBuffer);
+        m_pGstBuffer = NULL;
+    }
+
+    DeleteCriticalSection(&m_csBufferLock);
+}
+
+ // IMFMediaBuffer
+HRESULT CMFGSTBuffer::GetCurrentLength(DWORD *pcbCurrentLength)
+{
+    if (pcbCurrentLength == NULL)
+        return E_INVALIDARG;
+
+    (*pcbCurrentLength) = m_cbCurrentLength;
+
+    return S_OK;
+}
+
+HRESULT CMFGSTBuffer::GetMaxLength(DWORD *pcbMaxLength)
+{
+    if (pcbMaxLength == NULL)
+        return E_INVALIDARG;
+
+    (*pcbMaxLength) = m_cbMaxLength;
+
+    return S_OK;
+}
+
+HRESULT CMFGSTBuffer::SetCurrentLength(DWORD cbCurrentLength)
+{
+    if (cbCurrentLength > m_cbMaxLength)
+        return E_INVALIDARG;
+
+    m_cbCurrentLength = cbCurrentLength;
+
+    if (m_pGstBuffer)
+        gst_buffer_set_size(m_pGstBuffer, cbCurrentLength);
+
+    return S_OK;
+}
+
+HRESULT CMFGSTBuffer::Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength)
+{
+    HRESULT hr = E_FAIL;
+
+    if (ppbBuffer == NULL)
+        return E_INVALIDARG;
+
+    if (m_cbMaxLength == 0)
+        return E_INVALIDARG;
+
+    EnterCriticalSection(&m_csBufferLock);
+    // Unlikely Lock() will be called in infinite loop.
+    if (m_ulLockCount != ULONG_MAX)
+    {
+        hr = AllocateOrGetBuffer(ppbBuffer);
+        if (SUCCEEDED(hr))
+        {
+           if (pcbMaxLength != NULL)
+                (*pcbMaxLength) = m_cbMaxLength;
+
+            if (pcbCurrentLength != NULL)
+                (*pcbCurrentLength) = m_cbCurrentLength;
+
+            // Increment lock count when we provided buffer. Lock() can be called
+            // multiple times and memory pointer should stay valid until last
+            // Unlock() called. The caller MUST match Lock() / Unlock() calls
+            // based on documentation.
+            m_ulLockCount++;
+        }
+    }
+
+    LeaveCriticalSection(&m_csBufferLock);
+
+    return hr;
+}
+
+HRESULT CMFGSTBuffer::Unlock()
+{
+    HRESULT hr = E_FAIL;
+
+    EnterCriticalSection(&m_csBufferLock);
+    // If Unlock() called without Lock() we should fail.
+    if (m_ulLockCount > 0)
+    {
+        m_ulLockCount--;
+        if (m_ulLockCount == 0 && m_bUnmapGstBuffer)
+        {
+            gst_buffer_unmap(m_pGstBuffer, &m_GstMapInfo);
+            m_bUnmapGstBuffer = FALSE;
+        }
+        hr = S_OK;
+    }
+    LeaveCriticalSection(&m_csBufferLock);
+
+    return hr;
+}
+
+// IUnknown
+HRESULT CMFGSTBuffer::QueryInterface(REFIID riid, void **ppvObject)
+{
+    if (!ppvObject)
+    {
+        return E_POINTER;
+    }
+    else if (riid == IID_IUnknown)
+    {
+        (*ppvObject) = static_cast<IUnknown *>(static_cast<IMFMediaBuffer *>(this));
+    }
+    else if (riid == IID_IMFMediaBuffer)
+    {
+        (*ppvObject) = static_cast<IMFMediaBuffer *>(this);
+    }
+    else
+    {
+        (*ppvObject) = NULL;
+        return E_NOINTERFACE;
+    }
+    AddRef();
+    return S_OK;
+}
+
+ULONG CMFGSTBuffer::AddRef()
+{
+    return InterlockedIncrement(&m_ulRefCount);
+}
+
+ULONG CMFGSTBuffer::Release()
+{
+    ULONG uCount = InterlockedDecrement(&m_ulRefCount);
+    if (uCount == 0)
+    {
+        delete this;
+    }
+    return uCount;
+}
+
+// GStreamer interface
+HRESULT CMFGSTBuffer::GetGstBuffer(GstBuffer **ppBuffer)
+{
+    if (ppBuffer == NULL)
+        return E_INVALIDARG;
+
+    // If we do not have GStreamer buffer or if it is still locked
+    // return E_UNEXPECTED. Such condition should not happen, but
+    // just in case we need to check for it.
+    if (m_pGstBuffer == NULL || m_bUnmapGstBuffer)
+        return E_UNEXPECTED;
+
+    (*ppBuffer) = m_pGstBuffer;
+
+    m_pGstBuffer = NULL;
+
+    return S_OK;
+}
+
+HRESULT CMFGSTBuffer::SetCallbackData(sCallbackData *pCallbackData)
+{
+    if (pCallbackData == NULL)
+        ZeroMemory(&m_CallbackData, sizeof(sCallbackData));
+    else
+        m_CallbackData = (*pCallbackData);
+
+    return S_OK;
+}
+
+HRESULT CMFGSTBuffer::SetGetGstBufferCallback(void (*function)(GstBuffer **ppBuffer,
+            long lSize, sCallbackData *pCallbackData))
+{
+    if (function == NULL)
+        return E_INVALIDARG;
+
+    GetGstBufferCallback = function;
+
+    return S_OK;
+}
+
+HRESULT CMFGSTBuffer::AllocateOrGetBuffer(BYTE **ppbBuffer)
+{
+    if (ppbBuffer == NULL)
+        return E_INVALIDARG;
+
+    // If we have GStreamer get buffer callback set, then call it to get
+    // buffer. Otherwise allocate memory internally.
+    if (GetGstBufferCallback != NULL)
+    {
+        // Get buffer if needed
+        if (m_pGstBuffer == NULL)
+        {
+            GetGstBufferCallback(&m_pGstBuffer, (long)m_cbMaxLength, &m_CallbackData);
+            if (m_pGstBuffer == NULL)
+                return E_OUTOFMEMORY;
+        }
+
+        // Lock can be called multiple times, so if we have GStreamer buffer
+        // allocated and mapped just return it.
+        if (m_bUnmapGstBuffer)
+        {
+            (*ppbBuffer) = m_GstMapInfo.data;
+        }
+        else
+        {
+            // Map buffer and return it.
+            if (!gst_buffer_map(m_pGstBuffer, &m_GstMapInfo, GST_MAP_READWRITE))
+                return E_FAIL;
+
+            // Just in case check that we got right buffer size.
+            // GStreamer buffer can be bigger due to alligment.
+            if (m_GstMapInfo.maxsize < m_cbMaxLength)
+            {
+                gst_buffer_unmap(m_pGstBuffer, &m_GstMapInfo);
+                // INLINE - gst_buffer_unref()
+                gst_buffer_unref(m_pGstBuffer);
+                m_pGstBuffer = NULL;
+                return E_FAIL;
+            }
+
+            m_bUnmapGstBuffer = TRUE;
+
+            (*ppbBuffer) = m_GstMapInfo.data;
+        }
+    }
+    else
+    {
+        // Allocate new buffer if needed
+        if (m_pbBuffer == NULL)
+        {
+            m_pbBuffer = new (nothrow) BYTE[m_cbMaxLength];
+            if (m_pbBuffer == NULL)
+                return E_OUTOFMEMORY;
+
+            (*ppbBuffer) = m_pbBuffer;
+        }
+        else if (m_pbBuffer != NULL)
+        {
+            (*ppbBuffer) = m_pbBuffer;
+        }
+    }
+
+    return S_OK;
+}
diff --git a/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfgstbuffer.h b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfgstbuffer.h
new file mode 100644
index 00000000000..4505dbac041
--- /dev/null
+++ b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfgstbuffer.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code 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 General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef __MF_GST_BUFFER_H__
+#define __MF_GST_BUFFER_H__
+
+#include <gst/gst.h>
+
+#include <new>
+
+#include <mfidl.h>
+
+using namespace std;
+
+struct sCallbackData
+{
+    void *pCallbackData;
+};
+
+class CMFGSTBuffer : public IMFMediaBuffer
+{
+public:
+    CMFGSTBuffer(DWORD cbMaxLength);
+    ~CMFGSTBuffer();
+
+    // IMFMediaBuffer
+    HRESULT GetCurrentLength(DWORD *pcbCurrentLength);
+    HRESULT GetMaxLength(DWORD *pcbMaxLength);
+    HRESULT SetCurrentLength(DWORD cbCurrentLength);
+    HRESULT Lock(BYTE **ppbBuffer, DWORD *pcbMaxLength, DWORD *pcbCurrentLength);
+    HRESULT Unlock();
+
+    // IUnknown
+    HRESULT QueryInterface(REFIID riid, void **ppvObject);
+    ULONG AddRef();
+    ULONG Release();
+
+    // GStreamer interface
+    HRESULT GetGstBuffer(GstBuffer **ppBuffer);
+    HRESULT SetCallbackData(sCallbackData *pCallbackData);
+    HRESULT SetGetGstBufferCallback(void (*function)(GstBuffer **ppBuffer,
+            long lSize, sCallbackData *pCallbackData));
+
+private:
+    HRESULT AllocateOrGetBuffer(BYTE **ppbBuffer);
+
+    ULONG m_ulRefCount;
+
+    // Used to unlock buffer with last Unlock() call. Lock() / Unlock() can be
+    // called multiple times, but the caller should match calls for
+    // Lock() / Unlock().
+    ULONG m_ulLockCount;
+    // Used to protect Lock() / Unlock() which can be called by
+    // multiple threads.
+    CRITICAL_SECTION m_csBufferLock;
+
+    DWORD m_cbMaxLength;
+    DWORD m_cbCurrentLength;
+    BYTE *m_pbBuffer;
+
+    GstBuffer *m_pGstBuffer;
+    BOOL m_bUnmapGstBuffer;
+    GstMapInfo m_GstMapInfo;
+
+    sCallbackData m_CallbackData;
+    void (*GetGstBufferCallback)(GstBuffer **ppBuffer, long lSize,
+            sCallbackData *pCallbackData);
+};
+
+#endif // __MF_GST_BUFFER_H__
diff --git a/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp
index 1766cf36d06..6136fab06af 100644
--- a/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp
+++ b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,7 +32,8 @@
 #include <string.h>
 #include <stdio.h>
 
-#include <mfwrapper.h>
+#include "mfwrapper.h"
+
 #include <mfidl.h>
 #include <Wmcodecdsp.h>
 
@@ -41,6 +42,12 @@
 #define PTS_DEBUG 0
 #define MEDIA_FORMAT_DEBUG 0
 
+// 3 buffers is enough for rendering. During testing 2 buffers is actually
+// enough, but in some case 3 were allocated.
+#define MIN_BUFFERS 3
+// 6 buffers max, just in case.
+#define MAX_BUFFERS 6
+
 enum
 {
     PROP_0,
@@ -190,13 +197,14 @@ static void gst_mfwrapper_init(GstMFWrapper *decoder)
     decoder->is_eos_received = FALSE;
     decoder->is_eos = FALSE;
     decoder->is_decoder_initialized = FALSE;
+    decoder->is_decoder_error = FALSE;
     decoder->force_discontinuity = FALSE;
     decoder->force_output_discontinuity = FALSE;
 
     // Initialize Media Foundation
     bool bCallCoUninitialize = true;
 
-    if (FAILED(CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE)))
+    if (FAILED(CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE)))
         bCallCoUninitialize = false;
 
     decoder->hr_mfstartup = MFStartup(MF_VERSION, MFSTARTUP_LITE);
@@ -206,13 +214,17 @@ static void gst_mfwrapper_init(GstMFWrapper *decoder)
 
     decoder->pDecoder = NULL;
     decoder->pDecoderOutput = NULL;
+    decoder->pDecoderBuffer = NULL;
 
     for (int i = 0; i < MAX_COLOR_CONVERT; i++)
     {
         decoder->pColorConvert[i] = NULL;
         decoder->pColorConvertOutput[i] = NULL;
+        decoder->pColorConvertBuffer[i] = NULL;
     }
 
+    decoder->pool = NULL;
+
     decoder->header = NULL;
     decoder->header_size = 0;
 
@@ -230,15 +242,28 @@ static void gst_mfwrapper_dispose(GObject* object)
 {
     GstMFWrapper *decoder = GST_MFWRAPPER(object);
 
+    // No need to free pDecoderBuffer, it will be release when interface is
+    // release by MF.
     SafeRelease(&decoder->pDecoderOutput);
     SafeRelease(&decoder->pDecoder);
 
     for (int i = 0; i < MAX_COLOR_CONVERT; i++)
     {
+        // No need to free pColorConvertBuffer, it will be release when interface is
+        // release by MF.
         SafeRelease(&decoder->pColorConvertOutput[i]);
         SafeRelease(&decoder->pColorConvert[i]);
     }
 
+    if (decoder->pool)
+    {
+        if (gst_buffer_pool_is_active(decoder->pool))
+            gst_buffer_pool_set_active(decoder->pool, FALSE);
+
+        gst_object_unref(decoder->pool);
+        decoder->pool = NULL;
+    }
+
     if (decoder->hr_mfstartup == S_OK)
         MFShutdown();
 
@@ -296,6 +321,33 @@ static gboolean mfwrapper_is_decoder_by_codec_id_supported(GstMFWrapper *decoder
         return FALSE;
 }
 
+static HRESULT mfwrapper_create_sample(IMFSample **ppSample, DWORD dwSize, CMFGSTBuffer **ppMFGSTBuffer)
+{
+    if (ppSample == NULL || dwSize == 0 || ppMFGSTBuffer == NULL)
+        return E_INVALIDARG;
+
+    HRESULT hr = MFCreateSample(ppSample);
+    if (SUCCEEDED(hr))
+    {
+        (*ppMFGSTBuffer) = new (nothrow) CMFGSTBuffer(dwSize);
+        if ((*ppMFGSTBuffer) == NULL)
+            return E_OUTOFMEMORY;
+
+        IMFMediaBuffer *pBuffer = NULL;
+        hr = (*ppMFGSTBuffer)->QueryInterface(IID_IMFMediaBuffer, (void **)&pBuffer);
+        if (FAILED(hr) || pBuffer == NULL)
+        {
+            delete (*ppMFGSTBuffer);
+            return E_NOINTERFACE;
+        }
+
+        (*ppSample)->AddBuffer(pBuffer);
+        SafeRelease(&pBuffer);
+    }
+
+    return S_OK;
+}
+
 static void mfwrapper_set_src_caps(GstMFWrapper *decoder)
 {
     GstCaps *srcCaps = NULL;
@@ -353,17 +405,11 @@ static void mfwrapper_set_src_caps(GstMFWrapper *decoder)
 
     if (SUCCEEDED(hr))
     {
-        if (!((outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) || (outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
+        if (!((outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) ||
+              (outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
         {
-            hr = MFCreateSample(&decoder->pDecoderOutput);
-            if (SUCCEEDED(hr))
-            {
-                IMFMediaBuffer *pBuffer = NULL;
-                hr = MFCreateMemoryBuffer(outputStreamInfo.cbSize, &pBuffer);
-                if (SUCCEEDED(hr))
-                    hr = decoder->pDecoderOutput->AddBuffer(pBuffer);
-                SafeRelease(&pBuffer);
-            }
+            hr = mfwrapper_create_sample(&decoder->pDecoderOutput,
+                    outputStreamInfo.cbSize, &decoder->pDecoderBuffer);
         }
     }
 }
@@ -782,18 +828,21 @@ static HRESULT mfwrapper_configure_colorconvert_output_type(GstMFWrapper *decode
 // color convert with best possible output type.
 // ppColorConvert - Receives pointer to color convert.
 // ppColorConvertOutput - Receives pointer to color convert output buffer.
-// outputType - Will be set to color convert output type (IYUV or NV12)
+// outputType - Will be set to color convert output type (IYUV or NV12).
+// ppMFGSTBuffer - Receives CMFGSTBuffer object related to ppColorConvertOutput.
 static HRESULT mfwrapper_init_colorconvert(GstMFWrapper *decoder,
                                            IMFTransform *pInput,
                                            IMFTransform **ppColorConvert,
                                            IMFSample **ppColorConvertOutput,
-                                           GUID *outputType)
+                                           GUID *outputType,
+                                           CMFGSTBuffer **ppMFGSTBuffer)
 {
     DWORD dwStatus = 0;
     MFT_OUTPUT_STREAM_INFO outputStreamInfo;
 
     if (pInput == NULL || ppColorConvert == NULL ||
-        ppColorConvertOutput == NULL || outputType == NULL)
+        ppColorConvertOutput == NULL || outputType == NULL ||
+        ppMFGSTBuffer == NULL)
     {
         return E_POINTER;
     }
@@ -813,15 +862,8 @@ static HRESULT mfwrapper_init_colorconvert(GstMFWrapper *decoder,
         if (!((outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_PROVIDES_SAMPLES) ||
               (outputStreamInfo.dwFlags & MFT_OUTPUT_STREAM_CAN_PROVIDE_SAMPLES)))
         {
-            hr = MFCreateSample(ppColorConvertOutput);
-            if (SUCCEEDED(hr))
-            {
-                IMFMediaBuffer *pBuffer = NULL;
-                hr = MFCreateMemoryBuffer(outputStreamInfo.cbSize, &pBuffer);
-                if (SUCCEEDED(hr))
-                    hr = (*ppColorConvertOutput)->AddBuffer(pBuffer);
-                SafeRelease(&pBuffer);
-            }
+            hr = mfwrapper_create_sample(ppColorConvertOutput,
+                outputStreamInfo.cbSize, ppMFGSTBuffer);
         }
     }
 
@@ -844,6 +886,118 @@ static HRESULT mfwrapper_init_colorconvert(GstMFWrapper *decoder,
     return hr;
 }
 
+static void mfwrapper_get_gst_buffer_src(GstBuffer **ppBuffer, long lSize,
+        sCallbackData *pCallbackData)
+{
+    GstFlowReturn ret = GST_FLOW_OK;
+    GstMFWrapper *decoder = (GstMFWrapper*)pCallbackData->pCallbackData;
+    if (decoder == NULL || decoder->pool == NULL)
+    {
+        (*ppBuffer) = NULL;
+        return;
+    }
+
+    ret = gst_buffer_pool_acquire_buffer(decoder->pool, ppBuffer, NULL);
+    if (ret == GST_FLOW_OK)
+        return;
+
+    // Pool might fail in case of flushing, but MF still might want buffer.
+    // It is better to give buffer to MF just in case, then fail
+    // CMFGSTBuffer::Lock().
+    (*ppBuffer) = gst_buffer_new_allocate(NULL, lSize, NULL);
+}
+
+// Gets max length of configured media buffer we using for final rendering from
+// decoder or color convert.
+static HRESULT mfwrapper_get_media_buffer_max_length(GstMFWrapper *decoder, DWORD *pdwMaxLength)
+{
+    HRESULT hr = S_OK;
+
+    if (decoder == NULL || pdwMaxLength == NULL)
+        return E_INVALIDARG;
+
+    CMFGSTBuffer *pBuffer = NULL;
+    if (decoder->pColorConvertOutput[COLOR_CONVERT_IYUV] != NULL)
+        pBuffer = decoder->pColorConvertBuffer[COLOR_CONVERT_IYUV];
+    else if (decoder->pDecoderOutput != NULL)
+        pBuffer = decoder->pDecoderBuffer;
+
+    if (pBuffer == NULL)
+        return E_FAIL;
+
+    return pBuffer->GetMaxLength(pdwMaxLength);
+}
+
+static HRESULT mfwrapper_configure_media_buffer(GstMFWrapper *decoder)
+{
+    HRESULT hr = S_OK;
+
+    CMFGSTBuffer *pBuffer = NULL;
+    if (decoder->pColorConvertOutput[COLOR_CONVERT_IYUV] != NULL)
+        pBuffer = decoder->pColorConvertBuffer[COLOR_CONVERT_IYUV];
+    else if (decoder->pDecoderOutput != NULL)
+        pBuffer = decoder->pDecoderBuffer;
+
+    if (pBuffer == NULL)
+        return E_FAIL;
+
+    sCallbackData callbackData;
+    ZeroMemory(&callbackData, sizeof(sCallbackData));
+    callbackData.pCallbackData = (void*)decoder;
+    hr = pBuffer->SetCallbackData(&callbackData);
+    if (FAILED(hr))
+        return hr;
+
+    hr = pBuffer->SetGetGstBufferCallback(&mfwrapper_get_gst_buffer_src);
+    if (FAILED(hr))
+        return hr;
+
+    return hr;
+}
+
+static HRESULT mfwrapper_configure_buffer_pool(GstMFWrapper *decoder)
+{
+    // Free old pool. We might be called during format change.
+    if (decoder->pool)
+    {
+        if (gst_buffer_pool_is_active(decoder->pool))
+            gst_buffer_pool_set_active(decoder->pool, FALSE);
+
+        gst_object_unref(decoder->pool);
+        decoder->pool = NULL;
+    }
+
+    DWORD dwMaxLength = 0;
+    HRESULT hr = mfwrapper_get_media_buffer_max_length(decoder, &dwMaxLength);
+    // Pool only supports upto unsigned int, but buffer can be unsigned long.
+    if (FAILED(hr) || dwMaxLength > G_MAXUINT)
+        return E_FAIL;
+
+    decoder->pool = gst_buffer_pool_new();
+    if (decoder->pool == NULL)
+        return E_FAIL;
+
+    GstStructure *config = gst_buffer_pool_get_config(decoder->pool);
+    if (config == NULL)
+        return E_FAIL;
+
+    // By now we should caps configured on pad, so just use it.
+    GstCaps *caps = gst_pad_get_current_caps(decoder->srcpad);
+    if (caps == NULL)
+        return E_FAIL;
+
+    gst_buffer_pool_config_set_params(config, caps,
+            (guint)dwMaxLength, MIN_BUFFERS, MAX_BUFFERS);
+    gst_caps_unref(caps); // INLINE - gst_caps_unref()
+
+    if (!gst_buffer_pool_set_config(decoder->pool, config))
+        return E_FAIL;
+
+    gst_buffer_pool_set_active(decoder->pool, TRUE);
+
+    return S_OK;
+}
+
 static HRESULT mfwrapper_set_decoder_output_type(GstMFWrapper *decoder,
                                                  IMFMediaType *pOutputType,
                                                  gboolean bInitColorConverter)
@@ -932,22 +1086,25 @@ static HRESULT mfwrapper_set_decoder_output_type(GstMFWrapper *decoder,
         IMFTransform *pColorConvert = NULL;
         IMFSample *pColorConvertOutput = NULL;
         GUID outputType;
+        CMFGSTBuffer *pMFGSTBuffer = NULL;
 
         hr = mfwrapper_init_colorconvert(decoder, decoder->pDecoder,
-                    &pColorConvert, &pColorConvertOutput, &outputType);
+                    &pColorConvert, &pColorConvertOutput, &outputType, &pMFGSTBuffer);
         if (SUCCEEDED(hr) && IsEqualGUID(outputType, MFVideoFormat_NV12)) {
             decoder->pColorConvert[COLOR_CONVERT_NV12] = pColorConvert;
             decoder->pColorConvertOutput[COLOR_CONVERT_NV12] = pColorConvertOutput;
+            decoder->pColorConvertBuffer[COLOR_CONVERT_NV12] = pMFGSTBuffer;
 
             // We got NV12, so init second one for NV12->IYUV
             hr = mfwrapper_init_colorconvert(decoder,
                     decoder->pColorConvert[COLOR_CONVERT_NV12], &pColorConvert,
-                    &pColorConvertOutput, &outputType);
+                    &pColorConvertOutput, &outputType, &pMFGSTBuffer);
         }
 
         if (SUCCEEDED(hr) && IsEqualGUID(outputType, MFVideoFormat_IYUV)) {
             decoder->pColorConvert[COLOR_CONVERT_IYUV] = pColorConvert;
             decoder->pColorConvertOutput[COLOR_CONVERT_IYUV] = pColorConvertOutput;
+            decoder->pColorConvertBuffer[COLOR_CONVERT_IYUV] = pMFGSTBuffer;
         }
     }
 
@@ -955,6 +1112,17 @@ static HRESULT mfwrapper_set_decoder_output_type(GstMFWrapper *decoder,
     if (SUCCEEDED(hr))
         mfwrapper_set_src_caps(decoder);
 
+    // By now we should have output sample created. Figure out which one we
+    // will use to deliver frames and update media buffer in this sample to
+    // use GStreamer memory directly.
+    if (SUCCEEDED(hr))
+        hr = mfwrapper_configure_media_buffer(decoder);
+
+    // Configure GStreamer buffer pool to avoid memory allocation for each
+    // buffer.
+    if (SUCCEEDED(hr))
+        hr = mfwrapper_configure_buffer_pool(decoder);
+
     return hr;
 }
 
@@ -1120,76 +1288,47 @@ static gboolean mfwrapper_convert_output(GstMFWrapper *decoder)
     return result;
 }
 
-static GstFlowReturn mfwrapper_deliver_sample(GstMFWrapper *decoder, IMFSample *pSample)
+static GstFlowReturn mfwrapper_deliver_sample(GstMFWrapper *decoder,
+        IMFSample *pSample, CMFGSTBuffer *pMFGSTBuffer)
 {
     GstFlowReturn ret = GST_FLOW_OK;
+    GstBuffer *pGstBuffer = NULL;
     LONGLONG llTimestamp = 0;
     LONGLONG llDuration = 0;
-    IMFMediaBuffer *pMediaBuffer = NULL;
-    BYTE *pBuffer = NULL;
-    DWORD cbMaxLength = 0;
-    DWORD cbCurrentLength = 0;
-    GstMapInfo info;
 
-    HRESULT hr = pSample->ConvertToContiguousBuffer(&pMediaBuffer);
+    if (decoder == NULL || pSample == NULL || pMFGSTBuffer == NULL)
+        return GST_FLOW_ERROR;
 
-    if (SUCCEEDED(hr))
-        hr = pMediaBuffer->Lock(&pBuffer, &cbMaxLength, &cbCurrentLength);
-
-    if (SUCCEEDED(hr) && cbCurrentLength > 0)
-    {
-        GstBuffer *pGstBuffer = gst_buffer_new_allocate(NULL, cbCurrentLength, NULL);
-        if (pGstBuffer == NULL || !gst_buffer_map(pGstBuffer, &info, GST_MAP_WRITE))
-        {
-            pMediaBuffer->Unlock();
-             if (pGstBuffer != NULL)
-                gst_buffer_unref(pGstBuffer); // INLINE - gst_buffer_unref()
-            return GST_FLOW_ERROR;
-        }
-
-        memcpy(info.data, pBuffer, cbCurrentLength);
-        gst_buffer_unmap(pGstBuffer, &info);
-        gst_buffer_set_size(pGstBuffer, cbCurrentLength);
-
-        hr = pMediaBuffer->Unlock();
-        if (SUCCEEDED(hr))
-        {
-            hr = pSample->GetSampleTime(&llTimestamp);
-            GST_BUFFER_TIMESTAMP(pGstBuffer) = llTimestamp * 100;
-        }
-
-        if (SUCCEEDED(hr))
-        {
-            hr = pSample->GetSampleDuration(&llDuration);
-            GST_BUFFER_DURATION(pGstBuffer) = llDuration * 100;
-        }
-
-        if (SUCCEEDED(hr) && decoder->force_output_discontinuity)
-        {
-            pGstBuffer = gst_buffer_make_writable(pGstBuffer);
-            GST_BUFFER_FLAG_SET(pGstBuffer, GST_BUFFER_FLAG_DISCONT);
-            decoder->force_output_discontinuity = FALSE;
-        }
+    HRESULT hr = pMFGSTBuffer->GetGstBuffer(&pGstBuffer);
+    if (FAILED(hr))
+        return GST_FLOW_ERROR;
 
-#if PTS_DEBUG
-        if (GST_BUFFER_TIMESTAMP_IS_VALID(pGstBuffer) && GST_BUFFER_DURATION_IS_VALID(pGstBuffer))
-            g_print("JFXMEDIA H265 %I64u %I64u\n", GST_BUFFER_TIMESTAMP(pGstBuffer), GST_BUFFER_DURATION(pGstBuffer));
-        else if (GST_BUFFER_TIMESTAMP_IS_VALID(pGstBuffer) && !GST_BUFFER_DURATION_IS_VALID(pGstBuffer))
-            g_print("JFXMEDIA H265 %I64u -1\n", GST_BUFFER_TIMESTAMP(pGstBuffer));
-        else
-            g_print("JFXMEDIA H265 -1\n");
-#endif
+    hr = pSample->GetSampleTime(&llTimestamp);
+    GST_BUFFER_TIMESTAMP(pGstBuffer) = llTimestamp * 100;
 
-        ret = gst_pad_push(decoder->srcpad, pGstBuffer);
+    if (SUCCEEDED(hr))
+    {
+        hr = pSample->GetSampleDuration(&llDuration);
+        GST_BUFFER_DURATION(pGstBuffer) = llDuration * 100;
     }
-    else if (SUCCEEDED(hr))
+
+    if (SUCCEEDED(hr) && decoder->force_output_discontinuity)
     {
-        pMediaBuffer->Unlock();
+        pGstBuffer = gst_buffer_make_writable(pGstBuffer);
+        GST_BUFFER_FLAG_SET(pGstBuffer, GST_BUFFER_FLAG_DISCONT);
+        decoder->force_output_discontinuity = FALSE;
     }
 
-    SafeRelease(&pMediaBuffer);
+#if PTS_DEBUG
+    if (GST_BUFFER_TIMESTAMP_IS_VALID(pGstBuffer) && GST_BUFFER_DURATION_IS_VALID(pGstBuffer))
+        g_print("JFXMEDIA H265 %I64u %I64u\n", GST_BUFFER_TIMESTAMP(pGstBuffer), GST_BUFFER_DURATION(pGstBuffer));
+    else if (GST_BUFFER_TIMESTAMP_IS_VALID(pGstBuffer) && !GST_BUFFER_DURATION_IS_VALID(pGstBuffer))
+        g_print("JFXMEDIA H265 %I64u -1\n", GST_BUFFER_TIMESTAMP(pGstBuffer));
+    else
+        g_print("JFXMEDIA H265 -1\n");
+#endif
 
-    return ret;
+    return gst_pad_push(decoder->srcpad, pGstBuffer);
 }
 
 static gint mfwrapper_process_output(GstMFWrapper *decoder)
@@ -1238,15 +1377,25 @@ static gint mfwrapper_process_output(GstMFWrapper *decoder)
                 {
                     // Deliver from IYUV color converter
                     ret = mfwrapper_deliver_sample(decoder,
-                                decoder->pColorConvertOutput[COLOR_CONVERT_IYUV]);
+                                decoder->pColorConvertOutput[COLOR_CONVERT_IYUV],
+                                decoder->pColorConvertBuffer[COLOR_CONVERT_IYUV]);
                 }
             }
             else
             {
-                ret = mfwrapper_deliver_sample(decoder, decoder->pDecoderOutput);
+                ret = mfwrapper_deliver_sample(decoder, decoder->pDecoderOutput,
+                            decoder->pDecoderBuffer);
             }
         }
     }
+    else
+    {
+        decoder->is_decoder_error = TRUE;
+        gst_element_message_full(GST_ELEMENT(decoder), GST_MESSAGE_ERROR,
+                GST_STREAM_ERROR, GST_STREAM_ERROR_DECODE,
+                g_strdup_printf("Failed to decode stream (0x%X)", hr), NULL,
+                ("mfwrapper.c"), ("mfwrapper_process_output"), 0);
+    }
 
     if (decoder->is_eos || decoder->is_flushing || ret != GST_FLOW_OK)
         return PO_FLUSHING;
@@ -1320,13 +1469,17 @@ static gboolean mfwrapper_sink_event(GstPad* pad, GstObject *parent, GstEvent *e
     break;
     case GST_EVENT_FLUSH_STOP:
     {
-        decoder->pDecoder->ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
-        for (int i = 0; i < MAX_COLOR_CONVERT; i++)
+        if (!decoder->is_decoder_error)
         {
-            if (decoder->pColorConvert[i])
+            decoder->pDecoder->
+                    ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+            for (int i = 0; i < MAX_COLOR_CONVERT; i++)
             {
-                decoder->pColorConvert[i]->
-                        ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+                if (decoder->pColorConvert[i])
+                {
+                    decoder->pColorConvert[i]->
+                            ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+                }
             }
         }
 
@@ -1339,33 +1492,36 @@ static gboolean mfwrapper_sink_event(GstPad* pad, GstObject *parent, GstEvent *e
     {
         decoder->is_eos_received = TRUE;
 
-        // Let decoder know that we got end of stream
-        hr = decoder->pDecoder->
+        if (!decoder->is_decoder_error)
+        {
+            // Let decoder know that we got end of stream
+            hr = decoder->pDecoder->
                 ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
 
-        // Ask decoder to produce all remaining data
-        if (SUCCEEDED(hr))
-        {
-            decoder->pDecoder->
-                    ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
-        }
+            // Ask decoder to produce all remaining data
+            if (SUCCEEDED(hr))
+            {
+                decoder->pDecoder->
+                        ProcessMessage(MFT_MESSAGE_COMMAND_DRAIN, 0);
+            }
 
-        // Deliver remaining data
-        gint po_ret;
-        do
-        {
-            po_ret = mfwrapper_process_output(decoder);
-        } while (po_ret == PO_DELIVERED);
+            // Deliver remaining data
+            gint po_ret;
+            do
+            {
+                po_ret = mfwrapper_process_output(decoder);
+            } while (po_ret == PO_DELIVERED);
 
-        for (int i = 0; i < MAX_COLOR_CONVERT; i++)
-        {
-            if (decoder->pColorConvert[i])
+            for (int i = 0; i < MAX_COLOR_CONVERT; i++)
             {
-                hr = decoder->pColorConvert[i]->
-                        ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
-                if (SUCCEEDED(hr))
+                if (decoder->pColorConvert[i])
+                {
                     hr = decoder->pColorConvert[i]->
-                            ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+                            ProcessMessage(MFT_MESSAGE_NOTIFY_END_OF_STREAM, 0);
+                    if (SUCCEEDED(hr))
+                        hr = decoder->pColorConvert[i]->
+                                ProcessMessage(MFT_MESSAGE_COMMAND_FLUSH, 0);
+                }
             }
         }
 
diff --git a/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.h b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.h
index b38c588f702..1d5646eee68 100644
--- a/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.h
+++ b/modules/javafx.media/src/main/native/gstreamer/plugins/mfwrapper/mfwrapper.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2021, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -28,6 +28,8 @@
 
 #include <gst/gst.h>
 
+#include "mfgstbuffer.h"
+
 #include <mfapi.h>
 #include <mferror.h>
 #include <mftransform.h>
@@ -71,6 +73,9 @@ struct _GstMFWrapper
     gboolean is_eos_received;
     gboolean is_eos;
     gboolean is_decoder_initialized;
+    // If set to true do not call decoder it might hang.
+    // This flag should be set if decoder calls failed.
+    gboolean is_decoder_error;
 
     gboolean force_discontinuity;
     gboolean force_output_discontinuity;
@@ -79,9 +84,13 @@ struct _GstMFWrapper
 
     IMFTransform *pDecoder;
     IMFSample *pDecoderOutput;
+    CMFGSTBuffer *pDecoderBuffer;
 
     IMFTransform *pColorConvert[MAX_COLOR_CONVERT];
     IMFSample *pColorConvertOutput[MAX_COLOR_CONVERT];
+    CMFGSTBuffer *pColorConvertBuffer[MAX_COLOR_CONVERT];
+
+    GstBufferPool *pool;
 
     BYTE *header;
     gsize header_size;
diff --git a/modules/javafx.media/src/main/native/gstreamer/projects/win/fxplugins/Makefile b/modules/javafx.media/src/main/native/gstreamer/projects/win/fxplugins/Makefile
index 5777e87eed8..237cffbb6db 100644
--- a/modules/javafx.media/src/main/native/gstreamer/projects/win/fxplugins/Makefile
+++ b/modules/javafx.media/src/main/native/gstreamer/projects/win/fxplugins/Makefile
@@ -59,7 +59,8 @@ CPP_SOURCES = dshowwrapper/Allocator.cpp \
               dshowwrapper/dshowwrapper.cpp \
               dshowwrapper/Sink.cpp \
               dshowwrapper/Src.cpp \
-              mfwrapper/mfwrapper.cpp
+              mfwrapper/mfwrapper.cpp \
+              mfwrapper/mfgstbuffer.cpp
 
 COMPILER_FLAGS = -nologo -W3 -WX- -EHsc -GS -fp:precise \
                  -Zc:wchar_t -Zc:forScope- -analyze- -errorReport:queue -Gm-
diff --git a/modules/javafx.media/src/main/native/gstreamer/projects/win/gstreamer-lite.def b/modules/javafx.media/src/main/native/gstreamer/projects/win/gstreamer-lite.def
index 1f7c4ff2f45..1934014070d 100644
--- a/modules/javafx.media/src/main/native/gstreamer/projects/win/gstreamer-lite.def
+++ b/modules/javafx.media/src/main/native/gstreamer/projects/win/gstreamer-lite.def
@@ -10,139 +10,146 @@ gst_bin_add_many	@8	NONAME
 gst_bin_get_type	@9	NONAME
 gst_bin_iterate_elements	@10	NONAME
 gst_bin_new	@11	NONAME
-gst_bin_remove	@12	NONAME
-gst_buffer_fill	@13	NONAME
-gst_buffer_get_size	@14	NONAME
-gst_buffer_map	@15	NONAME
-gst_buffer_new_allocate	@16	NONAME
-gst_buffer_new_wrapped_full	@17	NONAME
-gst_buffer_resize	@18	NONAME
-gst_buffer_set_size	@19	NONAME
-gst_buffer_unmap	@20	NONAME
-gst_bus_create_watch	@21	NONAME
-gst_bus_post	@22	NONAME
-gst_caps_get_size	@23	NONAME
-gst_caps_get_structure	@24	NONAME
-gst_caps_new_simple	@25	NONAME
-gst_caps_set_simple	@26	NONAME
-gst_child_proxy_get_child_by_index	@27	NONAME
-gst_child_proxy_get_type	@28	NONAME
-gst_core_error_quark	@29	NONAME
-gst_element_add_pad	@30	NONAME
-gst_element_class_add_pad_template	@31	NONAME
-gst_element_class_get_pad_template	@32	NONAME
-gst_element_class_set_metadata	@33	NONAME
-gst_element_class_set_static_metadata	@34	NONAME
-gst_element_factory_make	@35	NONAME
-gst_element_get_factory	@36	NONAME
-gst_element_get_state	@37	NONAME
-gst_element_get_static_pad	@38	NONAME
-gst_element_get_type	@39	NONAME
-gst_element_link	@40	NONAME
-gst_element_link_many	@41	NONAME
-gst_element_message_full	@42	NONAME
-gst_element_no_more_pads	@43	NONAME
-gst_element_post_message	@44	NONAME
-gst_element_provide_clock	@45	NONAME
-gst_element_query_duration	@46	NONAME
-gst_element_query_position	@47	NONAME
-gst_element_register	@48	NONAME
-gst_element_remove_pad	@49	NONAME
-gst_element_seek	@50	NONAME
-gst_element_set_state	@51	NONAME
-gst_element_sync_state_with_parent	@52	NONAME
-gst_event_copy_segment	@53	NONAME
-gst_event_get_seqnum	@54	NONAME
-gst_event_new_caps	@55	NONAME
-gst_event_new_custom	@56	NONAME
-gst_event_new_eos	@57	NONAME
-gst_event_new_flush_start	@58	NONAME
-gst_event_new_flush_stop	@59	NONAME
-gst_event_new_seek	@60	NONAME
-gst_event_new_segment	@61	NONAME
-gst_event_new_stream_start	@62	NONAME
-gst_event_parse_caps	@63	NONAME
-gst_event_parse_seek	@64	NONAME
-gst_event_set_group_id	@65	NONAME
-gst_event_set_seqnum	@66	NONAME
-gst_ghost_pad_new	@67	NONAME
-gst_init_check	@68	NONAME
-gst_iterator_free	@69	NONAME
-gst_iterator_next	@70	NONAME
-gst_iterator_resync	@71	NONAME
-gst_message_get_structure	@72	NONAME
-gst_message_new_application	@73	NONAME
-gst_message_new_error	@74	NONAME
-gst_message_parse_error	@75	NONAME
-gst_message_parse_info	@76	NONAME
-gst_message_parse_state_changed	@77	NONAME
-gst_message_parse_warning	@78	NONAME
-gst_mini_object_copy	@79	NONAME
-gst_mini_object_make_writable	@80	NONAME
-gst_mini_object_ref	@81	NONAME
-gst_mini_object_unref	@82	NONAME
-gst_object_get_type	@83	NONAME
-gst_object_ref	@84	NONAME
-gst_object_unref	@85	NONAME
-gst_pad_activate_mode	@86	NONAME
-gst_pad_add_probe	@87	NONAME
-gst_pad_create_stream_id	@88	NONAME
-gst_pad_event_default	@89	NONAME
-gst_pad_get_current_caps	@90	NONAME
-gst_pad_is_active	@91	NONAME
-gst_pad_is_linked	@92	NONAME
-gst_pad_link	@93	NONAME
-gst_pad_new_from_static_template	@94	NONAME
-gst_pad_new_from_template	@95	NONAME
-gst_pad_pause_task	@96	NONAME
-gst_pad_peer_query_convert	@97	NONAME
-gst_pad_peer_query_duration	@98	NONAME
-gst_pad_push	@99	NONAME
-gst_pad_push_event	@100	NONAME
-gst_pad_query_default	@101	NONAME
-gst_pad_remove_probe	@102	NONAME
-gst_pad_set_activate_function_full	@103	NONAME
-gst_pad_set_activatemode_function_full	@104	NONAME
-gst_pad_set_active	@105	NONAME
-gst_pad_set_chain_function_full	@106	NONAME
-gst_pad_set_event_function_full	@107	NONAME
-gst_pad_set_getrange_function_full	@108	NONAME
-gst_pad_set_query_function_full	@109	NONAME
-gst_pad_start_task	@110	NONAME
-gst_pad_stop_task	@111	NONAME
-gst_pad_use_fixed_caps	@112	NONAME
-gst_pipeline_get_bus	@113	NONAME
-gst_pipeline_get_type	@114	NONAME
-gst_pipeline_new	@115	NONAME
-gst_pipeline_set_clock	@116	NONAME
-gst_query_add_scheduling_mode	@117	NONAME
-gst_query_parse_duration	@118	NONAME
-gst_query_parse_position	@119	NONAME
-gst_query_parse_seeking	@120	NONAME
-gst_query_set_duration	@121	NONAME
-gst_query_set_position	@122	NONAME
-gst_query_set_scheduling	@123	NONAME
-gst_query_set_seeking	@124	NONAME
-gst_resource_error_quark	@125	NONAME
-gst_sample_get_buffer	@126	NONAME
-gst_sample_get_caps	@127	NONAME
-gst_sample_new	@128	NONAME
-gst_segment_copy_into	@129	NONAME
-gst_segment_init	@130	NONAME
-gst_segtrap_set_enabled	@131	NONAME
-gst_static_pad_template_get	@132	NONAME
-gst_stream_error_quark	@133	NONAME
-gst_structure_get_boolean	@134	NONAME
-gst_structure_get_clock_time	@135	NONAME
-gst_structure_get_fraction	@136	NONAME
-gst_structure_get_int	@137	NONAME
-gst_structure_get_name	@138	NONAME
-gst_structure_get_string	@139	NONAME
-gst_structure_get_value	@140	NONAME
-gst_structure_has_name	@141	NONAME
-gst_structure_new	@142	NONAME
-gst_structure_new_empty	@143	NONAME
-gst_structure_set	@144	NONAME
-gst_util_group_id_next	@145	NONAME
-gst_value_list_get_value	@146	NONAME
-gst_bin_recalculate_latency	@148	NONAME
+gst_bin_recalculate_latency	@12	NONAME
+gst_bin_remove	@13	NONAME
+gst_buffer_fill	@14	NONAME
+gst_buffer_get_size	@15	NONAME
+gst_buffer_map	@16	NONAME
+gst_buffer_new_allocate	@17	NONAME
+gst_buffer_new_wrapped_full	@18	NONAME
+gst_buffer_pool_acquire_buffer	@19	NONAME
+gst_buffer_pool_config_set_params	@20	NONAME
+gst_buffer_pool_get_config	@21	NONAME
+gst_buffer_pool_is_active	@22	NONAME
+gst_buffer_pool_new	@23	NONAME
+gst_buffer_pool_set_active	@24	NONAME
+gst_buffer_pool_set_config	@25	NONAME
+gst_buffer_resize	@26	NONAME
+gst_buffer_set_size	@27	NONAME
+gst_buffer_unmap	@28	NONAME
+gst_bus_create_watch	@29	NONAME
+gst_bus_post	@30	NONAME
+gst_caps_get_size	@31	NONAME
+gst_caps_get_structure	@32	NONAME
+gst_caps_new_simple	@33	NONAME
+gst_caps_set_simple	@34	NONAME
+gst_child_proxy_get_child_by_index	@35	NONAME
+gst_child_proxy_get_type	@36	NONAME
+gst_core_error_quark	@37	NONAME
+gst_element_add_pad	@38	NONAME
+gst_element_class_add_pad_template	@39	NONAME
+gst_element_class_get_pad_template	@40	NONAME
+gst_element_class_set_metadata	@41	NONAME
+gst_element_class_set_static_metadata	@42	NONAME
+gst_element_factory_make	@43	NONAME
+gst_element_get_factory	@44	NONAME
+gst_element_get_state	@45	NONAME
+gst_element_get_static_pad	@46	NONAME
+gst_element_get_type	@47	NONAME
+gst_element_link	@48	NONAME
+gst_element_link_many	@49	NONAME
+gst_element_message_full	@50	NONAME
+gst_element_no_more_pads	@51	NONAME
+gst_element_post_message	@52	NONAME
+gst_element_provide_clock	@53	NONAME
+gst_element_query_duration	@54	NONAME
+gst_element_query_position	@55	NONAME
+gst_element_register	@56	NONAME
+gst_element_remove_pad	@57	NONAME
+gst_element_seek	@58	NONAME
+gst_element_set_state	@59	NONAME
+gst_element_sync_state_with_parent	@60	NONAME
+gst_event_copy_segment	@61	NONAME
+gst_event_get_seqnum	@62	NONAME
+gst_event_new_caps	@63	NONAME
+gst_event_new_custom	@64	NONAME
+gst_event_new_eos	@65	NONAME
+gst_event_new_flush_start	@66	NONAME
+gst_event_new_flush_stop	@67	NONAME
+gst_event_new_seek	@68	NONAME
+gst_event_new_segment	@69	NONAME
+gst_event_new_stream_start	@70	NONAME
+gst_event_parse_caps	@71	NONAME
+gst_event_parse_seek	@72	NONAME
+gst_event_set_group_id	@73	NONAME
+gst_event_set_seqnum	@74	NONAME
+gst_ghost_pad_new	@75	NONAME
+gst_init_check	@76	NONAME
+gst_iterator_free	@77	NONAME
+gst_iterator_next	@78	NONAME
+gst_iterator_resync	@79	NONAME
+gst_message_get_structure	@80	NONAME
+gst_message_new_application	@81	NONAME
+gst_message_new_error	@82	NONAME
+gst_message_parse_error	@83	NONAME
+gst_message_parse_info	@84	NONAME
+gst_message_parse_state_changed	@85	NONAME
+gst_message_parse_warning	@86	NONAME
+gst_mini_object_copy	@87	NONAME
+gst_mini_object_make_writable	@88	NONAME
+gst_mini_object_ref	@89	NONAME
+gst_mini_object_unref	@90	NONAME
+gst_object_get_type	@91	NONAME
+gst_object_ref	@92	NONAME
+gst_object_unref	@93	NONAME
+gst_pad_activate_mode	@94	NONAME
+gst_pad_add_probe	@95	NONAME
+gst_pad_create_stream_id	@96	NONAME
+gst_pad_event_default	@97	NONAME
+gst_pad_get_current_caps	@98	NONAME
+gst_pad_is_active	@99	NONAME
+gst_pad_is_linked	@100	NONAME
+gst_pad_link	@101	NONAME
+gst_pad_new_from_static_template	@102	NONAME
+gst_pad_new_from_template	@103	NONAME
+gst_pad_pause_task	@104	NONAME
+gst_pad_peer_query_convert	@105	NONAME
+gst_pad_peer_query_duration	@106	NONAME
+gst_pad_push	@107	NONAME
+gst_pad_push_event	@108	NONAME
+gst_pad_query_default	@109	NONAME
+gst_pad_remove_probe	@110	NONAME
+gst_pad_set_activate_function_full	@111	NONAME
+gst_pad_set_activatemode_function_full	@112	NONAME
+gst_pad_set_active	@113	NONAME
+gst_pad_set_chain_function_full	@114	NONAME
+gst_pad_set_event_function_full	@115	NONAME
+gst_pad_set_getrange_function_full	@116	NONAME
+gst_pad_set_query_function_full	@117	NONAME
+gst_pad_start_task	@118	NONAME
+gst_pad_stop_task	@119	NONAME
+gst_pad_use_fixed_caps	@120	NONAME
+gst_pipeline_get_bus	@121	NONAME
+gst_pipeline_get_type	@122	NONAME
+gst_pipeline_new	@123	NONAME
+gst_pipeline_set_clock	@124	NONAME
+gst_query_add_scheduling_mode	@125	NONAME
+gst_query_parse_duration	@126	NONAME
+gst_query_parse_position	@127	NONAME
+gst_query_parse_seeking	@128	NONAME
+gst_query_set_duration	@129	NONAME
+gst_query_set_position	@130	NONAME
+gst_query_set_scheduling	@131	NONAME
+gst_query_set_seeking	@132	NONAME
+gst_resource_error_quark	@133	NONAME
+gst_sample_get_buffer	@134	NONAME
+gst_sample_get_caps	@135	NONAME
+gst_sample_new	@136	NONAME
+gst_segment_copy_into	@137	NONAME
+gst_segment_init	@138	NONAME
+gst_segtrap_set_enabled	@139	NONAME
+gst_static_pad_template_get	@140	NONAME
+gst_stream_error_quark	@141	NONAME
+gst_structure_get_boolean	@142	NONAME
+gst_structure_get_clock_time	@143	NONAME
+gst_structure_get_fraction	@144	NONAME
+gst_structure_get_int	@145	NONAME
+gst_structure_get_name	@146	NONAME
+gst_structure_get_string	@147	NONAME
+gst_structure_get_value	@148	NONAME
+gst_structure_has_name	@149	NONAME
+gst_structure_new	@150	NONAME
+gst_structure_new_empty	@151	NONAME
+gst_structure_set	@152	NONAME
+gst_util_group_id_next	@153	NONAME
+gst_value_list_get_value	@154	NONAME
diff --git a/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj b/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj
index 7b449ab60dc..e7f34c6337f 100644
--- a/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj
+++ b/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj
@@ -33,6 +33,7 @@
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">WIN32;_WINDOWS;_USRDLL;ENABLE_PULL_MODE=1;ENABLE_SOURCE_SEEKING=1;GSTREAMER_LITE;GST_REMOVE_DEPRECATED;GST_REMOVE_DISABLED;GST_DISABLE_GST_DEBUG;GST_DISABLE_LOADSAVE;G_DISABLE_DEPRECATED;G_DISABLE_ASSERT;G_DISABLE_CHECKS;_WINDLL;_MBCS;INITGUID;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <ClCompile Include="..\..\gstreamer\plugins\mfwrapper\mfwrapper.cpp" />
+    <ClCompile Include="..\..\gstreamer\plugins\mfwrapper\mfgstbuffer.cpp" />
     <ClCompile Include="..\..\gstreamer\plugins\progressbuffer\hlsprogressbuffer.c">
       <PreprocessorDefinitions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">WIN32;_WINDOWS;_USRDLL;ENABLE_PULL_MODE=1;ENABLE_SOURCE_SEEKING=1;GSTREAMER_LITE;GST_REMOVE_DEPRECATED;GST_REMOVE_DISABLED;GST_DISABLE_GST_DEBUG;GST_DISABLE_LOADSAVE;G_DISABLE_DEPRECATED;G_DISABLE_ASSERT;G_DISABLE_CHECKS;_WINDLL;_MBCS;INITGUID;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
@@ -44,6 +45,7 @@
     </ClCompile>
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="..\..\gstreamer\plugins\mfwrapper\mfgstbuffer.h" />
     <ClInclude Include="..\..\gstreamer\plugins\progressbuffer\cache.h" />
     <ClInclude Include="..\..\gstreamer\plugins\progressbuffer\hlsprogressbuffer.h" />
     <ClInclude Include="..\..\gstreamer\plugins\progressbuffer\progressbuffer.h" />
diff --git a/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj.filters b/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj.filters
index 605b89c5037..2dd011850c8 100644
--- a/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj.filters
+++ b/modules/javafx.media/src/main/native/vs_project/plugins/plugins.vcxproj.filters
@@ -46,6 +46,9 @@
     <ClCompile Include="..\..\gstreamer\plugins\mfwrapper\mfwrapper.cpp">
       <Filter>mfwrapper</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\gstreamer\plugins\mfwrapper\mfgstbuffer.cpp">
+      <Filter>mfwrapper</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\gstreamer\plugins\mfwrapper\mfwrapper.h">
@@ -64,6 +67,9 @@
       <Filter>dshowwrapper</Filter>
     </ClInclude>
     <ClInclude Include="..\..\gstreamer\plugins\fxplugins_common.h" />
+    <ClInclude Include="..\..\gstreamer\plugins\mfwrapper\mfgstbuffer.h">
+      <Filter>mfwrapper</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\gstreamer\plugins\progressbuffer\cache.h">