Index: dsfilters/demux_mpc/src/mpc_file.cpp
===================================================================
--- dsfilters/demux_mpc/src/mpc_file.cpp	(revision 367)
+++ dsfilters/demux_mpc/src/mpc_file.cpp	(revision 368)
@@ -19,26 +19,16 @@
 	duration_10mhz(0),
 	reader(NULL),
-	packet(NULL),
 	seek_table(NULL),
 	seek_table_position(0)
 {
-	key = 0;
-	packet_max_size = 512 * 1024;			// well. hard to say. but I think this should be enough
-	packet_size = 0;
-	packet = (uint8*)malloc(packet_max_size);
-
-	ASSERT(packet);
+	extradata_max_size = 16*1024;			// way too much..
+	extradata_size = 0;
+	extradata = (uint8*)malloc(extradata_max_size);
 }
 
 CMPCFile::~CMPCFile()
 {
-	if (seek_table) {
-		free(seek_table);
-		seek_table = NULL;
-	}
-	if (packet) {
-		free(packet);
-		packet = NULL;
-	}
+	if (seek_table) { free(seek_table); seek_table = NULL; }
+	if (extradata) { free(extradata); extradata = NULL; }
 }
 
@@ -52,5 +42,4 @@
 	// keep a local copy of the reader
 	this->reader = reader;
-
 
 	// According to stream specification the first 4 bytes should be 'MPCK'
@@ -70,12 +59,24 @@
 
 	// now loop through a few packets
