[PATCH v2 3/3] winegstreamer: Reimplement the WAVE parser ontop of the wavparse plugin.

Zebediah Figura z.figura12 at gmail.com
Wed Sep 18 21:37:03 CDT 2019


Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
As might be implied by this patch, I also have patches to replace the AVI
splitter and the MPEG-1 splitter with avidemux and mpegaudioparse, respectively.

This of course means requiring GStreamer to decode all media files.

It is very rare for applications to try to use these filters directly; most
applications use autoplugging methods (Connect(), RenderFile(), etc.) Two
applications that do (in fact, the only two I am aware of) are Neocron 2 and
LEGO Drome Racers; both use the MPEG-1 stream splitter, and attempt to decode
audio and program streams respectively.

The benefits of these patches are the removal of a lot of old, very messy, and
not particularly well functioning parsing code from quartz. A further benefit of
moving the MPEG-1 splitter in specific is that it provides an easy way to add in
program stream support, on top of the mpegpsdemux plugin (as well as video
stream support on top of mpegvideoparse, though I sincerely doubt we'll ever
find an application that requires this).

All of the required plugins are in the "good" set, which as far as I'm aware has
full multiarch handling in all major Linux distributions. The mpegpsdemux and
mpegvideoparse elements are in the "bad" set, and some distributions still don't
fully support 32-bit or multiarch. That said, since we don't currently support
PS or video streams, it's not a regression from the current situation.

On MacOS, wineqtdecoder will still be used for most applications. Only those
very few which try to create the filters directly will suffer. Since it is also
possible to install GStreamer on MacOS, I don't see any blocking problem, but I
welcome those more familiar with Mac to point out problems that I overlooked.

 dlls/quartz/Makefile.in          |   3 +-
 dlls/quartz/main.c               |   1 -
 dlls/quartz/quartz_private.h     |   1 -
 dlls/quartz/quartz_strmif.idl    |   7 -
 dlls/quartz/regsvr.c             |  19 --
 dlls/quartz/tests/waveparser.c   |  13 +-
 dlls/quartz/waveparser.c         | 440 -------------------------------
 dlls/winegstreamer/gst_private.h |   1 +
 dlls/winegstreamer/gstdemux.c    | 109 ++++++++
 dlls/winegstreamer/main.c        |  50 ++++
 10 files changed, 173 insertions(+), 471 deletions(-)
 delete mode 100644 dlls/quartz/waveparser.c

diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in
index 3824efbfa98..7963e212fc5 100644
--- a/dlls/quartz/Makefile.in
+++ b/dlls/quartz/Makefile.in
@@ -23,8 +23,7 @@ C_SRCS = \
 	regsvr.c \
 	systemclock.c \
 	videorenderer.c \
-	vmr9.c \
-	waveparser.c
+	vmr9.c
 
 RC_SRCS = quartz.rc
 
diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c
index 2c7284de13b..115fc806fc7 100644
--- a/dlls/quartz/main.c
+++ b/dlls/quartz/main.c
@@ -80,7 +80,6 @@ static const struct object_creation_info object_creation[] =
     { &CLSID_AVIDec, AVIDec_create },
     { &CLSID_SystemClock, QUARTZ_CreateSystemClock },
     { &CLSID_ACMWrapper, ACMWrapper_create },
-    { &CLSID_WAVEParser, WAVEParser_create }
 };
 
 static HRESULT WINAPI DSCF_QueryInterface(IClassFactory *iface, REFIID riid, void **ppobj)
diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h
index 874b29f2b12..d43e445bd04 100644
--- a/dlls/quartz/quartz_private.h
+++ b/dlls/quartz/quartz_private.h
@@ -63,7 +63,6 @@ HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN
 HRESULT VideoRendererDefault_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN;
 HRESULT QUARTZ_CreateSystemClock(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN;
 HRESULT ACMWrapper_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN;
-HRESULT WAVEParser_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN;
 HRESULT VMR7Impl_create(IUnknown *pUnkOuter, LPVOID *ppv) DECLSPEC_HIDDEN;
 HRESULT VMR9Impl_create(IUnknown *pUnkOuter, LPVOID *ppv) DECLSPEC_HIDDEN;
 
diff --git a/dlls/quartz/quartz_strmif.idl b/dlls/quartz/quartz_strmif.idl
index ab1af89ac42..c84e3aea5cb 100644
--- a/dlls/quartz/quartz_strmif.idl
+++ b/dlls/quartz/quartz_strmif.idl
@@ -140,13 +140,6 @@ coclass VideoRendererDefault { interface IBaseFilter; }
 ]
 coclass ACMWrapper { interface IBaseFilter; }
 
