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">