[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-multimedia
Subject:    [PATCH - update] advanced multimedia streaming for KDE
From:       Matthias Welwarsky <matze () stud ! fbi ! fh-darmstadt ! de>
Date:       2002-03-05 18:00:44
[Download RAW message or body]

Hi list,

I've updated patch a little bit, after having talked to Stefan Westerfeld a 
little who explained the magic of synchronous data streams in arts to me. The 
result is that the patches to arts ( suspend()/resume() support ) are no 
longer necessary.

So what's new in this version:

* the kio_audiocd patch was sent for review but is now yet included, so I 
still include it.

* the kaboodle patch got merged into CVS, so I no longer include it.

* instead I have a patch for noatun so that it relies on the kplayobject 
factory finding out the correct mimetype and providing the correct 
playobject. You can now listen to Ogg Vorbis streams with noatun, too.

* little tweaks to the buffering logic of kioinputstream, making it look a 
little simpler and also work a little better.

* changed the DecoderBaseObject so that it no longer relies on 
suspend()/resume() but makes use of the flow control that's build into arts 
synchronous data streams. The solution is a little ugly because it introduces 
yet another queue to just convert beween different data representations. 
However, it's quite cost efficient because it only stores pointers to 
DataPackets. I use a std::queue, which will hopefully exist on other systems, 
too.

Efficiency is an issue, though. Data is copied multiple times on its' way from 
the IO-Job into the Playobject and into mpeglib - for now I don't care, it 
doesn't matter for low bitrate stuff, but for video streaming there are quite 
some improvements to be made.

KNOWN BUGS

* if you kill kaboodle or noatun with Ctrl-C, the IO-Job is not terminated and 
the slave continues to download the stream from the server. But where is the 
data going? And how to make sure the IO-Job is killed? help!

* the crash-on-every-other-ogg-vorbis-stream bug is back. In fact I think it 
was never really fixed (as Martin Vogt already suspected). help!

have fun,
	Matze

["kio_audiocd.patch" (text/x-diff)]

Index: audiocd.cpp
===================================================================
RCS file: /home/kde/kdebase/kioslave/audiocd/audiocd.cpp,v
retrieving revision 1.44
diff -u -3 -p -r1.44 audiocd.cpp
--- audiocd.cpp	2002/02/28 16:34:40	1.44
+++ audiocd.cpp	2002/03/05 17:57:52
@@ -755,24 +755,30 @@ AudioCDProtocol::get(const KURL & url)
 
 #ifdef HAVE_LAME
   if ( initLameLib() == true ){
-    if (filetype == "mp3")
+    if (filetype == "mp3") {
       totalSize((time_secs * d->bitrate * 1000)/8);
+      mimeType("audio/x-mp3");
+    }
   };
 #endif
 
 #ifdef HAVE_VORBIS
   if (filetype == "ogg") {
     totalSize((time_secs * d->vorbis_bitrate)/8);
+    mimeType("audio/x-ogg");
   }
 #endif
 
   if (filetype == "wav") {
     totalSize(44 + totalByteCount); // Include RIFF header length.
     writeHeader(totalByteCount);    // Write RIFF header.
+    mimeType("audio/x-wav");
   }
 
-  if (filetype == "cda")
+  if (filetype == "cda") {
     totalSize(totalByteCount);      // CDA is raw interleaved PCM Data with \
SampleRate 44100 and 16 Bit res.  +    mimeType("audio/x-cda");
+  }
 
   paranoiaRead(drive, firstSector, lastSector, filetype);
 


["kplayobject.patch" (text/x-diff)]

? kde/kplayobject-mimetype.patch
Index: kde/kioinputstream_impl.cpp
===================================================================
RCS file: /home/kde/kdelibs/arts/kde/kioinputstream_impl.cpp,v
retrieving revision 1.23
diff -u -3 -p -r1.23 kioinputstream_impl.cpp
--- kde/kioinputstream_impl.cpp	2002/01/30 16:20:29	1.23
+++ kde/kioinputstream_impl.cpp	2002/03/05 17:27:59
@@ -49,7 +49,9 @@ KIOInputStream_impl::KIOInputStream_impl
 	m_data = 0;
 	m_finished = false;
 	m_firstBuffer = false;
-	m_packetBuffer = 20;
+	m_packetBuffer = 16;
+	m_streamStarted = false;
+	m_streamSuspended = false;
 }
 
 KIOInputStream_impl::~KIOInputStream_impl()
@@ -60,32 +62,51 @@ KIOInputStream_impl::~KIOInputStream_imp
 
 void KIOInputStream_impl::streamStart()
 {
+	// prevent kill/reconnect
+	if (m_streamStarted) {
+		kdDebug() << "not restarting stream!\n";
+		if (m_job->isSuspended())
+			m_job->resume();
+		return;
+	}
+
+	kdDebug() << "(re)starting stream\n";
+
 	if(m_job != 0)
 		m_job->kill();
 	m_job = KIO::get(m_url, false, false);
-	m_job->addMetaData("accept", "audio/x-mp3");
+	m_job->addMetaData("accept", "audio/x-mp3, video/mpeg");
 	m_job->addMetaData("UserAgent", QString::fromLatin1("aRts/") + \
QString::fromLatin1(ARTS_VERSION));  
 	QObject::connect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
 			 this, SLOT(slotData(KIO::Job *, const QByteArray &)));		     
 	QObject::connect(m_job, SIGNAL(result(KIO::Job *)),
 			 this, SLOT(slotResult(KIO::Job *)));		     