-[
-    helpstring("Wave Parser"),
-    threading(both),
-    uuid(d51bd5a1-7548-11cf-a520-0080c77ef58a)
-]
-coclass WAVEParser { interface IBaseFilter; }
-
 [
     helpstring("Video Mixing Renderer"),
     threading(both),
diff --git a/dlls/quartz/regsvr.c b/dlls/quartz/regsvr.c
index 44b2f60d138..eebca1c00a6 100644
--- a/dlls/quartz/regsvr.c
+++ b/dlls/quartz/regsvr.c
@@ -354,25 +354,6 @@ static struct regsvr_filter const filter_list[] = {
 	    { 0xFFFFFFFF },
 	}
     },
-    {   &CLSID_WAVEParser,
-	&CLSID_LegacyAmFilterCategory,
-	{'W','a','v','e',' ','P','a','r','s','e','r',0},
-	0x400000,
-	{   {   0,
-		{   { &MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE },
-		    { &MEDIATYPE_Stream, &MEDIASUBTYPE_AU },
-		    { &MEDIATYPE_Stream, &MEDIASUBTYPE_AIFF },
-		    { NULL }
-		},
-	    },
-	    {   REG_PINFLAG_B_OUTPUT,
-		{   { &MEDIATYPE_Audio, &GUID_NULL },
-		    { NULL }
-		},
-	    },
-	    { 0xFFFFFFFF },
-	}
-    },
     { NULL }		/* list terminator */
 };
 
diff --git a/dlls/quartz/tests/waveparser.c b/dlls/quartz/tests/waveparser.c
index 4bfa17a9e5f..2e4cc914618 100644
--- a/dlls/quartz/tests/waveparser.c
+++ b/dlls/quartz/tests/waveparser.c
@@ -148,7 +148,7 @@ static void test_interfaces(void)
     check_interface(pin, &IID_IKsPropertySet, FALSE);
     check_interface(pin, &IID_IMemInputPin, FALSE);
     check_interface(pin, &IID_IMediaPosition, FALSE);
-    todo_wine check_interface(pin, &IID_IMediaSeeking, FALSE);
+    check_interface(pin, &IID_IMediaSeeking, FALSE);
 
     IPin_Release(pin);
 
@@ -157,6 +157,7 @@ static void test_interfaces(void)
     todo_wine check_interface(pin, &IID_IMediaPosition, TRUE);
     check_interface(pin, &IID_IMediaSeeking, TRUE);
     check_interface(pin, &IID_IPin, TRUE);
+    check_interface(pin, &IID_IQualityControl, TRUE);
     check_interface(pin, &IID_IUnknown, TRUE);
 
     check_interface(pin, &IID_IAsyncReader, FALSE);
