All pastes #940048 Raw Edit

Someone

public text v1 · immutable
·published 2008-03-12 19:07 UTC
rendered paste body
Index: src/pipeline.cpp
===================================================================
--- src/pipeline.cpp	(revision 98038)
+++ src/pipeline.cpp	(working copy)
@@ -2780,6 +2780,352 @@
 
 
 /*
+ * LiveSource
+ */
+
+#define LIVE_SOURCE_BUFFER_SIZE 1000000
+#define LIVE_SOURCE_PEEK_BUFFER_SIZE 64000
+
+
+
+LiveSource::LiveSource (Media *media) : IMediaSource (media)
+{
+	write_pos = 0;
+	read_pos = 0;
+	peek_buffer_size = 0;
+	requested_pos = -1;
+	size = -1;
+
+        pthread_mutex_init (&write_mutex, NULL);
+        pthread_cond_init (&write_cond, NULL);
+        cancel_wait = false;
+        wait_count = 0;
+	wait_size = 0;
+
+}
+
+LiveSource::~LiveSource ()
+{
+	delete buffer;
+	g_free (peek_buffer);
+
+	pthread_mutex_destroy (&write_mutex);
+	pthread_cond_destroy (&write_cond);
+}
+
+MediaResult
+LiveSource::Initialize ()
+{
+
+	buffer = new RingBuffer (LIVE_SOURCE_BUFFER_SIZE);
+	peek_buffer = (char*) g_malloc (LIVE_SOURCE_PEEK_BUFFER_SIZE);
+	return MEDIA_SUCCESS;
+}
+
+
+bool
+LiveSource::IsWaiting ()
+{
+	return g_atomic_int_get (&wait_count) != 0;
+}
+
+bool
+LiveSource::WakeUp ()
+{
+	return WakeUp (true);
+}
+
+bool
+LiveSource::WakeUp (bool lock)
+{
+	if (lock)
+		Lock ();
+	pthread_cond_signal (&write_cond);
+	if (lock)
+		Unlock ();
+	return true;
+}
+
+void
+LiveSource::Lock ()
+{
+	pthread_mutex_lock (&write_mutex);
+}
+
+void
+LiveSource::Unlock ()
+{
+	pthread_mutex_unlock (&write_mutex);
+}
+
+bool
+LiveSource::WaitForData (int size)
+{
+	bool result = false;
+	
+	g_atomic_int_inc (&wait_count);
+	
+	Lock ();
+	
+	if (size > wait_size)
+		wait_size = size;
+	
+	while (true) {
+		if (cancel_wait) {
+			goto cleanup;
+		}
+		
+		if (buffer->DataAvailable() > size) {
+			result = true;
+			goto cleanup;
+		}
+		
+		pthread_cond_wait (&write_cond, &write_mutex);
+	}
+	
+cleanup:
+	if (cancel_wait) {
+		cancel_wait = false;
+		// Wake up CancelWait (), which is waiting for us to finish.
+		WakeUp (false);
+	}
+	wait_size = 0;
+	Unlock ();
+	
+	g_atomic_int_dec_and_test (&wait_count);
+	
+	return result;
+}
+
+void
+LiveSource::CancelWait ()
+{
+	//printf ("%p ProgressiveSource::CancelWait () wait_pos: %lld.\n", this, wait_pos);
+	Lock ();
+	if (IsWaiting ()) {
+		cancel_wait = true;
+		WakeUp (false);
+		while (cancel_wait)
+			pthread_cond_wait (&write_cond, &write_mutex);
+	}
+	Unlock ();
+}
+
+
+
+void
+LiveSource::Write (void *buf, int64_t offset, int32_t n)
+{
+	int nwritten;
+	
+	if (n == 0) {
+		return;
+	}
+
+	Lock ();
+
+
+	nwritten = buffer->Write ((char*)buf, n);
+	write_pos += nwritten;
+	if (nwritten < n) {
+		/* re-try once */
+		int nwritten2 = buffer->Write ((char*)buf + nwritten, n - nwritten);
+		write_pos += nwritten2;
+		if (nwritten2 < n - nwritten) {
+			g_print ("LiveSource::Write: RingBuffer full write does not fit, should wait\n");
+			/* Pause the downloader */
+			requested_pos = -2;
+			Unlock ();
+			return;
+		}
+	}
+
+	if (IsWaiting ())
+                WakeUp (false);
+
+	/* Keep a copy for future Peeks */
+	if (peek_buffer_size < LIVE_SOURCE_PEEK_BUFFER_SIZE &&
+	    LIVE_SOURCE_PEEK_BUFFER_SIZE - peek_buffer_size > n) {
+		memcpy (peek_buffer + peek_buffer_size, buf, n);
+		peek_buffer_size += n;
+	}
+
+	Unlock ();
+
+}
+
+void
+LiveSource::NotifySize (int64_t size)
+{
+	this->size = size;
+}
+
+
+bool
+LiveSource::Seek (int64_t offset, int mode)
+{
+	g_print ("Ask to seek to %lld and readpos is %lld (writepos:%lld)\n", offset, read_pos, write_pos);
+	
+	switch (mode) {
+	case SEEK_SET:
+		// no-op, offset is already relative to BOF
+		break;
+	case SEEK_CUR:
+		offset += read_pos;
+		break;
+	case SEEK_END:
+		if (size == -1) {
+			// we don't know the stream size, so cannot perform this seek
+			return false;
+		}
+		
+		if (offset > 0) {
+			// attempting to seek beyond eof
+			return false;
+		}
+		
+		offset += size;
+		break;
+	default:
+		// invalid 'whence' argument
+		return false;
+	}
+	
+
+	if (offset < 0 || (size != -1 && offset > size)) {
+		// attempting to seek to an invalid position
+		return false;
+	}
+	if (offset == read_pos)
+		return true;
+
+	if (offset > read_pos) {
+		/* FIXME: Implement skip on RingBuffer */
+ 		if (offset < write_pos) {
+			int nread;
+			char stupid_buffer[offset - read_pos];
+			nread = Read(stupid_buffer, offset - read_pos);
+			return true;
+		} else if (offset - write_pos < 10000) {
+			if (!(WaitForData (10000)))
+				return false;
+			int nread;
+                        char stupid_buffer[offset - read_pos];
+                        nread = Read(stupid_buffer, offset - read_pos);
+                        return true;
+		}
+			
+	}
+
+	if (offset < read_pos) {
+		int nrewind;
+		nrewind = buffer->Rewind (read_pos - offset);
+		if (nrewind == read_pos - offset) {
+			read_pos = offset;
+			return true;
+		}
+	
+	}
+
+	g_print ("Requesting remote SEEK\n");
+
+	/* Need to get the stream in the new position */
+	requested_pos = offset;
+	/* Clear the buffer */
+	Lock ();
+	buffer->Clean();
+	/* Set it here and wait for data */
+	read_pos = offset;
+	write_pos = offset;
+	Unlock ();
+
+	/* Fill the buffer a little bit before continue (avoid extra seeks) */
+
+	if (!(WaitForData (10000)))
+		return false;
+
+	return true;
+		
+}
+
+
+bool
+LiveSource::Seek (int64_t offset)
+{
+	return Seek (offset, SEEK_SET);
+}
+
+int64_t
+LiveSource::GetPosition ()
+{
+	return read_pos;
+}
+
+int64_t
+LiveSource::GetWritePosition ()
+{
+	return write_pos;
+}
+
+
+
+
+int32_t
+LiveSource::Read (void *buf, uint32_t n)
+{
+	int nread;
+	int available;
+
+	Lock ();
+	available = buffer->DataAvailable();
+	Unlock ();
+
+	if (n > (uint32_t) available )
+	       if (!(WaitForData (n)))
+                        return 0;
+
+	nread = buffer->Read ((char*)buf, n);
+	if ((uint32_t)nread < n) {
+		g_print ("LiveSource::Read: Not enough data in the RingBuffer\n");
+	}
+
+	read_pos += nread;
+	
+	return nread;
+}
+
+bool
+LiveSource::ReadAll (void *buf, uint32_t n)
+{
+	/* Should be without the while in the read */
+	int nread = Read (buf, n);
+	return (uint32_t) nread == n;
+}
+
+bool
+LiveSource::Peek (void *buf, uint32_t n)
+{
+	if (n > (uint32_t) peek_buffer_size) {
+		/* we can't handle a peek of this size */
+		return false;
+	}
+	
+	memcpy (buf, peek_buffer, n);
+	return true;
+}
+
+void
+LiveSource::RequestPosition (int64_t *pos)
+{
+	if (requested_pos != -1) {
+		*pos = requested_pos;
+		requested_pos = -1;
+	}
+}
+
+
+
+/*
  * MediaClosure
  */ 
 
