Index: dsfilters/demux_mpc/src/mpc_filter.cpp
===================================================================
--- dsfilters/demux_mpc/src/mpc_filter.cpp	(revision 366)
+++ dsfilters/demux_mpc/src/mpc_filter.cpp	(revision 368)
@@ -47,11 +47,18 @@
 CMPCDemux::CMPCDemux(LPUNKNOWN pUnk, HRESULT *phr) :
 	CBaseFilter(_T("MPC Splitter"), pUnk, &lock_filter, CLSID_MusepackDemuxer, phr),
+	CAMThread(),
 	reader(NULL),
 	file(NULL),
-	wnd_prop(NULL)
+	wnd_prop(NULL),
+	rtCurrent(0),
+	rtStop(0xFFFFFFFFFFFFFF),
+	rate(1.0),
+	ev_abort(TRUE)
 {
 	input = new CMPCInputPin(NAME("MPC Input Pin"), this, phr, L"In");
 	output.RemoveAll();
 	retired.RemoveAll();
+
+	ev_abort.Reset();
 }
 
@@ -82,11 +89,8 @@
 	if (riid == IID_IMusepackSplitter) {
 		return GetInterface((IMusepackSplitter*)this, ppv);
-	} else{
-	/*
+	} else
     if (riid == IID_IMediaSeeking) {
-        return GetInterface((IMediaSeeking *)this, ppv);
-    } else 
-	*/
-
+        return GetInterface((IMediaSeeking*)this, ppv);
+	} else {
 		return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
 	}
@@ -185,4 +189,9 @@
 		}
 
