Index: dsfilters/dec_mpc/src/mpc_filter.cpp
===================================================================
--- dsfilters/dec_mpc/src/mpc_filter.cpp	(revision 370)
+++ dsfilters/dec_mpc/src/mpc_filter.cpp	(revision 371)
@@ -42,10 +42,17 @@
 CUnknown *CMPCDecoder::CreateInstance(LPUNKNOWN pUnk, HRESULT *phr)
 {
+	if (phr) *phr = NOERROR;
+
 	return new CMPCDecoder(pUnk, phr);
 }
 
 CMPCDecoder::CMPCDecoder(LPUNKNOWN pUnk, HRESULT *phr) :
-	CTransformFilter(_T("MPC Decoder"), pUnk, CLSID_MusepackDecoder)
-{
+	CTransformFilter(_T("MPC Decoder"), pUnk, CLSID_MusepackDecoder),
+	demux(NULL),
+	decoder_specific(NULL),
+	decoder_specific_size(0)
+{
+	if (phr) *phr = NOERROR;
+
 	m_pInput = new CTransformInputPin(NAME("Input"), this, phr, L"Input");
 	m_pOutput = new CTransformOutputPin(NAME("Output"), this, phr, L"Output");
@@ -108,5 +115,8 @@
 		if (pmt->formattype != FORMAT_WaveFormatEx) return E_FAIL;
 
-		WAVEFORMATEX *wfx = (WAVEFORMATEX*)pmt->pbFormat;
+		// keep a local copy so our decoder specific info doesn't go away
+		mtIn = *pmt;
+
+		WAVEFORMATEX *wfx = (WAVEFORMATEX*)mtIn.pbFormat;
 
 		// we assemble output format
@@ -116,7 +126,32 @@
 		wfOut.wFormatTag = WAVE_FORMAT_PCM;
 		wfOut.wBitsPerSample = 16;				// currently only 16-bit
+
+		// get hold of decoder specific info
+		decoder_specific = ((BYTE*)wfx) + sizeof(WAVEFORMATEX);
+		decoder_specific_size = wfx->cbSize;
+
+		mpc_demux	*dmx;
+
+		int ret = OpenDemux(&dmx, &stream_info);
+		if (ret < 0) {
+			mpc_demux_exit(dmx);
+			return E_FAIL;
+		}
+
+		// if the stream_info says something different...
+		if (stream_info.sample_freq != wfx->nSamplesPerSec ||
+			stream_info.channels != wfx->nChannels
+			) {
+
+			// update values
+			wfOut.nChannels = stream_info.channels;
+			wfOut.nSamplesPerSec = stream_info.sample_freq;
+		}
+
 		wfOut.nBlockAlign = (wfOut.wBitsPerSample * wfOut.nChannels) >> 3;
 		wfOut.nAvgBytesPerSec = wfOut.nBlockAlign * wfOut.nSamplesPerSec;
 
+		// done with the demuxer
+		mpc_demux_exit(dmx);
 	}
 	return NOERROR;
@@ -133,4 +168,8 @@
 			m_pOutput->Disconnect();
 		}
+
+		// cancel out decoder specific info
+		decoder_specific = NULL;
+		decoder_specific_size = 0;
 	}
 	return __super::BreakConnect(dir);
@@ -195,4 +234,11 @@
 	HRESULT hr = __super::StartStreaming();
 	if (FAILED(hr)) return hr;
+
+	ASSERT(!demux);
+
+	// now let's open the demuxer
+	int ret = OpenDemux(&demux, &stream_info);
+	if (ret < 0) return E_FAIL;
+
 	return hr;
 }
@@ -202,15 +248,294 @@
 	HRESULT hr = __super::StopStreaming();
 	if (FAILED(hr)) return hr;
+
+	// done with demuxer
+	mpc_demux_exit(demux);
+	demux = NULL;
+
 	return hr;
 }
 
