diff options
Diffstat (limited to 'mpeglib/lib/decoder')
-rw-r--r-- | mpeglib/lib/decoder/Makefile.am | 39 | ||||
-rw-r--r-- | mpeglib/lib/decoder/cddaPlugin.cpp | 150 | ||||
-rw-r--r-- | mpeglib/lib/decoder/cddaPlugin.h | 49 | ||||
-rw-r--r-- | mpeglib/lib/decoder/command.cpp | 85 | ||||
-rw-r--r-- | mpeglib/lib/decoder/command.h | 52 | ||||
-rw-r--r-- | mpeglib/lib/decoder/commandPipe.cpp | 163 | ||||
-rw-r--r-- | mpeglib/lib/decoder/commandPipe.h | 78 | ||||
-rw-r--r-- | mpeglib/lib/decoder/decoderPlugin.cpp | 428 | ||||
-rw-r--r-- | mpeglib/lib/decoder/decoderPlugin.h | 201 | ||||
-rw-r--r-- | mpeglib/lib/decoder/mpegPlugin.cpp | 160 | ||||
-rw-r--r-- | mpeglib/lib/decoder/mpegPlugin.h | 47 | ||||
-rw-r--r-- | mpeglib/lib/decoder/mpgPlugin.cpp | 260 | ||||
-rw-r--r-- | mpeglib/lib/decoder/mpgPlugin.h | 62 | ||||
-rw-r--r-- | mpeglib/lib/decoder/nukePlugin.cpp | 62 | ||||
-rw-r--r-- | mpeglib/lib/decoder/nukePlugin.h | 34 | ||||
-rw-r--r-- | mpeglib/lib/decoder/splayPlugin.cpp | 308 | ||||
-rw-r--r-- | mpeglib/lib/decoder/splayPlugin.h | 67 | ||||
-rw-r--r-- | mpeglib/lib/decoder/tplayPlugin.cpp | 264 | ||||
-rw-r--r-- | mpeglib/lib/decoder/tplayPlugin.h | 47 | ||||
-rw-r--r-- | mpeglib/lib/decoder/vorbisPlugin.cpp | 305 | ||||
-rw-r--r-- | mpeglib/lib/decoder/vorbisPlugin.h | 87 |
21 files changed, 2948 insertions, 0 deletions
diff --git a/mpeglib/lib/decoder/Makefile.am b/mpeglib/lib/decoder/Makefile.am new file mode 100644 index 00000000..9362e851 --- /dev/null +++ b/mpeglib/lib/decoder/Makefile.am @@ -0,0 +1,39 @@ +# libplayerplugin - Makefile.am + +INCLUDES = $(all_includes) + +noinst_LTLIBRARIES = libdecoder.la + +kmpgincludedir = $(includedir)/$(THIS_LIB_NAME)/decoder + +kmpginclude_HEADERS = decoderPlugin.h command.h \ + commandPipe.h nukePlugin.h \ + vorbisPlugin.h cddaPlugin.h \ + splayPlugin.h mpegPlugin.h \ + mpgPlugin.h tplayPlugin.h + +libdecoder_la_SOURCES = decoderPlugin.cpp command.cpp \ + commandPipe.cpp nukePlugin.cpp \ + vorbisPlugin.cpp cddaPlugin.cpp \ + splayPlugin.cpp mpegPlugin.cpp \ + mpgPlugin.cpp tplayPlugin.cpp + + + + + + + + + + + + + + + + + + + + diff --git a/mpeglib/lib/decoder/cddaPlugin.cpp b/mpeglib/lib/decoder/cddaPlugin.cpp new file mode 100644 index 00000000..fe84986b --- /dev/null +++ b/mpeglib/lib/decoder/cddaPlugin.cpp @@ -0,0 +1,150 @@ +/* + splay player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "cddaPlugin.h" + +#ifdef CDDA_PARANOIA + +#include <sys/types.h> + +#include <iostream> + +using namespace std; + +typedef int16_t size16; +typedef int32_t size32; + +extern "C" { +#include <cdda_interface.h> +#include <cdda_paranoia.h> +} + + +CDDAPlugin::CDDAPlugin() { +} + + +CDDAPlugin::~CDDAPlugin() { +} + + +// here we can config our decoder with special flags +void CDDAPlugin::config(const char* key,const char* value,void* user_data) { + DecoderPlugin::config(key,value,user_data); +} + + + +void CDDAPlugin::decoder_loop() { + + if (input == NULL) { + cout << "CDDAPlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "CDDAPlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + // init decoder + output->audioInit(); + TimeStamp* stamp; + char buf[CD_FRAMESIZE_RAW*4]; + int len=0; + // start decoding + while(runCheck()) { + + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : + output->audioSetup(44100,1,0,0,16); + output->audioOpen(); + setStreamState(_STREAM_STATE_PLAY); + len=getTotalLength(); + pluginInfo->setLength(len); + output->writeInfo(pluginInfo); + break; + case _STREAM_STATE_INIT : + setStreamState(_STREAM_STATE_PLAY); + break; + case _STREAM_STATE_PLAY : { + // decode + int read=input->read(buf,2*CD_FRAMESIZE_RAW); + int pos=input->getBytePosition(); + stamp=input->getTimeStamp(pos); + output->audioPlay(stamp,stamp,buf,read); + break; + } + case _STREAM_STATE_WAIT_FOR_END: + // exit while loop + lDecoderLoop=false; + break; + default: + cout << "unknown stream state:"<<streamState<<endl; + } + } + // remove decoder + + output->audioFlush(); +} + +// splay can seek in streams +int CDDAPlugin::seek_impl(int second) { + int bytes_per_second; + int seconds; + int back; + float frequence=44100; + int bits=16; + int channels=2; + + bytes_per_second = (int)(frequence * channels * (bits / 8)); + + + + seconds = bytes_per_second * second; + cout << "seek to :"<<seconds<<endl; + back=input->seek(seconds); + + return true; +} + + +int CDDAPlugin::getTotalLength() { + shutdownLock(); + float wavfilesize; + int back=0; + float frequence=44100; + if (input == NULL) { + shutdownUnlock(); + return 0; + } + wavfilesize = input->getByteLength(); + int bits=16; + int channels=2; + if (bits == 16) { + wavfilesize=wavfilesize/2; + } + if (channels==2) { + wavfilesize=wavfilesize/2; + } + if (frequence != 0) { + back=(int)(wavfilesize/frequence); + } + shutdownUnlock(); + return back; +} + + + + +#endif +//CDDA_PARANOIA + diff --git a/mpeglib/lib/decoder/cddaPlugin.h b/mpeglib/lib/decoder/cddaPlugin.h new file mode 100644 index 00000000..c0adf5e2 --- /dev/null +++ b/mpeglib/lib/decoder/cddaPlugin.h @@ -0,0 +1,49 @@ +/* + splay player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#ifndef __CDDAPLUGIN_H +#define __CDDAPLUGIN_H + +#include "nukePlugin.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef CDDA_PARANOIA +class CDDAPlugin : public NukePlugin { +}; +#else + + + +class CDDAPlugin : public DecoderPlugin { + + public: + CDDAPlugin(); + ~CDDAPlugin(); + + void decoder_loop(); + int seek_impl(int second); + void config(const char* key,const char* value,void* user_data); + + protected: + int getTotalLength(); + + +}; + +#endif +//CDDA_PARANOIA + +#endif diff --git a/mpeglib/lib/decoder/command.cpp b/mpeglib/lib/decoder/command.cpp new file mode 100644 index 00000000..8b29efe6 --- /dev/null +++ b/mpeglib/lib/decoder/command.cpp @@ -0,0 +1,85 @@ +/* + describes a command + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + +#include "command.h" + +#include <iostream> + +using namespace std; + +Command::Command(int id) { + this->id=id; + this->intArg=0; +} + +Command::Command(int id,int arg) { + this->id=id; + this->intArg=arg; +} + + +Command::~Command() { +} + + +int Command::getID() { + return id; +} + + +int Command::getIntArg() { + return intArg; +} + + +void Command::copyTo(Command* dest) { + dest->id=this->id; + dest->intArg=this->intArg; +} + +void Command::print(const char* text) { + cout << "COMMAND:"<<text<<endl; + switch(id) { + case _COMMAND_NONE: + cout << "_COMMAND_NONE"; + break; + case _COMMAND_PING: + cout << "_COMMAND_PING"; + break; + case _COMMAND_PAUSE: + cout << "_COMMAND_PAUSE"; + break; + case _COMMAND_PLAY: + cout << "_COMMAND_PLAY"; + break; + case _COMMAND_SEEK: + cout << "_COMMAND_SEEK"; + cout << " intArg:"<<intArg; + break; + case _COMMAND_CLOSE: + cout << "_COMMAND_CLOSE"; + break; + case _COMMAND_START: + cout << "_COMMAND_START"; + break; + case _COMMAND_RESYNC_START: + cout << "_COMMAND_RESYNC_START"; + break; + case _COMMAND_RESYNC_END: + cout << "_COMMAND_RESYNC_END"; + break; + + default: + cout << "unknown command id in Command::print"<<endl; + } + cout << endl; +} diff --git a/mpeglib/lib/decoder/command.h b/mpeglib/lib/decoder/command.h new file mode 100644 index 00000000..fc96fd73 --- /dev/null +++ b/mpeglib/lib/decoder/command.h @@ -0,0 +1,52 @@ +/* + describes a command + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + + + +#ifndef __COMMAND_H +#define __COMMAND_H + +#include "../util/abstract/abs_thread.h" +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#define _COMMAND_NONE 0 +#define _COMMAND_PLAY 1 +#define _COMMAND_PAUSE 2 +#define _COMMAND_SEEK 3 +#define _COMMAND_CLOSE 4 +#define _COMMAND_START 5 +#define _COMMAND_RESYNC_START 6 +#define _COMMAND_RESYNC_END 7 +#define _COMMAND_PING 8 + + + +class Command { + + int id; + int intArg; + + public: + Command(int id); + Command(int id,int arg); + ~Command(); + + int getID(); + int getIntArg(); + void copyTo(Command* dest); + void print(const char* text); +}; + +#endif diff --git a/mpeglib/lib/decoder/commandPipe.cpp b/mpeglib/lib/decoder/commandPipe.cpp new file mode 100644 index 00000000..05991ca5 --- /dev/null +++ b/mpeglib/lib/decoder/commandPipe.cpp @@ -0,0 +1,163 @@ +/* + thread safe fifo queue for commands + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "commandPipe.h" + +#define _COMMAND_ARRAY_SIZE 100 + +CommandPipe::CommandPipe() { + abs_thread_cond_init(&spaceCond); + abs_thread_cond_init(&emptyCond); + abs_thread_cond_init(&dataCond); + abs_thread_mutex_init(&pipeMut); + + entries=0; + readPos=0; + writePos=0; + + + int i; + + commandArray=new Command*[_COMMAND_ARRAY_SIZE]; + + + for(i=0;i<_COMMAND_ARRAY_SIZE;i++) { + commandArray[i]=new Command(_COMMAND_NONE,0); + } +} + + +CommandPipe::~CommandPipe() { + abs_thread_cond_destroy(&spaceCond); + abs_thread_cond_destroy(&emptyCond); + abs_thread_cond_destroy(&dataCond); + abs_thread_mutex_destroy(&pipeMut); + + + int i; + + for(i=0;i<_COMMAND_ARRAY_SIZE;i++) { + delete commandArray[i]; + } + delete [] commandArray; +} + +void CommandPipe::sendCommand(Command& cmd) { + sendCommand(cmd,true); +} + +void CommandPipe::sendCommandNoWait(Command& cmd) { + sendCommand(cmd,false); +} + + +void CommandPipe::sendCommand(Command& cmd,int lWait) { + lockCommandPipe(); + if (entries==_COMMAND_ARRAY_SIZE) { + waitForSpace(); + } + cmd.copyTo(commandArray[writePos]); + writePos++; + if (writePos==_COMMAND_ARRAY_SIZE) { + writePos=0; + } + entries++; + // low water signal + if (entries==1) { + signalData(); + } + unlockCommandPipe(); + if (lWait) { + waitForEmptyQueue(); + } +} + + +int CommandPipe::hasCommand(Command* dest) { + lockCommandPipe(); + if (entries==0) { + unlockCommandPipe(); + return false; + } + + commandArray[readPos]->copyTo(dest); + readPos++; + if (readPos==_COMMAND_ARRAY_SIZE) { + readPos=0; + } + entries--; + // low water + if (entries==0) { + signalEmpty(); + unlockCommandPipe(); + return true; + } + // if we are on highwater, signal space + if (entries==_COMMAND_ARRAY_SIZE-1) { + signalSpace(); + } + unlockCommandPipe(); + return true; +} + + +void CommandPipe::waitForEmptyQueue() { + lockCommandPipe(); + while (entries > 0) { + waitForEmpty(); + } + unlockCommandPipe(); +} + +void CommandPipe::waitForCommand() { + lockCommandPipe(); + while (entries == 0) { + waitForData(); + } + unlockCommandPipe(); +} + + +void CommandPipe::lockCommandPipe() { + abs_thread_mutex_lock(&pipeMut); +} + + +void CommandPipe::unlockCommandPipe() { + abs_thread_mutex_unlock(&pipeMut); +} + +void CommandPipe::waitForSpace() { + abs_thread_cond_wait(&spaceCond,&pipeMut); +} + +void CommandPipe::waitForEmpty() { + abs_thread_cond_wait(&emptyCond,&pipeMut); +} + +void CommandPipe::waitForData() { + abs_thread_cond_wait(&dataCond,&pipeMut); +} + + +void CommandPipe::signalSpace() { + abs_thread_cond_signal(&spaceCond); +} + +void CommandPipe::signalEmpty() { + abs_thread_cond_signal(&emptyCond); +} + +void CommandPipe::signalData() { + abs_thread_cond_signal(&dataCond); +} diff --git a/mpeglib/lib/decoder/commandPipe.h b/mpeglib/lib/decoder/commandPipe.h new file mode 100644 index 00000000..4ecf84eb --- /dev/null +++ b/mpeglib/lib/decoder/commandPipe.h @@ -0,0 +1,78 @@ +/* + thread safe fifo queue for commands + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#ifndef __COMMAND_PIPE_H +#define __COMMAND_PIPE_H + + + +#include "command.h" + +/** + This queue deals with the ugly deadlock problem. + We insert all commands in a queue and the thread + polls this queue for next commands. +*/ + +class CommandPipe { + + Command** commandArray; + int entries; + int readPos; + int writePos; + + abs_thread_mutex_t pipeMut; + abs_thread_cond_t spaceCond; + abs_thread_cond_t emptyCond; + abs_thread_cond_t dataCond; + + public: + CommandPipe(); + ~CommandPipe(); + + // writer thread: + void sendCommand(Command& cmd); + void sendCommandNoWait(Command& cmd); + + void waitForEmptyQueue(); + + // reader thread + int hasCommand(Command* dest); + void waitForCommand(); + + + + + private: + void sendCommand(Command& cmd,int lWait); + + void lockCommandPipe(); + void unlockCommandPipe(); + + + // writer thread wait here + void waitForSpace(); + void waitForEmpty(); + void waitForData(); + + // reader thread signals this + void signalSpace(); + void signalEmpty(); + void signalData(); + + + + +}; + +#endif diff --git a/mpeglib/lib/decoder/decoderPlugin.cpp b/mpeglib/lib/decoder/decoderPlugin.cpp new file mode 100644 index 00000000..0a45bb42 --- /dev/null +++ b/mpeglib/lib/decoder/decoderPlugin.cpp @@ -0,0 +1,428 @@ +/* + base class for the player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + +#include "decoderPlugin.h" + +#include <iostream> + +using namespace std; + + +static void *playerThread(void *arg){ + ((DecoderPlugin*)arg)->idleThread(); + return NULL; +} + +static int instanceCnt=0; + +DecoderPlugin::DecoderPlugin(){ + input=NULL; + output=NULL; + commandPipe=new CommandPipe(); + threadCommand=new Command(_COMMAND_NONE); + abs_thread_cond_init(&streamStateCond); + abs_thread_mutex_init(&streamStateMut); + abs_thread_mutex_init(&shutdownMut); + + lCreatorLoop=true; + lDecoderLoop=false; + linDecoderLoop=false; + streamState=_STREAM_STATE_EOF; + lDecode=false; + lhasLength=false; + // this default is necessary. if you have a blocking + // device and we start automatic the thread + // may block on it and all commands (including play) + // blocks everything + // *you should not use autoplay* + lAutoPlay=false; + + pluginInfo=new PluginInfo(); + runCheck_Counter=0; + decode_loopCounter=0; + instance=instanceCnt; + instanceCnt++; + abs_thread_create(&tr,playerThread,this); + + // we send a ping. because this signal is synchron + // we block until the thread is started and + // has read the ping singnal + Command cmd(_COMMAND_PING); + insertSyncCommand(&cmd); + + +} + + +DecoderPlugin::~DecoderPlugin(){ + void* ret; + lCreatorLoop=false; + Command cmd(_COMMAND_CLOSE); + insertAsyncCommand(&cmd); + + abs_thread_join(tr,&ret); + + abs_thread_cond_destroy(&streamStateCond); + abs_thread_mutex_destroy(&streamStateMut); + abs_thread_mutex_destroy(&shutdownMut); + + delete commandPipe; + delete threadCommand; + delete pluginInfo; +} + + +void DecoderPlugin::close(){ + // from here we can only walk to init or eof + // in both cases we sometimes catch out decoderMut :-) + Command cmd(_COMMAND_CLOSE); + insertAsyncCommand(&cmd); + shutdownLock(); + if (input != NULL) { + input->close(); + } + shutdownUnlock(); + insertSyncCommand(&cmd); + waitForStreamState(_STREAM_STATE_EOF); + input=NULL; +} + + +void DecoderPlugin::pause() { + Command cmd(_COMMAND_PAUSE); + insertSyncCommand(&cmd); +} + + + + +int DecoderPlugin::play() { + Command cmd(_COMMAND_PLAY); + insertSyncCommand(&cmd); + + return true; +} + +int DecoderPlugin::seek(int second) { + Command cmd(_COMMAND_SEEK,second); + insertSyncCommand(&cmd); + + return true; +} + +void DecoderPlugin::insertAsyncCommand(Command* cmd) { + commandPipe->sendCommandNoWait(*cmd); +} + +void DecoderPlugin::insertSyncCommand(Command* cmd) { + commandPipe->sendCommand(*cmd); +} + + +void DecoderPlugin::shutdownLock() { + abs_thread_mutex_lock(&shutdownMut); +} + + +void DecoderPlugin::shutdownUnlock() { + abs_thread_mutex_unlock(&shutdownMut); +} + +int DecoderPlugin::getTime(int lCurrent) { + int secLen=getTotalLength(); + + if (lCurrent==false) { + return secLen; + } + shutdownLock(); + int byteLen=1; + int pos=1; + if (input != NULL) { + pos=input->getBytePosition()+1; + byteLen=input->getByteLength()+1; + } + int back=(int)(((double)pos/(double)byteLen) * (double)secLen); + shutdownUnlock(); + return back; + +} + +int DecoderPlugin::getTotalLength() { + cout << "plugin does not support total playtime reporting"<<endl; + return 0; +} + +int DecoderPlugin::seek_impl(int) { + cout << "plugin does not support seek"<<endl; + return false; +} + + + + +void DecoderPlugin::setOutputPlugin(OutputStream* output) { + this->output=output; +} + + +int DecoderPlugin::setInputPlugin(InputStream* input) { + this->input=input; + + if (!input) { + cout << "input is NULL"<<endl; + exit(0); + } + pluginInfo->setUrl(input->getUrl()); + + + // the command is synchron we block until the + // thread has read it + Command cmd(_COMMAND_START); + insertSyncCommand(&cmd); + + + // now that we know he has read it, we send another + // command, this is only read if the thread is in the + // decode_loop, and we then know that the streamState + // is FIRST_INIT + Command ping(_COMMAND_PING); + insertSyncCommand(&ping); + + + if (lAutoPlay) { + play(); + } + return true; +} + + +void DecoderPlugin::config(const char* key,const char* value,void* ){ + if (strcmp(key,"-y")==0) { + if (strcmp(value,"on")==0) { + lAutoPlay=true; + } else { + lAutoPlay=false; + } + } + +} + +/** + during shutdown the streamState is undefined until + the thread has left the decode_loop(). + Make sure we wait for this. +*/ +int DecoderPlugin::getStreamState() { + shutdownLock(); + int back=streamState; + shutdownUnlock(); + return back; +} + + +int DecoderPlugin::waitForStreamState(int state) { + int back; + abs_thread_mutex_lock(&streamStateMut); + while ((streamState & state) == false) { + abs_thread_cond_wait(&streamStateCond,&streamStateMut); + } + back=streamState; + abs_thread_mutex_unlock(&streamStateMut); + return back; +} + + +void DecoderPlugin::setStreamState(int streamState) { + abs_thread_mutex_lock(&streamStateMut); + this->streamState=streamState; + abs_thread_cond_signal(&streamStateCond); + abs_thread_mutex_unlock(&streamStateMut); +} + + +void DecoderPlugin::decoder_loop() { + cout << "direct call decoder loop->plugin not found ???"<<endl; + TimeWrapper::usleep(100000); +} + + +void* DecoderPlugin::idleThread() { + + while(lCreatorLoop) { + linDecoderLoop=true; + commandPipe->waitForCommand(); + commandPipe->hasCommand(threadCommand); + int id=threadCommand->getID(); + switch(id) { + case _COMMAND_START: + lDecoderLoop=true; + break; + case _COMMAND_PING: + break; + /* + default: + threadCommand->print("ignoring non START command in idleThread"); + */ + } + + + if (lDecoderLoop) { + setStreamState(_STREAM_STATE_FIRST_INIT); + linDecoderLoop=false; + decode_loopCounter++; + runCheck_Counter=0; + shutdownLock(); + decoder_loop(); + lDecode=false; + lDecoderLoop=false; + lhasLength=false; + setStreamState(_STREAM_STATE_EOF); + shutdownUnlock(); + } + } + return NULL; +} + + +PluginInfo* DecoderPlugin::getPluginInfo() { + return pluginInfo; +} + + +int DecoderPlugin::runCheck() { + if (runCheck_Counter==0) { + shutdownUnlock(); + } + runCheck_Counter++; + while (lDecoderLoop && lCreatorLoop) { + + // if we have an eof this always leads to + // a shutdown of the decode_loop thread + // it has more priority than the resyn request + if (input->eof()) { + setStreamState(_STREAM_STATE_WAIT_FOR_END); + } + // + // if we are in _STREAM_STATE_RESYNC_COMMIT + // we only leave it if command is _COMMAND_RESYNC_END + // (or close) + + // + // check user commands + // + if (lDecode==false) { + commandPipe->waitForCommand(); + commandPipe->hasCommand(threadCommand); + } else { + if (commandPipe->hasCommand(threadCommand)==false) { + // no commands and lDecode=true + return true; + } + } + + // here we forward the command to a special + // method who can handle everything + // (the default method should work fine); + int nextCheck= processThreadCommand(threadCommand); + switch(nextCheck) { + case _RUN_CHECK_CONTINUE: + break; + case _RUN_CHECK_FALSE: + shutdownLock(); + return false; + case _RUN_CHECK_TRUE: + return true; + default: + cout << "unknown runCheck return command"<<endl; + exit(0); + } + + + } + + shutdownLock(); + return false; +} + +int DecoderPlugin::processThreadCommand(Command* command) { + + + int id=command->getID(); + int intArg; + + // + // if we are in _STREAM_STATE_RESYNC_COMMIT + // we only leave it if command is _COMMAND_RESYNC_END + // + if (streamState==_STREAM_STATE_RESYNC_COMMIT) { + switch(id) { + case _COMMAND_RESYNC_END: + setStreamState(_STREAM_STATE_INIT); + input->clear(); + break; + case _COMMAND_CLOSE: + // + // we return false so that the plugin clears + // all its allocated classes + // its a _must_ !! + // in the next call we exit immediately + return _RUN_CHECK_FALSE; + + /* + default: + command->print("ignore command in _STREAM_STATE_RESYNC_COMMIT"); + */ + } + return _RUN_CHECK_CONTINUE; + } + + + switch(id) { + case _COMMAND_NONE: + break; + case _COMMAND_PING: + break; + case _COMMAND_PAUSE: + lDecode=false; + break; + case _COMMAND_PLAY: + lDecode=true; + break; + case _COMMAND_SEEK: { + if (streamState==_STREAM_STATE_FIRST_INIT) { + command->print("ignore command seek in _STREAM_STATE_FIRST_INIT"); + } else { + intArg=command->getIntArg(); + seek_impl(intArg); + } + break; + } + case _COMMAND_CLOSE: + // + // we return false so that the plugin clears + // all its allocated classes + // its a _must_ !! + // in the next call we exit immediately + return _RUN_CHECK_FALSE; + case _COMMAND_RESYNC_START: + setStreamState(_STREAM_STATE_RESYNC_COMMIT); + input->clear(); + break; + /* + default: + cout << "unknown command id in Command::print"<<endl; + */ + } + return _RUN_CHECK_CONTINUE; +} + + diff --git a/mpeglib/lib/decoder/decoderPlugin.h b/mpeglib/lib/decoder/decoderPlugin.h new file mode 100644 index 00000000..b616ed51 --- /dev/null +++ b/mpeglib/lib/decoder/decoderPlugin.h @@ -0,0 +1,201 @@ +/* + base class for the player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + + + + +#ifndef __DECODERPLUGIN_H +#define __DECODERPLUGIN_H + + + + + +#include "commandPipe.h" +#include "../input/inputPlugin.h" +#include "../output/outPlugin.h" +#include "../util/timeWrapper.h" + +#include <kdemacros.h> + +/** + Note: streamstate can be "or'ed" for the waitStreamState call +*/ + +#define _STREAM_STATE_EOF 1 +#define _STREAM_STATE_FIRST_INIT 4 +#define _STREAM_STATE_INIT 8 +#define _STREAM_STATE_PLAY 16 +#define _STREAM_STATE_WAIT_FOR_END 32 +#define _STREAM_STATE_RESYNC_COMMIT 64 +#define _STREAM_STATE_ALL 1+4+8+16+32+64 + + +#define _RUN_CHECK_FALSE 0 +#define _RUN_CHECK_TRUE 1 +#define _RUN_CHECK_CONTINUE 2 + + + +/** + Here is the base class for the player plugin. + we can set the output of the player, and the input. + <p> + This class offer you a thread which you have to use + in derived class for the decoding work. + <p> + All calls to your decoder goes through this class + which must make sure that there are no races. + <p> + The life of the decoder thread: + ------------------------------ + + We start every time a thread if you make an instance of this class. + The thread then goes to the idleThread() method and waits + until we wake him up. + If we wake him um he graps the decoderMut and enters the + decode_loop() This method must be used for your plugin. + Then this thread "polls" during decoding the decoderChangeMut + (see runCheck()) + if he can get the decoderChangeMut,the thread is authenticated for another + decode round if not, he waits until we wake him up again. + If the stream ends or the user stops decoding we leave the decoder_loop + and go back to the idleThread(). + If you delete this class the thread is joined. + +*/ + +class KDE_EXPORT DecoderPlugin { + + public: + + DecoderPlugin(); + virtual ~DecoderPlugin(); + + // + // you can submit the following commands to the decode_loop thread + // + virtual void close(); + virtual void pause(); + virtual int play(); + virtual int seek(int second); + void insertAsyncCommand(Command* cmd); + void insertSyncCommand(Command* cmd); + + // returns total length (lCurrent==false) or current time (true) + // Note: you should not call this too often because + // it locks the decoder thread. + // Should be called only after the initialisation of the stream + // no need to override this, overide getTotalLength() + int getTime(int lCurrent); + + + + virtual void setOutputPlugin(OutputStream* output); + + // This method can only be called _once_ after a "close" + virtual int setInputPlugin(InputStream* input); + virtual void config(const char* key,const char* value,void* user_data); + virtual int getStreamState(); + + /** + Use this method to wait for a stream signal. + For example: after setInputPlugin the thread starts with + the state _EOF then the state changes between: + + After setInput you can wait for (INIT | DECODE | WAIT_FOR_END | EOF) this + make sure the first init is passed. (successful or not) + return value is current streamState, which had a succesfull match. + Note: after return the state may already have changed (nature of threads) + + */ + int waitForStreamState(int state); + PluginInfo* getPluginInfo(); + + // Needed for Video Embedding + int x11WindowId() { return output->x11WindowId(); } + + // never use this! + void* idleThread(); + + // Note: can only be called by the decode_loop thread !!! + void setStreamState(int streamState); + + protected: + + // override this if you have the total length in second + virtual int getTotalLength(); + // implement this if your plugin supports seek + // (called by decoder_loop thread + virtual int seek_impl(int second); + + + /** + should be called from decoder_loop + checks some mutex variables if user want decoder to pause/quit + returns: + false : quit decoding + true : continue decoding + + Note: method blocks if user "pauses" the stream + */ + int runCheck(); + + // this mut is set from the start of decoder_loop() + // its _not_ set if the thread runs in the while() loop + // it it set if the thread leaves the while loop (runCheck->false) + // (its used internally to make the getTime() call safe + void shutdownLock(); + void shutdownUnlock(); + + + // this is the method to override in your decoder + virtual void decoder_loop(); + + // this method handles the commands for the decode_loop thread + virtual int processThreadCommand(Command* command); + + OutputStream* output; + InputStream* input; + + abs_thread_t tr; + abs_thread_mutex_t shutdownMut; + abs_thread_mutex_t streamStateMut; + abs_thread_cond_t streamStateCond; + + + + + int lDecoderLoop; + int lCreatorLoop; + int linDecoderLoop; + int lDecode; + int streamState; + int lhasLength; + int lAutoPlay; + int decode_loopCounter; // count how much we started decode_loop + int runCheck_Counter; // count how much we called runCheck + int instance; + PluginInfo* pluginInfo; + + private: + + CommandPipe* commandPipe; + Command* threadCommand; + + + +}; + +#endif + diff --git a/mpeglib/lib/decoder/mpegPlugin.cpp b/mpeglib/lib/decoder/mpegPlugin.cpp new file mode 100644 index 00000000..e230adb5 --- /dev/null +++ b/mpeglib/lib/decoder/mpegPlugin.cpp @@ -0,0 +1,160 @@ +/* + mpeg player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "mpegPlugin.h" + +#include "../mpegplay/mpegVideoStream.h" +#include "../mpegplay/proto.h" +#include "../mpegplay/mpegVideoHeader.h" + +using namespace std; + + +MpegPlugin::MpegPlugin() { + init(); +} + + +MpegPlugin::~MpegPlugin() { +} + + +void MpegPlugin::init() { + lCalcLength=false; + mpegVideoHeader=NULL; + mpegVideoStream=NULL; +} + + +void MpegPlugin::decoder_loop() { + + + VideoDecoder* video=NULL; + if (input == NULL) { + cout << "MpegPlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "MpegPlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + + mpegVideoHeader=new MpegVideoHeader(); + mpegVideoStream=new MpegVideoStream(input); + + PictureArray* pictureArray; + YUVPicture* pic; + int skipMode=_SYNC_TO_NONE; + // decode loop + + while(runCheck()) { + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : + if (mpegVideoStream->firstInitialize(mpegVideoHeader)==false) { + + } else { + pluginInfo->setLength(getSongLength()); + + // now create pictureArray from the sequence + int width=mpegVideoHeader->getMB_Width()*16; + int height=mpegVideoHeader->getMB_Height()*16; + + output->openWindow(width,height,(char*)"kmpg"); + video=new VideoDecoder(mpegVideoStream,mpegVideoHeader); + setStreamState(_STREAM_STATE_INIT); + } + break; + case _STREAM_STATE_INIT : + // cout << "mpeg _STREAM_STATE_INI"<<endl; + if (skipMode==_SYNC_TO_GOP) { + if (mpegVideoStream->nextGOP()==false) { + continue; + } + video->resyncToI_Frame(); + } + if (skipMode==_SYNC_TO_PIC) { + if (mpegVideoStream->nextPIC()==false) { + continue; + } + } + skipMode=_SYNC_TO_NONE; + setStreamState(_STREAM_STATE_PLAY); + break; + case _STREAM_STATE_PLAY : + pictureArray=output->lockPictureArray(); + skipMode=video->mpegVidRsrc(pictureArray); + + if (skipMode != _SYNC_TO_NONE) { + setStreamState(_STREAM_STATE_INIT); + } + pic=pictureArray->getYUVPictureCallback(); + if (pic == NULL) { + // nothin to display + break; + } + + output->unlockPictureArray(pictureArray); + pictureArray->setYUVPictureCallback(NULL); + break; + case _STREAM_STATE_WAIT_FOR_END: + // exit while loop + lDecoderLoop=false; + break; + default: + cout << "unknown stream state:"<<streamState<<endl; + } + } + + output->flushWindow(); + // copy sequence back if needed + if (video != NULL) { + delete video; + } + delete mpegVideoStream; + delete mpegVideoHeader; + mpegVideoStream=NULL; + mpegVideoHeader=NULL; +} + + + + + +// here we can config our decoder with special flags +void MpegPlugin::config(const char* key,const char* value,void* user_data) { + if (strcmp(key,"-c")==0) { + lCalcLength=false; + } + + if (strcmp(key,"decode")==0) { + if (strcmp(value,"true")==0) { + lDecode=true; + } else { + lDecode=false; + } + } + DecoderPlugin::config(key,value,user_data); +} + + + +int MpegPlugin::getSongLength() { + int back=0; + return back; +} + + + + + + diff --git a/mpeglib/lib/decoder/mpegPlugin.h b/mpeglib/lib/decoder/mpegPlugin.h new file mode 100644 index 00000000..ff236f9b --- /dev/null +++ b/mpeglib/lib/decoder/mpegPlugin.h @@ -0,0 +1,47 @@ +/* + mpeg player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#ifndef __MPEGPLUGIN_H +#define __MPEGPLUGIN_H + +#include "../decoder/decoderPlugin.h" + + +class MpegVideoHeader; +class MpegVideoStream; + + +class MpegPlugin : public DecoderPlugin { + + int lCalcLength; + + MpegVideoHeader* mpegVideoHeader; + MpegVideoStream* mpegVideoStream; + + public: + MpegPlugin(); + ~MpegPlugin(); + + void decoder_loop(); + void config(const char* key,const char* value,void* user_data); + + + private: + void init(); + + int getSongLength(); + + +}; +#endif + diff --git a/mpeglib/lib/decoder/mpgPlugin.cpp b/mpeglib/lib/decoder/mpgPlugin.cpp new file mode 100644 index 00000000..fd7170c8 --- /dev/null +++ b/mpeglib/lib/decoder/mpgPlugin.cpp @@ -0,0 +1,260 @@ +/* + mpg I video/audio player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "mpgPlugin.h" + +#include "../mpegplay/mpegSystemStream.h" +#include "../mpgplayer/mpegStreamPlayer.h" +#include "../mpegplay/mpegVideoLength.h" + +#include "splayPlugin.h" +#include "mpegPlugin.h" + +#include <iostream> + +using namespace std; + + +MpgPlugin::MpgPlugin() { + + mpegSystemHeader=NULL; + mpegSystemStream=NULL; + mpegStreamPlayer=NULL; + mpegVideoLength=NULL; + + // make runtime config easier, no NULL check necessary + mpegSystemHeader=new MpegSystemHeader(); + timeStamp=new TimeStamp(); + lMono=false; + lDown=false; + lWriteStreams=false; + lDoLength=true; +} + + +MpgPlugin::~MpgPlugin() { + delete mpegSystemHeader; + delete timeStamp; +} + + + +void MpgPlugin::decoder_loop() { + + if (input == NULL) { + cout << "MPGPlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "MPGPlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + + // decoder + SplayPlugin* splayPlugin=new SplayPlugin(); + splayPlugin->config("-c","true",NULL); + if (lMono) { + splayPlugin->config("-m","true",NULL); + } + if (lDown) { + splayPlugin->config("-2","true",NULL); + } + + MpegPlugin* mpegplayPlugin=new MpegPlugin(); + + mpegSystemStream=new MpegSystemStream(input); + mpegStreamPlayer=new MpegStreamPlayer(input,output, + splayPlugin,mpegplayPlugin); + mpegStreamPlayer->setWriteToDisk(lWriteStreams); + mpegVideoLength=new MpegVideoLength(input); + + + int lSysLayer=false; + int lHasLength=false; + + while(runCheck()) { + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : + if ((lHasLength==false) && (lDoLength)) { + if (mpegVideoLength->firstInitialize()==false) { + continue; + } + lHasLength=true; + } + if (mpegSystemStream->firstInitialize(mpegSystemHeader)==false) { + //cout << "still initializing system stream"<<endl; + } else { + // if we have found a raw stream, + // make sure we pass as first argument a SEQ_START_CODE + if (mpegSystemHeader->getLayer() == _PACKET_SYSLAYER) { + lSysLayer=true; + mpegStreamPlayer->processSystemHeader(mpegSystemHeader); + } else { + //output->config("-s","false"); + unsigned int startCodeRaw=htonl(_SEQ_START_CODE); + mpegStreamPlayer-> + insertVideoDataRaw((unsigned char*)&startCodeRaw,4,timeStamp); + } + pluginInfo->setLength(mpegVideoLength->getLength()); + output->writeInfo(pluginInfo); + setStreamState(_STREAM_STATE_INIT); + + if (mpegSystemHeader->getMPEG2()==true) { + cout << "this plugin does not support MPEG2/VOB/DVD"<<endl; + lDecoderLoop=false; + if (lWriteStreams == true) { + cout << "demux is supported"<<endl; + lDecoderLoop=true; + + } + break; + } + + } + break; + case _STREAM_STATE_INIT : + setStreamState(_STREAM_STATE_PLAY); + break; + case _STREAM_STATE_PLAY : + // syslayer + + if (mpegSystemStream->nextPacket(mpegSystemHeader) == false) { + + break; + } + + if (mpegStreamPlayer->processSystemHeader(mpegSystemHeader) == false) { + mpegSystemStream->reset(); + setStreamState(_STREAM_STATE_INIT); + } + + break; + case _STREAM_STATE_WAIT_FOR_END: + if (mpegStreamPlayer->hasEnd()==true) { + // exit while loop + lDecoderLoop=false; + } + TimeWrapper::usleep(100000); + break; + default: + cout << "unknown stream state:"<<streamState<<endl; + } + } + + delete mpegStreamPlayer; + delete mpegSystemStream; + delete mpegVideoLength; + delete mpegplayPlugin; + delete splayPlugin; + + mpegSystemStream=NULL; + mpegStreamPlayer=NULL; + mpegVideoLength=NULL; + + + output->audioFlush(); + output->flushWindow(); + +} + + + +// here we can config our decoder with special flags +void MpgPlugin::config(const char* key,const char* value,void* user_data) { + if(strcmp("VideoLayer", key) == 0) { + int videoLayerSelect=atoi(value); + mpegSystemHeader->setVideoLayerSelect(videoLayerSelect); + } + + if(strcmp("AudioLayer", key) == 0) { + int audioLayerSelect=atoi(value); + mpegSystemHeader->setAudioLayerSelect(audioLayerSelect); + } + if (strcmp(key,"-2")==0) { + lDown=true; + } + if (strcmp(key,"-m")==0) { + lMono=true; + } + if (strcmp(key,"-c")==0) { + lDoLength=false; + } + if (strcmp(key,"-w")==0) { + if (strcmp(value,"true")==0) { + lWriteStreams=true; + } else { + lWriteStreams=true; + } + } + // now try to set it if stream is running: + shutdownLock(); + if (mpegStreamPlayer != NULL) { + mpegStreamPlayer->setWriteToDisk(lWriteStreams); + } + shutdownUnlock(); + + + DecoderPlugin::config(key,value,user_data); +} + + + + +int MpgPlugin::getTotalLength() { + shutdownLock(); + int back=0; + if (mpegVideoLength != NULL) { + back=mpegVideoLength->getLength(); + } else { + cout << "cannot report total length, plugin not initialized"<<endl; + } + shutdownUnlock(); + + return back; +} + + + + + +int MpgPlugin::processThreadCommand(Command* command) { + + int id=command->getID(); + int arg; + switch(id) { + case _COMMAND_SEEK: { + // + // mapping from second to bytePosition + // + if (mpegStreamPlayer->isInit()==false) { + command->print("MPGPLUGIN:ignore command in _STREAM_STATE_FIRST_INIT"); + } else { + arg=command->getIntArg(); + int pos=mpegVideoLength->getSeekPos(arg); + Command seek(_COMMAND_SEEK,pos); + // insert correct values + mpegStreamPlayer->processThreadCommand(&seek); + } + return _RUN_CHECK_CONTINUE; + } + + default: + // we forward the command to the mpegStreamPlayer + mpegStreamPlayer->processThreadCommand(command); + } + + // use default + return (DecoderPlugin::processThreadCommand(command)); +} + + diff --git a/mpeglib/lib/decoder/mpgPlugin.h b/mpeglib/lib/decoder/mpgPlugin.h new file mode 100644 index 00000000..79d986cc --- /dev/null +++ b/mpeglib/lib/decoder/mpgPlugin.h @@ -0,0 +1,62 @@ +/* + mpg I video/audio player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + + +#ifndef __MPGPLUGIN_H +#define __MPGPLUGIN_H + +#include "../decoder/decoderPlugin.h" +#include <kdemacros.h> + +#define _INSERT_NO 0 +#define _INSERT_VIDEO 1 +#define _INSERT_AUDIO 2 +#define _INSERT_ALL 3 + +class MpegSystemHeader; +class MpegSystemStream; +class MpegStreamPlayer; +class MpegVideoLength; + +class KDE_EXPORT MpgPlugin : public DecoderPlugin { + + MpegSystemHeader* mpegSystemHeader; + MpegSystemStream* mpegSystemStream; + MpegStreamPlayer* mpegStreamPlayer; + MpegVideoLength* mpegVideoLength; + TimeStamp* timeStamp; + int lMono; + int lDown; + int lWriteStreams; + int lDoLength; + + public: + MpgPlugin(); + ~MpgPlugin(); + + void decoder_loop(); + int getTime(int lCurrent); + + void config(const char* key,const char* value,void* user_data); + + int processThreadCommand(Command* command); + + + + protected: + int getTotalLength(); + + +}; +#endif + diff --git a/mpeglib/lib/decoder/nukePlugin.cpp b/mpeglib/lib/decoder/nukePlugin.cpp new file mode 100644 index 00000000..08c8ce89 --- /dev/null +++ b/mpeglib/lib/decoder/nukePlugin.cpp @@ -0,0 +1,62 @@ +/* + this plugin nukes the input data. + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "nukePlugin.h" + +#include <iostream> + +using namespace std; + +NukePlugin::NukePlugin() { +} + + +NukePlugin::~NukePlugin() { +} + + + +void NukePlugin::decoder_loop() { + if (input == NULL) { + cout << "NukePlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "NukePlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + char nukeBuffer[8192]; + + while(runCheck()) { + + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : + case _STREAM_STATE_INIT : + case _STREAM_STATE_PLAY : + input->read(nukeBuffer,8192); + break; + case _STREAM_STATE_WAIT_FOR_END: + // exit while loop + cout << "nukePlugin _STREAM_STATE_WAIT_FOR_END"<<endl; + lDecoderLoop=false; + break; + default: + cout << "unknown stream state:"<<streamState<<endl; + } + } +} + + +void NukePlugin::config(const char* key,const char* value,void* user_data) { + DecoderPlugin::config(key,value,user_data); +} diff --git a/mpeglib/lib/decoder/nukePlugin.h b/mpeglib/lib/decoder/nukePlugin.h new file mode 100644 index 00000000..8a9aa9a3 --- /dev/null +++ b/mpeglib/lib/decoder/nukePlugin.h @@ -0,0 +1,34 @@ +/* + this plugin nukes the input data. + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#ifndef __NUKEPLUGIN_H +#define __NUKEPLUGIN_H + + +#include "../decoder/decoderPlugin.h" +#include <kdemacros.h> + +class KDE_EXPORT NukePlugin : public DecoderPlugin { + + public: + + NukePlugin(); + ~NukePlugin(); + + void decoder_loop(); + void config(const char* key,const char* value,void* user_data); + + private: + +}; +#endif diff --git a/mpeglib/lib/decoder/splayPlugin.cpp b/mpeglib/lib/decoder/splayPlugin.cpp new file mode 100644 index 00000000..d0caa077 --- /dev/null +++ b/mpeglib/lib/decoder/splayPlugin.cpp @@ -0,0 +1,308 @@ +/* + splay player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "splayPlugin.h" +#include "../splay/mpegsound.h" + +#include "../splay/splayDecoder.h" +#include "../frame/floatFrame.h" +#include "../frame/pcmFrame.h" +#include "../splay/mpegAudioFrame.h" +#include "../splay/mpegAudioInfo.h" +#include "../input/fileAccessWrapper.h" + +#include <iostream> + +using namespace std; + +#define INPUTBUFFER_SIZE 8192 + +SplayPlugin::SplayPlugin() { + pow(6.0,3.0); // fixes bug in __math.h + doFloat = false; + lnoLength=false; + inputbuffer=new unsigned char[INPUTBUFFER_SIZE]; + pcmFrame=new PCMFrame(MP3FRAMESIZE); + floatFrame=new FloatFrame(MP3FRAMESIZE); + audioFrame=new AudioFrame(); + framer=new MpegAudioFrame(); + splay=new SplayDecoder(); + lenghtInSec=0; + + fileAccess=NULL; + info=NULL; + lOutput=true; +} + + +SplayPlugin::~SplayPlugin() { + delete [] inputbuffer; + delete pcmFrame; + delete floatFrame; + delete framer; + delete splay; + delete audioFrame; +} + + +// here we can config our decoder with special flags +void SplayPlugin::config(const char* key,const char* value,void* user_data) { + if (strcmp(key,"dofloat")==0) { + doFloat=true; + } + if (strcmp(key,"-m")==0) { + splay->config("m","0",NULL); + } + if (strcmp(key,"-2")==0) { + splay->config("2","1",NULL); + } + if (strcmp(key,"-c")==0) { + lnoLength=true; + } + if (strcmp(key,"-d")==0) { + lOutput=false; + } + + if (strcmp(key,"decode")==0) { + if (strcmp(value,"true")==0) { + lDecode=true; + } else { + lDecode=false; + } + } + DecoderPlugin::config(key,value,user_data); +} + + + +void SplayPlugin::decoder_loop() { + + if (input == NULL) { + cout << "SplayPlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "SplayPlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + // init decoder + output->audioInit(); + + // start decoding + + fileAccess=new FileAccessWrapper(input); + info= new MpegAudioInfo(fileAccess); + + + + framer->reset(); + lenghtInSec=0; + resyncCounter=0; + + AudioFrame* audioFrame=pcmFrame; + if (doFloat) { + audioFrame=floatFrame; + } + + output->audioInit(); + while(runCheck()) { + + // + // check for re-init or for "eof" + // + switch(streamState) { + case _STREAM_STATE_INIT : + framer->reset(); + resyncCounter=5; + setStreamState(_STREAM_STATE_PLAY); + continue; + case _STREAM_STATE_WAIT_FOR_END: + // exit while loop + lDecoderLoop=false; + continue; + } + if (doFrameFind() == true) { + if (splay->decode(framer->outdata(),framer->len(),audioFrame) == false){ + continue; + } + // send data out: + + int rest=framer->restBytes(); + // we have inserted more data already than the + // framer has processed. But framer tells us + // how much he still needs to process. + long pos=input->getBytePosition(); + TimeStamp* stamp=input->getTimeStamp(pos-rest); + processStreamState(stamp,audioFrame); + + + // make this stamp invalid for further synchronisation + stamp->setPTSFlag(false); + } + } + + output->audioFlush(); + + delete fileAccess; + delete info; + fileAccess=NULL; + info=NULL; + + +} + + +int SplayPlugin::doFrameFind() { + + // + // fine, we can work on the stream: + // + int back=false; + int framerState=framer->getState(); + switch(framerState) { + case FRAME_NEED: { + int bytes=framer->canStore(); + int read=input->read((char*)inputbuffer,bytes); + + if (read <= 0) { + // read error. reset framer, drop frames + setStreamState(_STREAM_STATE_INIT); + break; + } + framer->store(inputbuffer,read); + break; + } + case FRAME_WORK: + back=framer->work(); + break; + case FRAME_HAS: { + break; + } + default: + cout << "unknown state in mpeg audio framing"<<endl; + exit(0); + } + return back; +} + +void SplayPlugin::audioSetup(AudioFrame* setupFrame) { + setupFrame->copyFormat(audioFrame); + output->audioSetup(audioFrame->getFrequenceHZ(), + audioFrame->getStereo(), + audioFrame->getSigned(), + audioFrame->getBigEndian(), + audioFrame->getSampleSize()); +} + + + +void SplayPlugin::processStreamState(TimeStamp* stamp,AudioFrame* playFrame){ + + // we always have a frame here, with the correct timestamp here. + + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : + output->audioOpen(); + + audioSetup(playFrame); + + if (lnoLength==false) { + lenghtInSec=getTotalLength(); + pluginInfo->setLength(lenghtInSec); + output->writeInfo(pluginInfo); + } + + setStreamState(_STREAM_STATE_PLAY); + // yes, here is no break. + // we want to send the frame to the output. + + case _STREAM_STATE_PLAY : + if (resyncCounter > 0) { + resyncCounter--; + break; + } + if (audioFrame->isFormatEqual(playFrame)==false) { + audioSetup(playFrame); + } + if (lOutput == false) { + break; + } + if(doFloat) { + FloatFrame* floatFrame=(FloatFrame*)playFrame; + output->audioPlay(stamp,stamp, + (char*) floatFrame->getData(), + playFrame->getLen()*sizeof(float) ); + } else { + PCMFrame* pcmFrame=(PCMFrame*)playFrame; + output->audioPlay(stamp,stamp, + (char*)pcmFrame->getData(), + playFrame->getLen()*sizeof(short int)); + } + break; + default: + cout << "unknown stream state:"<<streamState<<endl; + } +} + + + +// splay can seek in streams +int SplayPlugin::seek_impl(int second) { + + + if (info != NULL) { + int pos=info->getSeekPosition(second); + input->seek(pos); + setStreamState(_STREAM_STATE_INIT); + } else { + cout << "cannot seek, plugin not initialized"<<endl; + } + return true; +} + + +int SplayPlugin::getTotalLength() { + shutdownLock(); + int back=0; + + if (info->getNeedInit()) { + long pos=input->getBytePosition(); + if (input->seek(0) == true) { + int bytes=1024; + // try reading all info, but not more + // than 1024 iterations. + info->reset(); + while(bytes>0) { + if (info->initialize()==true) { + break; + } + bytes--; + } + input->seek(pos); + } + // wheter successful or not, never touch + // the info thing again. + info->setNeedInit(false); + } + + back=info->getLength(); + + + shutdownUnlock(); + return back; +} + + + + + diff --git a/mpeglib/lib/decoder/splayPlugin.h b/mpeglib/lib/decoder/splayPlugin.h new file mode 100644 index 00000000..34a9751b --- /dev/null +++ b/mpeglib/lib/decoder/splayPlugin.h @@ -0,0 +1,67 @@ +/* + splay player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#ifndef __SPLAYPLUGIN_H +#define __SPLAYPLUGIN_H + +#include "../decoder/decoderPlugin.h" +#include <kdemacros.h> + +class SplayDecoder; +class MpegAudioFrame; +class AudioFrame; +class FloatFrame; +class PCMFrame; +class FileAccessWrapper; +class MpegAudioInfo; + +class KDE_EXPORT SplayPlugin : public DecoderPlugin { + + int lnoLength; + int lfirst; + int lOutput; + /* + * directly writes decoded data as float, instead of converting it to + * short int samples first. float->int conversions are _very_ + * time intensiv! + */ + bool doFloat; + + SplayDecoder* splay; + MpegAudioFrame* framer; + FloatFrame* floatFrame; + PCMFrame* pcmFrame; + unsigned char* inputbuffer; + int lenghtInSec; + MpegAudioInfo* info; + FileAccessWrapper* fileAccess; + int resyncCounter; + AudioFrame* audioFrame; + + + public: + SplayPlugin(); + ~SplayPlugin(); + + void decoder_loop(); + int seek_impl(int second); + void config(const char* key,const char* value,void* user_data); + + protected: + int getTotalLength(); + void processStreamState(TimeStamp* stamp,AudioFrame* audioFrame); + void audioSetup(AudioFrame* setupFrame); + int doFrameFind(); + +}; +#endif diff --git a/mpeglib/lib/decoder/tplayPlugin.cpp b/mpeglib/lib/decoder/tplayPlugin.cpp new file mode 100644 index 00000000..01c44cbc --- /dev/null +++ b/mpeglib/lib/decoder/tplayPlugin.cpp @@ -0,0 +1,264 @@ +/* + tplay player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "tplayPlugin.h" + +#include "../tplay/tplayfunctions.h" + +#include <iostream> + +using namespace std; + +TplayPlugin::TplayPlugin() { + info=new info_struct(); + + info->progname = NULL; + info->loop = FALSE; + info->in_seconds = FALSE; + info->speed = DEFAULT_SPEED; + info->bits = DEFAULT_BITS; + info->channels = DEFAULT_CHANNELS; + info->buffer_size = BUFFER_SIZE; + info->show_usage = FALSE; + info->swap = FALSE; + info->forceraw = FALSE; + info->force = FALSE; + info->device = NULL; + info->verbose = FALSE; + info->optind = 0; + info->buffer = NULL; + info->firstblock = NULL; + info->number_of_blocks = 0; + info->readblock = 0; + info->writeblock = 0; + info->readcount = 0; + info->writecount = 0; + info->alldone = FALSE; + info->overflow = FALSE; + info->underflow = FALSE; + info->audioset = FALSE; + info->headerskip = 0; + info->blocksize = 4096; + info->bytes_on_last_block = 0; + + startStamp=new TimeStamp(); + endStamp=new TimeStamp(); +} + + +TplayPlugin::~TplayPlugin() { + delete startStamp; + delete endStamp; + delete info; +} + + + +void TplayPlugin::decoder_loop() { + int bytesread, count, stereo; + char *p, *bufferp; + + if (input == NULL) { + cout << "TplayPlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "TplayPlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + + TimeStamp* stamp; + long pos; + + info->buffer = (char*) malloc(info->buffer_size * sizeof(char)); + + while(runCheck()) { + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : { + read_header(); + + if (info->channels == 1) + stereo = FALSE; + else + stereo = TRUE; + + info->number_of_blocks = 0; + bufferp = info->buffer; + pluginInfo->setLength(getTotalLength()); + output->writeInfo(pluginInfo); + lhasLength=true; + + setStreamState(_STREAM_STATE_INIT); + break; + } + case _STREAM_STATE_INIT : + setStreamState(_STREAM_STATE_PLAY); + cout << "audioSetup call"<<endl; + output->audioOpen(); + output->audioSetup(info->speed, stereo, 1, 0, info->bits); + break; + case _STREAM_STATE_PLAY : + bytesread = 0; + count = 0; + p = bufferp; + while ((bytesread < info->blocksize) && (count != -1) && + ((count = input->read(p,info->blocksize-bytesread))!=0)){ + p += count; + bytesread += count; + } + if (info->swap) { + swap_block(bufferp, bytesread); + } + + if (bytesread > 0) { + pos=input->getBytePosition(); + stamp=input->getTimeStamp(pos-bytesread); + output->audioPlay(stamp,endStamp,(char *) bufferp, bytesread); + } + + if (bytesread < info->blocksize) { + info->alldone = TRUE; + + } + break; + case _STREAM_STATE_WAIT_FOR_END: + // exit while loop + lDecoderLoop=false; + break; + default: + cout << "unknown stream state:"<<streamState<<endl; + } + } + cout << "tplay exit"<<endl; + free(info->buffer); + info->buffer = NULL; + output->audioFlush(); +} + + +int TplayPlugin::seek_impl(int second) { + int bytes_per_second; + int seconds; + int back; + + + bytes_per_second = info->speed * info->channels * (info->bits / 8); + + + + seconds = bytes_per_second * second; + back=input->seek(seconds); + + return back; +} + + +void TplayPlugin::config(const char* key,const char* value,void* user_data) { + DecoderPlugin::config(key,value,user_data); +} + + +void TplayPlugin::swap_block(char * buffer, int blocksize) { + register int i; + char c, *p; + + p = buffer; + for (i = 0; i < (blocksize / 2); i++) { + c = *p; + *p = *(p + 1); + *++p = c; + p++; + } +} + + +void TplayPlugin::read_header() { + int bytesread, count; + char *p, *bufferp; + + info->firstblock = (char*) malloc(info->blocksize * sizeof(char)); + bufferp = info->firstblock; + if (!info->forceraw) { + bytesread = 0; + count = 0; + p = bufferp; + while ((bytesread < info->blocksize) && (count != -1) && + ((count=input->read(p,info->blocksize-bytesread)) != 0)){ + p += count; + bytesread += count; + } + + if (bytesread < SUN_HDRSIZE) + cout << "Sample size is too small"<<endl; + + if (read_au(info,info->firstblock) && read_wav(info,info->firstblock)) { + if (info->verbose) + printf("Playing raw data: %ld samples/s, %d bits, %d channels.\n", + info->speed, info->bits, info->channels); + } + + if (info->swap) + swap_block(bufferp, bytesread); + + if (bytesread < info->blocksize) { + info->alldone = TRUE; + info->bytes_on_last_block = bytesread; + return; + } + + if (info->headerskip) { + count = 0; + bytesread = info->blocksize - info->headerskip; + p = info->firstblock + (info->blocksize - info->headerskip); + while ((bytesread < info->blocksize) && (count != -1) && + ((count = input->read(p,info->blocksize - bytesread)) != 0)) { + p += count; + bytesread += count; + } + } + + info->writeblock++; + info->writecount++; + } + else { + if (info->verbose) + printf("Playing raw data: %ld samples/s, %d bits, %d channels\n", + info->speed, info->bits, info->channels); + } +} + +/** + Nobody is perfect I'm too tired to fix this race +*/ + +int TplayPlugin::getTotalLength() { + float wavfilesize = input->getByteLength(); + int back=0; + + + float frequence=info->speed; + + int bits=info->bits; + + + if (bits == 16) { + wavfilesize=wavfilesize/2; + } + if (info->channels==2) { + wavfilesize=wavfilesize/2; + } + if (frequence != 0) { + back=(int)(wavfilesize/frequence); + } + return back; +} diff --git a/mpeglib/lib/decoder/tplayPlugin.h b/mpeglib/lib/decoder/tplayPlugin.h new file mode 100644 index 00000000..daa0de74 --- /dev/null +++ b/mpeglib/lib/decoder/tplayPlugin.h @@ -0,0 +1,47 @@ +/* + tplay player plugin + Copyright (C) 1999 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Library General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#ifndef __TPLAYPLUGIN_H +#define __TPLAYPLUGIN_H + +#include "../decoder/decoderPlugin.h" +#include <kdemacros.h> +/** + The tplayPlugin is ugly and needs a rewrite. + Im not sure if you can make mutiple instances of it +*/ + +class KDE_EXPORT TplayPlugin : public DecoderPlugin { + + struct info_struct* info; + class TimeStamp* startStamp; + class TimeStamp* endStamp; + + public: + TplayPlugin(); + ~TplayPlugin(); + + void decoder_loop(); + int seek_impl(int second); + void config(const char* key,const char* value,void* user_data); + + protected: + int getTotalLength(); + + private: + void swap_block(char* buffer, int blocksize); + void read_header(); + + +}; +#endif diff --git a/mpeglib/lib/decoder/vorbisPlugin.cpp b/mpeglib/lib/decoder/vorbisPlugin.cpp new file mode 100644 index 00000000..b32ba93f --- /dev/null +++ b/mpeglib/lib/decoder/vorbisPlugin.cpp @@ -0,0 +1,305 @@ +/* + vorbis player plugin + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#include "vorbisPlugin.h" + +#include <iostream> + +using namespace std; + +#ifdef OGG_VORBIS + +size_t fread_func(void *ptr, size_t size, size_t nmemb, void *stream) { + InputStream* input=((VorbisPlugin*)stream)->getInputStream(); + int bytes=input->read((char*)ptr,size*nmemb); + // workaround for RC3, report success during seek + /* + if (((VorbisPlugin*)stream)->vorbis_seek_bug_active == true) { + errno=0; + return 0; + } + */ + // error on read and no "seek workaround" + if (bytes == 0) { + // + // If different thread close the input we signal + // a read error to vorbis + // + if (input->isOpen() == false) { + // note: errno is in this thread another variable, than in + // the thread which closed the file. + // here we "fake" the errno var. + errno=EBADF; + return 0; + } + } + // successful read + return bytes; +} + + +int fseek_func(void *stream, ogg_int64_t offset, int whence) { + int ret=-1; + InputStream* input=((VorbisPlugin*)stream)->getInputStream(); + + switch(whence) { + case SEEK_SET: + ret=input->seek(offset); + break; + case SEEK_CUR: + ret=input->seek(input->getBytePosition()+offset); + break; + case SEEK_END: + ret=input->seek(input->getByteLength()); + break; + default: + cout << "fseek_func VorbisPlugn strange call"<<endl; + } + + if (ret == false) { + // vorbis does not handle errors in seek at all + // and if they are handled vorbis segfaults. (RC3) + // here we always "success" but set an seek_error_mark + // + ret=-1; + } + + return ret; + +} + + +int fclose_func (void *) { + //InputStream* input=(InputStream*) stream; + + // its handled different in kmpg + // we close the stream if the decoder signals eof. + return true; + +} + + +long ftell_func (void *stream) { + InputStream* input=((VorbisPlugin*)stream)->getInputStream(); + return input->getBytePosition(); +} + + +VorbisPlugin::VorbisPlugin() { + + + memset(&vf, 0, sizeof(vf)); + timeDummy=new TimeStamp(); + pcmout=new char[4096]; + lnoLength=false; + lshutdown=true; + +} + + +VorbisPlugin::~VorbisPlugin() { + delete timeDummy; + delete pcmout; +} + + +// here we can config our decoder with special flags +void VorbisPlugin::config(const char* key,const char* value,void* user_data) { + + if (strcmp(key,"-c")==0) { + lnoLength=true; + } + DecoderPlugin::config(key,value,user_data); +} + + +int VorbisPlugin::init() { + ov_callbacks callbacks; + + callbacks.read_func = fread_func; + callbacks.seek_func = fseek_func; + callbacks.close_func = fclose_func; + callbacks.tell_func = ftell_func; + + // here is the hack to pass the pointer to + // our streaming interface. + + if(ov_open_callbacks(this, &vf, NULL, 0, callbacks) < 0) { + return false; + } + + return true; +} + + +// called by decoder thread +int VorbisPlugin::processVorbis(vorbis_info* vi,vorbis_comment* comment) { + + // decode + int ret; + int current_section=-1; /* A vorbis physical bitstream may + consist of many logical sections + (information for each of which may be + fetched from the vf structure). This + value is filled in by ov_read to alert + us what section we're currently + decoding in case we need to change + playback settings at a section + boundary */ + ret=ov_read(&vf,pcmout,4096,0,2,1,¤t_section); + switch(ret){ + case 0: + /* EOF */ + lDecoderLoop=false; + break; + case -1: + /* error in the stream. Not a problem, just reporting it in + case we (the app) cares. In this case, we don't. */ + cout << "error found"<<endl; + break; + default: + if(current_section!=last_section){ + vi=ov_info(&vf,-1); /* The info struct is different in each + section. vf holds them all for the + given bitstream. This requests the + current one */ + + double timeoffset=ov_time_tell(&vf); + + comment = ov_comment(&vf, -1); + if(comment) { + cout << "we have a comment:"<<timeoffset<<endl; + } + } + last_section=current_section; + output->audioPlay(timeDummy,timeDummy,pcmout,ret); + break; + } + return true; +} + + +void VorbisPlugin::decoder_loop() { + vorbis_info *vi=NULL; + vorbis_comment *comment=NULL; + last_section=0; + current_section=0; + + + + if (input == NULL) { + cout << "VorbisPlugin::decoder_loop input is NULL"<<endl; + exit(0); + } + if (output == NULL) { + cout << "VorbisPlugin::decoder_loop output is NULL"<<endl; + exit(0); + } + // init audio stream + output->audioInit(); + + /********** Decode setup ************/ + // start decoding + lshutdown=false; + /** + Vorbis RC3 introducted a new bug: + seek on a closed stream segfaults vorbis. + The bugfix in vorbis is (RC3) around line 1190 should be: + seek_error: + // the caller of this goto may not set a return code + ret=OV_ENOSEEK; + The workaround is to check if we are in a seek operation + and always "fake" successful reads. + */ + vorbis_seek_bug_active=false; + + + while(runCheck()) { + + switch(streamState) { + case _STREAM_STATE_FIRST_INIT : + if (init()== false) { + // total failure. exit decoding + lDecoderLoop=false; + break; + } + // now init stream + vi=ov_info(&vf,-1); + if (lnoLength==false) { + pluginInfo->setLength(getTotalLength()); + output->writeInfo(pluginInfo); + } + output->audioOpen(); + output->audioSetup(vi->rate,vi->channels-1,1,0,16); + + + lhasLength=true; + setStreamState(_STREAM_STATE_PLAY); + break; + case _STREAM_STATE_INIT : + case _STREAM_STATE_PLAY : + processVorbis(vi,comment); + break; + case _STREAM_STATE_WAIT_FOR_END: + // exit while loop + lDecoderLoop=false; + usleep(2000000); + break; + default: + cout << "unknown stream state vorbis decoder:"<<streamState<<endl; + } + + } + + lshutdown=true; + ov_clear(&vf); /* ov_clear closes the stream if its open. Safe to + call on an uninitialized structure as long as + we've zeroed it */ + memset(&vf, 0, sizeof(vf)); + + output->audioFlush(); +} + +// vorbis can seek in streams +int VorbisPlugin::seek_impl(int second) { + vorbis_seek_bug_active=true; + ov_time_seek(&vf,(double) second); + vorbis_seek_bug_active=false; + return true; +} + + + +int VorbisPlugin::getTotalLength() { + int back=0; + int byteLen=input->getByteLength(); + if (byteLen == 0) { + return 0; + } + /* Retrieve the length in second*/ + shutdownLock(); + if (lshutdown==false) { + back = (int) ov_time_total(&vf, -1); + } + shutdownUnlock(); + + return back; +} + + + + +#endif +//OGG_VORBIS + + diff --git a/mpeglib/lib/decoder/vorbisPlugin.h b/mpeglib/lib/decoder/vorbisPlugin.h new file mode 100644 index 00000000..b680ed69 --- /dev/null +++ b/mpeglib/lib/decoder/vorbisPlugin.h @@ -0,0 +1,87 @@ +/* + vorbis player plugin + Copyright (C) 2000 Martin Vogt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation. + + For more information look at the file COPYRIGHT in this package + + */ + + +#ifndef __VORBISPLUGIN_H +#define __VORBISPLUGIN_H + +#include "nukePlugin.h" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <math.h> + +#ifndef OGG_VORBIS +class VorbisPlugin : public NukePlugin { +}; +#else + + +#include <vorbis/codec.h> +#include <vorbis/vorbisfile.h> + +/** + callbacks from vorbisfile +*/ +extern "C" { + +extern size_t fread_func (void *ptr,size_t size,size_t nmemb, void *stream); +extern int fseek_func (void *stream, ogg_int64_t offset, int whence); +extern int fclose_func (void *stream); +extern long ftell_func (void *stream); + +} + + +class VorbisPlugin : public DecoderPlugin { + + OggVorbis_File vf; + + + // END vorbis setup + + + int lnoLength; + int lAutoPlay; + TimeStamp* timeDummy; + char* pcmout; // temporay pcm buffer + int last_section; + int current_section; + int lshutdown; + + public: + VorbisPlugin(); + ~VorbisPlugin(); + + void decoder_loop(); + int seek_impl(int second); + void config(const char* key,const char* value,void* user_data); + + // vorbis bug workaround [START] + int vorbis_seek_bug_active; + ::InputStream* getInputStream() { return input; } + // vorbis bug workaround [END] + + private: + int processVorbis(vorbis_info* vi,vorbis_comment* comment); + int getTotalLength(); + int init(); + +}; + +#endif +//OGG_VORBIS + +#endif |