@@ -762,8 +763,18 @@ static void test_enum_media_types(void)
 
 START_TEST(waveparser)
 {
+    IBaseFilter *filter;
+
     CoInitialize(NULL);
 
+    if (FAILED(CoCreateInstance(&CLSID_WAVEParser, NULL, CLSCTX_INPROC_SERVER,
+            &IID_IBaseFilter, (void **)&filter)))
+    {
+        skip("Failed to create WAVE parser.\n");
+        return;
+    }
+    IBaseFilter_Release(filter);
+
     test_interfaces();
     test_aggregation();
     test_enum_pins();
diff --git a/dlls/quartz/waveparser.c b/dlls/quartz/waveparser.c
deleted file mode 100644
index 43bfff060b5..00000000000
--- a/dlls/quartz/waveparser.c
+++ /dev/null
@@ -1,440 +0,0 @@
-/*
- * WAVE Parser Filter
- *
- * Copyright 2005 Christian Costa
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
-
-#include "quartz_private.h"
-#include "pin.h"
-
-#include "uuids.h"
-#include "aviriff.h"
-#include "vfwmsgs.h"
-#include "mmsystem.h"
-
-#include "wine/debug.h"
-
-#include <math.h>
-#include <assert.h>
-
-#include "parser.h"
-
-WINE_DEFAULT_DEBUG_CHANNEL(quartz);
-
-static const WCHAR outputW[] = {'o','u','t','p','u','t',0};
-
-typedef struct WAVEParserImpl
-{
-    ParserImpl Parser;
-    LONGLONG StartOfFile; /* in media time */
-    LONGLONG EndOfFile;
-    DWORD nAvgBytesPerSec;
-    DWORD nBlockAlign;
-} WAVEParserImpl;
-
-static inline WAVEParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface )
-{
-    return CONTAINING_RECORD(iface, WAVEParserImpl, Parser.sourceSeeking.IMediaSeeking_iface);
-}
-
-static inline WAVEParserImpl *impl_from_strmbase_filter(struct strmbase_filter *iface)
-{
-    return CONTAINING_RECORD(iface, WAVEParserImpl, Parser.filter);
-}
-
-static LONGLONG bytepos_to_duration(WAVEParserImpl *This, LONGLONG bytepos)
-{
-    LONGLONG duration = BYTES_FROM_MEDIATIME(bytepos - This->StartOfFile);
-    duration *= 10000000;
-    duration /= This->nAvgBytesPerSec;
-
-    return duration;
-}
-
-static LONGLONG duration_to_bytepos(WAVEParserImpl *This, LONGLONG duration)
-{
-    LONGLONG bytepos;
-
-    bytepos = This->nAvgBytesPerSec;
-    bytepos *= duration;
-    bytepos /= 10000000;
-    bytepos -= bytepos % This->nBlockAlign;
-    bytepos += BYTES_FROM_MEDIATIME(This->StartOfFile);
-
-    return MEDIATIME_FROM_BYTES(bytepos);
-}
-
-static HRESULT WAVEParser_Sample(LPVOID iface, IMediaSample * pSample, DWORD_PTR cookie)
-{
-    WAVEParserImpl *This = iface;
-    LPBYTE pbSrcStream = NULL;
-    ULONG cbSrcStream = 0;
-    REFERENCE_TIME tStart, tStop;
-    HRESULT hr;
-    IMediaSample *newsample = NULL;
-    Parser_OutputPin *pOutputPin;
-    PullPin *pin = This->Parser.pInputPin;
-
-    IMediaSample_GetPointer(pSample, &pbSrcStream);
-    hr = IMediaSample_GetTime(pSample, &tStart, &tStop);
-
-    cbSrcStream = IMediaSample_GetActualDataLength(pSample);
-
-    /* Flush occurring */
-    if (cbSrcStream == 0)
-    {
-        TRACE(".. Why do I need you?\n");
-        return S_OK;
-    }
-
-    pOutputPin = This->Parser.sources[0];
-
-    if (SUCCEEDED(hr))
-        hr = IMemAllocator_GetBuffer(pin->pAlloc, &newsample, NULL, NULL, 0);
-
-    if (SUCCEEDED(hr))
-    {
-        LONGLONG rtSampleStart = pin->rtNext;
-        /* Add 4 for the next header, which should hopefully work */
-        LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(IMediaSample_GetSize(newsample));
-
-        if (rtSampleStop > pin->rtStop)
-            rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
-
-        IMediaSample_SetTime(newsample, &rtSampleStart, &rtSampleStop);
-
-        pin->rtCurrent = pin->rtNext;
-        pin->rtNext = rtSampleStop;
-
-        IMediaSample_SetPreroll(newsample, FALSE);
-        IMediaSample_SetDiscontinuity(newsample, FALSE);
-        IMediaSample_SetSyncPoint(newsample, TRUE);
-
-        hr = IAsyncReader_Request(pin->pReader, newsample, 0);
-    }
-
-    if (SUCCEEDED(hr))
-    {
-        REFERENCE_TIME tAviStart, tAviStop;
-
-        IMediaSample_SetSyncPoint(pSample, TRUE);
-        pOutputPin->dwSamplesProcessed++;
-
-        tAviStart = bytepos_to_duration(This, tStart);
-        tAviStop = bytepos_to_duration(This, tStart + MEDIATIME_FROM_BYTES(IMediaSample_GetActualDataLength(pSample)));
-
-        IMediaSample_SetTime(pSample, &tAviStart, &tAviStop);
-
-        hr = BaseOutputPinImpl_Deliver(&pOutputPin->pin, pSample);
-        if (hr != S_OK && hr != S_FALSE && hr != VFW_E_WRONG_STATE)
-            ERR("Error sending sample (%x)\n", hr);
-        else if (hr != S_OK)
-            /* Unset progression if denied! */
-            This->Parser.pInputPin->rtCurrent = tStart;
-    }
-
-    if (tStop >= This->EndOfFile || (bytepos_to_duration(This, tStop) >= This->Parser.sourceSeeking.llStop) || hr == VFW_E_NOT_CONNECTED)
-    {
-        unsigned int i;
-
-        TRACE("End of file reached\n");
-
-        for (i = 0; i < This->Parser.cStreams; i++)
-        {
-            IPin* ppin;
-            HRESULT hr;
-
-            TRACE("Send End Of Stream to output pin %u\n", i);
-
-            hr = IPin_ConnectedTo(&This->Parser.sources[i]->pin.pin.IPin_iface, &ppin);
-            if (SUCCEEDED(hr))
-            {
-                hr = IPin_EndOfStream(ppin);
-                IPin_Release(ppin);
-            }
-            if (FAILED(hr))
-            {
-                ERR("%x\n", hr);
-                break;
-            }
-        }
-
-        /* Force the pullpin thread to stop */
-        hr = S_FALSE;
-    }
-
-    return hr;
-}
-
-static HRESULT WAVEParser_QueryAccept(LPVOID iface, const AM_MEDIA_TYPE * pmt)
-{
-    if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream))
-	return S_FALSE;
-    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_WAVE))
-        return S_OK;
-    if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_AU) || IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_AIFF))
-	FIXME("AU and AIFF files not supported yet!\n");
-    return S_FALSE;
-}
-
-static HRESULT WINAPI WAVEParserImpl_seek(IMediaSeeking *iface)
-{
-    WAVEParserImpl *This = impl_from_IMediaSeeking(iface);
-    PullPin *pPin = This->Parser.pInputPin;
-    LONGLONG newpos, curpos, endpos, bytepos;
-    IPin *peer;
-
-    newpos = This->Parser.sourceSeeking.llCurrent;
-    curpos = bytepos_to_duration(This, pPin->rtCurrent);
-    endpos = bytepos_to_duration(This, This->EndOfFile);
-    bytepos = duration_to_bytepos(This, newpos);
-
-    if (newpos > endpos)
-    {
-        WARN("Requesting position %s beyond end of stream %s\n",
-             wine_dbgstr_longlong(newpos), wine_dbgstr_longlong(endpos));
-        return E_INVALIDARG;
-    }
-
-    if (curpos/1000000 == newpos/1000000)
-    {
-        TRACE("Requesting position %s same as current position %s\n",
-              wine_dbgstr_longlong(newpos), wine_dbgstr_longlong(curpos));
-        return S_OK;
-    }
-
-    TRACE("Moving sound to %08u bytes!\n", (DWORD)BYTES_FROM_MEDIATIME(bytepos));
-
-    EnterCriticalSection(&pPin->thread_lock);
-    IPin_BeginFlush(&pPin->pin.IPin_iface);
-
-    /* Make sure this is done while stopped, BeginFlush takes care of this */
-    EnterCriticalSection(&This->Parser.filter.csFilter);
-
-    if ((peer = This->Parser.sources[0]->pin.pin.pConnectedTo))
-        IPin_NewSegment(peer, newpos, endpos, pPin->dRate);
-
-    pPin->rtStart = pPin->rtCurrent = bytepos;
-    This->Parser.sources[0]->dwSamplesProcessed = 0;
-    LeaveCriticalSection(&This->Parser.filter.csFilter);
-
-    TRACE("Done flushing\n");
-    IPin_EndFlush(&pPin->pin.IPin_iface);
-    LeaveCriticalSection(&pPin->thread_lock);
-
-    return S_OK;
-}
-
-static HRESULT WAVEParser_InputPin_PreConnect(IPin * iface, IPin * pConnectPin, ALLOCATOR_PROPERTIES *props)
-{
-    PullPin *This = impl_PullPin_from_IPin(iface);
-    HRESULT hr;
-    RIFFLIST list;
-    RIFFCHUNK chunk;
-    LONGLONG pos = 0; /* in bytes */
-    AM_MEDIA_TYPE amt;
-    WAVEParserImpl *pWAVEParser = impl_from_strmbase_filter(This->pin.filter);
-
-    hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(list), (BYTE *)&list);
-    pos += sizeof(list);
-
-   if (list.fcc != FOURCC_RIFF)
-    {
-        ERR("Input stream not a RIFF file\n");
-        return E_FAIL;
-    }
-    if (list.cb > 1 * 1024 * 1024 * 1024) /* cannot be more than 1Gb in size */
-    {
-        ERR("Input stream violates RIFF spec\n");
-        return E_FAIL;
-    }
-    if (list.fccListType != mmioFOURCC('W','A','V','E'))
-    {
-        ERR("Input stream not an WAVE RIFF file\n");
-        return E_FAIL;
-    }
-
-    hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(chunk), (BYTE *)&chunk);
-    pos += sizeof(chunk);
-    if (chunk.fcc != mmioFOURCC('f','m','t',' '))
-    {
-        ERR("Expected 'fmt ' chunk, but got %.04s\n", (LPSTR)&chunk.fcc);
-        return E_FAIL;
-    }
-
-    amt.majortype = MEDIATYPE_Audio;
-    amt.formattype = FORMAT_WaveFormatEx;
-    amt.bFixedSizeSamples = TRUE;
-    amt.bTemporalCompression = FALSE;
-    amt.lSampleSize = 1;
-    amt.pUnk = NULL;
-    amt.cbFormat = max(chunk.cb, sizeof(WAVEFORMATEX));
-    amt.pbFormat = CoTaskMemAlloc(amt.cbFormat);
-    memset(amt.pbFormat, 0, amt.cbFormat);
-    IAsyncReader_SyncRead(This->pReader, pos, chunk.cb, amt.pbFormat);
-    amt.subtype = MEDIATYPE_Audio;
-    amt.subtype.Data1 = ((WAVEFORMATEX*)amt.pbFormat)->wFormatTag;
-
-    pos += chunk.cb;
-    hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(chunk), (BYTE *)&chunk);
-    while (chunk.fcc != mmioFOURCC('d','a','t','a'))
-    {
-        FIXME("Ignoring %s chunk.\n", debugstr_fourcc(chunk.fcc));
-        pos += sizeof(chunk) + chunk.cb;
-        hr = IAsyncReader_SyncRead(This->pReader, pos, sizeof(chunk), (BYTE *)&chunk);
-        if (hr != S_OK)
-            return E_FAIL;
-    }
-
-    pWAVEParser->StartOfFile = MEDIATIME_FROM_BYTES(pos + sizeof(RIFFCHUNK));
-    pWAVEParser->EndOfFile = MEDIATIME_FROM_BYTES(pos + chunk.cb + sizeof(RIFFCHUNK));
-
-    props->cbAlign = ((WAVEFORMATEX*)amt.pbFormat)->nBlockAlign;
-    props->cbPrefix = 0;
-    props->cbBuffer = 4096;
-    props->cBuffers = 3;
-    pWAVEParser->nBlockAlign = ((WAVEFORMATEX*)amt.pbFormat)->nBlockAlign;
-    pWAVEParser->nAvgBytesPerSec = ((WAVEFORMATEX*)amt.pbFormat)->nAvgBytesPerSec;
-    hr = Parser_AddPin(&pWAVEParser->Parser, outputW, props, &amt);
-    CoTaskMemFree(amt.pbFormat);
-
-    pWAVEParser->Parser.sourceSeeking.llCurrent = 0;
-    pWAVEParser->Parser.sourceSeeking.llStop = pWAVEParser->Parser.sourceSeeking.llDuration = bytepos_to_duration(pWAVEParser, pWAVEParser->EndOfFile);
-    TRACE("Duration: %u seconds\n", (DWORD)(pWAVEParser->Parser.sourceSeeking.llDuration / (LONGLONG)10000000));
-
-    This->rtStop = pWAVEParser->EndOfFile;
-    This->rtStart = pWAVEParser->StartOfFile;
-
-    TRACE("WAVE File ok\n");
-
-    return hr;
-}
-
-static HRESULT WAVEParser_Cleanup(LPVOID iface)
-{
-    WAVEParserImpl *This = iface;
-
-    TRACE("(%p)->()\n", This);
-
-    return S_OK;
-}
-
-static HRESULT WAVEParser_first_request(LPVOID iface)
-{
-    WAVEParserImpl *This = iface;
-    PullPin *pin = This->Parser.pInputPin;
-    HRESULT hr;
-    IMediaSample *sample;
-
-    if (pin->rtCurrent >= pin->rtStop)
-    {
-        /* Last sample has already been queued, request nothing more */
-        TRACE("Done!\n");
-        return S_OK;
-    }
-
-    hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0);
-
-    pin->rtNext = pin->rtCurrent;
-    if (SUCCEEDED(hr))
-    {
-        LONGLONG rtSampleStart = pin->rtNext;
-        /* Add 4 for the next header, which should hopefully work */
-        LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(IMediaSample_GetSize(sample));
-
-        if (rtSampleStop > pin->rtStop)
-            rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign));
-
-        IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop);
-
-        pin->rtCurrent = pin->rtNext;
-        pin->rtNext = rtSampleStop;
-
-        IMediaSample_SetPreroll(sample, FALSE);
-        if (!This->Parser.sources[0]->dwSamplesProcessed++)
-            IMediaSample_SetDiscontinuity(sample, TRUE);
-        else
-            IMediaSample_SetDiscontinuity(sample, FALSE);
-
-        hr = IAsyncReader_Request(pin->pReader, sample, 0);
-    }
-    if (FAILED(hr))
-        ERR("Horsemen of the apocalypse came to bring error 0x%08x %p\n", hr, sample);
-
-    return hr;
-}
-
-static HRESULT WAVEParser_disconnect(LPVOID iface)
-{
-    /* TODO: Find and plug memory leaks */
-    return S_OK;
-}
-
-static const IBaseFilterVtbl WAVEParser_Vtbl =
-{
-    BaseFilterImpl_QueryInterface,
-    BaseFilterImpl_AddRef,
-    BaseFilterImpl_Release,
-    BaseFilterImpl_GetClassID,
-    Parser_Stop,
-    Parser_Pause,
-    Parser_Run,
-    Parser_GetState,
-    Parser_SetSyncSource,
-    BaseFilterImpl_GetSyncSource,
-    BaseFilterImpl_EnumPins,
-    BaseFilterImpl_FindPin,
-    BaseFilterImpl_QueryFilterInfo,
-    BaseFilterImpl_JoinFilterGraph,
-    BaseFilterImpl_QueryVendorInfo,
-};
-
-static void wave_parser_destroy(struct strmbase_filter *iface)
-{
-    WAVEParserImpl *filter = impl_from_strmbase_filter(iface);
-    Parser_Destroy(&filter->Parser);
-}
-
-static const struct strmbase_filter_ops filter_ops =
-{
-    .filter_get_pin = parser_get_pin,
-    .filter_destroy = wave_parser_destroy,
-};
-
-HRESULT WAVEParser_create(IUnknown *outer, void **out)
-{
-    static const WCHAR sink_name[] = {'i','n','p','u','t',' ','p','i','n',0};
-    HRESULT hr;
-    WAVEParserImpl * This;
-
-    *out = NULL;
-
-    /* Note: This memory is managed by the transform filter once created */
-    This = CoTaskMemAlloc(sizeof(WAVEParserImpl));
-
-    hr = Parser_Create(&This->Parser, &WAVEParser_Vtbl, outer, &CLSID_WAVEParser,
-            &filter_ops, sink_name, WAVEParser_Sample, WAVEParser_QueryAccept,
-            WAVEParser_InputPin_PreConnect, WAVEParser_Cleanup, WAVEParser_disconnect,
-            WAVEParser_first_request, NULL, NULL, WAVEParserImpl_seek, NULL);
-
-    if (FAILED(hr))
-        return hr;
-
-    *out = &This->Parser.filter.IUnknown_inner;
-
-    return hr;
-}
diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h
index 18d6eb8a8e8..392cfa849d3 100644
--- a/dlls/winegstreamer/gst_private.h
+++ b/dlls/winegstreamer/gst_private.h
@@ -43,6 +43,7 @@ IUnknown * CALLBACK Gstreamer_Mp3_create(IUnknown *pUnkOuter, HRESULT *phr);
 IUnknown * CALLBACK Gstreamer_YUV2RGB_create(IUnknown *pUnkOuter, HRESULT *phr);
 IUnknown * CALLBACK Gstreamer_YUV2ARGB_create(IUnknown *pUnkOuter, HRESULT *phr);
 IUnknown * CALLBACK Gstreamer_Splitter_create(IUnknown *pUnkOuter, HRESULT *phr);