+		HRESULT			hr = NOERROR;
+		CMPCOutputPin	*opin = new CMPCOutputPin(_T("Outpin"), this, &hr, L"Out", 5);
+		ConfigureMediaType(opin);
+		AddOutputPin(opin);
+
 		// refresh property page if there is any
 		if (IsWindow(wnd_prop)) {
@@ -215,4 +224,35 @@
 
 
+HRESULT CMPCDemux::ConfigureMediaType(CMPCOutputPin *pin)
+{
+	CMediaType		mt;
+	mt.majortype = MEDIATYPE_Audio;
+	mt.subtype = MEDIASUBTYPE_MusepackPacket;
+	mt.formattype = FORMAT_WaveFormatEx;
+	mt.lSampleSize = 128*1024;				// should be way enough
+
+	ASSERT(file);
+	int		extrasize = file->extradata_size;
+
+	// let us fill the waveformatex structure
+	WAVEFORMATEX *wfx = (WAVEFORMATEX*)mt.AllocFormatBuffer(sizeof(WAVEFORMATEX) + extrasize);
+	memset(wfx, 0, sizeof(*wfx));
+	wfx->cbSize = extrasize;
+	wfx->wBitsPerSample = 0;
+	wfx->nChannels = file->channels;
+	wfx->nSamplesPerSec = file->sample_rate;
+	wfx->nBlockAlign = 1;
+	wfx->nAvgBytesPerSec = 0;
+	wfx->wFormatTag = 0;
+
+	// Extradata - Stream header + other stuff
+	uint8	*extra = ((uint8*)wfx) + sizeof(WAVEFORMATEX);
+	memcpy(extra, file->extradata, extrasize);
+
+	// the one and only type
+	pin->mt_types.Add(mt);
+	return NOERROR;
+}
+
 HRESULT CMPCDemux::BreakConnect(PIN_DIRECTION Dir, CBasePin *pCaller)
 {
@@ -221,5 +261,5 @@
 	if (Dir == PINDIR_INPUT) {
 		// let's disconnect the output pins
-		//ev_abort.Set();
+		ev_abort.Set();
 		//ev_ready.Set();
 
@@ -238,5 +278,5 @@
 		}
 
-		//ev_abort.Reset();
+		ev_abort.Reset();
 	} else 
 	if (Dir == PINDIR_OUTPUT) {
@@ -271,5 +311,291 @@
 }
 
-
-
-
+DWORD CMPCDemux::ThreadProc()
+{
+	DWORD	cmd, cmd2;
+	while (true) {
+		cmd = GetRequest();
+		switch (cmd) {
+		case CMD_EXIT:	Reply(NOERROR); return 0;
+		case CMD_STOP:	Reply(NOERROR); break;
+		case CMD_RUN:
+			{
+				Reply(NOERROR);
+				if (!file) break;
+
+				CMPCPacket		packet;
+				int32			ret=0;
+				bool			eos=false;
+				HRESULT			hr;
+				int64			current_sample;
+
+				/*
+					With a more complex demultiplexer we would need a mechanism
+					to identify streams. Now we have only one output stream
+					so it's easy.
+				*/
+
+				if (output.GetCount() <= 0) break;
+				if (output[0]->IsConnected() == FALSE) break;
+
+				do {
+
+					// are we supposed to abort ?
+					if (ev_abort.Check()) { 
+						ret = 0; 
+						break; 
+					}
+
+					ret = file->ReadAudioPacket(&packet, &current_sample);
+					if (ret < 0) {
+						// end of stream
+						break;
+					} else {
+						// compute time stamp
+						REFERENCE_TIME	tStart = (current_sample * 10000000) / file->sample_rate;
+						REFERENCE_TIME	tStop  = ((current_sample + 1152*file->audio_block_frames) * 10000000) / file->sample_rate;
+						packet.tStart = tStart;
+						packet.tStop  = tStop;
+
+						// deliver packet
+						output[0]->DeliverPacket(packet);
+					}
+
+				} while (!CheckRequest(&cmd2));
+
+				// end of stream
+				if (ret == -1) {
+					output[0]->DoEndOfStream();
+				}
+
+			}
+			break;
+		default:
+			Reply(E_UNEXPECTED);
+			break;
+		}
+	}
+	return 0;
+}
+
+
+// IMediaSeeking
+
+STDMETHODIMP CMPCDemux::GetCapabilities(DWORD* pCapabilities)
+{
+	return pCapabilities ? *pCapabilities =	
+			AM_SEEKING_CanGetStopPos|AM_SEEKING_CanGetDuration|AM_SEEKING_CanSeekAbsolute|AM_SEEKING_CanSeekForwards|AM_SEEKING_CanSeekBackwards, 
+			S_OK : E_POINTER;
+}
+STDMETHODIMP CMPCDemux::CheckCapabilities(DWORD* pCapabilities)
+{
+	CheckPointer(pCapabilities, E_POINTER);
+	if (*pCapabilities == 0) return S_OK;
+	DWORD caps;
+	GetCapabilities(&caps);
+	if ((caps&*pCapabilities) == 0) return E_FAIL;
+	if (caps == *pCapabilities) return S_OK;
+	return S_FALSE;
+}
+STDMETHODIMP CMPCDemux::IsFormatSupported(const GUID* pFormat) {return !pFormat ? E_POINTER : *pFormat == TIME_FORMAT_MEDIA_TIME ? S_OK : S_FALSE;}
+STDMETHODIMP CMPCDemux::QueryPreferredFormat(GUID* pFormat) {return GetTimeFormat(pFormat);}
+STDMETHODIMP CMPCDemux::GetTimeFormat(GUID* pFormat) {return pFormat ? *pFormat = TIME_FORMAT_MEDIA_TIME, S_OK : E_POINTER;}
+STDMETHODIMP CMPCDemux::IsUsingTimeFormat(const GUID* pFormat) {return IsFormatSupported(pFormat);}
+STDMETHODIMP CMPCDemux::SetTimeFormat(const GUID* pFormat) {return S_OK == IsFormatSupported(pFormat) ? S_OK : E_INVALIDARG;}
+STDMETHODIMP CMPCDemux::GetStopPosition(LONGLONG* pStop) {return this->rtStop; }
+STDMETHODIMP CMPCDemux::GetCurrentPosition(LONGLONG* pCurrent) {return E_NOTIMPL;}
+STDMETHODIMP CMPCDemux::ConvertTimeFormat(LONGLONG* pTarget, const GUID* pTargetFormat, LONGLONG Source, const GUID* pSourceFormat) {return E_NOTIMPL;}
+
+STDMETHODIMP CMPCDemux::SetPositions(LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
+{
+	return SetPositionsInternal(0, pCurrent, dwCurrentFlags, pStop, dwStopFlags);
+}
+
+STDMETHODIMP CMPCDemux::GetPositions(LONGLONG* pCurrent, LONGLONG* pStop)
+{
+	if(pCurrent) *pCurrent = rtCurrent;
+	if(pStop) *pStop = rtStop;
+	return S_OK;
+}
+STDMETHODIMP CMPCDemux::GetAvailable(LONGLONG* pEarliest, LONGLONG* pLatest)
+{
+	if(pEarliest) *pEarliest = 0;
+	return GetDuration(pLatest);
+}
+STDMETHODIMP CMPCDemux::SetRate(double dRate) {return dRate > 0 ? rate = dRate, S_OK : E_INVALIDARG;}
+STDMETHODIMP CMPCDemux::GetRate(double* pdRate) {return pdRate ? *pdRate = rate, S_OK : E_POINTER;}
+STDMETHODIMP CMPCDemux::GetPreroll(LONGLONG* pllPreroll) {return pllPreroll ? *pllPreroll = 0, S_OK : E_POINTER;}
+
+STDMETHODIMP CMPCDemux::GetDuration(LONGLONG* pDuration) 
+{	
+	CheckPointer(pDuration, E_POINTER); 
+	*pDuration = 0;
+
+	if (file) {
+		if (pDuration) *pDuration = file->duration_10mhz;
+	}
+	return S_OK;
+}
+
+STDMETHODIMP CMPCDemux::SetPositionsInternal(int iD, LONGLONG* pCurrent, DWORD dwCurrentFlags, LONGLONG* pStop, DWORD dwStopFlags)
+{
+	// only our first pin can seek
+	if (iD != 0) return NOERROR;
+	CAutoLock cAutoLock(&lock_filter);
+
+	if (!pCurrent && !pStop || (dwCurrentFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning 
+		&& (dwStopFlags&AM_SEEKING_PositioningBitsMask) == AM_SEEKING_NoPositioning)
+		return S_OK;
+
+	REFERENCE_TIME rtCurrent = this->rtCurrent, rtStop = this->rtStop;
+
+	if (pCurrent) {
+		switch(dwCurrentFlags&AM_SEEKING_PositioningBitsMask) {
+		case AM_SEEKING_NoPositioning: break;
+		case AM_SEEKING_AbsolutePositioning: rtCurrent = *pCurrent; break;
+		case AM_SEEKING_RelativePositioning: rtCurrent = rtCurrent + *pCurrent; break;
+		case AM_SEEKING_IncrementalPositioning: rtCurrent = rtCurrent + *pCurrent; break;
+		}
+	}
+
+	if (pStop) {
+		switch(dwStopFlags&AM_SEEKING_PositioningBitsMask) {
+		case AM_SEEKING_NoPositioning: break;
+		case AM_SEEKING_AbsolutePositioning: rtStop = *pStop; break;
+		case AM_SEEKING_RelativePositioning: rtStop += *pStop; break;
+		case AM_SEEKING_IncrementalPositioning: rtStop = rtCurrent + *pStop; break;
+		}
+	}
+
+	if (this->rtCurrent == rtCurrent && this->rtStop == rtStop) return S_OK;
+
+	this->rtCurrent = rtCurrent;
+	this->rtStop = rtStop;
+
+	// now there are new valid Current and Stop positions
+	HRESULT hr = DoNewSeek();
+	return hr;
+}
+
+HRESULT CMPCDemux::DoNewSeek()
+{
+	// stop first
+	ev_abort.Set();
+	if (reader) reader->BeginFlush();
+
+	for (int i=0; i<output.GetCount(); i++) {
+		CMPCOutputPin	*pin = output[i];
+		if (pin->IsConnected()) {
+			// abort
+			if (m_State != State_Stopped) {
+				if (pin->ThreadExists()) {
+					pin->ev_abort.Set();
+					pin->DeliverBeginFlush();
+					pin->CallWorker(CMD_STOP);
+					pin->FlushQueue();
+				}
+			}
+		}
+	}
+
+	for (int i=0; i<output.GetCount(); i++) {
+		CMPCOutputPin	*pin = output[i];
+		if (pin->IsConnected()) {
+			if (m_State != State_Stopped) {
+				if (pin->ThreadExists()) {
+					pin->ev_abort.Reset();
+					pin->DeliverEndFlush();
+				}
+			}
+			pin->DoNewSegment(rtCurrent, rtStop, rate);
+		}
+	}
+
+	if (ThreadExists()) {
+		CallWorker(CMD_STOP);
+	}
+	if (reader) reader->EndFlush();
+
+	// seek the file
+	if (file) {
+		int64 sample_pos = rtCurrent * file->sample_rate / 10000000;
+		file->Seek(sample_pos);
+	}
+
+	ev_abort.Reset();
+	if (ThreadExists()) {
+		CallWorker(CMD_RUN);
+	}
+
+	for (int i=0; i<output.GetCount(); i++) {
+		CMPCOutputPin	*pin = output[i];
+
+		// we only care about connected pins
+		if (pin->IsConnected()) {
+			if (m_State != State_Stopped) {
+				// spustime aj jeho thread
+				if (pin->ThreadExists()) {
+					pin->CallWorker(CMD_RUN);
+				}
+			}
+		}
+	}
+
+	return NOERROR;
+}
+
+
+STDMETHODIMP CMPCDemux::Pause()
+{
+	CAutoLock	lck(&lock_filter);
+
+	if (m_State == State_Stopped) {
+
+		ev_abort.Reset();
+
+		// activate pins
+		for (int i=0; i<output.GetCount(); i++) output[i]->Active();
+		if (input) input->Active();
+
+		// seekneme na danu poziciu
+		DoNewSeek();
+
+		// pustime parser thread
+		if (!ThreadExists()) {
+			Create();
+			CallWorker(CMD_RUN);
+		}
+	}
+
+	m_State = State_Paused;
+	return NOERROR;
+}
+
+STDMETHODIMP CMPCDemux::Stop()
+{
+	CAutoLock	lock(&lock_filter);
+	HRESULT		hr = NOERROR;
+
+	if (m_State != State_Stopped) {
+
+		// set abort
+		ev_abort.Set();
+		if (reader) reader->BeginFlush();
+
+		// deaktivujeme piny
+		if (input) input->Inactive();
+		for (int i=0; i<output.GetCount(); i++) output[i]->Inactive();
+
+		// zrusime parser thread
+		if (ThreadExists()) {
+			CallWorker(CMD_EXIT);
+			Close();
+		}
+
+		if (reader) reader->EndFlush();
+	}
+
+
+	m_State = State_Stopped;
+	return hr;
+}
