rendered paste bodyIndex: 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);
}
};