+	QObject::connect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)),
+			 this, SLOT(slotScanMimeType(KIO::Job *, const QString &)));
+
+	m_streamStarted = true;
 }
 
 void KIOInputStream_impl::streamEnd()
 {
+	kdDebug() << "streamEnd()\n";
+
 	if(m_job != 0)
 	{
 		QObject::disconnect(m_job, SIGNAL(data(KIO::Job *, const QByteArray &)),
 	    				this, SLOT(slotData(KIO::Job *, const QByteArray &)));
 		QObject::disconnect(m_job, SIGNAL(result(KIO::Job *)),
 						this, SLOT(slotResult(KIO::Job *)));		     
+		QObject::disconnect(m_job, SIGNAL(mimetype(KIO::Job *, const QString &)),
+				 this, SLOT(slotScanMimeType(KIO::Job *, const QString &)));
 
 		m_job->kill();
 		m_job = 0;
 	}	
 
 	outdata.endPull();
+	m_streamStarted = false;
 }
 
 bool KIOInputStream_impl::openURL(const std::string& url)
@@ -110,12 +131,23 @@ void KIOInputStream_impl::slotResult(KIO
 {
 	// jobs delete themselves after emitting their result
 	m_finished = true;
+	m_streamStarted = false;
 	m_job = 0;
 
-	if(job->error())
-	    job->showErrorDialog();
+	if(job->error()) {
+		// break out of the event loop in case of
+		// connection error
+	    	emit mimeTypeFound("application/x-zerosize");
+		job->showErrorDialog();
+	}
 }
 
+void KIOInputStream_impl::slotScanMimeType(KIO::Job *, const QString &mimetype)
+{
+	kdDebug() << "got mimetype: " << mimetype << endl;
+	emit mimeTypeFound(mimetype);
+}
+
 bool KIOInputStream_impl::eof()
 {
 	return (m_finished && m_data.size() == 0);
@@ -143,24 +175,23 @@ void KIOInputStream_impl::processQueue()
 		if(m_data.size() > (m_packetBuffer * m_packetSize * 2) && !m_job->isSuspended())
 		{
 			kdDebug() << "STREAMING: suspend job" << endl;
-	    	m_job->suspend();
+			m_job->suspend();
 		}
 		else if(m_data.size() < (m_packetBuffer * m_packetSize) && m_job->isSuspended())
 		{
 			kdDebug() << "STREAMING: resume job" << endl;
-	    	m_job->resume();
+			m_job->resume();
 		}
 	}
 
-	if(m_data.size() < (m_packetBuffer * m_packetSize) && !m_firstBuffer)
-	{
-		kdDebug() << "STREAMING: Buffering in progress... (Needed bytes before it starts \
                to play: " << ((m_packetBuffer * m_packetSize) - m_data.size()) << \
                ")" << endl;
-		return;
-	}
-	else if( !m_firstBuffer )
-	{
-		m_firstBuffer = true;
-		outdata.setPull(PACKET_COUNT, m_packetSize);
+	if (!m_firstBuffer) {
+		if(m_data.size() < (m_packetBuffer * m_packetSize * 2) ) {
+			kdDebug() << "STREAMING: Buffering in progress... (Needed bytes before it starts \
to play: " << ((m_packetBuffer * m_packetSize) - m_data.size()) << ")" << endl; \
+			return; +		} else {
+			m_firstBuffer = true;
+			outdata.setPull(PACKET_COUNT, m_packetSize);
+		} 
 	}
 }
 
@@ -170,12 +201,15 @@ void KIOInputStream_impl::request_outdat
 	packet->size = std::min(m_packetSize, m_data.size());
 	//kdDebug() << "STREAMING: Filling one DataPacket with " << packet->size << " bytes \
of the stream!" << endl;  
-	if((unsigned)packet->size < m_packetSize || ! m_firstBuffer)
-	{
-		m_firstBuffer = false;
-		packet->size = 0;
+	if (!m_finished) {
+		if( (unsigned)packet->size < m_packetSize || ! m_firstBuffer) {
+			m_firstBuffer = false;
+			packet->size = 0;
+			outdata.endPull();
+		}
 	}
-	else
+	
+	if (packet->size > 0)
 	{
 		memcpy(packet->contents, m_data.data(), packet->size);
 		memmove(m_data.data(), m_data.data() + packet->size, m_data.size() - \
                packet->size);
Index: kde/kioinputstream_impl.h
===================================================================
RCS file: /home/kde/kdelibs/arts/kde/kioinputstream_impl.h,v
retrieving revision 1.16
diff -u -3 -p -r1.16 kioinputstream_impl.h
--- kde/kioinputstream_impl.h	2002/01/30 16:20:30	1.16
+++ kde/kioinputstream_impl.h	2002/03/05 17:27:59
@@ -54,10 +54,14 @@ public:
 	void bufferPackets(long i) { m_packetBuffer = i; }
 
 	long packetSize() { return m_packetSize; }
+
+signals:
+	void mimeTypeFound(const QString & mimetype);
 	
 private slots:
 	void slotData(KIO::Job *, const QByteArray &);
 	void slotResult(KIO::Job *);
+	void slotScanMimeType(KIO::Job *, const QString &mimetype);
 
 private:
 	KURL m_url;
@@ -65,6 +69,8 @@ private:
 	QByteArray m_data;
 	bool m_finished;
 	bool m_firstBuffer;
+	bool m_streamStarted;
+	bool m_streamSuspended;
 
 	unsigned int m_packetBuffer;
 	const unsigned int m_packetSize;
@@ -73,3 +79,5 @@ private:
 };
 
 };
+
+
Index: kde/kplayobjectfactory.cc
===================================================================
RCS file: /home/kde/kdelibs/arts/kde/kplayobjectfactory.cc,v
retrieving revision 1.16
diff -u -3 -p -r1.16 kplayobjectfactory.cc
--- kde/kplayobjectfactory.cc	2001/10/29 20:57:36	1.16
+++ kde/kplayobjectfactory.cc	2002/03/05 17:28:00
@@ -23,9 +23,14 @@
 #include "kplayobject.h"
 #include "artskde.h"
 #include "kplayobjectfactory.h"
+#include "kplayobjectfactory.moc"
+#include "kioinputstream_impl.h"
 
 #include <qfile.h>
+#include <kapplication.h>
 
+#include <kdebug.h>
+
 using namespace std;
 
 KPlayObjectFactory::KPlayObjectFactory(Arts::SoundServerV2 server)
@@ -41,14 +46,75 @@ KPlayObjectFactory::~KPlayObjectFactory(
 
 KPlayObject *KPlayObjectFactory::createPlayObject(const KURL& url, bool createBUS)
 {
+
+	// no need to go any further, and I hate deep indentation
+	if (m_server.isNull())
+		return new KPlayObject();
+
+	// check if streaming is allowed or the URL is a local file
+	if (m_allowStreaming && !url.isLocalFile())
+	{
+		// This is the RightWay(tm) according to stw
+		Arts::KIOInputStream_impl* instream_impl = new Arts::KIOInputStream_impl();
+		Arts::KIOInputStream instream = Arts::KIOInputStream::_from_base(instream_impl);
+
+		// signal will be called once the ioslave knows the mime-type of the stream
+		QObject::connect(instream_impl, SIGNAL(mimeTypeFound(const QString &)),
+				 this, SLOT(slotMimeType(const QString &)));
+
+		// GO!
+		instream.openURL(url.url().latin1());
+		instream.streamStart();
+
+		m_eventLoopEntered = true;
+		// FIXME: need to handle timeouts?
+		// this is UGLY, but I cannot do anything else without changing the interface
+		// the application blocks here, and restarts once slotMimeType() is called.
+		kapp->enter_loop();
+		
+		// wb :D
+		// some error occoured
+		if (m_mimeType == "application/x-zerosize")
+		    return new KPlayObject();
+
+		// ok, now we know the mimetype of the stream
+		m_stream = true;		
+		return new KPlayObject(m_server.createPlayObjectForStream(instream, 
+									  string(m_mimeType.latin1()), 
+									  createBUS), true);
+	}
+	kdDebug() << "stream is local file: " << url.url() << endl;
+
+	// usual stuff if we have a local file
 	KMimeType::Ptr mimetype = KMimeType::findByURL(url);
-	return createPlayObject(url, mimetype->name(), createBUS);
+	return new KPlayObject(m_server.createPlayObjectForURL(string(QFile::encodeName(url.path())), \
 +							       string(mimetype->name().latin1()), 
+							       createBUS), 
+			       false);
+}
+
+void KPlayObjectFactory::slotMimeType(const QString& mimetype)
+{
+
+	kdDebug() << "slotMimeType called: " << mimetype << endl;
+
+	if ( mimetype == "application/octet-stream" )
+	    m_mimeType = "audio/x-mp3";
+	else
+	    m_mimeType = mimetype;
+
+	if (m_eventLoopEntered) {
+		m_eventLoopEntered = false;
+		kapp->exit_loop();
+	}
 }
 
 KPlayObject *KPlayObjectFactory::createPlayObject(const KURL& url, const QString \
&mimetype, bool createBUS)  {
 	if(!m_server.isNull())
 	{
+		kdDebug() << "createPlayObject: mimetype is " << mimetype << endl;
+
 		if(mimetype == "application/octet-stream" && m_allowStreaming)
 		{
 			Arts::KIOInputStream instream;
@@ -58,6 +124,15 @@ KPlayObject *KPlayObjectFactory::createP
 		
 			// TODO: what else than hardcoding audio/x-mp3 ?
 			return new KPlayObject(m_server.createPlayObjectForStream(instream, \
string("audio/x-mp3"), createBUS), true); +		}
+		else if(mimetype == "video/mpeg" && m_allowStreaming)
+		{
+			Arts::KIOInputStream instream;
+			instream.openURL(url.url().latin1());
+
+			m_stream = true;
+
+			return new KPlayObject(m_server.createPlayObjectForStream(instream, \
string("video/mpeg"), createBUS), true);  }
 		else
 			return new KPlayObject(m_server.createPlayObjectForURL(string(QFile::encodeName(url.path())), \
                string(mimetype.latin1()), createBUS), false);
Index: kde/kplayobjectfactory.h
===================================================================
RCS file: /home/kde/kdelibs/arts/kde/kplayobjectfactory.h,v
retrieving revision 1.9
diff -u -3 -p -r1.9 kplayobjectfactory.h
--- kde/kplayobjectfactory.h	2001/10/29 20:57:36	1.9
+++ kde/kplayobjectfactory.h	2002/03/05 17:28:00
@@ -23,11 +23,13 @@
 #define KPLAYOBJECTFACTORY_H
 
 #include <kurl.h>
+#include <qobject.h>
 #include "soundserver.h"
 #include "kplayobject.h"
 
-class KPlayObjectFactory
+class KPlayObjectFactory : public QObject
 {
+Q_OBJECT
 public:
 	KPlayObjectFactory(Arts::SoundServerV2 server);
 	~KPlayObjectFactory();
@@ -39,11 +41,16 @@ public:
 	bool allowStreaming() { return m_allowStreaming; }
 
 	bool isAStream() { return m_stream; }
-	
+
+private slots:
+        void slotMimeType(const QString &mimetype);
+
 private:
 	Arts::SoundServerV2 m_server;
 	bool m_allowStreaming;
 	bool m_stream;
+	bool m_eventLoopEntered;
+	QString m_mimeType;
 };
 
 #endif


["mpeglib-bis.patch" (text/x-diff)]

? example/splay/mp3framing
Index: lib/input/bufferInputStream.cpp
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib/lib/input/bufferInputStream.cpp,v
retrieving revision 1.3
diff -u -3 -p -r1.3 bufferInputStream.cpp
--- lib/input/bufferInputStream.cpp	2000/09/13 02:18:26	1.3
+++ lib/input/bufferInputStream.cpp	2002/03/05 17:30:37
@@ -108,11 +108,13 @@ int BufferInputStream::write(char* ptr,i
   int canWrite=n;
   char* writePtr;
 
-  lockBuffer();
-  long key;
-  key=bytePos+fillgrade;
-  InputStream::insertTimeStamp(stamp,key,len);
-  unlockBuffer();
+  if (stamp) {
+    lockBuffer();
+    long key;
+    key=bytePos+fillgrade;
+    InputStream::insertTimeStamp(stamp,key,len);
+    unlockBuffer();
+  }
   // if eof is set we do not insert any more data
   // we do not call eof() !!!
   while((leof==false) && (n > 0)) {
@@ -146,11 +148,13 @@ int BufferInputStream::write(InputStream
   int didWrite;
   char* writePtr;
 
-  lockBuffer();
-  long key;
-  key=bytePos+fillgrade;
-  InputStream::insertTimeStamp(stamp,key,len);
-  unlockBuffer();
+  if (stamp) {
+    lockBuffer();
+    long key;
+    key=bytePos+fillgrade;
+    InputStream::insertTimeStamp(stamp,key,len);
+    unlockBuffer();
+  }
   // if eof is set we do not insert any more data
   // we do not call eof() !!!
   while((leof==false) && (n > 0)) {

["mpeglib_artsplug-streaming.patch" (text/x-diff)]

Index: MP3PlayObject.mcopclass
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/MP3PlayObject.mcopclass,v
retrieving revision 1.5
diff -u -3 -p -r1.5 MP3PlayObject.mcopclass
--- MP3PlayObject.mcopclass	2002/02/21 16:54:55	1.5
+++ MP3PlayObject.mcopclass	2002/03/05 17:33:04
@@ -1,4 +1,4 @@
-Interface=MP3PlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object
 +Interface=MP3PlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object
  Author="Martin Vogt <mvogt@rhrk.uni-kl.de>"
 URL="http://mpeglib.sourceforge.net"
 Extension=mp3,mp1,mp2
Index: MPGPlayObject.mcopclass
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/MPGPlayObject.mcopclass,v
retrieving revision 1.6
diff -u -3 -p -r1.6 MPGPlayObject.mcopclass
--- MPGPlayObject.mcopclass	2002/02/21 16:54:55	1.6
+++ MPGPlayObject.mcopclass	2002/03/05 17:33:04
@@ -1,4 +1,4 @@
-Interface=MPGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object
 +Interface=MPGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object
  Author="Martin Vogt <mvogt@rhrk.uni-kl.de>"
 URL="http://mpeglib.sourceforge.net"
 Extension=mpg,dat,mpeg
Index: OGGPlayObject.mcopclass
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/OGGPlayObject.mcopclass,v
retrieving revision 1.6
diff -u -3 -p -r1.6 OGGPlayObject.mcopclass
--- OGGPlayObject.mcopclass	2002/02/21 16:54:55	1.6
+++ OGGPlayObject.mcopclass	2002/03/05 17:33:04
@@ -1,4 +1,4 @@
-Interface=OGGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object
 +Interface=OGGPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object
  Author="Martin Vogt <mvogt@rhrk.uni-kl.de>"
 URL="http://mpeglib.sourceforge.net"
 Extension=ogg
Index: WAVPlayObject.mcopclass
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/WAVPlayObject.mcopclass,v
retrieving revision 1.6
diff -u -3 -p -r1.6 WAVPlayObject.mcopclass
--- WAVPlayObject.mcopclass	2002/02/25 13:25:57	1.6
+++ WAVPlayObject.mcopclass	2002/03/05 17:33:04
@@ -1,4 +1,4 @@
-Interface=WAVPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::SynthModule,Arts::Object
 +Interface=WAVPlayObject,Arts::PitchablePlayObject,Arts::PlayObject,Arts::StreamPlayObject,Arts::SynthModule,Arts::Object
  Author="Martin Vogt <mvogt@rhrk.uni-kl.de>"
 URL="http://mpeglib.sourceforge.net"
 Extension=wav,au
Index: decoderBaseObject.idl
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/decoderBaseObject.idl,v
retrieving revision 1.8
diff -u -3 -p -r1.8 decoderBaseObject.idl
--- decoderBaseObject.idl	2002/03/01 22:10:12	1.8
+++ decoderBaseObject.idl	2002/03/05 17:33:04
@@ -4,10 +4,12 @@
 /* the interfaces below are not kept binary compatible */
 
 interface DecoderBaseObject :
-    Arts::PlayObject,
+    Arts::StreamPlayObject,
     Arts::SynthModule,
     Arts::PitchablePlayObject
 {
+
+  async in byte stream indata;
   /**
    * blocking flag - defaults to false - when set to true, mpeglib will not
    * try to minimize latencies by generating answers (i.e. empty blocks)
Index: decoderBaseObject_impl.cpp
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/decoderBaseObject_impl.cpp,v
retrieving revision 1.23
diff -u -3 -p -r1.23 decoderBaseObject_impl.cpp
--- decoderBaseObject_impl.cpp	2001/08/08 12:05:07	1.23
+++ decoderBaseObject_impl.cpp	2002/03/05 17:33:05
@@ -10,9 +10,13 @@
 
  */
 
+#include <queue>
+
+#include <connect.h>
+
 #include "decoderBaseObject_impl.h"
 #include "../mpeglib/lib/decoder/decoderPlugin.h"
-#include "../mpeglib/lib/decoder/splayPlugin.h"
+//#include "../mpeglib/lib/frame/frameQueue.h"
 #include "debug.h"
 
 // define this to run the playobject without the
@@ -29,19 +33,22 @@ DecoderBaseObject_impl::DecoderBaseObjec
 
   flpos=0.0;
   _blocking = false;
+
 #ifdef _STRIP_ZERO
   outputStream=NULL;
 #else
-  outputStream=new ArtsOutputStream(NULL);
+  m_outputStream=new ArtsOutputStream(NULL);
   arts_debug("outputStream created");
   decoderPlugin=NULL;
 #endif
   startTime=0.0;
-  inputStream=NULL;
+  m_inputStream=NULL;
   setStreamState(_THREADSTATE_INIT);
   _state=posIdle;
   instance=instanceCnt;
   instanceCnt++;
+
+  m_packetQueue = new std::queue<DataPacket<mcopbyte>*>;
 }
 
 DecoderBaseObject_impl::~DecoderBaseObject_impl() {
@@ -53,11 +60,16 @@ DecoderBaseObject_impl::~DecoderBaseObje
     delete decoderPlugin;
     decoderPlugin=NULL;
   }
-  if (outputStream != NULL) {
+  if (m_outputStream != NULL) {
     arts_debug("delete outputStream");
-    delete outputStream;
-    outputStream=NULL;
+    delete m_outputStream;
+    m_outputStream=NULL;
   }
+
+  if (m_streaming)
+      m_artsInputStream.streamEnd();
+
+  delete m_packetQueue;
 }
 
 
@@ -74,10 +86,12 @@ DecoderPlugin* DecoderBaseObject_impl::c
 
 
 bool DecoderBaseObject_impl::loadMedia(const string &filename) {
+  arts_debug("loadMedia");
   int back=true;
 
+  m_streaming = false;
 
-  if ( inputStream != NULL ) {
+  if ( m_inputStream != NULL ) {
     arts_fatal("remove resources first with a call to: halt()");
   }
   if (decoderPlugin == NULL) {
@@ -99,26 +113,95 @@ bool DecoderBaseObject_impl::loadMedia(c
   return true;
 #endif
 
-  inputStream=createInputStream(filename.c_str());
+  m_inputStream=createInputStream(filename.c_str());
 
   // the plugin does not open the stream!
   // we do it.
-  back=inputStream->open((char*)filename.c_str());
+  back=m_inputStream->open((char*)filename.c_str());
   setStreamState(_THREADSTATE_OPENED);
 
   // we are still in posIdle here
-  outputStream->audioOpen();
+  m_outputStream->audioOpen();
 
   // watch the order!
-  decoderPlugin->setOutputPlugin(outputStream);
-  decoderPlugin->setInputPlugin(inputStream);
+  decoderPlugin->setOutputPlugin(m_outputStream);
+  decoderPlugin->setInputPlugin(m_inputStream);
 
-
   return back;
 }
 
+#define INPUT_BUFFER_SIZE 32768
+
+bool DecoderBaseObject_impl::streamMedia(Arts::InputStream instream) {
+	arts_debug("DecoderBaseObject_impl::streamMedia -s");
+
+	bool back = true;
+
+	if (m_inputStream != NULL) {
+		arts_fatal("resource in use, call halt() first");
+	}
+	if (decoderPlugin == NULL) {
+		decoderPlugin = createPlugin();
+		if (doFloat())
+			decoderPlugin->config("dofloat", 0, 0);
+		// streaming, don't know the length
+		decoderPlugin->config("-c", 0, 0);
+	}
+
+	flpos = 0.0;
+	startTime = 0.0;
+	m_streaming = true;
+	lastAudioBufferSize = -1;
 
+        m_artsInputStream = instream;
 
+	m_inputStream = new BufferInputStream(INPUT_BUFFER_SIZE, 4096, \
(char*)"InputStream"); +	m_inputStream->open((char*)"InputStream");
+
+	// connect the stream now
+	StreamPlayObject self = StreamPlayObject::_from_base(_copy());
+	connect(m_artsInputStream, "outdata", self);
+
+	setStreamState(_THREADSTATE_OPENED);
+
+	m_outputStream->audioOpen();
+
+	decoderPlugin->setOutputPlugin(m_outputStream);
+	decoderPlugin->setInputPlugin(m_inputStream);
+
+	arts_debug("DecoderBaseObject_impl::streamMedia -e");
+
+	return back;
+}
+
+void DecoderBaseObject_impl::process_indata(DataPacket<mcopbyte> *inpacket) {
+
+	m_packetQueue->push(inpacket);
+	processQueue();
+}
+
+void DecoderBaseObject_impl::processQueue() {
+
+	// early exit if no packets in the queue
+	if (m_packetQueue->empty())
+		return;
+
+	// see how much space we have in the stream
+	BufferInputStream* stream = (BufferInputStream*)m_inputStream;
+
+	int length = stream->getByteLength();
+	int freeSpace = INPUT_BUFFER_SIZE - length;
+
+	DataPacket<mcopbyte> *inpacket;
+	inpacket = m_packetQueue->front();
+
+	if (freeSpace >= inpacket->size) {
+		stream->write((char*)inpacket->contents, inpacket->size, 0);
+		m_packetQueue->pop();
+		inpacket->processed();
+	}
+}
+
 string DecoderBaseObject_impl::description() {
   arts_debug("description");
   string back;
@@ -141,7 +224,7 @@ poTime DecoderBaseObject_impl::currentTi
 #ifdef _STRIP_ZERO
   return time;
 #endif
-  AudioTime* audioTime=outputStream->getAudioTime();
+  AudioTime* audioTime=m_outputStream->getAudioTime();
   float currentTime=audioTime->getTime()+(float)startTime;
   time.seconds=(long)(currentTime);
   time.ms=(long) (1000.0*(currentTime-(float)time.seconds));
@@ -190,10 +273,10 @@ poState DecoderBaseObject_impl::state() 
 void DecoderBaseObject_impl::play() {
   arts_debug("play: %d", (int)streamState);
   if (streamState == _THREADSTATE_OPENED) {
-    decoderPlugin->play();
+      decoderPlugin->play();
   } else {
-    Command cmd(_COMMAND_PLAY);
-    decoderPlugin->insertAsyncCommand(&cmd);
+      Command cmd(_COMMAND_PLAY);
+      decoderPlugin->insertAsyncCommand(&cmd);
   }
   setStreamState(_THREADSTATE_PLAYING);
   _state = posPlaying;
@@ -214,11 +297,11 @@ void DecoderBaseObject_impl::seek(const 
 
   // if the thread blocks on the artsOutputstream: kick him out
   // the next command will the the seek command
-  outputStream->audioClose();
+  m_outputStream->audioClose();
 
 
   // thread blocking allowed
-  outputStream->audioOpen();
+  m_outputStream->audioOpen();
   arts_debug("************ reopen");
   // now set a new startTime
   startTime=sec;
@@ -255,13 +338,14 @@ void DecoderBaseObject_impl::streamInit(
 
 
 void DecoderBaseObject_impl::streamStart() {
+    arts_debug("DecoderBaseObject_impl::streamStart");
 }
 
 int DecoderBaseObject_impl::fillArts(unsigned long samples,
 				     float* left , float* right) {
   unsigned long haveSamples = 0;
 
-  AudioTime* audioTime=outputStream->getAudioTime();
+  AudioTime* audioTime=m_outputStream->getAudioTime();
   int wav_samplingRate=audioTime->getSpeed();
   int wav_sampleWidth=audioTime->getSampleSize();
   int wav_channelCount=audioTime->getStereo()+1;
@@ -269,7 +353,10 @@ int DecoderBaseObject_impl::fillArts(uns
   if(doFloat()) wav_sampleWidth = sizeof(float)*8;
 
   // here seems to be an error, I have clicks sometimes in the stream
-  int byteMultiplikator=(wav_sampleWidth/8)*wav_channelCount;
+  //int byteMultiplikator=(wav_sampleWidth/8)*wav_channelCount;
+
+  // maybe first multiply, then divide?
+  int byteMultiplikator = wav_channelCount * wav_sampleWidth / 8;
 
   char* buffer;
   int hasBytes = 0;
@@ -277,7 +364,7 @@ int DecoderBaseObject_impl::fillArts(uns
   int bufferSize=getBufferSize();
   if (bufferSize != lastAudioBufferSize) {
     lastAudioBufferSize=bufferSize;
-    outputStream->setAudioBufferSize(bufferSize);
+    m_outputStream->setAudioBufferSize(bufferSize);
   }
 
   /* difference between the sampling rates in percent */
@@ -291,7 +378,7 @@ int DecoderBaseObject_impl::fillArts(uns
    */
   if(_state == posPlaying && doFloat() && diff < 0.0005) {
     wantBytes = sizeof(float) * wav_channelCount * samples;
-    hasBytes = outputStream->read(&buffer,wantBytes);
+    hasBytes = m_outputStream->read(&buffer,wantBytes);
     float *flptr = (float *)buffer;
 
     if(wav_channelCount == 1)
@@ -311,7 +398,7 @@ int DecoderBaseObject_impl::fillArts(uns
 	haveSamples++;
       }
     }
-    outputStream->forwardReadPtr(haveSamples*sizeof(float)*wav_channelCount);
+    m_outputStream->forwardReadPtr(haveSamples*sizeof(float)*wav_channelCount);
   }
   else if(_state == posPlaying) {
     //
@@ -330,7 +417,7 @@ int DecoderBaseObject_impl::fillArts(uns
 
     // convert that into bytes and try to read that many bytes
     wantBytes=(int) (wantWavSamples*byteMultiplikator);
-    hasBytes=outputStream->read(&buffer,wantBytes);
+    hasBytes=m_outputStream->read(&buffer,wantBytes);
 
     int format = doFloat()?uni_convert_float_ne:wav_sampleWidth;
 
@@ -354,7 +441,7 @@ int DecoderBaseObject_impl::fillArts(uns
 
     flpos = flpos - floor(flpos);
 
-    outputStream->forwardReadPtr(forward);
+    m_outputStream->forwardReadPtr(forward);
   }
 
   if(haveSamples != samples) {
@@ -374,9 +461,10 @@ void DecoderBaseObject_impl::calculateBl
 
 #ifndef _STRIP_ZERO
 
-  int audioState=outputStream->waitStreamState(_OUTPUT_WAIT_METHOD_POLL,
+  int audioState=m_outputStream->waitStreamState(_OUTPUT_WAIT_METHOD_POLL,
 					       _STREAM_MASK_ALL,
 					       _STREAMTYPE_AUDIO);
+
   if (audioState & _STREAM_MASK_IS_INIT) {
     // now check if we already have enough data
     int lenough=false;
@@ -388,13 +476,27 @@ void DecoderBaseObject_impl::calculateBl
 
       lenough=true;
     }
-    if (outputStream->getBufferFillgrade() >= 0) {
+    if (m_outputStream->getBufferFillgrade() >= 4096) {
       lenough=true;
-    }
-    if ( ((lenough) || _blocking) && (_state == posPlaying) ) {
-      fillArts(samples,left,right);
-      return;
     }
+
+    if (_state == posPlaying) {
+	    if (m_streaming) {
+		    // produce more data
+		    processQueue();
+		    // check for stream end
+		    if ( m_inputStream->getByteLength() == 0 ) {
+			    if ( m_artsInputStream.eof() ) {
+				    m_inputStream->close();
+				    m_artsInputStream.streamEnd();
+			    }
+		    }
+	    }
+ 	    if (lenough || _blocking) {
+		    fillArts(samples, left, right);
+		    return;
+	    }
+   }
   }
 #endif
 
@@ -406,9 +508,11 @@ void DecoderBaseObject_impl::calculateBl
 }
 
 void DecoderBaseObject_impl::streamEnd() {
+  arts_debug("streamEnd");
 #ifdef _STRIP_ZERO
   return;
 #endif
+  
   halt();
 }
 
@@ -432,6 +536,7 @@ int DecoderBaseObject_impl::getBufferSiz
 
 
 void DecoderBaseObject_impl::shudownPlugins() {
+  arts_debug("shudownPlugins -s");
   /**
      The order here is important.
      First we close the audio so that the thread never blocks
@@ -443,25 +548,36 @@ void DecoderBaseObject_impl::shudownPlug
   */
 
   // this should theoretically be faster
-  Command cmd(_COMMAND_CLOSE);
-  decoderPlugin->insertAsyncCommand(&cmd);
-
-  if (outputStream != NULL) {
-    outputStream->audioClose();
+  if (decoderPlugin != NULL) {
+    Command cmd(_COMMAND_CLOSE);
+    decoderPlugin->insertAsyncCommand(&cmd);
+  }
+  arts_debug("shudownPlugins -s 1");
+  if (m_outputStream != NULL) {
+    m_outputStream->audioClose();
   }
+  arts_debug("shudownPlugins -s 2");
 
   // very likely the thread already is closed
   // because of the asyncCommand above.
   if (decoderPlugin != NULL) {
     decoderPlugin->close();
   }
+  arts_debug("shudownPlugins -s 3");
 
 
-  if (inputStream != NULL) {
-    delete inputStream;
-    inputStream=NULL;
+  if (m_inputStream != NULL) {
+    delete m_inputStream;
+    m_inputStream=NULL;
   }
+  arts_debug("shudownPlugins -s 4");
+  
+  if (m_streaming)
+    m_artsInputStream.streamEnd();
+
   setStreamState(_THREADSTATE_CLOSED);
+
+  arts_debug("shudownPlugins -e");
 }
 
 void DecoderBaseObject_impl::setStreamState(int state) {
Index: decoderBaseObject_impl.h
===================================================================
RCS file: /home/kde/kdemultimedia/mpeglib_artsplug/decoderBaseObject_impl.h,v
retrieving revision 1.11
diff -u -3 -p -r1.11 decoderBaseObject_impl.h
--- decoderBaseObject_impl.h	2001/08/08 12:05:07	1.11
+++ decoderBaseObject_impl.h	2002/03/05 17:33:05
@@ -25,32 +25,35 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <arts/kmedia2.h>
+
 #define _THREADSTATE_INIT         0
 #define _THREADSTATE_OPENED       1
 #define _THREADSTATE_PAUSED       2
 #define _THREADSTATE_PLAYING      3
 #define _THREADSTATE_CLOSED       4
-
 
+#include <queue>
 
 class DecoderPlugin;
 class InputStream;
 class ArtsOutputStream;
 
-
 using namespace std;
 using Arts::poState;
 using Arts::poTime;
 using Arts::poCapabilities;
-
+using Arts::DataPacket;
+using Arts::mcopbyte;
 
 class DecoderBaseObject_impl :
   virtual public Arts::StdSynthModule,
   virtual public DecoderBaseObject_skel {
 
   poState _state;
-  InputStream* inputStream;
-  ArtsOutputStream* outputStream;
+  InputStream* m_inputStream;
+  Arts::InputStream m_artsInputStream;
+  ArtsOutputStream* m_outputStream;
   
   double flpos;
   float startTime;
@@ -60,6 +63,10 @@ class DecoderBaseObject_impl :
   bool _blocking;
   float _speed;
 
+  bool m_streaming;
+
+  queue<DataPacket<mcopbyte>*> *m_packetQueue;
+
 public:
 
   DecoderBaseObject_impl();
@@ -70,6 +77,10 @@ public:
   virtual bool doFloat() { return false; }
 
   bool loadMedia(const string &filename);
+  bool streamMedia(Arts::InputStream instream);
+  void process_indata(DataPacket<mcopbyte>* inpacket);
+  Arts::InputStream inputStream() { return m_artsInputStream; }
+
   string description();
   void description(const string &);
 
@@ -102,6 +113,7 @@ public:
   int getBufferSize();
   int fillArts(unsigned long samples,float* left , float* right);
   void setStreamState(int state);
+  void processQueue();
 
 };
 


["noatun-streaming.patch" (text/x-diff)]

Index: engine.cpp
===================================================================
RCS file: /home/kde/kdemultimedia/noatun/library/engine.cpp,v
retrieving revision 1.77
diff -u -3 -p -r1.77 engine.cpp
--- engine.cpp	2002/03/03 00:36:38	1.77
+++ engine.cpp	2002/03/05 17:29:28
@@ -290,7 +290,9 @@ bool Engine::open(const PlaylistItem &fi
 
 	if (file.isProperty("stream_"))
 	{
-		d->playobj=factory.createPlayObject(file.property("stream_"), file.mimetype(), false);
+		// let the factory decide
+		// d->playobj=factory.createPlayObject(file.property("stream_"), file.mimetype(), false);
+		d->playobj=factory.createPlayObject(file.property("stream_"), false);
 	}
 	else
 	{
Index: playlistsaver.cpp
===================================================================
RCS file: /home/kde/kdemultimedia/noatun/library/playlistsaver.cpp,v
retrieving revision 1.17
diff -u -3 -p -r1.17 playlistsaver.cpp
--- playlistsaver.cpp	2002/03/02 19:49:26	1.17
+++ playlistsaver.cpp	2002/03/05 17:29:29
@@ -67,7 +67,7 @@ bool PlaylistSaver::metalist(const KURL 
 			if (type!="application/octet-stream")
 				return false;
 			QMap<QString,QString> map;
-			map["playObject"]="SplayPlayObject";
+			map["playObject"]="Arts::StreamPlayObject";
 			map["title"] = i18n("Stream from %1").arg(url.host());
 			
 			KURL u(url);

_______________________________________________
kde-multimedia mailing list
kde-multimedia@mail.kde.org
http://mail.kde.org/mailman/listinfo/kde-multimedia

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic