Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/Makefile.in | 1 - dlls/quartz/main.c | 1 - dlls/quartz/mpegsplit.c | 890 ------------------------------- dlls/quartz/quartz_private.h | 1 - dlls/quartz/quartz_strmif.idl | 7 - dlls/quartz/regsvr.c | 27 - dlls/quartz/tests/mpegsplit.c | 14 +- dlls/winegstreamer/gst_private.h | 1 + dlls/winegstreamer/gstdemux.c | 292 +++++++++- dlls/winegstreamer/main.c | 66 +++ 10 files changed, 359 insertions(+), 941 deletions(-) delete mode 100644 dlls/quartz/mpegsplit.c
diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index 689783e98c6..e33c4e58b99 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -16,7 +16,6 @@ C_SRCS = \ filtermapper.c \ main.c \ memallocator.c \ - mpegsplit.c \ parser.c \ pin.c \ regsvr.c \ diff --git a/dlls/quartz/main.c b/dlls/quartz/main.c index fbb124a4a63..36ec59c4e03 100644 --- a/dlls/quartz/main.c +++ b/dlls/quartz/main.c @@ -69,7 +69,6 @@ static const struct object_creation_info object_creation[] = { &CLSID_FilterMapper2, FilterMapper2_create }, { &CLSID_AsyncReader, AsyncReader_create }, { &CLSID_MemoryAllocator, StdMemAllocator_create }, - { &CLSID_MPEG1Splitter, MPEGSplitter_create }, { &CLSID_VideoRenderer, VideoRenderer_create }, { &CLSID_VideoMixingRenderer, VMR7Impl_create }, { &CLSID_VideoMixingRenderer9, VMR9Impl_create }, diff --git a/dlls/quartz/mpegsplit.c b/dlls/quartz/mpegsplit.c deleted file mode 100644 index a34344cd3a3..00000000000 --- a/dlls/quartz/mpegsplit.c +++ /dev/null @@ -1,890 +0,0 @@ -/* - * MPEG Splitter Filter - * - * Copyright 2003 Robert Shearman - * Copyright 2004-2005 Christian Costa - * Copyright 2007 Chris Robinson - * Copyright 2008 Maarten Lankhorst - * - * 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 <assert.h> -#include <math.h> - -#include "quartz_private.h" -#include "pin.h" - -#include "uuids.h" -#include "mmreg.h" -#include "mmsystem.h" - -#include "winternl.h" - -#include "wine/debug.h" - -#include "parser.h" - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -#define SEQUENCE_HEADER_CODE 0xB3 -#define PACK_START_CODE 0xBA - -#define SYSTEM_START_CODE 0xBB -#define AUDIO_ELEMENTARY_STREAM 0xC0 -#define VIDEO_ELEMENTARY_STREAM 0xE0 - -#define MPEG_SYSTEM_HEADER 3 -#define MPEG_VIDEO_HEADER 2 -#define MPEG_AUDIO_HEADER 1 -#define MPEG_NO_HEADER 0 - -typedef struct MPEGSplitterImpl -{ - ParserImpl Parser; - IAMStreamSelect IAMStreamSelect_iface; - LONGLONG EndOfFile; - LONGLONG position; - DWORD begin_offset; - BYTE header[4]; - - /* Whether we just seeked (or started playing) */ - BOOL seek; -} MPEGSplitterImpl; - -static inline MPEGSplitterImpl *impl_from_IBaseFilter( IBaseFilter *iface ) -{ - return CONTAINING_RECORD(iface, MPEGSplitterImpl, Parser.filter.IBaseFilter_iface); -} - -static inline MPEGSplitterImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) -{ - return CONTAINING_RECORD(iface, MPEGSplitterImpl, Parser.sourceSeeking.IMediaSeeking_iface); -} - -static inline MPEGSplitterImpl *impl_from_IAMStreamSelect( IAMStreamSelect *iface ) -{ - return CONTAINING_RECORD(iface, MPEGSplitterImpl, IAMStreamSelect_iface); -} - -static int MPEGSplitter_head_check(const BYTE *header) -{ - /* If this is a possible start code, check for a system or video header */ - if (header[0] == 0 && header[1] == 0 && header[2] == 1) - { - /* Check if we got a system or elementary stream start code */ - if (header[3] == PACK_START_CODE || - header[3] == VIDEO_ELEMENTARY_STREAM || - header[3] == AUDIO_ELEMENTARY_STREAM) - return MPEG_SYSTEM_HEADER; - - /* Check for a MPEG video sequence start code */ - if (header[3] == SEQUENCE_HEADER_CODE) - return MPEG_VIDEO_HEADER; - } - - /* This should give a good guess if we have an MPEG audio header */ - if(header[0] == 0xff && ((header[1]>>5)&0x7) == 0x7 && - ((header[1]>>1)&0x3) != 0 && ((header[2]>>4)&0xf) != 0xf && - ((header[2]>>2)&0x3) != 0x3) - return MPEG_AUDIO_HEADER; - - /* Nothing yet.. */ - return MPEG_NO_HEADER; -} - -static const WCHAR wszAudioStream[] = {'A','u','d','i','o',0}; - -static const DWORD freqs[10] = { 44100, 48000, 32000, 22050, 24000, 16000, 11025, 12000, 8000, 0 }; - -static const DWORD tabsel_123[2][3][16] = { - { {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,}, - {0,32,48,56, 64, 80, 96,112,128,160,192,224,256,320,384,}, - {0,32,40,48, 56, 64, 80, 96,112,128,160,192,224,256,320,} }, - - { {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,}, - {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,}, - {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,} } -}; - -static HRESULT parse_header(BYTE *header, LONGLONG *plen, LONGLONG *pduration) -{ - int bitrate_index, freq_index, lsf = 1, mpeg1, layer, padding, bitrate, length; - LONGLONG duration; - - if (MPEGSplitter_head_check(header) != MPEG_AUDIO_HEADER) - { - FIXME("Not a valid header: %02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3]); - return E_INVALIDARG; - } - - mpeg1 = (header[1]>>4)&0x1; - if (mpeg1) - lsf = ((header[1]>>3)&0x1)^1; - - layer = 4-((header[1]>>1)&0x3); - bitrate_index = ((header[2]>>4)&0xf); - freq_index = ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6); - padding = ((header[2]>>1)&0x1); - - bitrate = tabsel_123[lsf][layer-1][bitrate_index] * 1000; - if (!bitrate) - { - FIXME("Not a valid header: %02x:%02x:%02x:%02x\n", header[0], header[1], header[2], header[3]); - return E_INVALIDARG; - } - - if (layer == 1) - length = 4 * (12 * bitrate / freqs[freq_index] + padding); - else if (layer == 2) - length = 144 * bitrate / freqs[freq_index] + padding; - else if (layer == 3) - length = 144 * bitrate / (freqs[freq_index]<<lsf) + padding; - else - { - ERR("Impossible layer %d\n", layer); - return E_INVALIDARG; - } - - duration = (ULONGLONG)10000000 * (ULONGLONG)(length) / (ULONGLONG)(bitrate/8); - *plen = length; - if (pduration) - *pduration += duration; - return S_OK; -} - -static HRESULT FillBuffer(MPEGSplitterImpl *This, IMediaSample *pCurrentSample) -{ - Parser_OutputPin *pOutputPin = This->Parser.sources[0]; - LONGLONG length = 0; - LONGLONG pos = BYTES_FROM_MEDIATIME(This->Parser.pInputPin->rtNext); - LONGLONG time = This->position, rtstop, rtstart; - HRESULT hr; - BYTE *fbuf = NULL; - DWORD len = IMediaSample_GetActualDataLength(pCurrentSample); - - TRACE("Source length: %u\n", len); - IMediaSample_GetPointer(pCurrentSample, &fbuf); - - /* Find the next valid header.. it <SHOULD> be right here */ - hr = parse_header(fbuf, &length, &This->position); - assert(hr == S_OK); - IMediaSample_SetActualDataLength(pCurrentSample, length); - - /* Queue the next sample */ - if (length + 4 == len) - { - PullPin *pin = This->Parser.pInputPin; - LONGLONG stop = BYTES_FROM_MEDIATIME(pin->rtStop); - - hr = S_OK; - memcpy(This->header, fbuf + length, 4); - while (FAILED(hr = parse_header(This->header, &length, NULL))) - { - memmove(This->header, This->header+1, 3); - if (pos + 4 >= stop) - break; - IAsyncReader_SyncRead(pin->pReader, ++pos, 1, This->header + 3); - } - pin->rtNext = MEDIATIME_FROM_BYTES(pos); - - if (SUCCEEDED(hr)) - { - /* Remove 4 for the last header, which should hopefully work */ - IMediaSample *sample = NULL; - LONGLONG rtSampleStart = pin->rtNext - MEDIATIME_FROM_BYTES(4); - LONGLONG rtSampleStop = rtSampleStart + MEDIATIME_FROM_BYTES(length + 4); - - if (rtSampleStop > pin->rtStop) - rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign)); - - hr = IMemAllocator_GetBuffer(pin->pAlloc, &sample, NULL, NULL, 0); - if (SUCCEEDED(hr)) - { - IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop); - IMediaSample_SetPreroll(sample, FALSE); - IMediaSample_SetDiscontinuity(sample, FALSE); - IMediaSample_SetSyncPoint(sample, TRUE); - hr = IAsyncReader_Request(pin->pReader, sample, 0); - if (SUCCEEDED(hr)) - { - pin->rtCurrent = rtSampleStart; - pin->rtNext = rtSampleStop; - } - else - IMediaSample_Release(sample); - } - if (FAILED(hr)) - FIXME("o_Ox%08x\n", hr); - } - } - /* If not, we're presumably at the end of file */ - - TRACE("Media time : %u.%03u\n", (DWORD)(This->position/10000000), (DWORD)((This->position/10000)%1000)); - - if (IMediaSample_IsDiscontinuity(pCurrentSample) == S_OK) { - IPin *victim; - EnterCriticalSection(&This->Parser.filter.csFilter); - pOutputPin->pin.pin.tStart = time; - pOutputPin->pin.pin.dRate = This->Parser.sourceSeeking.dRate; - hr = IPin_ConnectedTo(&pOutputPin->pin.pin.IPin_iface, &victim); - if (hr == S_OK) - { - hr = IPin_NewSegment(victim, time, This->Parser.sourceSeeking.llStop, - This->Parser.sourceSeeking.dRate); - if (hr != S_OK) - FIXME("NewSegment returns %08x\n", hr); - IPin_Release(victim); - } - LeaveCriticalSection(&This->Parser.filter.csFilter); - if (hr != S_OK) - return hr; - } - rtstart = (double)(time - pOutputPin->pin.pin.tStart) / pOutputPin->pin.pin.dRate; - rtstop = (double)(This->position - pOutputPin->pin.pin.tStart) / pOutputPin->pin.pin.dRate; - IMediaSample_SetTime(pCurrentSample, &rtstart, &rtstop); - IMediaSample_SetMediaTime(pCurrentSample, &time, &This->position); - - hr = BaseOutputPinImpl_Deliver(&pOutputPin->pin, pCurrentSample); - - if (hr != S_OK) - { - if (hr != S_FALSE) - TRACE("Error sending sample (%x)\n", hr); - else - TRACE("S_FALSE (%d), holding\n", IMediaSample_GetActualDataLength(pCurrentSample)); - } - - return hr; -} - - -static HRESULT MPEGSplitter_process_sample(LPVOID iface, IMediaSample * pSample, DWORD_PTR cookie) -{ - MPEGSplitterImpl *This = iface; - BYTE *pbSrcStream; - DWORD cbSrcStream = 0; - REFERENCE_TIME tStart, tStop, tAviStart = This->position; - HRESULT hr; - - hr = IMediaSample_GetTime(pSample, &tStart, &tStop); - if (SUCCEEDED(hr)) - { - cbSrcStream = IMediaSample_GetActualDataLength(pSample); - hr = IMediaSample_GetPointer(pSample, &pbSrcStream); - } - - /* Flush occurring */ - if (cbSrcStream == 0) - { - FIXME(".. Why do I need you?\n"); - return S_OK; - } - - /* trace removed for performance reasons */ - /* TRACE("(%p), %llu -> %llu\n", pSample, tStart, tStop); */ - - /* Now, try to find a new header */ - hr = FillBuffer(This, pSample); - if (hr != S_OK) - { - WARN("Failed with hres: %08x!\n", hr); - - /* Unset progression if denied! */ - if (hr == VFW_E_WRONG_STATE || hr == S_FALSE) - { - memcpy(This->header, pbSrcStream, 4); - This->Parser.pInputPin->rtCurrent = tStart; - This->position = tAviStart; - } - } - - if (BYTES_FROM_MEDIATIME(tStop) >= This->EndOfFile || This->position >= This->Parser.sourceSeeking.llStop) - { - unsigned int i; - - TRACE("End of file reached\n"); - - for (i = 0; i < This->Parser.cStreams; i++) - { - IPin *peer; - - if ((peer = This->Parser.sources[i]->pin.pin.pConnectedTo)) - hr = IPin_EndOfStream(peer); - if (FAILED(hr)) - WARN("Error sending EndOfStream to pin %u (%x)\n", i, hr); - } - - /* Force the pullpin thread to stop */ - hr = S_FALSE; - } - - return hr; -} - - -static HRESULT MPEGSplitter_query_accept(LPVOID iface, const AM_MEDIA_TYPE *pmt) -{ - if (!IsEqualIID(&pmt->majortype, &MEDIATYPE_Stream)) - return S_FALSE; - - if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Audio)) - return S_OK; - - if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1Video)) - FIXME("MPEG-1 video streams not yet supported.\n"); - else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1System)) - FIXME("MPEG-1 system streams not yet supported.\n"); - else if (IsEqualIID(&pmt->subtype, &MEDIASUBTYPE_MPEG1VideoCD)) - FIXME("MPEG-1 VideoCD streams not yet supported.\n"); - else FIXME("%s\n", debugstr_guid(&pmt->subtype)); - - return S_FALSE; -} - - -static HRESULT MPEGSplitter_init_audio(MPEGSplitterImpl *This, const BYTE *header, AM_MEDIA_TYPE *pamt) -{ - WAVEFORMATEX *format; - int bitrate_index; - int freq_index; - int mode_ext; - int emphasis; - int padding; - int lsf = 1; - int mpeg1; - int layer; - int mode; - - ZeroMemory(pamt, sizeof(*pamt)); - - pamt->formattype = FORMAT_WaveFormatEx; - pamt->majortype = MEDIATYPE_Audio; - pamt->subtype = MEDIASUBTYPE_MPEG1AudioPayload; - - pamt->lSampleSize = 0; - pamt->bFixedSizeSamples = FALSE; - pamt->bTemporalCompression = 0; - - mpeg1 = (header[1]>>4)&0x1; - if (mpeg1) - lsf = ((header[1]>>3)&0x1)^1; - - layer = 4-((header[1]>>1)&0x3); - bitrate_index = ((header[2]>>4)&0xf); - padding = ((header[2]>>1)&0x1); - freq_index = ((header[2]>>2)&0x3) + (mpeg1?(lsf*3):6); - mode = ((header[3]>>6)&0x3); - mode_ext = ((header[3]>>4)&0x3); - emphasis = ((header[3]>>0)&0x3); - - if (!bitrate_index) - { - /* Set to highest bitrate so samples will fit in for sure */ - FIXME("Variable-bitrate audio not fully supported.\n"); - bitrate_index = 15; - } - - pamt->cbFormat = ((layer==3)? sizeof(MPEGLAYER3WAVEFORMAT) : - sizeof(MPEG1WAVEFORMAT)); - pamt->pbFormat = CoTaskMemAlloc(pamt->cbFormat); - if (!pamt->pbFormat) - return E_OUTOFMEMORY; - ZeroMemory(pamt->pbFormat, pamt->cbFormat); - format = (WAVEFORMATEX*)pamt->pbFormat; - - format->wFormatTag = ((layer == 3) ? WAVE_FORMAT_MPEGLAYER3 : - WAVE_FORMAT_MPEG); - format->nChannels = ((mode == 3) ? 1 : 2); - format->nSamplesPerSec = freqs[freq_index]; - format->nAvgBytesPerSec = tabsel_123[lsf][layer-1][bitrate_index] * 1000 / 8; - - if (layer == 3) - format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 / - (format->nSamplesPerSec<<lsf) + padding; - else if (layer == 2) - format->nBlockAlign = format->nAvgBytesPerSec * 8 * 144 / - format->nSamplesPerSec + padding; - else - format->nBlockAlign = 4 * (format->nAvgBytesPerSec * 8 * 12 / format->nSamplesPerSec + padding); - - format->wBitsPerSample = 0; - - if (layer == 3) - { - MPEGLAYER3WAVEFORMAT *mp3format = (MPEGLAYER3WAVEFORMAT*)format; - - format->cbSize = MPEGLAYER3_WFX_EXTRA_BYTES; - - mp3format->wID = MPEGLAYER3_ID_MPEG; - mp3format->fdwFlags = MPEGLAYER3_FLAG_PADDING_ON; - mp3format->nBlockSize = format->nBlockAlign; - mp3format->nFramesPerBlock = 1; - - /* Beware the evil magic numbers. This struct is apparently horribly - * under-documented, and the only references I could find had it being - * set to this with no real explanation. It works fine though, so I'm - * not complaining (yet). - */ - mp3format->nCodecDelay = 1393; - } - else - { - MPEG1WAVEFORMAT *mpgformat = (MPEG1WAVEFORMAT*)format; - - format->cbSize = 22; - - mpgformat->fwHeadLayer = ((layer == 1) ? ACM_MPEG_LAYER1 : - ((layer == 2) ? ACM_MPEG_LAYER2 : - ACM_MPEG_LAYER3)); - mpgformat->dwHeadBitrate = format->nAvgBytesPerSec * 8; - mpgformat->fwHeadMode = ((mode == 3) ? ACM_MPEG_SINGLECHANNEL : - ((mode == 2) ? ACM_MPEG_DUALCHANNEL : - ((mode == 1) ? ACM_MPEG_JOINTSTEREO : - ACM_MPEG_STEREO))); - mpgformat->fwHeadModeExt = ((mode == 1) ? 0x0F : (1<<mode_ext)); - mpgformat->wHeadEmphasis = emphasis + 1; - mpgformat->fwHeadFlags = ACM_MPEG_ID_MPEG1; - } - pamt->subtype.Data1 = format->wFormatTag; - - TRACE("MPEG audio stream detected:\n" - "\tLayer %d (%#x)\n" - "\tFrequency: %d\n" - "\tChannels: %d (%d)\n" - "\tBytesPerSec: %d\n", - layer, format->wFormatTag, format->nSamplesPerSec, - format->nChannels, mode, format->nAvgBytesPerSec); - - dump_AM_MEDIA_TYPE(pamt); - - return S_OK; -} - - -static HRESULT MPEGSplitter_pre_connect(IPin *iface, IPin *pConnectPin, ALLOCATOR_PROPERTIES *props) -{ - PullPin *pPin = impl_PullPin_from_IPin(iface); - MPEGSplitterImpl *This = impl_from_IBaseFilter(&pPin->pin.filter->IBaseFilter_iface); - HRESULT hr; - LONGLONG pos = 0; /* in bytes */ - BYTE header[10]; - int streamtype; - LONGLONG total, avail; - AM_MEDIA_TYPE amt; - - IAsyncReader_Length(pPin->pReader, &total, &avail); - This->EndOfFile = total; - - hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header); - if (SUCCEEDED(hr)) - pos += 4; - - /* Skip ID3 v2 tag, if any */ - if (SUCCEEDED(hr) && !memcmp("ID3", header, 3)) - do { - UINT length = 0; - hr = IAsyncReader_SyncRead(pPin->pReader, pos, 6, header + 4); - if (FAILED(hr)) - break; - pos += 6; - TRACE("Found ID3 v2.%d.%d\n", header[3], header[4]); - if(header[3] <= 4 && header[4] != 0xff && - (header[5]&0x0f) == 0 && (header[6]&0x80) == 0 && - (header[7]&0x80) == 0 && (header[8]&0x80) == 0 && - (header[9]&0x80) == 0) - { - length = (header[6]<<21) | (header[7]<<14) | - (header[8]<< 7) | (header[9] ); - if((header[5]&0x10)) - length += 10; - TRACE("Length: %u\n", length); - } - pos += length; - - /* Read the real header for the mpeg splitter */ - hr = IAsyncReader_SyncRead(pPin->pReader, pos, 4, header); - if (SUCCEEDED(hr)) - pos += 4; - } while (0); - - while(SUCCEEDED(hr)) - { - TRACE("Testing header %x:%x:%x:%x\n", header[0], header[1], header[2], header[3]); - - streamtype = MPEGSplitter_head_check(header); - if (streamtype == MPEG_AUDIO_HEADER) - { - LONGLONG length; - if (parse_header(header, &length, NULL) == S_OK) - { - BYTE next_header[4]; - /* Ensure we have a valid header by seeking for the next frame, some bad - * encoded ID3v2 may have an incorrect length and we end up finding bytes - * like FF FE 00 28 which are nothing more than a Unicode BOM followed by - * ')' character from inside a ID3v2 tag. Unfortunately that sequence - * matches like a valid mpeg audio header. - */ - hr = IAsyncReader_SyncRead(pPin->pReader, pos + length - 4, 4, next_header); - if (FAILED(hr)) - break; - if (parse_header(next_header, &length, NULL) == S_OK) - break; - TRACE("%x:%x:%x:%x is a fake audio header, looking for next...\n", - header[0], header[1], header[2], header[3]); - } - } - else if (streamtype) /* Video or System stream */ - break; - - /* No valid header yet; shift by a byte and check again */ - memmove(header, header+1, 3); - hr = IAsyncReader_SyncRead(pPin->pReader, pos++, 1, header + 3); - } - if (FAILED(hr)) - return hr; - pos -= 4; - This->begin_offset = pos; - memcpy(This->header, header, 4); - - switch(streamtype) - { - case MPEG_AUDIO_HEADER: - { - LONGLONG duration = 0; - WAVEFORMATEX *format; - - hr = MPEGSplitter_init_audio(This, header, &amt); - if (SUCCEEDED(hr)) - { - format = (WAVEFORMATEX*)amt.pbFormat; - - props->cbAlign = 1; - props->cbPrefix = 0; - /* Make the output buffer a multiple of the frame size */ - props->cbBuffer = 0x4000 / format->nBlockAlign * - format->nBlockAlign; - props->cBuffers = 3; - hr = Parser_AddPin(&This->Parser, wszAudioStream, props, &amt); - } - - if (FAILED(hr)) - { - CoTaskMemFree(amt.pbFormat); - ERR("Could not create pin for MPEG audio stream (%x)\n", hr); - break; - } - - /* Check for idv1 tag, and remove it from stream if found */ - hr = IAsyncReader_SyncRead(pPin->pReader, This->EndOfFile-128, 3, header); - if (FAILED(hr)) - break; - if (!strncmp((char*)header, "TAG", 3)) - This->EndOfFile -= 128; - This->Parser.pInputPin->rtStop = MEDIATIME_FROM_BYTES(This->EndOfFile); - This->Parser.pInputPin->rtStart = This->Parser.pInputPin->rtCurrent = MEDIATIME_FROM_BYTES(This->begin_offset); - - duration = (This->EndOfFile-This->begin_offset) * 10000000 / format->nAvgBytesPerSec; - TRACE("Duration: %d seconds\n", (DWORD)(duration / 10000000)); - - This->Parser.sourceSeeking.llCurrent = 0; - This->Parser.sourceSeeking.llDuration = duration; - This->Parser.sourceSeeking.llStop = duration; - break; - } - case MPEG_VIDEO_HEADER: - FIXME("MPEG video processing not yet supported!\n"); - hr = E_FAIL; - break; - case MPEG_SYSTEM_HEADER: - FIXME("MPEG system streams not yet supported!\n"); - hr = E_FAIL; - break; - - default: - break; - } - This->position = 0; - - return hr; -} - -static HRESULT MPEGSplitter_cleanup(LPVOID iface) -{ - MPEGSplitterImpl *This = iface; - - TRACE("(%p)\n", This); - - return S_OK; -} - -static HRESULT WINAPI MPEGSplitter_seek(IMediaSeeking *iface) -{ - MPEGSplitterImpl *This = impl_from_IMediaSeeking(iface); - PullPin *pPin = This->Parser.pInputPin; - LONGLONG newpos, timepos, bytepos; - HRESULT hr = E_INVALIDARG; - BYTE header[4]; - - newpos = This->Parser.sourceSeeking.llCurrent; - if (This->position/1000000 == newpos/1000000) - { - TRACE("Requesting position %x%08x same as current position %x%08x\n", (DWORD)(newpos>>32), (DWORD)newpos, (DWORD)(This->position>>32), (DWORD)This->position); - return S_OK; - } - - bytepos = This->begin_offset; - timepos = 0; - /* http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm has a whole read up on audio headers */ - while (bytepos + 3 < This->EndOfFile) - { - LONGLONG duration = timepos; - LONGLONG length = 0; - hr = IAsyncReader_SyncRead(pPin->pReader, bytepos, 4, header); - if (hr != S_OK) - break; - while ((hr=parse_header(header, &length, &duration)) != S_OK && - bytepos + 4 < This->EndOfFile) - { - /* No valid header yet; shift by a byte and check again */ - memmove(header, header+1, 3); - hr = IAsyncReader_SyncRead(pPin->pReader, ++bytepos + 3, 1, header + 3); - if (hr != S_OK) - break; - } - if (hr != S_OK || duration > newpos) - break; - bytepos += length; - timepos = duration; - } - - if (SUCCEEDED(hr)) - { - PullPin *pin = This->Parser.pInputPin; - - TRACE("Moving sound to %08u bytes!\n", (DWORD)bytepos); - - EnterCriticalSection(&pin->thread_lock); - IPin_BeginFlush(&pin->pin.IPin_iface); - - /* Make sure this is done while stopped, BeginFlush takes care of this */ - EnterCriticalSection(&This->Parser.filter.csFilter); - memcpy(This->header, header, 4); - - pin->rtStart = pin->rtCurrent = MEDIATIME_FROM_BYTES(bytepos); - pin->rtStop = MEDIATIME_FROM_BYTES((REFERENCE_TIME)This->EndOfFile); - This->seek = TRUE; - This->position = newpos; - LeaveCriticalSection(&This->Parser.filter.csFilter); - - TRACE("Done flushing\n"); - IPin_EndFlush(&pin->pin.IPin_iface); - LeaveCriticalSection(&pin->thread_lock); - } - return hr; -} - -static HRESULT MPEGSplitter_disconnect(LPVOID iface) -{ - /* TODO: Find memory leaks etc */ - return S_OK; -} - -static HRESULT MPEGSplitter_first_request(LPVOID iface) -{ - MPEGSplitterImpl *This = iface; - PullPin *pin = This->Parser.pInputPin; - HRESULT hr; - LONGLONG length; - IMediaSample *sample; - - TRACE("Seeking? %d\n", This->seek); - - hr = parse_header(This->header, &length, NULL); - assert(hr == S_OK); - - if (pin->rtCurrent >= pin->rtStop) - { - /* Last sample has already been queued, request nothing more */ - FIXME("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(length + 4); - - if (rtSampleStop > pin->rtStop) - rtSampleStop = MEDIATIME_FROM_BYTES(ALIGNUP(BYTES_FROM_MEDIATIME(pin->rtStop), pin->cbAlign)); - - IMediaSample_SetTime(sample, &rtSampleStart, &rtSampleStop); - IMediaSample_SetPreroll(sample, FALSE); - IMediaSample_SetDiscontinuity(sample, TRUE); - IMediaSample_SetSyncPoint(sample, 1); - This->seek = FALSE; - - hr = IAsyncReader_Request(pin->pReader, sample, 0); - if (SUCCEEDED(hr)) - { - pin->rtCurrent = pin->rtNext; - pin->rtNext = rtSampleStop; - } - else - IMediaSample_Release(sample); - } - if (FAILED(hr)) - ERR("Horsemen of the apocalypse came to bring error 0x%08x\n", hr); - - return hr; -} - -static const IBaseFilterVtbl MPEGSplitter_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 HRESULT WINAPI AMStreamSelect_QueryInterface(IAMStreamSelect *iface, REFIID riid, void **ppv) -{ - MPEGSplitterImpl *This = impl_from_IAMStreamSelect(iface); - - return IBaseFilter_QueryInterface(&This->Parser.filter.IBaseFilter_iface, riid, ppv); -} - -static ULONG WINAPI AMStreamSelect_AddRef(IAMStreamSelect *iface) -{ - MPEGSplitterImpl *This = impl_from_IAMStreamSelect(iface); - - return IBaseFilter_AddRef(&This->Parser.filter.IBaseFilter_iface); -} - -static ULONG WINAPI AMStreamSelect_Release(IAMStreamSelect *iface) -{ - MPEGSplitterImpl *This = impl_from_IAMStreamSelect(iface); - - return IBaseFilter_Release(&This->Parser.filter.IBaseFilter_iface); -} - -static HRESULT WINAPI AMStreamSelect_Count(IAMStreamSelect *iface, DWORD *streams) -{ - MPEGSplitterImpl *This = impl_from_IAMStreamSelect(iface); - - FIXME("(%p/%p)->(%p) stub!\n", This, iface, streams); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AMStreamSelect_Info(IAMStreamSelect *iface, LONG index, AM_MEDIA_TYPE **media_type, DWORD *flags, LCID *lcid, DWORD *group, WCHAR **name, IUnknown **object, IUnknown **unknown) -{ - MPEGSplitterImpl *This = impl_from_IAMStreamSelect(iface); - - FIXME("(%p/%p)->(%d,%p,%p,%p,%p,%p,%p,%p) stub!\n", This, iface, index, media_type, flags, lcid, group, name, object, unknown); - - return E_NOTIMPL; -} - -static HRESULT WINAPI AMStreamSelect_Enable(IAMStreamSelect *iface, LONG index, DWORD flags) -{ - MPEGSplitterImpl *This = impl_from_IAMStreamSelect(iface); - - FIXME("(%p/%p)->(%d,%x) stub!\n", This, iface, index, flags); - - return E_NOTIMPL; -} - -static const IAMStreamSelectVtbl AMStreamSelectVtbl = -{ - AMStreamSelect_QueryInterface, - AMStreamSelect_AddRef, - AMStreamSelect_Release, - AMStreamSelect_Count, - AMStreamSelect_Info, - AMStreamSelect_Enable -}; - -static void mpeg_splitter_destroy(struct strmbase_filter *iface) -{ - MPEGSplitterImpl *filter = impl_from_IBaseFilter(&iface->IBaseFilter_iface); - Parser_Destroy(&filter->Parser); -} - -static HRESULT mpeg_splitter_query_interface(struct strmbase_filter *iface, REFIID iid, void **out) -{ - MPEGSplitterImpl *filter = impl_from_IBaseFilter(&iface->IBaseFilter_iface); - - if (IsEqualGUID(iid, &IID_IAMStreamSelect)) - { - *out = &filter->IAMStreamSelect_iface; - IUnknown_AddRef((IUnknown *)*out); - return S_OK; - } - - return E_NOINTERFACE; -} - -static const struct strmbase_filter_ops filter_ops = -{ - .filter_get_pin = parser_get_pin, - .filter_destroy = mpeg_splitter_destroy, - .filter_query_interface = mpeg_splitter_query_interface, -}; - -HRESULT MPEGSplitter_create(IUnknown *outer, void **out) -{ - static const WCHAR sink_name[] = {'I','n','p','u','t',0}; - MPEGSplitterImpl *This; - HRESULT hr = E_FAIL; - - *out = NULL; - - This = CoTaskMemAlloc(sizeof(MPEGSplitterImpl)); - if (!This) - return E_OUTOFMEMORY; - - ZeroMemory(This, sizeof(MPEGSplitterImpl)); - hr = Parser_Create(&This->Parser, &MPEGSplitter_Vtbl, outer, &CLSID_MPEG1Splitter, - &filter_ops, sink_name, MPEGSplitter_process_sample, MPEGSplitter_query_accept, - MPEGSplitter_pre_connect, MPEGSplitter_cleanup, MPEGSplitter_disconnect, - MPEGSplitter_first_request, NULL, NULL, MPEGSplitter_seek, NULL); - if (FAILED(hr)) - { - CoTaskMemFree(This); - return hr; - } - This->IAMStreamSelect_iface.lpVtbl = &AMStreamSelectVtbl; - This->seek = TRUE; - - *out = &This->Parser.filter.IUnknown_inner; - - return hr; -} diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index 4014b6fb0d9..e475cd01477 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -55,7 +55,6 @@ HRESULT FilterMapper2_create(IUnknown *pUnkOuter, LPVOID *ppObj) DECLSPEC_HIDDEN HRESULT FilterMapper_create(IUnknown *pUnkOuter, LPVOID *ppObj) DECLSPEC_HIDDEN; HRESULT AsyncReader_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT StdMemAllocator_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; -HRESULT MPEGSplitter_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT AVIDec_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT DSoundRender_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; HRESULT VideoRenderer_create(IUnknown * pUnkOuter, LPVOID * ppv) DECLSPEC_HIDDEN; diff --git a/dlls/quartz/quartz_strmif.idl b/dlls/quartz/quartz_strmif.idl index 0ecaeb08c54..b0b43ee2f33 100644 --- a/dlls/quartz/quartz_strmif.idl +++ b/dlls/quartz/quartz_strmif.idl @@ -84,13 +84,6 @@ coclass SeekingPassThru { interface ISeekingPassThru; } ] coclass AsyncReader { interface IBaseFilter; }
-[ - helpstring("MPEG-I Stream Splitter"), - threading(both), - uuid(336475d0-942a-11ce-a870-00aa002feab5) -] -coclass MPEG1Splitter { interface IBaseFilter; } - [ helpstring("AVI Decompressor"), threading(both), diff --git a/dlls/quartz/regsvr.c b/dlls/quartz/regsvr.c index 07348936307..ed3bca3d95c 100644 --- a/dlls/quartz/regsvr.c +++ b/dlls/quartz/regsvr.c @@ -178,33 +178,6 @@ static HRESULT unregister_filters(struct regsvr_filter const *list) */
static struct regsvr_filter const filter_list[] = { - { &CLSID_MPEG1Splitter, - &CLSID_LegacyAmFilterCategory, - {'M','P','E','G','-','I',' ','S','t','r','e','a','m',' ','S','p','l','i','t','t','e','r',0}, - 0x5ffff0, - { { 0, - { { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Audio }, - { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Video }, - { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1System }, - { &MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1VideoCD }, - { NULL } - }, - }, - { REG_PINFLAG_B_OUTPUT, - { { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1Packet }, - { &MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1AudioPayload }, - { NULL } - }, - }, - { REG_PINFLAG_B_OUTPUT, - { { &MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Packet }, - { &MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Payload }, - { NULL } - }, - }, - { 0xFFFFFFFF }, - } - }, { &CLSID_NullRenderer, &CLSID_LegacyAmFilterCategory, {'N','u','l','l',' ','R','e','n','d','e','r','e','r',0}, diff --git a/dlls/quartz/tests/mpegsplit.c b/dlls/quartz/tests/mpegsplit.c index 5661c73e19a..0281b67ce21 100644 --- a/dlls/quartz/tests/mpegsplit.c +++ b/dlls/quartz/tests/mpegsplit.c @@ -153,7 +153,7 @@ static void test_interfaces(void)
check_interface(pin, &IID_IKsPropertySet, FALSE); check_interface(pin, &IID_IMediaPosition, FALSE); - todo_wine check_interface(pin, &IID_IMediaSeeking, FALSE); + check_interface(pin, &IID_IMediaSeeking, FALSE);
IPin_Release(pin);
@@ -161,7 +161,7 @@ static void test_interfaces(void)
check_interface(pin, &IID_IMediaSeeking, TRUE); check_interface(pin, &IID_IPin, TRUE); - todo_wine check_interface(pin, &IID_IQualityControl, TRUE); + check_interface(pin, &IID_IQualityControl, TRUE); check_interface(pin, &IID_IUnknown, TRUE);
check_interface(pin, &IID_IAsyncReader, FALSE); @@ -999,8 +999,18 @@ static void test_enum_media_types(void)
START_TEST(mpegsplit) { + IBaseFilter *filter; + CoInitialize(NULL);
+ if (FAILED(CoCreateInstance(&CLSID_MPEG1Splitter, NULL, CLSCTX_INPROC_SERVER, + &IID_IBaseFilter, (void **)&filter))) + { + skip("Failed to create MPEG-1 splitter.\n"); + return; + } + IBaseFilter_Release(filter); + test_interfaces(); test_aggregation(); test_enum_pins(); diff --git a/dlls/winegstreamer/gst_private.h b/dlls/winegstreamer/gst_private.h index d42c8dbf0b4..596724cf261 100644 --- a/dlls/winegstreamer/gst_private.h +++ b/dlls/winegstreamer/gst_private.h @@ -39,6 +39,7 @@ void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt);
IUnknown * CALLBACK avi_splitter_create(IUnknown *outer, HRESULT *phr) DECLSPEC_HIDDEN; +IUnknown * CALLBACK mpeg_splitter_create(IUnknown *outer, HRESULT *phr) DECLSPEC_HIDDEN; IUnknown * CALLBACK Gstreamer_AudioConvert_create(IUnknown *pUnkOuter, HRESULT *phr); IUnknown * CALLBACK Gstreamer_Mp3_create(IUnknown *pUnkOuter, HRESULT *phr); IUnknown * CALLBACK Gstreamer_YUV2RGB_create(IUnknown *pUnkOuter, HRESULT *phr); diff --git a/dlls/winegstreamer/gstdemux.c b/dlls/winegstreamer/gstdemux.c index 6109d6be66e..c8daec2f538 100644 --- a/dlls/winegstreamer/gstdemux.c +++ b/dlls/winegstreamer/gstdemux.c @@ -50,6 +50,7 @@ static pthread_key_t wine_gst_key; struct gstdemux { struct strmbase_filter filter; + IAMStreamSelect IAMStreamSelect_iface;
BasePin sink; IAsyncReader *reader; @@ -65,7 +66,7 @@ struct gstdemux GstBus *bus; guint64 start, nextofs, nextpullofs, stop; ALLOCATOR_PROPERTIES props; - HANDLE no_more_pads_event; + HANDLE no_more_pads_event, duration_event;
HANDLE push_thread;
@@ -123,7 +124,7 @@ BOOL is_wine_thread(void) return pthread_getspecific(wine_gst_key) != NULL; }
-static gboolean amt_from_gst_caps_audio(const GstCaps *caps, AM_MEDIA_TYPE *amt) +static gboolean amt_from_gst_caps_audio_raw(const GstCaps *caps, AM_MEDIA_TYPE *amt) { WAVEFORMATEXTENSIBLE *wfe; WAVEFORMATEX *wfx; @@ -184,7 +185,7 @@ static gboolean amt_from_gst_caps_audio(const GstCaps *caps, AM_MEDIA_TYPE *amt) return TRUE; }
-static gboolean amt_from_gst_caps_video(const GstCaps *caps, AM_MEDIA_TYPE *amt) +static gboolean amt_from_gst_caps_video_raw(const GstCaps *caps, AM_MEDIA_TYPE *amt) { VIDEOINFOHEADER *vih; BITMAPINFOHEADER *bih; @@ -269,14 +270,82 @@ static gboolean amt_from_gst_caps_video(const GstCaps *caps, AM_MEDIA_TYPE *amt) return TRUE; }
+static gboolean amt_from_gst_caps_audio_mpeg(const GstCaps *caps, AM_MEDIA_TYPE *mt) +{ + GstStructure *structure = gst_caps_get_structure(caps, 0); + gint layer, channels, rate; + + mt->majortype = MEDIATYPE_Audio; + mt->subtype = MEDIASUBTYPE_MPEG1AudioPayload; + mt->bFixedSizeSamples = FALSE; + mt->bTemporalCompression = FALSE; + mt->lSampleSize = 0; + mt->formattype = FORMAT_WaveFormatEx; + mt->pUnk = NULL; + + if (!gst_structure_get_int(structure, "layer", &layer)) + { + WARN("Missing 'layer' value.\n"); + return FALSE; + } + if (!gst_structure_get_int(structure, "channels", &channels)) + { + WARN("Missing 'channels' value.\n"); + return FALSE; + } + if (!gst_structure_get_int(structure, "rate", &rate)) + { + WARN("Missing 'rate' value.\n"); + return FALSE; + } + + if (layer == 3) + { + MPEGLAYER3WAVEFORMAT *wfx = CoTaskMemAlloc(sizeof(*wfx)); + memset(wfx, 0, sizeof(*wfx)); + + mt->subtype.Data1 = WAVE_FORMAT_MPEGLAYER3; + mt->cbFormat = sizeof(*wfx); + mt->pbFormat = (BYTE *)wfx; + wfx->wfx.wFormatTag = WAVE_FORMAT_MPEGLAYER3; + wfx->wfx.nChannels = channels; + wfx->wfx.nSamplesPerSec = rate; + /* FIXME: We can't get most of the MPEG data from the caps. We may have + * to manually parse the header. */ + wfx->wfx.cbSize = sizeof(*wfx) - sizeof(WAVEFORMATEX); + wfx->wID = MPEGLAYER3_ID_MPEG; + wfx->fdwFlags = MPEGLAYER3_FLAG_PADDING_ON; + wfx->nFramesPerBlock = 1; + wfx->nCodecDelay = 1393; + } + else + { + MPEG1WAVEFORMAT *wfx = CoTaskMemAlloc(sizeof(*wfx)); + memset(wfx, 0, sizeof(*wfx)); + + mt->subtype.Data1 = WAVE_FORMAT_MPEG; + mt->cbFormat = sizeof(*wfx); + mt->pbFormat = (BYTE *)wfx; + wfx->wfx.wFormatTag = WAVE_FORMAT_MPEG; + wfx->wfx.nChannels = channels; + wfx->wfx.nSamplesPerSec = rate; + wfx->wfx.cbSize = sizeof(*wfx) - sizeof(WAVEFORMATEX); + wfx->fwHeadLayer = layer; + } + + return TRUE; +} + static gboolean amt_from_gst_caps(const GstCaps *caps, AM_MEDIA_TYPE *mt) { const char *type = gst_structure_get_name(gst_caps_get_structure(caps, 0));
if (!strcmp(type, "audio/x-raw")) - return amt_from_gst_caps_audio(caps, mt); + return amt_from_gst_caps_audio_raw(caps, mt); else if (!strcmp(type, "video/x-raw")) - return amt_from_gst_caps_video(caps, mt); + return amt_from_gst_caps_video_raw(caps, mt); + else if (!strcmp(type, "audio/mpeg")) + return amt_from_gst_caps_audio_mpeg(caps, mt); else { FIXME("Unhandled type %s.\n", debugstr_a(type)); @@ -1037,24 +1106,34 @@ static GstAutoplugSelectResult autoplug_blacklist(GstElement *bin, GstPad *pad,
static GstBusSyncReply watch_bus(GstBus *bus, GstMessage *msg, gpointer data) { - struct gstdemux *This = data; + struct gstdemux *filter = data; GError *err = NULL; gchar *dbg_info = NULL;
- TRACE("filter %p, message type %s.\n", This, GST_MESSAGE_TYPE_NAME(msg)); + TRACE("filter %p, message type %s.\n", filter, GST_MESSAGE_TYPE_NAME(msg));
- if (GST_MESSAGE_TYPE(msg) & GST_MESSAGE_ERROR) { + switch (msg->type) + { + case GST_MESSAGE_ERROR: gst_message_parse_error(msg, &err, &dbg_info); ERR("%s: %s\n", GST_OBJECT_NAME(msg->src), err->message); ERR("%s\n", dbg_info); - } else if (GST_MESSAGE_TYPE(msg) & GST_MESSAGE_WARNING) { + g_error_free(err); + g_free(dbg_info); + break; + case GST_MESSAGE_WARNING: gst_message_parse_warning(msg, &err, &dbg_info); WARN("%s: %s\n", GST_OBJECT_NAME(msg->src), err->message); WARN("%s\n", dbg_info); - } - if (err) g_error_free(err); - g_free(dbg_info); + g_free(dbg_info); + break; + case GST_MESSAGE_DURATION_CHANGED: + SetEvent(filter->duration_event); + break; + default: + break; + } return GST_BUS_DROP; }
@@ -1126,6 +1205,7 @@ static void gstdemux_destroy(struct strmbase_filter *iface) HRESULT hr;
CloseHandle(filter->no_more_pads_event); + CloseHandle(filter->duration_event);
/* Don't need to clean up output pins, disconnecting input pin will do that */ if (filter->sink.pConnectedTo) @@ -1405,6 +1485,60 @@ static const IBaseFilterVtbl GST_Vtbl = { BaseFilterImpl_QueryVendorInfo };
+static struct gstdemux *impl_from_IAMStreamSelect(IAMStreamSelect *iface) +{ + return CONTAINING_RECORD(iface, struct gstdemux, IAMStreamSelect_iface); +} + +static HRESULT WINAPI stream_select_QueryInterface(IAMStreamSelect *iface, REFIID iid, void **out) +{ + struct gstdemux *filter = impl_from_IAMStreamSelect(iface); + return IUnknown_QueryInterface(filter->filter.outer_unk, iid, out); +} + +static ULONG WINAPI stream_select_AddRef(IAMStreamSelect *iface) +{ + struct gstdemux *filter = impl_from_IAMStreamSelect(iface); + return IUnknown_AddRef(filter->filter.outer_unk); +} + +static ULONG WINAPI stream_select_Release(IAMStreamSelect *iface) +{ + struct gstdemux *filter = impl_from_IAMStreamSelect(iface); + return IUnknown_Release(filter->filter.outer_unk); +} + +static HRESULT WINAPI stream_select_Count(IAMStreamSelect *iface, DWORD *count) +{ + FIXME("iface %p, count %p, stub!\n", iface, count); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_select_Info(IAMStreamSelect *iface, LONG index, + AM_MEDIA_TYPE **mt, DWORD *flags, LCID *lcid, DWORD *group, WCHAR **name, + IUnknown **object, IUnknown **unknown) +{ + FIXME("iface %p, index %d, mt %p, flags %p, lcid %p, group %p, name %p, object %p, unknown %p, stub!\n", + iface, index, mt, flags, lcid, group, name, object, unknown); + return E_NOTIMPL; +} + +static HRESULT WINAPI stream_select_Enable(IAMStreamSelect *iface, LONG index, DWORD flags) +{ + FIXME("iface %p, index %d, flags %#x, stub!\n", iface, index, flags); + return E_NOTIMPL; +} + +static const IAMStreamSelectVtbl stream_select_vtbl = +{ + stream_select_QueryInterface, + stream_select_AddRef, + stream_select_Release, + stream_select_Count, + stream_select_Info, + stream_select_Enable, +}; + static HRESULT WINAPI GST_ChangeCurrent(IMediaSeeking *iface) { struct gstdemux_source *This = impl_from_IMediaSeeking(iface); @@ -2385,3 +2519,137 @@ IUnknown * CALLBACK avi_splitter_create(IUnknown *outer, HRESULT *phr) TRACE("Created AVI splitter %p.\n", object); return &object->filter.IUnknown_inner; } + +static HRESULT WINAPI mpeg_splitter_sink_CheckMediaType(BasePin *iface, const AM_MEDIA_TYPE *mt) +{ + if (!IsEqualGUID(&mt->majortype, &MEDIATYPE_Stream)) + return S_FALSE; + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1Audio)) + return S_OK; + if (IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1Video) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1System) + || IsEqualGUID(&mt->subtype, &MEDIASUBTYPE_MPEG1VideoCD)) + FIXME("Unsupported subtype %s.\n", wine_dbgstr_guid(&mt->subtype)); + return S_FALSE; +} + +static const BasePinFuncTable mpeg_splitter_sink_ops = +{ + .pfnCheckMediaType = mpeg_splitter_sink_CheckMediaType, + .pfnGetMediaType = BasePinImpl_GetMediaType, +}; + +static BOOL mpeg_splitter_init_gst(struct gstdemux *filter) +{ + static const WCHAR source_name[] = {'A','u','d','i','o',0}; + struct gstdemux_source *pin; + GstElement *element; + LONGLONG duration; + int ret; + + if (!(element = gst_element_factory_make("mpegaudioparse", NULL))) + { + ERR("Failed to create mpegaudioparse; 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; + gst_object_ref(pin->their_src = gst_element_get_static_pad(element, "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; + } + + WaitForSingleObject(filter->duration_event, INFINITE); + 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; +} + +static HRESULT mpeg_splitter_query_interface(struct strmbase_filter *iface, REFIID iid, void **out) +{ + struct gstdemux *filter = impl_from_strmbase_filter(iface); + + if (IsEqualGUID(iid, &IID_IAMStreamSelect)) + { + *out = &filter->IAMStreamSelect_iface; + IUnknown_AddRef((IUnknown *)*out); + return S_OK; + } + + return E_NOINTERFACE; +} + +static const struct strmbase_filter_ops mpeg_splitter_ops = +{ + .filter_query_interface = mpeg_splitter_query_interface, + .filter_get_pin = gstdemux_get_pin, + .filter_destroy = gstdemux_destroy, +}; + +IUnknown * CALLBACK mpeg_splitter_create(IUnknown *outer, HRESULT *phr) +{ + static const WCHAR sink_name[] = {'I','n','p','u','t',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_MPEG1Splitter, &mpeg_splitter_ops); + object->IAMStreamSelect_iface.lpVtbl = &stream_select_vtbl; + + object->duration_event = CreateEventW(NULL, FALSE, FALSE, NULL); + 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 = &mpeg_splitter_sink_ops; + object->init_gst = mpeg_splitter_init_gst; + *phr = S_OK; + + TRACE("Created MPEG-1 splitter %p.\n", object); + return &object->filter.IUnknown_inner; +} diff --git a/dlls/winegstreamer/main.c b/dlls/winegstreamer/main.c index 80c76c33dd4..5a8e05e8872 100644 --- a/dlls/winegstreamer/main.c +++ b/dlls/winegstreamer/main.c @@ -50,6 +50,8 @@ static const WCHAR wave_parserW[] = {'W','a','v','e',' ','P','a','r','s','e','r',0}; static const WCHAR avi_splitterW[] = {'A','V','I',' ','S','p','l','i','t','t','e','r',0}; +static const WCHAR mpeg_splitterW[] = +{'M','P','E','G','-','I',' ','S','t','r','e','a','m',' ','S','p','l','i','t','t','e','r',0};
static WCHAR wNull[] = {'\0'};
@@ -259,6 +261,63 @@ static const AMOVIESETUP_FILTER avi_splitter_filter_data = avi_splitter_pin_data, };
+static const AMOVIESETUP_MEDIATYPE mpeg_splitter_sink_type_data[] = +{ + {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Audio}, + {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1Video}, + {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1System}, + {&MEDIATYPE_Stream, &MEDIASUBTYPE_MPEG1VideoCD}, +}; + +static const AMOVIESETUP_MEDIATYPE mpeg_splitter_audio_type_data[] = +{ + {&MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1Packet}, + {&MEDIATYPE_Audio, &MEDIASUBTYPE_MPEG1AudioPayload}, +}; + +static const AMOVIESETUP_MEDIATYPE mpeg_splitter_video_type_data[] = +{ + {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Packet}, + {&MEDIATYPE_Video, &MEDIASUBTYPE_MPEG1Payload}, +}; + +static const AMOVIESETUP_PIN mpeg_splitter_pin_data[] = +{ + { + NULL, + FALSE, FALSE, FALSE, FALSE, + &GUID_NULL, + NULL, + ARRAY_SIZE(mpeg_splitter_sink_type_data), + mpeg_splitter_sink_type_data, + }, + { + NULL, + FALSE, TRUE, FALSE, FALSE, + &GUID_NULL, + NULL, + ARRAY_SIZE(mpeg_splitter_audio_type_data), + mpeg_splitter_audio_type_data, + }, + { + NULL, + FALSE, TRUE, FALSE, FALSE, + &GUID_NULL, + NULL, + ARRAY_SIZE(mpeg_splitter_video_type_data), + mpeg_splitter_video_type_data, + }, +}; + +static const AMOVIESETUP_FILTER mpeg_splitter_filter_data = +{ + &CLSID_MPEG1Splitter, + mpeg_splitterW, + 0x5ffff0, + ARRAY_SIZE(mpeg_splitter_pin_data), + mpeg_splitter_pin_data, +}; + FactoryTemplate const g_Templates[] = { { wGstreamer_Splitter, @@ -309,6 +368,13 @@ FactoryTemplate const g_Templates[] = { NULL, &avi_splitter_filter_data, }, + { + mpeg_splitterW, + &CLSID_MPEG1Splitter, + mpeg_splitter_create, + NULL, + &mpeg_splitter_filter_data, + }, };
const int g_cTemplates = ARRAY_SIZE(g_Templates);
Signed-off-by: Zebediah Figura z.figura12@gmail.com --- dlls/quartz/Makefile.in | 2 - dlls/quartz/acmwrapper.c | 1 - dlls/quartz/avidec.c | 1 - dlls/quartz/dsoundrender.c | 1 - dlls/quartz/filesource.c | 1 - dlls/quartz/parser.c | 709 ------------------------------ dlls/quartz/parser.h | 77 ---- dlls/quartz/pin.c | 818 ----------------------------------- dlls/quartz/pin.h | 133 ------ dlls/quartz/quartz_private.h | 12 +- dlls/quartz/videorenderer.c | 1 - dlls/quartz/vmr9.c | 1 - 12 files changed, 1 insertion(+), 1756 deletions(-) delete mode 100644 dlls/quartz/parser.c delete mode 100644 dlls/quartz/parser.h delete mode 100644 dlls/quartz/pin.c delete mode 100644 dlls/quartz/pin.h
diff --git a/dlls/quartz/Makefile.in b/dlls/quartz/Makefile.in index e33c4e58b99..fd2397668d0 100644 --- a/dlls/quartz/Makefile.in +++ b/dlls/quartz/Makefile.in @@ -16,8 +16,6 @@ C_SRCS = \ filtermapper.c \ main.c \ memallocator.c \ - parser.c \ - pin.c \ regsvr.c \ systemclock.c \ videorenderer.c \ diff --git a/dlls/quartz/acmwrapper.c b/dlls/quartz/acmwrapper.c index c6ff1d7c113..d1e4803fac7 100644 --- a/dlls/quartz/acmwrapper.c +++ b/dlls/quartz/acmwrapper.c @@ -19,7 +19,6 @@ */
#include "quartz_private.h" -#include "pin.h"
#include "uuids.h" #include "mmreg.h" diff --git a/dlls/quartz/avidec.c b/dlls/quartz/avidec.c index cd92b646977..ce38b6963ce 100644 --- a/dlls/quartz/avidec.c +++ b/dlls/quartz/avidec.c @@ -19,7 +19,6 @@ */
#include "quartz_private.h" -#include "pin.h"
#include "uuids.h" #include "amvideo.h" diff --git a/dlls/quartz/dsoundrender.c b/dlls/quartz/dsoundrender.c index 29b6492adb9..dbb5b523fa8 100644 --- a/dlls/quartz/dsoundrender.c +++ b/dlls/quartz/dsoundrender.c @@ -19,7 +19,6 @@ */
#include "quartz_private.h" -#include "pin.h"
#include "uuids.h" #include "vfwmsgs.h" diff --git a/dlls/quartz/filesource.c b/dlls/quartz/filesource.c index cbd54b60ccb..21f93ff7d7f 100644 --- a/dlls/quartz/filesource.c +++ b/dlls/quartz/filesource.c @@ -24,7 +24,6 @@ #include "quartz_private.h"
#include "wine/debug.h" -#include "pin.h" #include "uuids.h" #include "vfwmsgs.h" #include "winbase.h" diff --git a/dlls/quartz/parser.c b/dlls/quartz/parser.c deleted file mode 100644 index e4e6036aff7..00000000000 --- a/dlls/quartz/parser.c +++ /dev/null @@ -1,709 +0,0 @@ -/* - * Parser (Base for parsers and splitters) - * - * Copyright 2003 Robert Shearman - * Copyright 2004-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 "vfwmsgs.h" -#include "amvideo.h" - -#include "wine/debug.h" - -#include <math.h> -#include <assert.h> - -#include "parser.h" - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -static const IMediaSeekingVtbl Parser_Seeking_Vtbl; -static const IPinVtbl Parser_OutputPin_Vtbl; -static const IPinVtbl Parser_InputPin_Vtbl; - -static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface); -static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface); -static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface); -static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(struct strmbase_source *iface, - IMemAllocator *allocator, ALLOCATOR_PROPERTIES *props); -static HRESULT WINAPI Parser_OutputPin_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE *pmt); -static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt); -static HRESULT WINAPI Parser_OutputPin_DecideAllocator(struct strmbase_source *iface, - IMemInputPin *peer, IMemAllocator **allocator); - -static inline ParserImpl *impl_from_IMediaSeeking( IMediaSeeking *iface ) -{ - return CONTAINING_RECORD(iface, ParserImpl, sourceSeeking.IMediaSeeking_iface); -} - -static inline ParserImpl *impl_from_IBaseFilter( IBaseFilter *iface ) -{ - return CONTAINING_RECORD(iface, ParserImpl, filter.IBaseFilter_iface); -} - -static inline ParserImpl *impl_from_strmbase_filter(struct strmbase_filter *iface) -{ - return CONTAINING_RECORD(iface, ParserImpl, filter); -} - -IPin *parser_get_pin(struct strmbase_filter *iface, unsigned int index) -{ - ParserImpl *filter = impl_from_strmbase_filter(iface); - - if (!index) - return &filter->pInputPin->pin.IPin_iface; - else if (index <= filter->cStreams) - return &filter->sources[index - 1]->pin.pin.IPin_iface; - return NULL; -} - -HRESULT Parser_Create(ParserImpl *pParser, const IBaseFilterVtbl *vtbl, IUnknown *outer, - const CLSID *clsid, const struct strmbase_filter_ops *func_table, const WCHAR *sink_name, - PFN_PROCESS_SAMPLE fnProcessSample, PFN_QUERY_ACCEPT fnQueryAccept, PFN_PRE_CONNECT fnPreConnect, - PFN_CLEANUP fnCleanup, PFN_DISCONNECT fnDisconnect, REQUESTPROC fnRequest, - STOPPROCESSPROC fnDone, SourceSeeking_ChangeStop stop, - SourceSeeking_ChangeStart start, SourceSeeking_ChangeRate rate) -{ - HRESULT hr; - - strmbase_filter_init(&pParser->filter, vtbl, outer, clsid, func_table); - - pParser->fnDisconnect = fnDisconnect; - - pParser->cStreams = 0; - pParser->sources = CoTaskMemAlloc(0 * sizeof(IPin *)); - - if (!start) - start = Parser_ChangeStart; - - if (!stop) - stop = Parser_ChangeStop; - - if (!rate) - rate = Parser_ChangeRate; - - SourceSeeking_Init(&pParser->sourceSeeking, &Parser_Seeking_Vtbl, stop, start, rate, &pParser->filter.csFilter); - - hr = PullPin_Construct(&Parser_InputPin_Vtbl, &pParser->filter, sink_name, - fnProcessSample, (void *)pParser, fnQueryAccept, fnCleanup, fnRequest, - fnDone, (IPin **)&pParser->pInputPin); - - if (SUCCEEDED(hr)) - { - pParser->pInputPin->fnPreConnect = fnPreConnect; - } - else - { - CoTaskMemFree(pParser->sources); - strmbase_filter_cleanup(&pParser->filter); - CoTaskMemFree(pParser); - } - - return hr; -} - -HRESULT WINAPI Parser_QueryInterface(IBaseFilter * iface, REFIID riid, LPVOID * ppv) -{ - ParserImpl *This = impl_from_IBaseFilter(iface); - TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if ( IsEqualIID(riid, &IID_IUnknown) - || IsEqualIID(riid, &IID_IPersist) - || IsEqualIID(riid, &IID_IMediaFilter) - || IsEqualIID(riid, &IID_IBaseFilter) ) - *ppv = &This->filter.IBaseFilter_iface; - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)*ppv); - return S_OK; - } - - if (!IsEqualIID(riid, &IID_IPin) && !IsEqualIID(riid, &IID_IVideoWindow)) - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -ULONG WINAPI Parser_AddRef(IBaseFilter * iface) -{ - return BaseFilterImpl_AddRef(iface); -} - -void Parser_Destroy(ParserImpl *This) -{ - IPin *connected = NULL; - HRESULT hr; - - PullPin_WaitForStateChange(This->pInputPin, INFINITE); - - /* Don't need to clean up output pins, freeing input pin will do that */ - IPin_ConnectedTo(&This->pInputPin->pin.IPin_iface, &connected); - if (connected) - { - hr = IPin_Disconnect(connected); - assert(hr == S_OK); - IPin_Release(connected); - hr = IPin_Disconnect(&This->pInputPin->pin.IPin_iface); - assert(hr == S_OK); - } - - PullPin_destroy(This->pInputPin); - - CoTaskMemFree(This->sources); - strmbase_filter_cleanup(&This->filter); - - TRACE("Destroying parser\n"); - CoTaskMemFree(This); -} - -/** IMediaFilter methods **/ - -HRESULT WINAPI Parser_Stop(IBaseFilter * iface) -{ - ParserImpl *This = impl_from_IBaseFilter(iface); - PullPin *pin = This->pInputPin; - ULONG i; - - TRACE("%p->()\n", This); - - EnterCriticalSection(&pin->thread_lock); - - IAsyncReader_BeginFlush(This->pInputPin->pReader); - EnterCriticalSection(&This->filter.csFilter); - - if (This->filter.state == State_Stopped) - { - LeaveCriticalSection(&This->filter.csFilter); - IAsyncReader_EndFlush(This->pInputPin->pReader); - LeaveCriticalSection(&pin->thread_lock); - return S_OK; - } - - This->filter.state = State_Stopped; - - for (i = 0; i < This->cStreams; ++i) - { - BaseOutputPinImpl_Inactive(&This->sources[i]->pin); - } - - LeaveCriticalSection(&This->filter.csFilter); - - PullPin_PauseProcessing(This->pInputPin); - PullPin_WaitForStateChange(This->pInputPin, INFINITE); - IAsyncReader_EndFlush(This->pInputPin->pReader); - - LeaveCriticalSection(&pin->thread_lock); - return S_OK; -} - -HRESULT WINAPI Parser_Pause(IBaseFilter * iface) -{ - HRESULT hr = S_OK; - ParserImpl *This = impl_from_IBaseFilter(iface); - PullPin *pin = This->pInputPin; - - TRACE("%p->()\n", This); - - EnterCriticalSection(&pin->thread_lock); - EnterCriticalSection(&This->filter.csFilter); - - if (This->filter.state == State_Paused) - { - LeaveCriticalSection(&This->filter.csFilter); - LeaveCriticalSection(&pin->thread_lock); - return S_OK; - } - - if (This->filter.state == State_Stopped) - { - LeaveCriticalSection(&This->filter.csFilter); - hr = IBaseFilter_Run(iface, -1); - EnterCriticalSection(&This->filter.csFilter); - } - - if (SUCCEEDED(hr)) - This->filter.state = State_Paused; - - LeaveCriticalSection(&This->filter.csFilter); - LeaveCriticalSection(&pin->thread_lock); - - return hr; -} - -HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart) -{ - HRESULT hr = S_OK; - ParserImpl *This = impl_from_IBaseFilter(iface); - PullPin *pin = This->pInputPin; - - ULONG i; - - TRACE("%p->(%s)\n", This, wine_dbgstr_longlong(tStart)); - - EnterCriticalSection(&pin->thread_lock); - EnterCriticalSection(&This->filter.csFilter); - { - HRESULT hr_any = VFW_E_NOT_CONNECTED; - - This->filter.rtStreamStart = tStart; - if (This->filter.state == State_Running || This->filter.state == State_Paused) - { - This->filter.state = State_Running; - LeaveCriticalSection(&This->filter.csFilter); - LeaveCriticalSection(&pin->thread_lock); - return S_OK; - } - - for (i = 0; i < This->cStreams; ++i) - { - hr = BaseOutputPinImpl_Active(&This->sources[i]->pin); - if (SUCCEEDED(hr)) - hr_any = hr; - } - - hr = hr_any; - if (SUCCEEDED(hr)) - { - LeaveCriticalSection(&This->filter.csFilter); - hr = PullPin_StartProcessing(This->pInputPin); - EnterCriticalSection(&This->filter.csFilter); - } - - if (SUCCEEDED(hr)) - This->filter.state = State_Running; - } - LeaveCriticalSection(&This->filter.csFilter); - LeaveCriticalSection(&pin->thread_lock); - - return hr; -} - -HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState) -{ - ParserImpl *This = impl_from_IBaseFilter(iface); - PullPin *pin = This->pInputPin; - HRESULT hr = S_OK; - - TRACE("%p->(%d, %p)\n", This, dwMilliSecsTimeout, pState); - - EnterCriticalSection(&pin->thread_lock); - EnterCriticalSection(&This->filter.csFilter); - { - *pState = This->filter.state; - } - LeaveCriticalSection(&This->filter.csFilter); - - if (This->pInputPin && (PullPin_WaitForStateChange(This->pInputPin, dwMilliSecsTimeout) == S_FALSE)) - hr = VFW_S_STATE_INTERMEDIATE; - LeaveCriticalSection(&pin->thread_lock); - - return hr; -} - -HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock) -{ - ParserImpl *This = impl_from_IBaseFilter(iface); - PullPin *pin = This->pInputPin; - - TRACE("%p->(%p)\n", This, pClock); - - EnterCriticalSection(&pin->thread_lock); - BaseFilterImpl_SetSyncSource(iface,pClock); - LeaveCriticalSection(&pin->thread_lock); - - return S_OK; -} - -static const struct strmbase_source_ops source_ops = -{ - { - Parser_OutputPin_CheckMediaType, - Parser_OutputPin_GetMediaType - }, - BaseOutputPinImpl_AttemptConnection, - Parser_OutputPin_DecideBufferSize, - Parser_OutputPin_DecideAllocator, -}; - -HRESULT Parser_AddPin(ParserImpl *filter, const WCHAR *name, - ALLOCATOR_PROPERTIES *props, const AM_MEDIA_TYPE *mt) -{ - Parser_OutputPin **old_sources; - Parser_OutputPin *object; - - if (!(object = CoTaskMemAlloc(sizeof(*object)))) - return E_OUTOFMEMORY; - - old_sources = filter->sources; - - filter->sources = CoTaskMemAlloc((filter->cStreams + 1) * sizeof(filter->sources[0])); - memcpy(filter->sources, old_sources, filter->cStreams * sizeof(filter->sources[0])); - filter->sources[filter->cStreams] = object; - - strmbase_source_init(&object->pin, &Parser_OutputPin_Vtbl, &filter->filter, - name, &source_ops); - - object->pmt = CoTaskMemAlloc(sizeof(AM_MEDIA_TYPE)); - CopyMediaType(object->pmt, mt); - object->dwSamplesProcessed = 0; - object->allocProps = *props; - filter->cStreams++; - BaseFilterImpl_IncrementPinVersion(&filter->filter); - CoTaskMemFree(old_sources); - - return S_OK; -} - -static void free_source_pin(Parser_OutputPin *pin) -{ - if (pin->pin.pin.pConnectedTo) - { - IPin_Disconnect(pin->pin.pin.pConnectedTo); - IPin_Disconnect(&pin->pin.pin.IPin_iface); - } - - FreeMediaType(pin->pmt); - CoTaskMemFree(pin->pmt); - strmbase_source_cleanup(&pin->pin); - CoTaskMemFree(pin); -} - -static HRESULT Parser_RemoveOutputPins(ParserImpl * This) -{ - /* NOTE: should be in critical section when calling this function */ - ULONG i; - Parser_OutputPin **old_sources = This->sources; - - TRACE("(%p)\n", This); - - This->sources = CoTaskMemAlloc(0); - - for (i = 0; i < This->cStreams; i++) - free_source_pin(old_sources[i]); - - BaseFilterImpl_IncrementPinVersion(&This->filter); - This->cStreams = 0; - CoTaskMemFree(old_sources); - - return S_OK; -} - -static HRESULT WINAPI Parser_ChangeStart(IMediaSeeking *iface) -{ - FIXME("(%p) filter hasn't implemented start position change!\n", iface); - return S_OK; -} - -static HRESULT WINAPI Parser_ChangeStop(IMediaSeeking *iface) -{ - FIXME("(%p) filter hasn't implemented stop position change!\n", iface); - return S_OK; -} - -static HRESULT WINAPI Parser_ChangeRate(IMediaSeeking *iface) -{ - FIXME("(%p) filter hasn't implemented rate change!\n", iface); - return S_OK; -} - - -static HRESULT WINAPI Parser_Seeking_QueryInterface(IMediaSeeking * iface, REFIID riid, LPVOID * ppv) -{ - ParserImpl *This = impl_from_IMediaSeeking(iface); - - return IBaseFilter_QueryInterface(&This->filter.IBaseFilter_iface, riid, ppv); -} - -static ULONG WINAPI Parser_Seeking_AddRef(IMediaSeeking * iface) -{ - ParserImpl *This = impl_from_IMediaSeeking(iface); - - return IBaseFilter_AddRef(&This->filter.IBaseFilter_iface); -} - -static ULONG WINAPI Parser_Seeking_Release(IMediaSeeking * iface) -{ - ParserImpl *This = impl_from_IMediaSeeking(iface); - - return IBaseFilter_Release(&This->filter.IBaseFilter_iface); -} - -static const IMediaSeekingVtbl Parser_Seeking_Vtbl = -{ - Parser_Seeking_QueryInterface, - Parser_Seeking_AddRef, - Parser_Seeking_Release, - SourceSeekingImpl_GetCapabilities, - SourceSeekingImpl_CheckCapabilities, - SourceSeekingImpl_IsFormatSupported, - SourceSeekingImpl_QueryPreferredFormat, - SourceSeekingImpl_GetTimeFormat, - SourceSeekingImpl_IsUsingTimeFormat, - SourceSeekingImpl_SetTimeFormat, - SourceSeekingImpl_GetDuration, - SourceSeekingImpl_GetStopPosition, - SourceSeekingImpl_GetCurrentPosition, - SourceSeekingImpl_ConvertTimeFormat, - SourceSeekingImpl_SetPositions, - SourceSeekingImpl_GetPositions, - SourceSeekingImpl_GetAvailable, - SourceSeekingImpl_SetRate, - SourceSeekingImpl_GetRate, - SourceSeekingImpl_GetPreroll -}; - -static HRESULT WINAPI Parser_OutputPin_DecideBufferSize(struct strmbase_source *iface, - IMemAllocator *pAlloc, ALLOCATOR_PROPERTIES *ppropInputRequest) -{ - Parser_OutputPin *This = (Parser_OutputPin*)iface; - ALLOCATOR_PROPERTIES actual; - - if (ppropInputRequest->cbAlign && ppropInputRequest->cbAlign != This->allocProps.cbAlign) - FIXME("Requested Buffer cbAlign mismatch %i,%i\n",This->allocProps.cbAlign, ppropInputRequest->cbAlign); - if (ppropInputRequest->cbPrefix) - FIXME("Requested Buffer cbPrefix mismatch %i,%i\n",This->allocProps.cbPrefix, ppropInputRequest->cbPrefix); - if (ppropInputRequest->cbBuffer) - FIXME("Requested Buffer cbBuffer mismatch %i,%i\n",This->allocProps.cbBuffer, ppropInputRequest->cbBuffer); - if (ppropInputRequest->cBuffers) - FIXME("Requested Buffer cBuffers mismatch %i,%i\n",This->allocProps.cBuffers, ppropInputRequest->cBuffers); - - return IMemAllocator_SetProperties(pAlloc, &This->allocProps, &actual); -} - -static HRESULT WINAPI Parser_OutputPin_GetMediaType(BasePin *iface, int iPosition, AM_MEDIA_TYPE *pmt) -{ - Parser_OutputPin *This = (Parser_OutputPin*)iface; - if (iPosition < 0) - return E_INVALIDARG; - if (iPosition > 0) - return VFW_S_NO_MORE_ITEMS; - CopyMediaType(pmt, This->pmt); - return S_OK; -} - -static HRESULT WINAPI Parser_OutputPin_DecideAllocator(struct strmbase_source *iface, - IMemInputPin *pPin, IMemAllocator **pAlloc) -{ - Parser_OutputPin *This = (Parser_OutputPin*)iface; - HRESULT hr; - - *pAlloc = NULL; - - if (This->alloc) - { - hr = IMemInputPin_NotifyAllocator(pPin, This->alloc, This->readonly); - if (SUCCEEDED(hr)) - { - *pAlloc = This->alloc; - IMemAllocator_AddRef(*pAlloc); - } - } - else - hr = VFW_E_NO_ALLOCATOR; - - return hr; -} - -static HRESULT WINAPI Parser_OutputPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) -{ - Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); - - TRACE("(%s, %p)\n", qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = iface; - else if (IsEqualIID(riid, &IID_IPin)) - *ppv = iface; - /* The Parser filter does not support querying IMediaSeeking, return it directly */ - else if (IsEqualIID(riid, &IID_IMediaSeeking)) - *ppv = &impl_from_IBaseFilter(&This->pin.pin.filter->IBaseFilter_iface)->sourceSeeking; - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -static HRESULT WINAPI Parser_OutputPin_Connect(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - Parser_OutputPin *This = unsafe_impl_Parser_OutputPin_from_IPin(iface); - ParserImpl *parser = impl_from_IBaseFilter(&This->pin.pin.filter->IBaseFilter_iface); - - /* Set the allocator to our input pin's */ - EnterCriticalSection(&parser->filter.csFilter); - This->alloc = parser->pInputPin->pAlloc; - LeaveCriticalSection(&parser->filter.csFilter); - - return BaseOutputPinImpl_Connect(iface, pReceivePin, pmt); -} - -static HRESULT WINAPI Parser_OutputPin_CheckMediaType(BasePin *pin, const AM_MEDIA_TYPE *pmt) -{ - Parser_OutputPin *This = (Parser_OutputPin *)pin; - - dump_AM_MEDIA_TYPE(pmt); - - return (memcmp(This->pmt, pmt, sizeof(AM_MEDIA_TYPE)) == 0); -} - -static const IPinVtbl Parser_OutputPin_Vtbl = -{ - Parser_OutputPin_QueryInterface, - BasePinImpl_AddRef, - BasePinImpl_Release, - Parser_OutputPin_Connect, - BaseOutputPinImpl_ReceiveConnection, - BaseOutputPinImpl_Disconnect, - BasePinImpl_ConnectedTo, - BasePinImpl_ConnectionMediaType, - BasePinImpl_QueryPinInfo, - BasePinImpl_QueryDirection, - BasePinImpl_QueryId, - BasePinImpl_QueryAccept, - BasePinImpl_EnumMediaTypes, - BasePinImpl_QueryInternalConnections, - BaseOutputPinImpl_EndOfStream, - BaseOutputPinImpl_BeginFlush, - BaseOutputPinImpl_EndFlush, - BasePinImpl_NewSegment -}; - -static HRESULT WINAPI Parser_PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) -{ - PullPin *This = impl_PullPin_from_IPin(iface); - - TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - /* - * It is important to capture the request for the IMediaSeeking interface before it is passed - * on to PullPin_QueryInterface, this is necessary since the Parser filter does not support - * querying IMediaSeeking - */ - if (IsEqualIID(riid, &IID_IMediaSeeking)) - *ppv = &impl_from_IBaseFilter(&This->pin.filter->IBaseFilter_iface)->sourceSeeking; - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - return PullPin_QueryInterface(iface, riid, ppv); -} - -static HRESULT WINAPI Parser_PullPin_Disconnect(IPin * iface) -{ - HRESULT hr; - PullPin *This = impl_PullPin_from_IPin(iface); - - TRACE("()\n"); - - EnterCriticalSection(&This->thread_lock); - EnterCriticalSection(&This->pin.filter->csFilter); - { - if (This->pin.pConnectedTo) - { - FILTER_STATE state; - ParserImpl *Parser = impl_from_IBaseFilter(&This->pin.filter->IBaseFilter_iface); - - LeaveCriticalSection(&This->pin.filter->csFilter); - hr = IBaseFilter_GetState(&This->pin.filter->IBaseFilter_iface, INFINITE, &state); - EnterCriticalSection(&This->pin.filter->csFilter); - - if (SUCCEEDED(hr) && (state == State_Stopped) && SUCCEEDED(Parser->fnDisconnect(Parser))) - { - LeaveCriticalSection(&This->pin.filter->csFilter); - PullPin_Disconnect(iface); - EnterCriticalSection(&This->pin.filter->csFilter); - hr = Parser_RemoveOutputPins(impl_from_IBaseFilter(&This->pin.filter->IBaseFilter_iface)); - } - else - hr = VFW_E_NOT_STOPPED; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(&This->pin.filter->csFilter); - LeaveCriticalSection(&This->thread_lock); - - return hr; -} - -static HRESULT WINAPI Parser_PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - HRESULT hr; - - TRACE("()\n"); - - hr = PullPin_ReceiveConnection(iface, pReceivePin, pmt); - if (FAILED(hr)) - { - BasePin *This = (BasePin *)iface; - - EnterCriticalSection(&This->filter->csFilter); - Parser_RemoveOutputPins(impl_from_IBaseFilter(&This->filter->IBaseFilter_iface)); - LeaveCriticalSection(&This->filter->csFilter); - } - - return hr; -} - -static HRESULT WINAPI Parser_PullPin_EnumMediaTypes(IPin *iface, IEnumMediaTypes **ppEnum) -{ - BasePin *This = (BasePin *)iface; - - TRACE("(%p/%p)->(%p)\n", This, iface, ppEnum); - - return EnumMediaTypes_Construct(This, BasePinImpl_GetMediaType, BasePinImpl_GetMediaTypeVersion, ppEnum); -} - -static const IPinVtbl Parser_InputPin_Vtbl = -{ - Parser_PullPin_QueryInterface, - BasePinImpl_AddRef, - BasePinImpl_Release, - BaseInputPinImpl_Connect, - Parser_PullPin_ReceiveConnection, - Parser_PullPin_Disconnect, - BasePinImpl_ConnectedTo, - BasePinImpl_ConnectionMediaType, - BasePinImpl_QueryPinInfo, - BasePinImpl_QueryDirection, - BasePinImpl_QueryId, - PullPin_QueryAccept, - Parser_PullPin_EnumMediaTypes, - BasePinImpl_QueryInternalConnections, - PullPin_EndOfStream, - PullPin_BeginFlush, - PullPin_EndFlush, - PullPin_NewSegment -}; diff --git a/dlls/quartz/parser.h b/dlls/quartz/parser.h deleted file mode 100644 index 748b7131926..00000000000 --- a/dlls/quartz/parser.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Parser declarations - * - * 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 - */ - -typedef struct ParserImpl ParserImpl; - -typedef HRESULT (*PFN_PROCESS_SAMPLE) (LPVOID iface, IMediaSample * pSample, DWORD_PTR cookie); -typedef HRESULT (*PFN_QUERY_ACCEPT) (LPVOID iface, const AM_MEDIA_TYPE * pmt); -typedef HRESULT (*PFN_PRE_CONNECT) (IPin * iface, IPin * pConnectPin, ALLOCATOR_PROPERTIES *prop); -typedef HRESULT (*PFN_CLEANUP) (LPVOID iface); -typedef HRESULT (*PFN_DISCONNECT) (LPVOID iface); - -typedef struct Parser_OutputPin -{ - struct strmbase_source pin; - - AM_MEDIA_TYPE * pmt; - LONGLONG dwSamplesProcessed; - ALLOCATOR_PROPERTIES allocProps; - - IMemAllocator *alloc; - BOOL readonly; -} Parser_OutputPin; - -struct ParserImpl -{ - struct strmbase_filter filter; - - PFN_DISCONNECT fnDisconnect; - - PullPin *pInputPin; - Parser_OutputPin **sources; - ULONG cStreams; - SourceSeeking sourceSeeking; -}; - -extern HRESULT Parser_AddPin(ParserImpl *filter, const WCHAR *name, - ALLOCATOR_PROPERTIES *props, const AM_MEDIA_TYPE *mt); - -HRESULT Parser_Create(ParserImpl *parser, const IBaseFilterVtbl *vtbl, IUnknown *outer, - const CLSID *clsid, const struct strmbase_filter_ops *func_table, const WCHAR *sink_name, - PFN_PROCESS_SAMPLE, PFN_QUERY_ACCEPT, PFN_PRE_CONNECT, PFN_CLEANUP, PFN_DISCONNECT, - REQUESTPROC, STOPPROCESSPROC, SourceSeeking_ChangeStop, - SourceSeeking_ChangeStart, SourceSeeking_ChangeRate) DECLSPEC_HIDDEN; - -/* Override the _Release function and call this when releasing */ -extern void Parser_Destroy(ParserImpl *This); - -extern HRESULT WINAPI Parser_Stop(IBaseFilter * iface); -extern HRESULT WINAPI Parser_Pause(IBaseFilter * iface); -extern HRESULT WINAPI Parser_Run(IBaseFilter * iface, REFERENCE_TIME tStart); -extern HRESULT WINAPI Parser_GetState(IBaseFilter * iface, DWORD dwMilliSecsTimeout, FILTER_STATE *pState); -extern HRESULT WINAPI Parser_SetSyncSource(IBaseFilter * iface, IReferenceClock *pClock); - -IPin *parser_get_pin(struct strmbase_filter *iface, unsigned int index) DECLSPEC_HIDDEN; - -/* COM helpers */ -static inline Parser_OutputPin *unsafe_impl_Parser_OutputPin_from_IPin( IPin *iface ) -{ - return CONTAINING_RECORD(iface, Parser_OutputPin, pin.pin.IPin_iface); -} diff --git a/dlls/quartz/pin.c b/dlls/quartz/pin.c deleted file mode 100644 index bf31799641d..00000000000 --- a/dlls/quartz/pin.c +++ /dev/null @@ -1,818 +0,0 @@ -/* - * Generic Implementation of IPin Interface - * - * Copyright 2003 Robert Shearman - * - * 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 "wine/debug.h" -#include "uuids.h" -#include "vfwmsgs.h" -#include <assert.h> - -WINE_DEFAULT_DEBUG_CHANNEL(quartz); - -#define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) -#define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) - -typedef HRESULT (*SendPinFunc)( IPin *to, LPVOID arg ); - -/** Helper function, there are a lot of places where the error code is inherited - * The following rules apply: - * - * Return the first received error code (E_NOTIMPL is ignored) - * If no errors occur: return the first received non-error-code that isn't S_OK - */ -static HRESULT updatehres( HRESULT original, HRESULT new ) -{ - if (FAILED( original ) || new == E_NOTIMPL) - return original; - - if (FAILED( new ) || original == S_OK) - return new; - - return original; -} - -/** Sends a message from a pin further to other, similar pins - * fnMiddle is called on each pin found further on the stream. - * fnEnd (can be NULL) is called when the message can't be sent any further (this is a renderer or source) - * - * If the pin given is an input pin, the message will be sent downstream to other input pins - * If the pin given is an output pin, the message will be sent upstream to other output pins - */ -static HRESULT SendFurther( IPin *from, SendPinFunc fnMiddle, LPVOID arg, SendPinFunc fnEnd ) -{ - PIN_INFO pin_info; - ULONG amount = 0; - HRESULT hr = S_OK; - HRESULT hr_return = S_OK; - IEnumPins *enumpins = NULL; - BOOL foundend = TRUE; - PIN_DIRECTION from_dir; - - IPin_QueryDirection( from, &from_dir ); - - hr = IPin_QueryInternalConnections( from, NULL, &amount ); - if (hr != E_NOTIMPL && amount) - FIXME("Use QueryInternalConnections!\n"); - - pin_info.pFilter = NULL; - hr = IPin_QueryPinInfo( from, &pin_info ); - if (FAILED(hr)) - goto out; - - hr = IBaseFilter_EnumPins( pin_info.pFilter, &enumpins ); - if (FAILED(hr)) - goto out; - - hr = IEnumPins_Reset( enumpins ); - while (hr == S_OK) { - IPin *pin = NULL; - hr = IEnumPins_Next( enumpins, 1, &pin, NULL ); - if (hr == VFW_E_ENUM_OUT_OF_SYNC) - { - hr = IEnumPins_Reset( enumpins ); - continue; - } - if (pin) - { - PIN_DIRECTION dir; - - IPin_QueryDirection( pin, &dir ); - if (dir != from_dir) - { - IPin *connected = NULL; - - foundend = FALSE; - IPin_ConnectedTo( pin, &connected ); - if (connected) - { - HRESULT hr_local; - - hr_local = fnMiddle( connected, arg ); - hr_return = updatehres( hr_return, hr_local ); - IPin_Release(connected); - } - } - IPin_Release( pin ); - } - else - { - hr = S_OK; - break; - } - } - - if (!foundend) - hr = hr_return; - else if (fnEnd) { - HRESULT hr_local; - - hr_local = fnEnd( from, arg ); - hr_return = updatehres( hr_return, hr_local ); - } - -out: - if (enumpins) - IEnumPins_Release( enumpins ); - if (pin_info.pFilter) - IBaseFilter_Release( pin_info.pFilter ); - return hr; -} - -static HRESULT deliver_endofstream(IPin* pin, LPVOID unused) -{ - return IPin_EndOfStream( pin ); -} - -static HRESULT deliver_beginflush(IPin* pin, LPVOID unused) -{ - return IPin_BeginFlush( pin ); -} - -static HRESULT deliver_endflush(IPin* pin, LPVOID unused) -{ - return IPin_EndFlush( pin ); -} - -typedef struct newsegmentargs -{ - REFERENCE_TIME tStart, tStop; - double rate; -} newsegmentargs; - -static HRESULT deliver_newsegment(IPin *pin, LPVOID data) -{ - newsegmentargs *args = data; - return IPin_NewSegment(pin, args->tStart, args->tStop, args->rate); -} - -/*** PullPin implementation ***/ - -static HRESULT PullPin_Init(const IPinVtbl *PullPin_Vtbl, struct strmbase_filter *filter, - const WCHAR *name, SAMPLEPROC_PULL pSampleProc, void *pUserData, - QUERYACCEPTPROC pQueryAccept, CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, - STOPPROCESSPROC pDone, PullPin *pPinImpl) -{ - /* Common attributes */ - pPinImpl->pin.IPin_iface.lpVtbl = PullPin_Vtbl; - pPinImpl->pin.pConnectedTo = NULL; - wcscpy(pPinImpl->pin.name, name); - pPinImpl->pin.dir = PINDIR_INPUT; - pPinImpl->pin.filter = filter; - ZeroMemory(&pPinImpl->pin.mtCurrent, sizeof(AM_MEDIA_TYPE)); - - /* Input pin attributes */ - pPinImpl->pUserData = pUserData; - pPinImpl->fnQueryAccept = pQueryAccept; - pPinImpl->fnSampleProc = pSampleProc; - pPinImpl->fnCleanProc = pCleanUp; - pPinImpl->fnDone = pDone; - pPinImpl->fnPreConnect = NULL; - pPinImpl->pAlloc = NULL; - pPinImpl->prefAlloc = NULL; - pPinImpl->pReader = NULL; - pPinImpl->hThread = NULL; - pPinImpl->hEventStateChanged = CreateEventW(NULL, TRUE, TRUE, NULL); - pPinImpl->thread_sleepy = CreateEventW(NULL, FALSE, FALSE, NULL); - - pPinImpl->rtStart = 0; - pPinImpl->rtCurrent = 0; - pPinImpl->rtStop = ((LONGLONG)0x7fffffff << 32) | 0xffffffff; - pPinImpl->dRate = 1.0; - pPinImpl->state = Req_Die; - pPinImpl->fnCustomRequest = pCustomRequest; - pPinImpl->stop_playback = TRUE; - - InitializeCriticalSection(&pPinImpl->thread_lock); - pPinImpl->thread_lock.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": PullPin.thread_lock"); - - return S_OK; -} - -HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, struct strmbase_filter *filter, const WCHAR *name, - SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, - CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, - IPin ** ppPin) -{ - PullPin * pPinImpl; - - *ppPin = NULL; - - pPinImpl = CoTaskMemAlloc(sizeof(*pPinImpl)); - - if (!pPinImpl) - return E_OUTOFMEMORY; - - if (SUCCEEDED(PullPin_Init(PullPin_Vtbl, filter, name, pSampleProc, pUserData, - pQueryAccept, pCleanUp, pCustomRequest, pDone, pPinImpl))) - { - *ppPin = &pPinImpl->pin.IPin_iface; - return S_OK; - } - - CoTaskMemFree(pPinImpl); - return E_FAIL; -} - -static HRESULT PullPin_InitProcessing(PullPin * This); - -HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt) -{ - PIN_DIRECTION pindirReceive; - HRESULT hr = S_OK; - PullPin *This = impl_PullPin_from_IPin(iface); - - TRACE("(%p/%p)->(%p, %p)\n", This, iface, pReceivePin, pmt); - dump_AM_MEDIA_TYPE(pmt); - - EnterCriticalSection(&This->pin.filter->csFilter); - if (!This->pin.pConnectedTo) - { - ALLOCATOR_PROPERTIES props; - - props.cBuffers = 3; - props.cbBuffer = 64 * 1024; /* 64 KB */ - props.cbAlign = 1; - props.cbPrefix = 0; - - if (This->fnQueryAccept(This->pUserData, pmt) != S_OK) - hr = VFW_E_TYPE_NOT_ACCEPTED; /* FIXME: shouldn't we just map common errors onto - * VFW_E_TYPE_NOT_ACCEPTED and pass the value on otherwise? */ - - if (SUCCEEDED(hr)) - { - IPin_QueryDirection(pReceivePin, &pindirReceive); - - if (pindirReceive != PINDIR_OUTPUT) - { - ERR("Can't connect from non-output pin\n"); - hr = VFW_E_INVALID_DIRECTION; - } - } - - This->pReader = NULL; - This->pAlloc = NULL; - This->prefAlloc = NULL; - if (SUCCEEDED(hr)) - { - hr = IPin_QueryInterface(pReceivePin, &IID_IAsyncReader, (LPVOID *)&This->pReader); - } - - if (SUCCEEDED(hr) && This->fnPreConnect) - { - hr = This->fnPreConnect(iface, pReceivePin, &props); - } - - /* - * Some custom filters (such as the one used by Fallout 3 - * and Fallout: New Vegas) expect to be passed a non-NULL - * preferred allocator. - */ - if (SUCCEEDED(hr)) - { - hr = StdMemAllocator_create(NULL, (LPVOID *) &This->prefAlloc); - } - - if (SUCCEEDED(hr)) - { - hr = IAsyncReader_RequestAllocator(This->pReader, This->prefAlloc, &props, &This->pAlloc); - } - - if (SUCCEEDED(hr)) - { - CopyMediaType(&This->pin.mtCurrent, pmt); - This->pin.pConnectedTo = pReceivePin; - IPin_AddRef(pReceivePin); - hr = IMemAllocator_Commit(This->pAlloc); - } - - if (SUCCEEDED(hr)) - hr = PullPin_InitProcessing(This); - - if (FAILED(hr)) - { - if (This->pReader) - IAsyncReader_Release(This->pReader); - This->pReader = NULL; - if (This->prefAlloc) - IMemAllocator_Release(This->prefAlloc); - This->prefAlloc = NULL; - if (This->pAlloc) - IMemAllocator_Release(This->pAlloc); - This->pAlloc = NULL; - } - } - else - hr = VFW_E_ALREADY_CONNECTED; - LeaveCriticalSection(&This->pin.filter->csFilter); - return hr; -} - -HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv) -{ - PullPin *This = impl_PullPin_from_IPin(iface); - - TRACE("(%p/%p)->(%s, %p)\n", This, iface, qzdebugstr_guid(riid), ppv); - - *ppv = NULL; - - if (IsEqualIID(riid, &IID_IUnknown)) - *ppv = iface; - else if (IsEqualIID(riid, &IID_IPin)) - *ppv = iface; - else if (IsEqualIID(riid, &IID_IMediaSeeking) || - IsEqualIID(riid, &IID_IQualityControl)) - { - return IBaseFilter_QueryInterface(&This->pin.filter->IBaseFilter_iface, riid, ppv); - } - - if (*ppv) - { - IUnknown_AddRef((IUnknown *)(*ppv)); - return S_OK; - } - - FIXME("No interface for %s!\n", qzdebugstr_guid(riid)); - - return E_NOINTERFACE; -} - -void PullPin_destroy(PullPin *pin) -{ - WaitForSingleObject(pin->hEventStateChanged, INFINITE); - assert(!pin->hThread); - - if (pin->prefAlloc) - IMemAllocator_Release(pin->prefAlloc); - if (pin->pAlloc) - IMemAllocator_Release(pin->pAlloc); - if (pin->pReader) - IAsyncReader_Release(pin->pReader); - CloseHandle(pin->thread_sleepy); - CloseHandle(pin->hEventStateChanged); - pin->thread_lock.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&pin->thread_lock); - CoTaskMemFree(pin); -} - -static void PullPin_Flush(PullPin *This) -{ - IMediaSample *pSample; - TRACE("Flushing!\n"); - - if (This->pReader) - { - /* Do not allow state to change while flushing */ - EnterCriticalSection(&This->pin.filter->csFilter); - - /* Flush outstanding samples */ - IAsyncReader_BeginFlush(This->pReader); - - for (;;) - { - DWORD_PTR dwUser; - - pSample = NULL; - IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser); - - if (!pSample) - break; - - assert(!IMediaSample_GetActualDataLength(pSample)); - - IMediaSample_Release(pSample); - } - - IAsyncReader_EndFlush(This->pReader); - - LeaveCriticalSection(&This->pin.filter->csFilter); - } -} - -static void PullPin_Thread_Process(PullPin *This) -{ - HRESULT hr; - IMediaSample * pSample = NULL; - ALLOCATOR_PROPERTIES allocProps; - - hr = IMemAllocator_GetProperties(This->pAlloc, &allocProps); - - This->cbAlign = allocProps.cbAlign; - - if (This->rtCurrent < This->rtStart) - This->rtCurrent = MEDIATIME_FROM_BYTES(ALIGNDOWN(BYTES_FROM_MEDIATIME(This->rtStart), This->cbAlign)); - - TRACE("Start\n"); - - if (This->rtCurrent >= This->rtStop) - { - IPin_EndOfStream(&This->pin.IPin_iface); - return; - } - - /* There is no sample in our buffer */ - hr = This->fnCustomRequest(This->pUserData); - - if (FAILED(hr)) - ERR("Request error: %x\n", hr); - - EnterCriticalSection(&This->pin.filter->csFilter); - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(&This->pin.filter->csFilter); - - if (SUCCEEDED(hr)) - do - { - DWORD_PTR dwUser; - - TRACE("Process sample\n"); - - pSample = NULL; - hr = IAsyncReader_WaitForNext(This->pReader, 10000, &pSample, &dwUser); - - /* Return an empty sample on error to the implementation in case it does custom parsing, so it knows it's gone */ - if (SUCCEEDED(hr)) - { - hr = This->fnSampleProc(This->pUserData, pSample, dwUser); - } - else - { - if (hr == VFW_E_TIMEOUT) - { - if (pSample != NULL) - WARN("Non-NULL sample returned with VFW_E_TIMEOUT.\n"); - hr = S_OK; - } - /* FIXME: Errors are not well handled yet! */ - else - ERR("Processing error: %x\n", hr); - } - - if (pSample) - { - IMediaSample_Release(pSample); - pSample = NULL; - } - } while (This->rtCurrent < This->rtStop && hr == S_OK && !This->stop_playback); - - /* - * Sample was rejected, and we are asked to terminate. When there is more than one buffer - * it is possible for a filter to have several queued samples, making it necessary to - * release all of these pending samples. - */ - if (This->stop_playback || FAILED(hr)) - { - DWORD_PTR dwUser; - - do - { - if (pSample) - IMediaSample_Release(pSample); - pSample = NULL; - IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser); - } while(pSample); - } - - /* Can't reset state to Sleepy here because that might race, instead PauseProcessing will do that for us - * Flush remaining samples - */ - if (This->fnDone) - This->fnDone(This->pUserData); - - TRACE("End: %08x, %d\n", hr, This->stop_playback); -} - -static void PullPin_Thread_Pause(PullPin *This) -{ - PullPin_Flush(This); - - EnterCriticalSection(&This->pin.filter->csFilter); - This->state = Req_Sleepy; - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(&This->pin.filter->csFilter); -} - -static void PullPin_Thread_Stop(PullPin *This) -{ - TRACE("(%p)->()\n", This); - - EnterCriticalSection(&This->pin.filter->csFilter); - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(&This->pin.filter->csFilter); - - IPin_Release(&This->pin.IPin_iface); - - CoUninitialize(); - ExitThread(0); -} - -static DWORD WINAPI PullPin_Thread_Main(LPVOID pv) -{ - PullPin *This = pv; - CoInitializeEx(NULL, COINIT_MULTITHREADED); - - PullPin_Flush(This); - - for (;;) - { - WaitForSingleObject(This->thread_sleepy, INFINITE); - - TRACE("State: %d\n", This->state); - - switch (This->state) - { - case Req_Die: PullPin_Thread_Stop(This); break; - case Req_Run: PullPin_Thread_Process(This); break; - case Req_Pause: PullPin_Thread_Pause(This); break; - case Req_Sleepy: ERR("Should not be signalled with SLEEPY!\n"); break; - default: ERR("Unknown state request: %d\n", This->state); break; - } - } - return 0; -} - -static HRESULT PullPin_InitProcessing(PullPin * This) -{ - HRESULT hr = S_OK; - - TRACE("(%p)->()\n", This); - - /* if we are connected */ - if (This->pAlloc) - { - DWORD dwThreadId; - - WaitForSingleObject(This->hEventStateChanged, INFINITE); - EnterCriticalSection(&This->pin.filter->csFilter); - - assert(!This->hThread); - assert(This->state == Req_Die); - assert(This->stop_playback); - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - This->state = Req_Sleepy; - - IPin_AddRef(&This->pin.IPin_iface); - - This->hThread = CreateThread(NULL, 0, PullPin_Thread_Main, This, 0, &dwThreadId); - if (!This->hThread) - { - hr = HRESULT_FROM_WIN32(GetLastError()); - IPin_Release(&This->pin.IPin_iface); - } - - if (SUCCEEDED(hr)) - { - SetEvent(This->hEventStateChanged); - /* If assert fails, that means a command was not processed before the thread previously terminated */ - } - LeaveCriticalSection(&This->pin.filter->csFilter); - } - - TRACE(" -- %x\n", hr); - - return hr; -} - -HRESULT PullPin_StartProcessing(PullPin * This) -{ - /* if we are connected */ - TRACE("(%p)->()\n", This); - if(This->pAlloc) - { - assert(This->hThread); - - PullPin_WaitForStateChange(This, INFINITE); - - assert(This->state == Req_Sleepy); - - /* Wake up! */ - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - This->state = Req_Run; - This->stop_playback = FALSE; - ResetEvent(This->hEventStateChanged); - SetEvent(This->thread_sleepy); - } - - return S_OK; -} - -HRESULT PullPin_PauseProcessing(PullPin * This) -{ - /* if we are connected */ - TRACE("(%p)->()\n", This); - if(This->pAlloc) - { - assert(This->hThread); - - PullPin_WaitForStateChange(This, INFINITE); - - EnterCriticalSection(&This->pin.filter->csFilter); - - assert(!This->stop_playback); - assert(This->state == Req_Run|| This->state == Req_Sleepy); - - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - - This->state = Req_Pause; - This->stop_playback = TRUE; - ResetEvent(This->hEventStateChanged); - SetEvent(This->thread_sleepy); - - /* Release any outstanding samples */ - if (This->pReader) - { - IMediaSample *pSample; - DWORD_PTR dwUser; - - do - { - pSample = NULL; - IAsyncReader_WaitForNext(This->pReader, 0, &pSample, &dwUser); - if (pSample) - IMediaSample_Release(pSample); - } while(pSample); - } - - LeaveCriticalSection(&This->pin.filter->csFilter); - } - - return S_OK; -} - -static HRESULT PullPin_StopProcessing(PullPin * This) -{ - TRACE("(%p)->()\n", This); - - /* if we are alive */ - assert(This->hThread); - - PullPin_WaitForStateChange(This, INFINITE); - - assert(This->state == Req_Pause || This->state == Req_Sleepy); - - This->stop_playback = TRUE; - This->state = Req_Die; - assert(WaitForSingleObject(This->thread_sleepy, 0) == WAIT_TIMEOUT); - ResetEvent(This->hEventStateChanged); - SetEvent(This->thread_sleepy); - return S_OK; -} - -HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds) -{ - if (WaitForSingleObject(This->hEventStateChanged, dwMilliseconds) == WAIT_TIMEOUT) - return S_FALSE; - return S_OK; -} - -HRESULT WINAPI PullPin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt) -{ - PullPin *This = impl_PullPin_from_IPin(iface); - - TRACE("(%p/%p)->(%p)\n", This, iface, pmt); - - return (This->fnQueryAccept(This->pUserData, pmt) == S_OK ? S_OK : S_FALSE); -} - -HRESULT WINAPI PullPin_EndOfStream(IPin * iface) -{ - PullPin *This = impl_PullPin_from_IPin(iface); - HRESULT hr = S_FALSE; - - TRACE("(%p)->()\n", iface); - - EnterCriticalSection(&This->pin.filter->csFilter); - hr = SendFurther( iface, deliver_endofstream, NULL, NULL ); - SetEvent(This->hEventStateChanged); - LeaveCriticalSection(&This->pin.filter->csFilter); - - return hr; -} - -HRESULT WINAPI PullPin_BeginFlush(IPin * iface) -{ - PullPin *This = impl_PullPin_from_IPin(iface); - TRACE("(%p)->()\n", This); - - EnterCriticalSection(&This->pin.filter->csFilter); - { - SendFurther( iface, deliver_beginflush, NULL, NULL ); - } - LeaveCriticalSection(&This->pin.filter->csFilter); - - EnterCriticalSection(&This->thread_lock); - { - if (This->pReader) - IAsyncReader_BeginFlush(This->pReader); - PullPin_WaitForStateChange(This, INFINITE); - - if (This->hThread && This->state == Req_Run) - { - PullPin_PauseProcessing(This); - PullPin_WaitForStateChange(This, INFINITE); - } - } - LeaveCriticalSection(&This->thread_lock); - - EnterCriticalSection(&This->pin.filter->csFilter); - { - This->fnCleanProc(This->pUserData); - } - LeaveCriticalSection(&This->pin.filter->csFilter); - - return S_OK; -} - -HRESULT WINAPI PullPin_EndFlush(IPin * iface) -{ - PullPin *This = impl_PullPin_from_IPin(iface); - - TRACE("(%p)->()\n", iface); - - /* Send further first: Else a race condition might terminate processing early */ - EnterCriticalSection(&This->pin.filter->csFilter); - SendFurther( iface, deliver_endflush, NULL, NULL ); - LeaveCriticalSection(&This->pin.filter->csFilter); - - EnterCriticalSection(&This->thread_lock); - { - FILTER_STATE state; - - if (This->pReader) - IAsyncReader_EndFlush(This->pReader); - - IBaseFilter_GetState(&This->pin.filter->IBaseFilter_iface, INFINITE, &state); - - if (state != State_Stopped) - PullPin_StartProcessing(This); - - PullPin_WaitForStateChange(This, INFINITE); - } - LeaveCriticalSection(&This->thread_lock); - - return S_OK; -} - -HRESULT WINAPI PullPin_Disconnect(IPin *iface) -{ - HRESULT hr; - PullPin *This = impl_PullPin_from_IPin(iface); - - TRACE("()\n"); - - EnterCriticalSection(&This->pin.filter->csFilter); - { - if (FAILED(hr = IMemAllocator_Decommit(This->pAlloc))) - ERR("Allocator decommit failed with error %x. Possible memory leak\n", hr); - - if (This->pin.pConnectedTo) - { - IPin_Release(This->pin.pConnectedTo); - This->pin.pConnectedTo = NULL; - PullPin_StopProcessing(This); - - FreeMediaType(&This->pin.mtCurrent); - ZeroMemory(&This->pin.mtCurrent, sizeof(This->pin.mtCurrent)); - hr = S_OK; - } - else - hr = S_FALSE; - } - LeaveCriticalSection(&This->pin.filter->csFilter); - - WaitForSingleObject(This->hThread, INFINITE); - CloseHandle(This->hThread); - This->hThread = NULL; - - return hr; -} - -HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate) -{ - newsegmentargs args; - FIXME("(%p)->(%s, %s, %g) stub\n", iface, wine_dbgstr_longlong(tStart), wine_dbgstr_longlong(tStop), dRate); - - args.tStart = tStart; - args.tStop = tStop; - args.rate = dRate; - - return SendFurther( iface, deliver_newsegment, &args, NULL ); -} diff --git a/dlls/quartz/pin.h b/dlls/quartz/pin.h deleted file mode 100644 index fb39d3a7e39..00000000000 --- a/dlls/quartz/pin.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * IPin function declarations to allow inheritance - * - * Copyright 2003 Robert Shearman - * - * 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 - */ - -/* This function will process incoming samples to the pin. - * Any return value valid in IMemInputPin::Receive is allowed here - * - * Cookie is the cookie that was set when requesting the buffer, if you don't - * implement custom requesting, you can safely ignore this - */ -typedef HRESULT (* SAMPLEPROC_PULL)(LPVOID userdata, IMediaSample * pSample, DWORD_PTR cookie); - -/* This function will determine whether a type is supported or not. - * It is allowed to return any error value (within reason), as opposed - * to IPin::QueryAccept which is only allowed to return S_OK or S_FALSE. - */ -typedef HRESULT (* QUERYACCEPTPROC)(LPVOID userdata, const AM_MEDIA_TYPE * pmt); - -/* This function is called prior to finalizing a connection with - * another pin and can be used to get things from the other pin - * like IMemInput interfaces. - * - * props contains some defaults, but you can safely override them to your liking - */ -typedef HRESULT (* PRECONNECTPROC)(IPin * iface, IPin * pConnectPin, ALLOCATOR_PROPERTIES *props); - -/* This function is called whenever a cleanup operation has to occur, - * this is usually after a flush, seek, or end of stream notification. - * This code may even be repeated multiple times, so build your code to - * tolerate this behavior. Return value is ignored and should be S_OK. - */ -typedef HRESULT (* CLEANUPPROC) (LPVOID userdata); - -/* This function is called whenever a request for a new sample is made, - * If you implement it (it can be NULL for default behavior), you have to - * call IMemAllocator_GetBuffer and IMemAllocator_RequestBuffer - * This is useful if you want to request more than 1 buffer at simultaneously - * - * This will also cause the Sample Proc to be called with empty buffers to indicate - * failure in retrieving the sample. - */ -typedef HRESULT (* REQUESTPROC) (LPVOID userdata); - -/* This function is called after processing is done (for whatever reason that is caused) - * This is useful if you create processing threads that need to die - */ -typedef HRESULT (* STOPPROCESSPROC) (LPVOID userdata); - -#define ALIGNDOWN(value,boundary) ((value)/(boundary)*(boundary)) -#define ALIGNUP(value,boundary) (ALIGNDOWN((value)+(boundary)-1, (boundary))) - -typedef struct PullPin -{ - /* inheritance C style! */ - BasePin pin; - LPVOID pUserData; - - REFERENCE_TIME rtStart, rtCurrent, rtNext, rtStop; - IAsyncReader * pReader; - IMemAllocator * prefAlloc; - IMemAllocator * pAlloc; - QUERYACCEPTPROC fnQueryAccept; - SAMPLEPROC_PULL fnSampleProc; - PRECONNECTPROC fnPreConnect; - REQUESTPROC fnCustomRequest; - CLEANUPPROC fnCleanProc; - STOPPROCESSPROC fnDone; - double dRate; - BOOL stop_playback; - DWORD cbAlign; - - /* Any code that touches the thread must hold the thread lock, - * lock order: thread_lock and then the filter critical section - * also signal thread_sleepy so the thread knows to wake up - */ - CRITICAL_SECTION thread_lock; - HANDLE hThread; - DWORD requested_state; - HANDLE hEventStateChanged, thread_sleepy; - DWORD state; -} PullPin; - -#define Req_Sleepy 0 -#define Req_Die 1 -#define Req_Run 2 -#define Req_Pause 3 - -/*** Constructors ***/ -HRESULT PullPin_Construct(const IPinVtbl *PullPin_Vtbl, struct strmbase_filter *filter, const WCHAR *name, - SAMPLEPROC_PULL pSampleProc, LPVOID pUserData, QUERYACCEPTPROC pQueryAccept, - CLEANUPPROC pCleanUp, REQUESTPROC pCustomRequest, STOPPROCESSPROC pDone, - IPin **ppPin); -void PullPin_destroy(PullPin *pin) DECLSPEC_HIDDEN; - -/**************************/ -/*** Pin Implementation ***/ - -/* Pull Pin */ -HRESULT WINAPI PullPin_ReceiveConnection(IPin * iface, IPin * pReceivePin, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI PullPin_Disconnect(IPin * iface); -HRESULT WINAPI PullPin_QueryInterface(IPin * iface, REFIID riid, LPVOID * ppv); -HRESULT WINAPI PullPin_EndOfStream(IPin * iface); -HRESULT WINAPI PullPin_QueryAccept(IPin * iface, const AM_MEDIA_TYPE * pmt); -HRESULT WINAPI PullPin_BeginFlush(IPin * iface); -HRESULT WINAPI PullPin_EndFlush(IPin * iface); -HRESULT WINAPI PullPin_NewSegment(IPin * iface, REFERENCE_TIME tStart, REFERENCE_TIME tStop, double dRate); - -/* Thread interaction functions: Hold the thread_lock before calling them */ -HRESULT PullPin_StartProcessing(PullPin * This); -HRESULT PullPin_PauseProcessing(PullPin * This); -HRESULT PullPin_WaitForStateChange(PullPin * This, DWORD dwMilliseconds); - -/* COM helpers */ -static inline PullPin *impl_PullPin_from_IPin( IPin *iface ) -{ - return CONTAINING_RECORD(iface, PullPin, pin.IPin_iface); -} diff --git a/dlls/quartz/quartz_private.h b/dlls/quartz/quartz_private.h index e475cd01477..353d1e5a577 100644 --- a/dlls/quartz/quartz_private.h +++ b/dlls/quartz/quartz_private.h @@ -36,18 +36,9 @@ #include "wine/strmbase.h" #include "wine/list.h"
-static inline const char *debugstr_fourcc(DWORD fourcc) -{ - if (!fourcc) return "''"; - return wine_dbg_sprintf("'%c%c%c%c'", (char)(fourcc), (char)(fourcc >> 8), - (char)(fourcc >> 16), (char)(fourcc >> 24)); -} - /* see IAsyncReader::Request on MSDN for the explanation of this */ #define MEDIATIME_FROM_BYTES(x) ((LONGLONG)(x) * 10000000) -#define SEC_FROM_MEDIATIME(time) ((time) / 10000000) -#define BYTES_FROM_MEDIATIME(time) SEC_FROM_MEDIATIME(time) -#define MSEC_FROM_MEDIATIME(time) ((time) / 10000) +#define BYTES_FROM_MEDIATIME(time) ((time) / 10000000)
HRESULT FilterGraph_create(IUnknown *pUnkOuter, LPVOID *ppObj) DECLSPEC_HIDDEN; HRESULT FilterGraphNoThread_create(IUnknown *pUnkOuter, LPVOID *ppObj) DECLSPEC_HIDDEN; @@ -71,7 +62,6 @@ HRESULT IEnumRegFiltersImpl_Construct(REGFILTER * pInRegFilters, const ULONG siz extern const char * qzdebugstr_guid(const GUID * id) DECLSPEC_HIDDEN; extern void video_unregister_windowclass(void) DECLSPEC_HIDDEN;
-BOOL CompareMediaTypes(const AM_MEDIA_TYPE * pmt1, const AM_MEDIA_TYPE * pmt2, BOOL bWildcards); void dump_AM_MEDIA_TYPE(const AM_MEDIA_TYPE * pmt) DECLSPEC_HIDDEN;
BOOL get_media_type(const WCHAR *filename, GUID *majortype, GUID *subtype, GUID *source_clsid) DECLSPEC_HIDDEN; diff --git a/dlls/quartz/videorenderer.c b/dlls/quartz/videorenderer.c index 26bb05f8d92..aee362c7ef2 100644 --- a/dlls/quartz/videorenderer.c +++ b/dlls/quartz/videorenderer.c @@ -19,7 +19,6 @@ */
#include "quartz_private.h" -#include "pin.h"
#include "uuids.h" #include "vfwmsgs.h" diff --git a/dlls/quartz/vmr9.c b/dlls/quartz/vmr9.c index 184937b0385..d81c3252b05 100644 --- a/dlls/quartz/vmr9.c +++ b/dlls/quartz/vmr9.c @@ -34,7 +34,6 @@ #include "dvdmedia.h" #include "d3d9.h" #include "vmr9.h" -#include "pin.h"
#include "wine/debug.h"