Index: src/downloader.cpp
===================================================================
--- src/downloader.cpp	(revision 98038)
+++ src/downloader.cpp	(working copy)
@@ -293,6 +293,13 @@
 }
 
 void
+Downloader::RequestPosition (int64_t *pos)
+{
+	if (request_position)
+		request_position (pos, consumer_closure);
+}
+
+void
 Downloader::NotifyFinished (const char *fname)
 {
 	if (aborted)
@@ -363,7 +370,14 @@
 	this->consumer_closure = data;
 }
 
+
 void
+Downloader::SetRequestPositionFunc (downloader_request_position_func request_position)
+{
+	this->request_position = request_position;
+}
+
+void
 Downloader::SetFunctions (downloader_create_state_func create_state,
 			  downloader_destroy_state_func destroy_state,
 			  downloader_open_func open,
@@ -468,6 +482,12 @@
 	dl->NotifySize (size);
 }
 
+void
+downloader_request_position (Downloader *dl, int64_t *pos)
+{
+	dl->RequestPosition (pos);
+}
+
 void 
 dummy_downloader_write (void *buf, int32_t offset, int32_t n, gpointer cb_data)
 {
Index: src/media.h
===================================================================
--- src/media.h	(revision 98038)
+++ src/media.h	(working copy)
@@ -186,6 +186,7 @@
 	
 	// downloader methods/data
 	ProgressiveSource *downloaded_file;
+	LiveSource *live_stream;
 	Downloader *downloader;
 	char *part_name;
 	uint64_t buffering_start; // The last write position in the file when we started buffering
@@ -195,6 +196,7 @@
 	int advance_frame_timeout_id;
 	
 	void DataWrite (void *data, int32_t offset, int32_t n);
+	void DataRequestPosition (int64_t *pos);
 	void DownloaderAbort ();
 	void DownloaderComplete ();
 	void BufferingComplete ();
@@ -211,6 +213,7 @@
 	bool MediaOpened (Media *media);
 	
 	static void data_write (void *data, int32_t offset, int32_t n, void *closure);
+	static void data_request_position (int64_t *pos, void *closure);
 	static void downloader_complete (EventObject *sender, EventArgs *calldata, gpointer closure);
 	static void size_notify (int64_t size, gpointer data);
 	
Index: src/downloader.h
===================================================================
--- src/downloader.h	(revision 98038)
+++ src/downloader.h	(working copy)
@@ -25,6 +25,7 @@
 
 typedef void     (*downloader_write_func) (void *buf, int32_t offset, int32_t n, gpointer cb_data);
 typedef void     (*downloader_notify_size_func) (int64_t size, gpointer cb_data);
+typedef void     (*downloader_request_position_func) (int64_t *pos, gpointer cb_data);
 
 typedef gpointer (*downloader_create_state_func) (Downloader *dl);
 typedef void     (*downloader_destroy_state_func) (gpointer state);
@@ -68,11 +69,14 @@
 	void NotifyFailed (const char *msg);
 	void NotifySize (int64_t size);
 
+	void RequestPosition (int64_t *pos);
+
 	// This is called by the consumer of the downloaded data (the
 	// Image class for instance)
 	void SetWriteFunc (downloader_write_func write,
 			   downloader_notify_size_func notify_size,
 			   gpointer closure);
+	void SetRequestPositionFunc (downloader_request_position_func request_position);
 
 	// This is called by the supplier of the downloaded data (the
 	// managed framework, the browser plugin, the demo test)
@@ -102,9 +106,10 @@
 	bool aborted;
 	
 	// Set by the consumer
-	downloader_write_func       write;
-	downloader_notify_size_func notify_size;
+	downloader_write_func             write;
+	downloader_notify_size_func       notify_size;
 	gpointer consumer_closure;
+	downloader_request_position_func  request_position;
 
 	// Set by the supplier.
 	gpointer downloader_state;
@@ -146,6 +151,8 @@
 void downloader_notify_finished (Downloader *dl, const char *filename);
 void downloader_notify_error    (Downloader *dl, const char *msg);
 
+void downloader_request_position (Downloader *dl, int64_t *pos);
+
 void downloader_init (void);
 
 G_END_DECLS
Index: src/pipeline.h
===================================================================
--- src/pipeline.h	(revision 98038)
+++ src/pipeline.h	(working copy)
@@ -650,25 +650,152 @@
 	void NotifySize (int64_t size);
 };
 