+IUnknown * CALLBACK wave_parser_create(IUnknown *outer, HRESULT *phr) DECLSPEC_HIDDEN;
 
 BOOL init_gstreamer(void) DECLSPEC_HIDDEN;
 
diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c
index 87a1deb6f90..1b4857a2a18 100644
--- a/dlls/winegstreamer/gstdemux.c
+++ b/dlls/winegstreamer/gstdemux.c
@@ -2172,3 +2172,112 @@ void start_dispatch_thread(void)
     pthread_key_create(&wine_gst_key, NULL);
     CloseHandle(CreateThread(NULL, 0, &dispatch_thread, NULL, 0, NULL));
 }
+
+static HRESULT WINAPI wave_parser_sink_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE *mt)
+{
+    if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream))
+        return S_FALSE;
+    if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_WAVE))
+        return S_OK;
+    if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_AU) || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_AIFF))
+        FIXME("AU and AIFF files are not yet supported.\n");
+    return S_FALSE;
+}
+
+static const BasePinFuncTable wave_parser_sink_ops =
+{
+    .pfnCheckMediaType = wave_parser_sink_CheckMediaType,
+    .pfnGetMediaType = BasePinImpl_GetMediaType,
+};
+
+static BOOL wave_parser_init_gst(struct gstdemux *filter)
+{
+    static const WCHAR source_name[] = {'o','u','t','p','u','t',0};
+    struct gstdemux_source *pin;
+    GstElement *element;
+    LONGLONG duration;
+    int ret;
+
+    if (!(element = gst_element_factory_make("wavparse", NULL)))
+    {
+        ERR("Failed to create wavparse; are %u-bit GStreamer \"good\" plugins installed?\n",
+                8 * (int)sizeof(void*));
+        return FALSE;
+    }
+
+    gst_bin_add(GST_BIN(filter->container), element);
+
+    filter->their_sink = gst_element_get_static_pad(element, "sink");
+    if ((ret = gst_pad_link(filter->my_src, filter->their_sink)) < 0)
+    {
+        ERR("Failed to link sink pads, error %d.\n", ret);
+        return FALSE;
+    }
+
+    if (!(pin = create_pin(filter, source_name)))
+        return FALSE;
+    pin->their_src = gst_element_get_static_pad(element, "src");
+    gst_object_ref(pin->their_src);
+    if ((ret = gst_pad_link(pin->their_src, pin->my_sink)) < 0)
+    {
+        ERR("Failed to link source pads, error %d.\n", ret);
+        return FALSE;
+    }
+
+    gst_pad_set_active(pin->my_sink, 1);
+    gst_element_set_state(filter->container, GST_STATE_PAUSED);
+    ret = gst_element_get_state(filter->container, NULL, NULL, -1);
+    if (ret == GST_STATE_CHANGE_FAILURE)
+    {
+        ERR("Failed to play stream.\n");
+        return FALSE;
+    }
+
+    gst_pad_query_duration(pin->their_src, GST_FORMAT_TIME, &duration);
+    pin->seek.llDuration = pin->seek.llStop = duration / 100;
+    pin->seek.llCurrent = 0;
+    if (!pin->seek.llDuration)
+        pin->seek.dwCapabilities = 0;
+
+    WaitForSingleObject(pin->caps_event, INFINITE);
+
+    filter->ignore_flush = TRUE;
+    gst_element_set_state(filter->container, GST_STATE_READY);
+    gst_element_get_state(filter->container, NULL, NULL, -1);
+    filter->ignore_flush = FALSE;
+
+    return TRUE;
+}
+
+IUnknown * CALLBACK wave_parser_create(IUnknown *outer, HRESULT *phr)
+{
+    static const WCHAR sink_name[] = {'i','n','p','u','t',' ','p','i','n',0};
+    struct gstdemux *object;
+
+    if (!init_gstreamer())
+    {
+        *phr = E_FAIL;
+        return NULL;
+    }
+
+    mark_wine_thread();
+
+    if (!(object = heap_alloc_zero(sizeof(*object))))
+    {
+        *phr = E_OUTOFMEMORY;
+        return NULL;
+    }
+
+    strmbase_filter_init(&object->filter, &GST_Vtbl, outer, &CLSID_WAVEParser, &filter_ops);
+
+    object->sink.dir = PINDIR_INPUT;
+    object->sink.filter = &object->filter;
+    lstrcpynW(object->sink.name, sink_name, ARRAY_SIZE(object->sink.name));
+    object->sink.IPin_iface.lpVtbl = &GST_InputPin_Vtbl;
+    object->sink.pFuncsTable = &wave_parser_sink_ops;
+    object->init_gst = wave_parser_init_gst;
+    *phr = S_OK;
+
+    TRACE("Created WAVE parser %p.\n", object);
+    return &object->filter.IUnknown_inner;
+}
diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c
index 4419a6fde54..8503f9c7aba 100644
--- a/dlls/winegstreamer/main.c
+++ b/dlls/winegstreamer/main.c
@@ -46,6 +46,8 @@ static const WCHAR wGstreamer_Mp3[] =
 {'G','S','t','r','e','a','m','e','r',' ','M','p','3',' ','f','i','l','t','e','r',0};
 static const WCHAR wGstreamer_AudioConvert[] =
 {'G','S','t','r','e','a','m','e','r',' ','A','u','d','i','o','C','o','n','v','e','r','t',' ','f','i','l','t','e','r',0};