+	CMPCPacket		packet;
 	do {
-		ret = ReadNextPacket();
+		ret = packet.Load(reader);
 		if (ret < 0) return -1;			// end of file reached before initialization is done ?
 
-		switch (key) {
-		case MPC_KEY('S','H'):	ret = ReadStreamHeader(); break;
-		case MPC_KEY('R','G'):  ret = ReadReplaygain(); break;
-		case MPC_KEY('S','O'):	ret = ReadSeekOffset(); break;
+		switch (packet.key) {
+		case MPC_KEY('S','H'):	
+			ret = ReadStreamHeader(&packet); 
+			StoreExtraDataPacket(&packet);
+			break;
+		case MPC_KEY('R','G'):  
+			ret = ReadReplaygain(&packet); 
+			StoreExtraDataPacket(&packet);
+			break;
+		case MPC_KEY('S','O'):	
+			ret = ReadSeekOffset(&packet); 
+			break;
+		case MPC_KEY('E','I'):
+			StoreExtraDataPacket(&packet);
+			break;
 
 		// audio packet - initialization is over
@@ -89,40 +90,33 @@
 	// if there was a seek table, load it
 	if (seek_table_position != 0) {
-		ret = ReadSeekTable(); 
+		int64 first_ap_pos, avail;
+		reader->GetPosition(&first_ap_pos, &avail);
+
+		reader->Seek(seek_table_position);
+		ret = packet.Load(reader);
+		ret = ReadSeekTable(&packet); 
 		if (ret < 0) return ret;
-	}
-
-	return 0;
-}
-
-int CMPCFile::ReadNextPacket()
-{
-	uint16	key_val;
-	int64	size_val;
-	int32	size_len;
-	int		ret;
-	int64	avail;
-
-	reader->GetPosition(&packet_pos, &avail);
-	ret = reader->GetKey(key_val);					if (ret < 0) return ret;
-	ret = reader->GetSizeElm(size_val, size_len);	if (ret < 0) return ret;
-
-	// if the key is not valid, quit
-	if (!reader->KeyValid(key_val)) return -1;
-	key = key_val;
-
-	// size_val is the total size including key, variable size field and payload
-	packet_size = size_val - 2 - size_len;
-	ASSERT(packet_size <= packet_max_size);
-
-	ret = reader->Read(packet, packet_size);		if (ret < 0) return ret;
-	return 0;
+
+		// seek back to first AP
+		reader->Seek(first_ap_pos);
+	}
+
+	// we're at start
+	current_sample = 0;
+	return 0;
+}
+
+void CMPCFile::StoreExtraDataPacket(CMPCPacket *packet)
+{
+	// we add current packet to extradata
+	uint8	*out = extradata + extradata_size;
+	memcpy(out, packet->packet, packet->packet_size);
+	extradata_size += packet->packet_size;
 }
 
 // parsing packets
-
-int CMPCFile::ReadReplaygain()
-{
-	Bitstream	b(packet);
+int CMPCFile::ReadReplaygain(CMPCPacket *packet)
+{
+	Bitstream	b(packet->payload);
 	b.NeedBits();
 
@@ -139,10 +133,10 @@
 }
 
-int CMPCFile::ReadSeekOffset()
-{
-	Bitstream	b(packet);
+int CMPCFile::ReadSeekOffset(CMPCPacket *packet)
+{
+	Bitstream	b(packet->payload);
 
 	seek_table_position = b.GetMpcSize();
-	seek_table_position += packet_pos;
+	seek_table_position += packet->file_position;
 
 	// success 
@@ -150,18 +144,12 @@
 }
 
-int CMPCFile::ReadSeekTable()
-{
-	reader->Seek(seek_table_position);
-	int ret;
-
-	ret = ReadNextPacket();
-	if (ret < 0) return ret;
-
-	Bitstream	b(packet);
+int CMPCFile::ReadSeekTable(CMPCPacket *packet)
+{
+	Bitstream	b(packet->payload);
 
 	// calculate size as seen in mpc_demux.c
 	int64 tmp = b.GetMpcSize();	b.NeedBits();
 	seek_table_size = tmp;
-	int	seek_pwr = block_pwr + b.UGetBits(4);
+	seek_pwr = block_pwr + b.UGetBits(4);
 	tmp = 2+total_samples / (1152 << seek_pwr);
 	if (tmp < seek_table_size) tmp = seek_table_size;
@@ -188,7 +176,7 @@
 }
 
-int CMPCFile::ReadStreamHeader()
-{
-	Bitstream	b(packet);
+int CMPCFile::ReadStreamHeader(CMPCPacket *packet)
+{
+	Bitstream	b(packet->payload);
 	b.NeedBits();
 
@@ -249,5 +237,5 @@
 
 			// store absolute position of stream header
-			header_position = packet_pos;
+			header_position = packet->file_position -4;
 		}
 		break;
@@ -261,3 +249,136 @@
 }
 
-
+// parsing out packets
+int CMPCFile::ReadAudioPacket(CMPCPacket *packet, int64 *cur_sample)
+{
+	// we just load packets until we face the SE packet. Then we return -1
+	int ret;
+
+	do {
+		ret = packet->Load(reader);
+		if (ret < 0) return ret;
+
+		switch (packet->key) {
+		case MPC_KEY('A','P'):	
+			{
+				// keep track of samples...
+				if (cur_sample) *cur_sample = current_sample;
+				current_sample += (1152*audio_block_frames);
+
+				return 0;			// we got one
+			}
+		case MPC_KEY('S','E'):	return -1;			// end of stream
+		}
+
+		// skip other packets
+	} while (1);
+
+	// unexpected...
+	return 0;
+}
+
+int CMPCFile::Seek(int64 seek_sample)
+{
+	/*
+		This will be a little tricky. I would like to support also 
+		less precise seeking with files that don't have seeking table. 
+		But if there is one, we	would use that one.
+
+		Original implementation also deals with introductory silence.
+		But since I don't know of any dshow filters capable of
+		gapless playback we would ignore this. Of course it can
+		be implemented later.
+
+		It is absolutely okay to do AP-level seeking. The caller
+		knows the exact time it wants to seek to and we will provide
+		the nearest AP. If the requested time is in the middle of AP,
+		the (current_time - requested_time) expression would be negative
+		and decoder will skip samples until positive time values are encountered.
+		This way we can do sample-precise seeking.
+	*/
+
+	// cannot seek
+	if (seek_table == NULL || seek_table_size == 0) return -1;
+
+	int packet_num = seek_sample / (1152*audio_block_frames);
+	int i = (packet_num >> (seek_pwr - block_pwr));
+	if (i >= seek_table_size) {
+		i = seek_table_size-1;
+	}
+
+	// seek to position
+	uint32 pos = seek_table[i] >> 3;
+	reader->Seek(pos);
+
+	// shift back
+	i = i << (seek_pwr - block_pwr);
+	current_sample = i*audio_block_frames;
+
+	return 0;
+}
+
+
+//-----------------------------------------------------------------------------
+//
+//	CMPCPacket
+//
+//-----------------------------------------------------------------------------
+
+CMPCPacket::CMPCPacket() :
+	file_position(0),
+	packet(NULL),
+	payload(NULL),
+	packet_size(0),
+	payload_size(0),
+	key(0)
+{
+}
+
+CMPCPacket::~CMPCPacket()
+{
+	// just let it go
+	Release();
+}
+
+void CMPCPacket::Release()
+{
+	if (packet) { free(packet); packet = NULL; }
+	payload = NULL;
+	packet_size = 0;
+	payload_size = 0;
+	key = 0;
+	file_position = 0;
+}
+
+int CMPCPacket::Load(CMPCReader *reader)
+{
+	uint16	key_val;
+	int64	size_val, avail;
+	int32	size_len;
+	int		ret;
+	Release();
+	reader->GetPosition(&file_position, &avail);
+
+	// end of stream
+	if (file_position >= avail) return -1;
+
+	ret = reader->GetKey(key_val);					if (ret < 0) return ret;
+	ret = reader->GetSizeElm(size_val, size_len);	if (ret < 0) return ret;
+	// if the key is not valid, quit
+	if (!reader->KeyValid(key_val)) return -1;
+	key = key_val;
+
+	// now load the packet
+	packet_size  = size_val;
+	payload_size = size_val - 2 - size_len;
+	packet = (uint8*)malloc(packet_size);
+	payload = packet + 2 + size_len;				// pointer to packet payload
+
+	// roll back the bytes
+	reader->Seek(file_position);
+	ret = reader->Read(packet, packet_size);		if (ret < 0) return ret;
+
+	return 0;
+}
+
+