+class RingBuffer {
+private:
+	int size;
+	char *data;
+	char *end; 
+	char *load, *consume;
+	int max_load, max_consume, data_in_buffer;
+	void Update () {
+		if (load == end)
+			load = data;
+		if (consume == end)
+			consume = data;
+
+		if (load == consume) {
+			if (data_in_buffer > 0) {
+				max_consume = end - consume;
+				max_load = 0;
+			} else {
+				max_load = end - load;
+				max_consume = 0;
+			}
+		} else if (load > consume) {
+			max_load = end - load;
+			max_consume = load - consume;
+		} else {
+			max_load = consume - load;
+			max_consume = end - consume;
+		}
+	}
+
+public:
+	RingBuffer (int size) { 
+		data = (char*) g_malloc (size);
+		this->size = size;
+		end = data + size;
+		load = data;
+		consume = data;
+		max_load = size;
+		max_consume = 0;
+		data_in_buffer = 0;
+		
+	}
+	~RingBuffer () { g_free (data); }
+
+	void Clean () {
+		end = data + size;
+		load = data;
+		consume = data;
+		max_load = size;
+		max_consume = 0;
+		data_in_buffer = 0;
+	}
+		
+	int GetSize () { return size; }
+	int Write (const char *data, int size) {
+		if (size > max_load) 
+			size = max_load;
+		memcpy (load, data, size);
+		data_in_buffer += size;
+		load += size;
+		Update();
+		return size;
+	}
+
+	int Read (char *data, int size) {
+		if (size > max_consume)
+			size = max_consume;
+		memcpy (data, consume, size);
+		consume += size;
+		data_in_buffer -= size;
+		Update();
+		return size;
+	}
+
+	int Rewind (int size) {
+		/* FIXME do the real checks */
+		if (size > max_load)
+			size = max_load;
+		consume -= size;
+		data_in_buffer += size;
+		Update();
+		return size;
+	}
+
+	int DataAvailable () {
+		return max_consume;
+	}
+};
+
 class LiveSource : public IMediaSource {
+private:
+	int64_t write_pos;
+	int64_t read_pos;
+	int64_t requested_pos;
+	int64_t size;
+	bool can_seek;
+	RingBuffer *buffer;
+	char *peek_buffer;
+	int peek_buffer_size;
+
+	pthread_mutex_t write_mutex;
+	pthread_cond_t write_cond;
+	bool cancel_wait;
+	int wait_count; // Counter of how many threads are waiting in WaitForPosition
+	int wait_size;
+
+	
+	static void write (void *buf, int32_t offset, int32_t n, gpointer cb_data);
+	static void position (int64_t *pos, gpointer cb_data);
+
 protected:
-	virtual ~LiveSource () {}
+	virtual ~LiveSource ();
 
 public:
-	LiveSource (Media *media) : IMediaSource (media) {}
+	LiveSource (Media *media);
 	
-	virtual MediaResult Initialize () { return MEDIA_FAIL; }
+	virtual MediaResult Initialize ();
 	virtual MediaSourceType GetType () { return MediaSourceTypeLive; }
+
+	// Blocks until the position have data
+	// Returns false if failure (one possibility being that the requested position is beyond the end of the file)
+	bool WaitForData (int size);
+	// Wakes up WaitForPosition to check if the position has been reached, or if the wait should be cancelled
+	bool WakeUp ();
+	bool WakeUp (bool lock); // lock: set to false if the write_lock is already acquired by the caller
+	bool IsWaiting ();
+	// Cancels any pending waits
+	void CancelWait (); 
+	void Lock ();
+	void Unlock ();
 	
-	virtual bool IsSeekable () { return false; }
-	virtual int64_t GetPosition () { return 0; }
-	virtual bool Seek (int64_t position) { return false; }
-	virtual bool Seek (int64_t position, int mode) { return false; }
-	virtual int32_t Read (void *buffer, uint32_t n) { return -1; }
-	virtual bool ReadAll (void *buffer, uint32_t n) { return false; }
-	virtual bool Peek (void *buffer, uint32_t n) { return false; }
-	virtual int64_t GetSize () { return -1; }
-	virtual bool Eof () { return false; }
+	
+	virtual bool IsSeekable () { return true; } // TEMPORAL
+	virtual int64_t GetPosition ();
+	virtual bool Seek (int64_t position);
+	virtual bool Seek (int64_t position, int mode);
+	virtual int32_t Read (void *buffer, uint32_t n);
+	virtual bool ReadAll (void *buffer, uint32_t n);
+	virtual bool Peek (void *buffer, uint32_t n);
+	virtual int64_t GetSize () { return size; }
+	virtual bool Eof () { return write_pos == size; }
+
+	int64_t GetWritePosition ();
+	void Write (void *buf, int64_t offset, int32_t n);
+	void NotifySize (int64_t size);
+	void RequestPosition (int64_t *pos);
 };
 
 class VideoStream : public IMediaStream {
Index: src/media.cpp
===================================================================
--- src/media.cpp	(revision 98038)
+++ src/media.cpp	(working copy)
@@ -335,6 +335,7 @@
 
 	streamed_markers = NULL;
 	downloaded_file = NULL;
+	live_stream = NULL;
 	downloader = NULL;
 	part_name = NULL;
 	mplayer = NULL;
@@ -413,6 +414,10 @@
 		downloaded_file->unref ();
 		downloaded_file = NULL;
 	}