+static const WCHAR wave_parserW[] =
+{'W','a','v','e',' ','P','a','r','s','e','r',0};
 
 static WCHAR wNull[] = {'\0'};
 
@@ -180,6 +182,47 @@ AMOVIESETUP_FILTER const amfAudioConvert =
     amfAudioConvertPin
 };
 
+static const AMOVIESETUP_MEDIATYPE wave_parser_sink_type_data[] =
+{
+    {&MEDIATYPE_Stream, &MEDIASUBTYPE_WAVE},
+    {&MEDIATYPE_Stream, &MEDIASUBTYPE_AU},
+    {&MEDIATYPE_Stream, &MEDIASUBTYPE_AIFF},
+};
+
+static const AMOVIESETUP_MEDIATYPE wave_parser_source_type_data[] =
+{
+    {&MEDIATYPE_Audio, &GUID_NULL},
+};
+
+static const AMOVIESETUP_PIN wave_parser_pin_data[] =
+{
+    {
+        NULL,
+        FALSE, FALSE, FALSE, FALSE,
+        &GUID_NULL,
+        NULL,
+        ARRAY_SIZE(wave_parser_sink_type_data),
+        wave_parser_sink_type_data,
+    },
+    {
+        NULL,
+        FALSE, FALSE, FALSE, FALSE,
+        &GUID_NULL,
+        NULL,
+        ARRAY_SIZE(wave_parser_source_type_data),
+        wave_parser_source_type_data,
+    },
+};
+
+static const AMOVIESETUP_FILTER wave_parser_filter_data =
+{
+    &CLSID_WAVEParser,
+    wave_parserW,
+    MERIT_UNLIKELY,
+    ARRAY_SIZE(wave_parser_pin_data),
+    wave_parser_pin_data,
+};
+
 FactoryTemplate const g_Templates[] = {
     {
         wGstreamer_Splitter,
@@ -216,6 +259,13 @@ FactoryTemplate const g_Templates[] = {
         NULL,
         &amfAudioConvert,
     },
+    {
+        wave_parserW,
+        &CLSID_WAVEParser,
+        wave_parser_create,
+        NULL,
+        &wave_parser_filter_data,
+    },
 };
 
 const int g_cTemplates = ARRAY_SIZE(g_Templates);
-- 
2.23.0




More information about the wine-devel mailing list