+#define FLOAT_CLIP(x)		(x < -1.0 ? -1.0 : x > 1.0 ? 1.0 : x)
+
+static void convert_float_to_int16_c(float *src, short *dst, int count)
+{
+	count -= 8;
+	while (count > 0) {
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		count -= 8;
+	}
+	count += 8;
+
+	// last few must be done one-by-one
+	while (count > 0) {
+		*dst++ = (short)(FLOAT_CLIP(*src) * 16380);	src++;
+		count --;
+	}
+}
+
 HRESULT CMPCDecoder::Receive(IMediaSample *pSample)
 {
 	if (!m_pOutput->IsConnected()) return NOERROR;
 
-	// todo:
-	return NOERROR;
-}
-
-
-
+	// we receive whole AP packets so just decode the frames :D
+	BYTE *pdata = NULL;
+	long lsize  = 0;
+	pSample->GetPointer(&pdata);
+	lsize = pSample->GetActualDataLength();
+
+	// set the reader
+	reader.SetData(pdata, lsize);
+	reader.AppendSE();
+
+	// manually clear the buffer for demuxer
+	demux->bytes_total = 0;
+	demux->bits_reader.buff = demux->buffer;
+	demux->bits_reader.count = 8;
+	demux->block_bits = 0;
+	demux->block_frames = 0;
+
+	// TODO: use some more clever way of doing this.
+	MPC_SAMPLE_FORMAT	samples[1152 * 8];
+	int					dec_samples;
+
+	// handling timestamps
+	REFERENCE_TIME		rtStart, rtStop;
+	__int64				current_sample = 0;
+	__int64				samples_to_skip = 0;
+	bool				has_timestamp = false;
+
+	if (pSample->GetTime(&rtStart, &rtStop) == NOERROR) {
+		has_timestamp = true;
+		// calculate relative sample_time
+		current_sample = (rtStart * stream_info.sample_freq) / 10000000;
+
+		if (current_sample < 0) {
+			samples_to_skip = -current_sample;
+		}
+	}
+
+	// now scan through the frames
+	while (true) {
+
+		//---------------------------------------------------------------------
+		//	Decoding Part
+		//---------------------------------------------------------------------
+
+		mpc_frame_info	frame;
+		mpc_status		err;
+
+		frame.buffer = (MPC_SAMPLE_FORMAT*)samples;
+
+		// decode one frame
+		err = mpc_demux_decode(demux, &frame);
+		if (err != MPC_STATUS_OK) break;
+		if (frame.bits == -1) break;				// done.
+
+		//---------------------------------------------------------------------
+		//	Skipping samples...
+		//---------------------------------------------------------------------
+
+		MPC_SAMPLE_FORMAT	*src_samples = frame.buffer;
+		int					decoded_time_samples = frame.samples;
+
+		if (has_timestamp) {
+			if (samples_to_skip > 0) {
+
+				// skip sample counters
+				__int64 to_skip = min(frame.samples, samples_to_skip);
+				decoded_time_samples -= to_skip;
+				current_sample	 	 += to_skip;
+				src_samples			 += (to_skip * stream_info.channels);
+			}
+		}
+
+		// if there's nothing left, continue
+		if (decoded_time_samples <= 0) continue;
+
+		// total number of decoded samples
+		dec_samples = decoded_time_samples * stream_info.channels;
+
+		//---------------------------------------------------------------------
+		//	Convert and deliver
+		//---------------------------------------------------------------------
+
+		// deliver decoded data
+		IMediaSample	*sample;
+		HRESULT			hr;
+		hr = GetDeliveryBuffer(&sample);
+		if (FAILED(hr)) break;				// perhaps allocator is decommited
+
+		BYTE *outp;
+		sample->GetPointer(&outp);
+
+		// this should definitely be true
+		ASSERT(sample->GetSize() >= (dec_samples * sizeof(short)));
+
+		// do format conversion
+#ifdef MPC_FIXED_POINT
+		// TODO: find ranges in headers somewhere
+#else
+		convert_float_to_int16_c((float*)src_samples, (short*)outp, dec_samples);
+		sample->SetActualDataLength(dec_samples * sizeof(short));
+#endif
+
+		// IMediaSample properties
+		if (has_timestamp) {
+			REFERENCE_TIME	tstart, tstop;
+			tstart = (current_sample * 10000000) / stream_info.sample_freq;
+			tstop  = ((current_sample+decoded_time_samples) * 10000000) / stream_info.sample_freq;
+			sample->SetTime(&tstart, &tstop);
+		}
+		sample->SetSyncPoint(TRUE);
+		sample->SetDiscontinuity(FALSE);
+
+		// advance time
+		current_sample += decoded_time_samples;
+
+		hr = m_pOutput->Deliver(sample);
+		sample->Release();
+
+		// something went wrong. stop decoding.
+		if (FAILED(hr)) break;
+	}
+
+	return NOERROR;
+}
+
+int CMPCDecoder::OpenDemux(mpc_demux **dmx, mpc_streaminfo *si)
+{
+	// some data needed
+	if (!decoder_specific || decoder_specific_size <= 0) return -1;
+
+	reader.SetData(decoder_specific, decoder_specific_size);
+	(*dmx) = mpc_demux_init(&reader.rd);
+	if (!(*dmx)) return -1;
+
+	mpc_demux_get_info((*dmx), si);
+	return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//	CMPCReader class
+//
+//-----------------------------------------------------------------------------
+
+static mpc_int32_t mpc_read_proc(mpc_reader *p_reader, void *ptr, mpc_int32_t size)
+{
+	CMPCReader *instance = (CMPCReader*)p_reader->data;
+	ASSERT(instance);
+	return instance->Read(ptr, size);
+}
+
+static mpc_bool_t mpc_seek_proc(mpc_reader *p_reader, mpc_int32_t offset)
+{
+	CMPCReader *instance = (CMPCReader*)p_reader->data;
+	ASSERT(instance);
+	return instance->Seek(offset);
+}
+
+static mpc_int32_t mpc_tell_proc(mpc_reader *p_reader)
+{
+	CMPCReader *instance = (CMPCReader*)p_reader->data;
+	ASSERT(instance);
+	return instance->Tell();
+}
+
+static mpc_int32_t mpc_get_size_proc(mpc_reader *p_reader)
+{
+	CMPCReader *instance = (CMPCReader*)p_reader->data;
+	ASSERT(instance);
+	return instance->GetSize();
+}
+
+static mpc_bool_t mpc_canseek_proc(mpc_reader *p_reader)
+{
+	CMPCReader *instance = (CMPCReader*)p_reader->data;
+	ASSERT(instance);
+	return instance->CanSeek();
+}
+
+CMPCReader::CMPCReader()
+{
+	buf = (BYTE*)malloc(256*1024);		// 256 KB should be enough
+	size = 0;
+
+	rd.data = (void*)this;
+	rd.read = mpc_read_proc;
+	rd.seek = mpc_seek_proc;
+	rd.tell = mpc_tell_proc;
+	rd.get_size = mpc_get_size_proc;
+	rd.canseek = mpc_canseek_proc;
+}
+
+CMPCReader::~CMPCReader()
+{
+	free(buf);
+}
+
+int CMPCReader::Read(void *buf, int size)
+{
+	// return the number of bytes read
+	int toread_max = min(this->size - this->pos, size);
+	memcpy(buf, this->buf + this->pos, toread_max);
+	this->pos += toread_max;
+	return toread_max;
+}
+
+bool CMPCReader::Seek(int offset)
+{
+	// sorry no seeking here
+	return false;
+}
+
+int CMPCReader::Tell()
+{
+	// that's where we are
+	return pos;
+}
+
+int CMPCReader::GetSize()
+{
+	// size of our supplied buffer
+	return size;
+}
+
+bool CMPCReader::CanSeek()
+{
+	// no. we are not seekable. upstream demuxer is.
+	return false;
+}
+
+void CMPCReader::SetData(BYTE *data, int size)
+{
+	ASSERT(size < 256*1024);
+	memcpy(buf, data, size);
+	this->size = size;
+	this->pos = 0;
+}
+
+void CMPCReader::AppendSE()
+{
+	BYTE *out = buf + size;
+	out[0] = 'S';
+	out[1] = 'E';
+	out[2] = 0x03;
+	size += 3;
+}
+
+
+
+
+
+
+
+