+	if (live_stream) {
+		live_stream->unref ();
+		live_stream = NULL;
+	}
 	
 	flags |= UpdatingPosition;
 	SetValue (MediaElement::PositionProperty, Value (0, Type::TIMESPAN));
@@ -668,9 +673,17 @@
 	// CHECK: if buffering, will DownloadCompletedEvent be emitted?
 	
 	if (IsBuffering ()) {
-		int64_t size = downloaded_file->GetSize ();
+		int64_t size;
+		if (downloaded_file != NULL)
+			size = downloaded_file->GetSize ();
+		if (live_stream != NULL);
+			size = live_stream->GetSize ();
 		int64_t buffering_time = TimeSpan_ToPts (GetValue (MediaElement::BufferingTimeProperty)->AsTimeSpan ());
-		int64_t write_pos = downloaded_file->GetWritePosition ();
+		int64_t write_pos;
+		if (downloaded_file != NULL)
+			write_pos = downloaded_file->GetWritePosition ();
+		if (live_stream != NULL)
+			write_pos = live_stream->GetWritePosition ();
 		int64_t wait_pos = media == NULL ? 0 : media->GetDemuxer ()->EstimatePtsPosition (buffering_pts + buffering_time);
 		int64_t buffer_size = wait_pos - buffering_start;
 		int64_t buffered_size = write_pos - buffering_start;
@@ -755,6 +768,12 @@
 		if (!(flags & BufferingFailed) && IsOpening () && offset > 1024 && (part_name == NULL || part_name[0] == 0))
 			TryOpen ();
 	}
+
+	if (live_stream != NULL) {
+		live_stream->Write (buf, (int64_t) offset, n);
+		if (!(flags & BufferingFailed) && IsOpening () && offset > 1024)
+			TryOpen ();
+	}
 	
 	// Delay the propogating progress 1.0 until
 	// the downloader has notified us it is done.
@@ -764,6 +783,13 @@
 		UpdateProgress ();
 }
 
+void
+MediaElement::DataRequestPosition (int64_t *position)
+{
+	if (live_stream != NULL)
+		live_stream->RequestPosition (position);
+}
+
 void 
 MediaElement::data_write (void *buf, int32_t offset, int32_t n, gpointer data)
 {
@@ -777,6 +803,8 @@
 	
 	if (element->downloaded_file != NULL)
 		element->downloaded_file->NotifySize (size);
+	if (element->live_stream != NULL)
+		element->live_stream->NotifySize (size);
 }
 
 void
@@ -785,6 +813,14 @@
 	((MediaElement *) closure)->DownloaderComplete ();
 }
 
+void 
+MediaElement::data_request_position (int64_t *position, gpointer data)
+{
+	((MediaElement *) data)->DataRequestPosition (position);
+}
+
+
+
 void
 MediaElement::BufferingComplete ()
 {
@@ -853,7 +889,8 @@
 	} else {
 		element->flags |=  BufferingFailed;
 		// Seek back to the beginning of the file
-		element->downloaded_file->Seek (0, SEEK_SET);
+		if (element->downloaded_file != NULL)
+			element->downloaded_file->Seek (0, SEEK_SET);
 	}
 	delete closure;
 	return false;
@@ -898,16 +935,23 @@
 	LOG_MEDIAELEMENT ("MediaElement::TryOpen ()\n");
 
 	if (flags & DownloadComplete) {
-		IMediaSource *current_downloaded_file = downloaded_file;
-		char *filename = downloader_get_response_file (downloader, part_name);
 		Media *media = new Media (this);
 		IMediaSource *source;
+		IMediaSource *current_downloaded_file = NULL;
+
+		if (downloaded_file != NULL) {
+			current_downloaded_file = downloaded_file;
+			char *filename = downloader_get_response_file (downloader, part_name);
 		
-		if (current_downloaded_file)
-			current_downloaded_file->ref ();
+			if (current_downloaded_file)
+				current_downloaded_file->ref ();
 
-		source = new FileSource (media, filename);
-		g_free (filename);
+			source = new FileSource (media, filename);
+			g_free (filename);
+		}
+		if (live_stream != NULL) {
+			source = live_stream;
+		}
 		
 		if (MEDIA_SUCCEEDED (source->Initialize ()) && MEDIA_SUCCEEDED (media->Open (source))) {
 			if (MediaOpened (media)) {
@@ -942,7 +986,11 @@
 		
 		MediaClosure *closure = new MediaClosure (media_element_open_callback);
 		closure->SetContext (this);
-		media->OpenAsync (downloaded_file, closure);
+		if (downloaded_file != NULL) {
+			media->OpenAsync (downloaded_file, closure);
+		} else if (live_stream != NULL) {
+			media->OpenAsync (live_stream, closure);
+		}
 	}
 	
 	// FIXME: specify which audio stream index the player should use
@@ -990,10 +1038,13 @@
 void
 MediaElement::SetSourceInternal (Downloader *dl, const char *PartName)
 {
+	bool is_live = false;
+	if (g_str_has_prefix (dl->GetValue (Downloader::UriProperty)->AsString (), "mms")) {
+		is_live = true;
 #if DEBUG
-	if (g_str_has_prefix (dl->GetValue (Downloader::UriProperty)->AsString (), "mms")) 
 		printf ("MediaElement is trying to load an mms stream, which isn't supported yet (%s)\n", dl->GetValue (Downloader::UriProperty)->AsString ());
 #endif	
+	}
 	
 	LOG_MEDIAELEMENT ("MediaElement::SetSourceInternal (%p, '%s'), uri: %s\n", dl, PartName, dl->GetValue (Downloader::UriProperty)->AsString ());
 	
@@ -1013,19 +1064,25 @@
 		
 		TryOpen ();
 	} else {
-		downloaded_file = new ProgressiveSource (mplayer->media);
+		if (is_live) {
+			live_stream = new LiveSource (mplayer->media);
+			live_stream->Initialize ();
+			downloader->SetWriteFunc (data_write, size_notify, this);
+			downloader->SetRequestPositionFunc (data_request_position);
+		} else {
+			downloaded_file = new ProgressiveSource (mplayer->media);
+			// FIXME: error check Initialize()
+			downloaded_file->Initialize ();
+			downloader->SetWriteFunc (data_write, size_notify, this);
+		}
 		
-		// FIXME: error check Initialize()
-		downloaded_file->Initialize ();
-		
-		downloader->SetWriteFunc (data_write, size_notify, this);
 	}
 	
 	if (!(flags & DownloadComplete))
 		downloader->AddHandler (downloader->CompletedEvent, downloader_complete, this);
 	
 	// This is what actually triggers the download
-	if (downloaded_file != NULL)
+	if (downloaded_file != NULL || live_stream != NULL)
 		downloader->Send ();
 	
 	Invalidate ();
Index: plugin/plugin-downloader.h
===================================================================
--- plugin/plugin-downloader.h	(revision 98038)
+++ plugin/plugin-downloader.h	(working copy)
@@ -33,6 +33,8 @@
 		this->npp = NULL;
 		this->stream = NULL;
 
+		ignore_non_data = false;
+
 		// The Downloader will call destroy_state from it's destructor,
 		// but if we ref the Downloader, its destructor will never get called.
 		// No need to keep a ref, since this instance will never live longer
@@ -60,6 +62,7 @@
 	bool mmsh;
 	NPStream *stream;
 	NPP npp;
+	bool ignore_non_data;
 };
 
 void downloader_set_stream_data (Downloader *downloader, NPP npp, NPStream *stream);
Index: plugin/browser-mmsh.cpp
===================================================================
--- plugin/browser-mmsh.cpp	(revision 98038)
+++ plugin/browser-mmsh.cpp	(working copy)
@@ -11,6 +11,7 @@
  */
 
 #include "browser-mmsh.h"
+#include "plugin-downloader.h"
 #include <asf/asf.h>
 
 #define LE_16(val) (GINT16_FROM_LE (*((u_int16_t*)(val))))
@@ -139,6 +140,7 @@
 BrowserMmshResponse::Abort ()
 {
 	this->channel->Cancel (NS_BINDING_ABORTED);
+	this->aborted = true;
 }
 
 typedef struct {
@@ -347,6 +349,7 @@
 {
 	PRUint32 length;
 	char *read_buffer;
+	PluginDownloader *pd = (PluginDownloader*) this->context;
 
 	if (tmp_buffer) {
 		read_buffer = (char *) NS_Realloc (tmp_buffer, tmp_size + count);
@@ -392,13 +395,16 @@
 				asf_header_parse (mms_packet+8, packet_size - 8, &file_size, &asf_packet_size);
 				if (file_size && notifier)
 					notifier (this, this->context, NULL, file_size);
-				reader (this, this->context, mms_packet+8, this->size, packet_size - 8);
-				this->size += packet_size - 8;
+				if (!pd->ignore_non_data) {
+					reader (this, this->context, mms_packet+8, this->size, packet_size - 8);
+					this->size += packet_size - 8;
+				}
 		} else if (type == MMS_DATA) {
 				char *new_data = (char*)g_malloc0 (asf_packet_size);
 				memcpy (new_data, mms_packet+8, packet_size - 8);
 				reader (this, this->context, new_data, this->size, asf_packet_size);
 				this->size += asf_packet_size;
+					
 				g_free (new_data);
 		}
 		length -= size + 4;
@@ -460,7 +466,7 @@
 	nsresult rs = NS_OK;
 	AsyncBrowserMmshResponse *response;
 
-	response = new AsyncBrowserMmshResponse (channel, reader, notifier, finisher, context);
+	response = new AsyncBrowserMmshResponse (channel, this->uri, reader, notifier, finisher, context);
 	rs = channel->AsyncOpen (response, (BrowserMmshResponse *) response);
 	return !NS_FAILED (rs);
 }
Index: plugin/plugin-downloader.cpp
===================================================================
--- plugin/plugin-downloader.cpp	(revision 98038)
+++ plugin/plugin-downloader.cpp	(working copy)
@@ -15,6 +15,8 @@
 
 bool downloader_shutdown = false;
 
+static NPError p_downloader_mmsh_send (PluginDownloader *pd, int64_t offset);
+
 static gpointer
 p_downloader_create_state (Downloader *dl)
 {
@@ -48,26 +50,38 @@
 static void
 p_downloader_mmsh_reader (BrowserMmshResponse *response, gpointer context, char *buffer, int offset, PRUint32 length)
 {
-	StreamNotify *notify = (StreamNotify*) context;
-	Downloader *dl = (Downloader *) notify->pdata;
+	int64_t requested_pos = -1;
+	PluginDownloader *pd = (PluginDownloader*) context;
 
 	if (downloader_shutdown) {
 		response->Abort ();
 		return;
 	}
 
-	dl->Write (buffer, offset, length);
+	if (response->aborted) {
+		g_print ("Dude! we had aborted!\n");
+		return;
+	}
 
+	pd->dl->RequestPosition (&requested_pos);
+	if (requested_pos != -1 ) {
+
+		response->Abort ();
+		p_downloader_mmsh_send (pd, requested_pos);
+		return;
+	}
+
+	pd->dl->Write (buffer, offset, length);
+
 }
 
 static void
 p_downloader_mmsh_notifier (BrowserMmshResponse *response, gpointer context, char *name, int64_t size)
 {
-	StreamNotify *notify = (StreamNotify*) context;
-	Downloader *dl = (Downloader *) notify->pdata;
+	PluginDownloader *pd = (PluginDownloader*) context;
 
 	g_print ("Notifing a size of %d\n", size);
-	dl->NotifySize (size);
+	pd->dl->NotifySize (size);
 }
 
 
@@ -75,30 +89,34 @@
 p_downloader_mmsh_finished (BrowserMmshResponse *response, gpointer context)
 {
 	char *fname;
-	StreamNotify *notify = (StreamNotify*) context;
-	Downloader *dl = (Downloader *) notify->pdata;
-
+	PluginDownloader *pd = (PluginDownloader*) context;
 	if (downloader_shutdown) {
 		return;
 	}
 
-	fname = dl->GetResponseFile (NULL);
-        dl->NotifyFinished (fname);
+	fname = pd->dl->GetResponseFile (NULL);
+        pd->dl->NotifyFinished (fname);
 
 }
 
 
 static NPError
-p_downloader_mmsh_send (NPP_t *plugin, const char *uri, StreamNotify *notify)
+p_downloader_mmsh_send (PluginDownloader *pd, int64_t offset)
 {
-	BrowserMmshRequest *mmsh_request = new BrowserMmshRequest ("GET", uri);
+	BrowserMmshRequest *mmsh_request = new BrowserMmshRequest ("GET", pd->uri);
 	mmsh_request->SetHttpHeader ("User-Agent", "NSPlayer/11.1.0.3856");
-	mmsh_request->SetHttpHeader ("Pragma", "no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,max-duration=0");
+	mmsh_request->SetHttpHeader ("Pragma", "no-cache,rate=1.000000,stream-time=0,max-duration=0");
 	mmsh_request->SetHttpHeader ("Pragma", "xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}");
 	mmsh_request->SetHttpHeader ("Pragma", "xPlayStrm=1");
 	mmsh_request->SetHttpHeader ("Pragma", "stream-switch-count=0");
 	mmsh_request->SetHttpHeader ("Pragma", "stream-switch-entry=ffff:1:0 ffff:4:0");
-	return mmsh_request->GetAsyncResponse (p_downloader_mmsh_reader, p_downloader_mmsh_notifier, p_downloader_mmsh_finished, notify);
+	if (offset != -1) {
+		char *header = g_strdup_printf ("stream-offset=%d:%d", (unsigned int)(offset >> 32), (unsigned int)offset);
+		mmsh_request->SetHttpHeader ("Pragma", header);
+		g_free (header);
+		pd->ignore_non_data = true;
+	}
+	return mmsh_request->GetAsyncResponse (p_downloader_mmsh_reader, p_downloader_mmsh_notifier, p_downloader_mmsh_finished, pd);
 	
 }
 
@@ -126,7 +144,7 @@
 		NPError err;
 		
 		if (pd->mmsh) {
-			err = p_downloader_mmsh_send (plugin, pd->uri, notify);
+			err = p_downloader_mmsh_send (pd, -1);
 		} else {
 			err = NPN_GetURLNotify (plugin, pd->uri, NULL, notify);
 		}
Index: plugin/browser-mmsh.h
===================================================================
--- plugin/browser-mmsh.h	(revision 98038)
+++ plugin/browser-mmsh.h	(working copy)
@@ -41,25 +41,32 @@
 class BrowserMmshResponse : public nsIHttpHeaderVisitor {
 	nsCOMPtr<nsIChannel> channel;
 	HttpHeaderHandler handler;
+	char *uri;
 
 protected:
 	NS_DECL_NSIHTTPHEADERVISITOR
 
 public:
 	NS_DECL_ISUPPORTS
+	bool aborted;
 
 	BrowserMmshResponse (nsCOMPtr<nsIChannel> channel) : handler (NULL)
 	{
+		aborted = false;
+		this->uri = NULL;
 		this->channel = channel;
 	}
 
 	virtual ~BrowserMmshResponse ()
 	{
+		g_free (uri);
 	}
 
 	void Abort ();
 	void VisitHeaders (HttpHeaderHandler handler);
 	char *GetStatus (int *code);
+	void SetUri (const char *uri) { this->uri = g_strdup (uri); }
+	const char *GetUri () { return this->uri; }
 
 	//virtual void *Read (int *length) = 0;
 };
@@ -90,6 +97,7 @@
 	NS_DECL_ISUPPORTS
 
 	AsyncBrowserMmshResponse (nsCOMPtr<nsIChannel> channel,
+				  const char *uri,
 				  AsyncMmshResponseDataAvailableHandler reader, 
 				  AsyncMmshResponseNotifierHandler notifier, 
 				  AsyncMmshResponseFinishedHandler finisher,
@@ -107,11 +115,14 @@
 		this->reader = reader;
 		this->finisher = finisher;
 		this->context = context;
+		SetUri (uri);
+
 	}
 
 	void MmsMetadataParse (int, const char*);
 	virtual ~AsyncBrowserMmshResponse ()
 	{
+		g_free (tmp_buffer);
 	}
 
 };